📜  如何在Java对LinkedList进行排序?

📅  最后修改于: 2021-05-06 23:50:34             🧑  作者: Mango

链表是一个线性数据结构,其中的元素是不能存储在连续的存储单元。

按升序对单链接列表的节点进行排序:

原始清单

原始清单

SortedList

排序清单

我们可以通过许多排序技术对LinkedList进行排序:

  1. 气泡排序
  2. 插入排序
  3. 快速分类
  4. 合并排序

方法1:使用冒泡排序进行排序

  • 为了完成此任务,我们维护两个指针:current和index。
  • 最初,当前指向头节点,索引将指向当前旁边的节点。
  • 通过将当前数据与索引数据进行比较,遍历列表直到当前指向null。
  • 对于每个当前值,索引是当前节点的下一个节点,它从当前的下一个节点开始遍历直到为空。
  • 然后,将当前节点的值与从其下一个节点到最后一个节点的每个值进行比较,如果该值小于当前值,则将交换这些值,并以这种方式将最小值作为当前索引。
Java
// Java program to sort a Linked List using Bubble Sort
  
public class SortList {
  
    // Represent a node of the singly linked list
    class Node {
        int data;
        Node next;
  
        public Node(int data)
        {
            this.data = data;
            this.next = null;
        }
    }
  
    // Represent the head and tail of the singly linked list
    public Node head = null;
    public Node tail = null;
  
    // addNode() will add a new node to the list
    public void addNode(int data)
    {
  
        // Create a new node
        Node newNode = new Node(data);
  
        // Checks if the list is empty
        if (head == null) {
  
            // If list is empty, both head and tail will
            // point to new node
            head = newNode;
            tail = newNode;
        }
        else {
  
            // newNode will be added after tail such that
            // tail's next will point to newNode
            tail.next = newNode;
  
            // newNode will become new tail of the list
            tail = newNode;
        }
    }
  
    // sortList() will sort nodes of the list in ascending
    // order
    public void sortList()
    {
  
        // Node current will point to head
        Node current = head, index = null;
  
        int temp;
  
        if (head == null) {
            return;
        }
        else {
            while (current != null) {
                // Node index will point to node next to
                // current
                index = current.next;
  
                while (index != null) {
                    // If current node's data is greater
                    // than index's node data, swap the data
                    // between them
                    if (current.data > index.data) {
                        temp = current.data;
                        current.data = index.data;
                        index.data = temp;
                    }
  
                    index = index.next;
                }
                current = current.next;
            }
        }
    }
  
    // display() will display all the nodes present in the
    // list
    public void display()
    {
        // Node current will point to head
        Node current = head;
  
        if (head == null) {
            System.out.println("List is empty");
            return;
        }
        while (current != null) {
            // Prints each node by incrementing pointer
            System.out.print(current.data + " ");
            current = current.next;
        }
  
        System.out.println();
    }
  
    public static void main(String[] args)
    {
  
        SortList sList = new SortList();
  
        // Adds data to the list
        sList.addNode(8);
        sList.addNode(3);
        sList.addNode(7);
        sList.addNode(4);
  
        // Displaying original list
        System.out.println("Original list: ");
        sList.display();
  
        // Sorting list
        sList.sortList();
  
        // Displaying sorted list
        System.out.println("Sorted list: ");
        sList.display();
    }
}


Java
// Java program to sort Linked List using Insertion Sort 
  
public class LinkedlistIS 
{ 
    node head; 
    node sorted; 
  
    class node 
    { 
        int val; 
        node next; 
  
        public node(int val) 
        { 
            this.val = val; 
        } 
    } 
  
    void push(int val) 
    { 
        // allocate node 
        node newnode = new node(val);
        
        // link the old list off the new node 
        newnode.next = head; 
        
        // move the head to point to the new node 
        head = newnode; 
    } 
  
