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

📅  最后修改于: 2021-09-06 17:47:16             🧑  作者: Mango

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

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

原始列表

原始列表

排序列表

排序列表

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

  1. 冒泡排序
  2. 插入排序
  3. 快速排序
  4. 归并排序

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

  • 为了完成这个任务,我们维护了两个指针:current 和 index。
  • 最初,当前指向头节点,索引将指向当前旁边的节点。
  • 通过比较当前的数据和索引的数据,遍历列表直到当前指向空。
  • 对于每个当前的值,索引是当前节点的下一个,从当前的下一个节点遍历到空。
  • 然后将当前节点的值与其下一个节点到最后一个节点的每个值进行比较,如果该值小于当前值,则交换这些值,这样最小值作为当前索引。
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:使用归并排序进行排序

合并排序通常用于对链表进行排序。链表缓慢的随机访问性能使得其他一些算法(如快速排序)表现不佳,而其他算法(如堆排序)则完全不可能。

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

  • 设 head 是要排序的链表的第一个节点, headRef 是指向 head 的指针。
  • 请注意,我们需要在 MergeSort() 中引用 head,因为下面的实现更改了 next 链接以对链表进行排序(不是节点处的数据),因此如果原始 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)