http://blog.csdn.net/lalor/article/details/7430624
当我们需要对链表进行排序时,由于不能对它的元素进行随机访问,所以更适合使用归并排序,大名鼎鼎的快速排序用到链表上,效率也很低,原因还是在于不能对链表中的元素进行随机访问,同理,采用堆排序更是不可能的事情。
算法具体实现时需要一个指向头节点(链表的第一个节点,链表中不包含额外的一个节点来作头节点)的指针,这是因为在算法实现的时候,不大可能第一个节点正好就是所有元素中最小的一个,则链表的头节点会改变,因此我们需要一个指向头节点的指针来存储不断变化的头节点。
算法思想:
MergeSort(headRef)
1) If head is NULL or there is only one element in the Linked List
then return.
2) Else divide the linked list into two halves.
FrontBackSplit(head, &a, &b); /* a and b are two halves */
3) Sort the two halves a and b.
MergeSort(a);
MergeSort(b);
4) Merge the sorted a and b (using SortedMerge() discussed here)
and update the head pointer using headRef.
*headRef = SortedMerge(a, b);
代码示例:
时间复杂度为O(nLogn)。
- #include <stdio.h>
- #include <stdlib.h>
- /*Link list node*/
- struct node
- {
- int data;
- struct node* next;
- };
- /*function prototype */
- struct node* SortedMerge(struct node* a, struct node* b);
- void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef);
- /*sorts the linked list by changing next pointers(not data) */
- void MergeSort(struct node** headRef)
- {
- struct node* head = *headRef;
- struct node* a;
- struct node* b;
- /*base case-- length 0 or 1 */
- if((head == NULL) || (head->next == NULL))
- {
- return;
- }
- /*Split head into 'a' and 'b' sublists */
- FrontBackSplit(head, &a, &b);
- /*Recursively sort the sublists */
- MergeSort(&a);
- MergeSort(&b);
- /* answer = merge the two sorted lists together */
- *headRef = SortedMerge(a, b);
- }
- struct node* SortedMerge(struct node* a, struct node* b)
- {
- struct node* result = NULL;
- /* Base cases */
- if(a == NULL)
- return (b);
- else if(b == NULL)
- return (a);
- /* Pick either a or b recur */
- if(a->data <= b->data)
- {
- result = a;
- result->next = SortedMerge(a->next, b);
- }
- else
- {
- result = b;
- result->next = SortedMerge(a, b->next);
- }
- return (result);
- }
- /* UTILITY FUNCTIONS */
- /* Split the nodes of the given list into front and back halves,
- and return the two lists using the references parameters.
- If the length is odd, the extra node shold go in the front list.
- Uses the fast/slow pointer strategy. */
- void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef)
- {
- struct node* fast;
- struct node* slow;
- if(source == NULL || source->next == NULL)
- {
- *frontRef = source;
- *backRef = NULL;
- }
- else
- {
- slow = source;
- fast = source->next;
- /* Advance 'fast' two nodes, and advance 'slow' one node */
- while(fast != NULL)
- {
- fast = fast->next;
- if( fast != NULL )
- {
- slow = slow->next;
- fast = fast->next;
- }
- }
- *frontRef = source;
- *backRef = slow->next;
- slow->next = NULL;
- }
- }
- /*Function to print nodes in a given linked list*/
- void printList(struct node* node)
- {
- while( node != NULL )
- {
- printf("%d ", node->data);
- node = node->next;
- }
- }
- /* Function to insert a node at the begining of the linked list*/
- void push(struct node** head_ref, int new_data)
- {
- /*allocate node*/
- struct node* new_node = (struct node*)malloc(sizeof(struct node));
- /*put in the data*/
- new_node->data = new_data;
- /*link the old list off the new node*/
- new_node->next = (*head_ref);
- /*move the head to point to the new node*/
- (*head_ref) = new_node;
- }
- /* Drier program to test above functions*/
- int main()
- {
- /* Start with the empty list */
- struct node* res = NULL;
- struct node* a = NULL;
- /* Let us create a unsorted linked lists to test the functions
- Created lists shall be a: 2->3->20->5->10->15 */
- push(&a, 15);
- push(&a, 10);
- push(&a, 5);
- push(&a, 20);
- push(&a, 3);
- push(&a, 2);
- /* Sort the above created Linked List */
- MergeSort(&a);
- printf("\n Sorted Linked List is: \n");
- printList(a);
- return 0;
- }
貌似MergeSort的时间复杂度为O(nLogn),Split的时间复杂度也为O(nLogn)?当然了,总的时间复杂度还是O(nLogn),但是肯定没有对数组进行归并排序快。http://www.geeksforgeeks.org/archives/7740