    // function to sort a singly linked list using insertion sort 
    void insertionSort(node headref) 
    { 
        // Initialize sorted linked list 
        sorted = null; 
        node current = headref; 
        
        // Traverse the given linked list and insert every 
        // node to sorted 
        while (current != null) 
        { 
            // Store next for next iteration 
            node next = current.next; 
            
            // insert current in sorted linked list 
            sortedInsert(current); 
            
            // Update current 
            current = next; 
        } 
        
        // Update head_ref to point to sorted linked list 
        head = sorted; 
    } 
  
      
    // function to insert a new_node in a list. Note that 
    // this function expects a pointer to head_ref as this 
    // can modify the head of the input linked list 
    // (similar to push()) 
    void sortedInsert(node newnode) 
    { 
        // Special case for the head end 
        if (sorted == null || sorted.val >= newnode.val) 
        { 
            newnode.next = sorted; 
            sorted = newnode; 
        } 
        else
        { 
            node current = sorted; 
            
            // Locate the node before the point of insertion 
            while (current.next != null && current.next.val < newnode.val) 
            { 
                current = current.next; 
            } 
            
            newnode.next = current.next; 
            current.next = newnode; 
        } 
    } 
  
    // Function to print linked list 
    void printlist(node head) 
    { 
        while (head != null) 
        { 
            System.out.print(head.val + " "); 
            head = head.next; 
        } 
    } 
      
    // Driver program to test above functions 
    public static void main(String[] args) 
    { 
        LinkedlistIS list = new LinkedlistIS(); 
        
        list.push(4); 
        list.push(7); 
        list.push(3); 
        list.push(8); 
        
        System.out.println("Linked List before Sorting.."); 
        list.printlist(list.head); 
        
        list.insertionSort(list.head); 
        
        System.out.println("\nLinkedList After sorting"); 
        list.printlist(list.head); 
    } 
}


Java
// Java program for Quick Sort on Singly Linked List 
    
public class QuickSortLinkedList  
{ 
static class Node 
{ 
    int data; 
    Node next; 
    
    Node(int d) 
    { 
        this.data = d; 
        this.next= null; 
    } 
} 
    
Node head; 
    
void addNode(int data) 
{ 
    if(head == null) 
    { 
        head = new Node(data); 
        return; 
    } 
    
    Node curr = head; 
    
    while(curr.next != null) 
        curr = curr.next; 
    
    Node newNode = new Node(data); 
    curr.next = newNode; 
} 
    
void printList(Node n) 
{ 
    while(n != null) 
    { 
        System.out.print(n.data); 
        System.out.print(" "); 
        n = n.next; 
    } 
} 
    
// takes first and last node, 
// but do not break any links in  
// the whole linked list 
Node paritionLast(Node start, Node end) 
{ 
    if(start == end ||  
       start == null || end == null)
        
        return start; 
    
    Node pivot_prev = start; 
    Node curr = start;  
    int pivot = end.data;  
        
    // iterate till one before the end,  
    // no need to iterate till the end  
    // because end is pivot 
    while(start != end ) 
    { 
        if(start.data < pivot) 
        {  
            // keep tracks of last modified item 
            pivot_prev = curr;  
            int temp = curr.data;  
            curr.data = start.data;  
            start.data = temp;  
            curr = curr.next;  
        } 
        
        start = start.next;  
    } 
        
    // swap the position of curr i.e. 
    // next suitable index and pivot 
    int temp = curr.data;  
    curr.data = pivot;  
    end.data = temp;  
    
    // return one previous to current 
    // because current is now pointing to pivot 
    return pivot_prev; 
} 
    
void sort(Node start, Node end) 
{ 
    if(start == end ) 
        return; 
            
    // split list and partion recurse 
    Node pivot_prev = paritionLast(start, end); 
    
    sort(start, pivot_prev); 
        
    // if pivot is picked and moved to the start, 
    // that means start and pivot is same  
    // so pick from next of pivot 
    if( pivot_prev != null &&  
        pivot_prev == start ) 
        sort(pivot_prev.next, end); 
            
    // if pivot is in between of the list, 
    // start from next of pivot,  
    // since we have pivot_prev, so we move two nodes 
    else if(pivot_prev != null &&  
            pivot_prev.next != null) 
        sort(pivot_prev.next.next, end); 
} 
    
// Driver Code 
public static void main(String[] args) 
{ 
    QuickSortLinkedList list = new QuickSortLinkedList(); 
    
    list.addNode(8); 
    list.addNode(3); 
    list.addNode(7); 
    list.addNode(4); 
    
    Node n = list.head; 
    
    while(n.next != null) 
        n= n.next; 
    
    System.out.println("Original List: "); 
    list.printList(list.head); 
    
    list.sort(list.head , n); 
    
    System.out.println("\nSorted List: "); 
    list.printList(list.head); 
} 
}


Java
// Java program to sort linkedList using Merge Sort
  
public class linkedList 
{ 
    node head = null; 
    
    // node a, b; 
    static class node { 
        int val; 
        node next; 
  
        public node(int val) 
        { 
            this.val = val; 
        } 
    } 
  
    node sortedMerge(node a, node b) 
    { 
        node result = null; 
        
        // Base cases 
        if (a == null) 
            return b; 
        if (b == null) 
            return a; 
  
        // Pick either a or b, and recur 
        if (a.val < b.val)
        { 
            result = a; 
            result.next = sortedMerge(a.next, b); 
        } 
        else
        { 
            result = b; 
            result.next = sortedMerge(a, b.next); 
        } 
        
        return result; 
    } 
  
    node mergeSort(node h) 
    { 
        // Base case : if head is null 
        if (h == null || h.next == null)
        { 
            return h; 
        } 
  
        // get the middle of the list 
        node middle = getMiddle(h); 
        node nextofmiddle = middle.next; 
  
        // set the next of middle node to null 
        middle.next = null; 
  
        // Apply mergeSort on left list 
        node left = mergeSort(h); 
  
        // Apply mergeSort on right list 
        node right = mergeSort(nextofmiddle); 
  
        // Merge the left and right lists 
        node sortedlist = sortedMerge(left, right); 
        
        return sortedlist; 
    } 
  
    // Utility function to get the middle of the linked list 
    public static node getMiddle(node head) 
    { 
        if (head == null) 
            return head; 
  
        node slow = head, fast = head; 
  
        while (fast.next != null && fast.next.next != null)
        { 
            slow = slow.next; 
            fast = fast.next.next; 
        } 
        
        return slow; 
    } 
  
    void push(int new_data) 
    { 
        // allocate node 
        node new_node = new node(new_data); 
  
        // link the old list off the new node 
        new_node.next = head; 
  
        // move the head to point to the new node 
        head = new_node; 
    } 
  
    // Utility function to print the linked list 
    void printList(node headref) 
    { 
        while (headref != null) { 
            System.out.print(headref.val + " "); 
            headref = headref.next; 
        } 
    } 
  
    public static void main(String[] args) 
    { 
  
        linkedList li = new linkedList(); 
           
        li.push(4);
          li.push(7);    
          li.push(3);
          li.push(8); 
            
          System.out.print("\nOriginal List: \n");
        li.printList(li.head);
        
        // Apply merge Sort 
        li.head = li.mergeSort(li.head); 
        
        System.out.print("\nSorted List: \n"); 
        li.printList(li.head); 
    } 
}


输出
Original list: 
8 3 7 4 
Sorted list: 
3 4 7 8

时间复杂度: O(n ^ 2)

空间复杂度: O(1)

方法2:使用插入排序进行排序

  • 在插入排序技术中,我们假定列表中当前元素之前的所有元素均已排序,并且我们从当前元素开始。
  • 将当前元素与其之前的所有元素进行比较,如果不按顺序交换,则将其交换。对所有后续元素重复此过程。
  • 通常,插入排序技术会将每个元素与其所有先前的元素进行比较,并对元素进行排序以将其放置在适当的位置。

如前所述,插入排序技术对于较小的数据集更可行,因此可以使用有效的插入排序对具有少量元素的数组进行排序。

插入排序在对链表数据结构进行排序时特别有用。如您所知,链接列表的指针指向其下一个元素(单链接列表)和上一个元素(双链接列表)。这样可以更轻松地跟踪上一个和下一个元素。

Java

// Java program to sort Linked List using Insertion Sort 
  
public class LinkedlistIS 
{ 
    node head; 
    node sorted; 
  
    class node 
    { 
        int val; 
        node next; 
  
        public node(int val) 
        { 
            this.val = val; 
        } 
    } 
  
    void push(int val) 
    { 
        // allocate node 
        node newnode = new node(val);
        
        // link the old list off the new node 
        newnode.next = head; 
        
        // move the head to point to the new node 
        head = newnode; 
    } 
  
    // function to sort a singly linked list using insertion sort 
    void insertionSort(node headref) 
    { 
        // Initialize sorted linked list 
        sorted = null; 
        node current = headref; 
        
        // Traverse the given linked list and insert every 
        // node to sorted 
        while (current != null) 
        { 
            // Store next for next iteration 
            node next = current.next; 
            
            // insert current in sorted linked list 
            sortedInsert(current); 
            
            // Update current 
            current = next; 
        } 
        
        // Update head_ref to point to sorted linked list 
        head = sorted; 
    } 
  
      
    // function to insert a new_node in a list. Note that 
    // this function expects a pointer to head_ref as this 
    // can modify the head of the input linked list 
    // (similar to push()) 
    void sortedInsert(node newnode) 
    { 
        // Special case for the head end 
        if (sorted == null || sorted.val >= newnode.val) 
        { 
            newnode.next = sorted; 
            sorted = newnode; 
        } 
        else
        { 
            node current = sorted; 
            
            // Locate the node before the point of insertion 
            while (current.next != null && current.next.val < newnode.val) 
            { 
                current = current.next; 
            } 
            
            newnode.next = current.next; 
            current.next = newnode; 
        } 
    } 
  
    // Function to print linked list 
    void printlist(node head) 
    { 
        while (head != null) 
        { 
            System.out.print(head.val + " "); 
            head = head.next; 
        } 
    } 
      
    // Driver program to test above functions 
    public static void main(String[] args) 
    { 
        LinkedlistIS list = new LinkedlistIS(); 
        
        list.push(4); 
        list.push(7); 
        list.push(3); 
        list.push(8); 
        
        System.out.println("Linked List before Sorting.."); 
        list.printlist(list.head); 
        
        list.insertionSort(list.head); 
        
        System.out.println("\nLinkedList After sorting"); 
        list.printlist(list.head); 
    } 
} 
输出
Linked List before Sorting..
8 3 7 4 
LinkedList After sorting
3 4 7 8

时间复杂度: O(n ^ 2)

空间复杂度: O(1)

方法3:使用快速排序进行排序

快速分类遵循分而治之的方法。它选择一个元素作为枢轴,并围绕拾取的枢轴对给定的数组进行分区。

quickSort中的关键过程是partition()。分区的目标是,给定一个数组和一个数组元素x作为枢轴,将x放在排序数组中的正确位置,并将所有较小的元素(小于x)放在x之前,并将所有较大的元素(大于x)放在之后X。所有这些都应在线性时间内完成。

快速排序优先于合并排序,因为快速排序是一种就地算法(意味着不需要额外的存储空间)。

Java

// Java program for Quick Sort on Singly Linked List 
    
public class QuickSortLinkedList  
{ 
static class Node 
{ 
    int data; 
    Node next; 
    
    Node(int d) 
    { 
        this.data = d; 
        this.next= null; 
    } 
} 
    
Node head; 
    
void addNode(int data) 
{ 
    if(head == null) 
    { 
        head = new Node(data); 
        return; 
    } 
    
    Node curr = head; 
    
    while(curr.next != null) 
        curr = curr.next; 
    
    Node newNode = new Node(data); 
    curr.next = newNode; 
} 
    
void printList(Node n) 
{ 
    while(n != null) 
    { 
        System.out.print(n.data); 
        System.out.print(" "); 
        n = n.next; 
    } 
} 
    
// takes first and last node, 
// but do not break any links in  
// the whole linked list 
Node paritionLast(Node start, Node end) 
{ 
    if(start == end ||  
       start == null || end == null)
        
        return start; 
    
    Node pivot_prev = start; 
    Node curr = start;  
    int pivot = end.data;  
        
    // iterate till one before the end,  
    // no need to iterate till the end  
    // because end is pivot 
    while(start != end ) 
    { 
        if(start.data < pivot) 
        {  
            // keep tracks of last modified item 
            pivot_prev = curr;  
            int temp = curr.data;  
            curr.data = start.data;  
            start.data = temp;  
            curr = curr.next;  
        } 
        
        start = start.next;  
    } 
        
    // swap the position of curr i.e. 
    // next suitable index and pivot 
    int temp = curr.data;  
    curr.data = pivot;  
    end.data = temp;  
    
    // return one previous to current 
    // because current is now pointing to pivot 
    return pivot_prev; 
} 
    
void sort(Node start, Node end) 
{ 
    if(start == end ) 
        return; 
            
    // split list and partion recurse 
    Node pivot_prev = paritionLast(start, end); 
    
    sort(start, pivot_prev); 
        
    // if pivot is picked and moved to the start, 
    // that means start and pivot is same  
    // so pick from next of pivot 
    if( pivot_prev != null &&  
        pivot_prev == start ) 
        sort(pivot_prev.next, end); 
            
    // if pivot is in between of the list, 
    // start from next of pivot,  
    // since we have pivot_prev, so we move two nodes 
    else if(pivot_prev != null &&  
            pivot_prev.next != null) 
        sort(pivot_prev.next.next, end); 
} 
    
// Driver Code 
public static void main(String[] args) 
{ 
    QuickSortLinkedList list = new QuickSortLinkedList(); 
    
    list.addNode(8); 
    list.addNode(3); 
    list.addNode(7); 
    list.addNode(4); 
    
    Node n = list.head; 
    
    while(n.next != null) 
        n= n.next; 
    
    System.out.println("Original List: "); 
    list.printList(list.head); 
    
    list.sort(list.head , n); 
    
    System.out.println("\nSorted List: "); 
    list.printList(list.head); 
} 
}
输出
Original List: 
8 3 7 4 
Sorted List: 
3 4 7 8

时间复杂度: O(n ^ 2)

空间复杂度: O(1)

方法3:使用合并排序

合并排序通常是对链表进行排序的首选。链表的随机访问性能较慢,使得其他一些算法(例如quicksort)的性能较差,而其他算法(例如堆排序)则完全不可能。

合并排序是一种分而治之算法。它将输入数组分为两个半部分,将自身称为两个半部分,然后合并两个已排序的半个部分。 merge()函数用于合并两个半部分。 merge(arr,l,m,r)是一个关键过程,假定对arr [l..m]和arr [m + 1..r]进行排序并将两个排序后的子数组合并为一个。

  • 令head是要排序的链表的第一个节点,而headRef是指向head的指针。
  • 请注意,我们需要在MergeSort()中引用head,因为以下实现会更改下一个链接以对链接列表进行排序(而不是节点上的数据),因此,如果原始head上的数据不是最小值,则必须更改head节点。在链接列表中。

Java

// Java program to sort linkedList using Merge Sort
  
public class linkedList 
{ 
    node head = null; 
    
    // node a, b; 
    static class node { 
        int val; 
        node next; 
  
        public node(int val) 
        { 
            this.val = val; 
        } 
    } 
  
    node sortedMerge(node a, node b) 
    { 
        node result = null; 
        
        // Base cases 
        if (a == null) 
            return b; 
        if (b == null) 
            return a; 
  
        // Pick either a or b, and recur 
        if (a.val < b.val)
        { 
            result = a; 
            result.next = sortedMerge(a.next, b); 
        } 
        else
        { 
            result = b; 
            result.next = sortedMerge(a, b.next); 
        } 
        
        return result; 
    } 
  
    node mergeSort(node h) 
    { 
        // Base case : if head is null 
        if (h == null || h.next == null)
        { 
            return h; 
        } 
  
        // get the middle of the list 
        node middle = getMiddle(h); 
        node nextofmiddle = middle.next; 
  
        // set the next of middle node to null 
        middle.next = null; 
  
        // Apply mergeSort on left list 
        node left = mergeSort(h); 
  
        // Apply mergeSort on right list 
        node right = mergeSort(nextofmiddle); 
  
        // Merge the left and right lists 
        node sortedlist = sortedMerge(left, right); 
        
        return sortedlist; 
    } 
  
    // Utility function to get the middle of the linked list 
    public static node getMiddle(node head) 
    { 
        if (head == null) 
            return head; 
  
        node slow = head, fast = head; 
  
        while (fast.next != null && fast.next.next != null)
        { 
            slow = slow.next; 
            fast = fast.next.next; 
        } 
        
        return slow; 
    } 
  
    void push(int new_data) 
    { 
        // allocate node 
        node new_node = new node(new_data); 
  
        // link the old list off the new node 
        new_node.next = head; 
  
        // move the head to point to the new node 
        head = new_node; 
    } 
  
    // Utility function to print the linked list 
    void printList(node headref) 
    { 
        while (headref != null) { 
            System.out.print(headref.val + " "); 
            headref = headref.next; 
        } 
    } 
  
    public static void main(String[] args) 
    { 
  
        linkedList li = new linkedList(); 
           
        li.push(4);
          li.push(7);    
          li.push(3);
          li.push(8); 
            
          System.out.print("\nOriginal List: \n");
        li.printList(li.head);
        
        // Apply merge Sort 
        li.head = li.mergeSort(li.head); 
        
        System.out.print("\nSorted List: \n"); 
        li.printList(li.head); 
    } 
} 
输出
Original List: 
8 3 7 4 
Sorted List: 
3 4 7 8

时间复杂度: O(n log n)

空间复杂度: O(1)