用歸併排序對鏈表進行排序

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);
代碼示例:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. /*Link list node*/  
  5. struct node  
  6. {  
  7.     int data;  
  8.     struct node* next;  
  9. };  
  10.   
  11. /*function prototype */  
  12. struct node* SortedMerge(struct node* a, struct node* b);  
  13. void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef);  
  14.   
  15. /*sorts the linked list by changing next pointers(not data) */  
  16. void MergeSort(struct node** headRef)  
  17. {  
  18.     struct node* head = *headRef;  
  19.     struct node* a;  
  20.     struct node* b;  
  21.   
  22.     /*base case-- length 0 or 1 */  
  23.     if((head == NULL) || (head->next == NULL))  
  24.     {  
  25.         return;  
  26.     }  
  27.       
  28.     /*Split head into 'a' and 'b' sublists */  
  29.     FrontBackSplit(head, &a, &b);  
  30.   
  31.     /*Recursively sort the sublists */  
  32.     MergeSort(&a);  
  33.     MergeSort(&b);  
  34.   
  35.     /* answer = merge the two sorted lists together */  
  36.     *headRef = SortedMerge(a, b);  
  37. }  
  38.   
  39. struct node* SortedMerge(struct node* a, struct node* b)  
  40. {  
  41.     struct node* result = NULL;  
  42.   
  43.     /* Base cases */  
  44.     if(a == NULL)  
  45.         return (b);  
  46.     else if(b == NULL)  
  47.         return (a);  
  48.   
  49.     /* Pick either a or b recur */  
  50.     if(a->data <= b->data)  
  51.     {  
  52.         result = a;  
  53.         result->next = SortedMerge(a->next, b);  
  54.     }  
  55.     else  
  56.     {  
  57.         result = b;  
  58.         result->next = SortedMerge(a, b->next);     
  59.     }  
  60.     return (result);  
  61. }  
  62.   
  63. /* UTILITY FUNCTIONS */  
  64. /* Split the nodes of the given list into front and back halves, 
  65.     and return the two lists using the references parameters. 
  66.     If the length is odd, the extra node shold go in the front list. 
  67.     Uses the fast/slow pointer strategy. */  
  68. void FrontBackSplit(struct node* source, struct node** frontRef, struct node** backRef)  
  69. {  
  70.     struct node* fast;  
  71.     struct node* slow;  
  72.   
  73.     if(source == NULL || source->next == NULL)  
  74.     {  
  75.         *frontRef = source;  
  76.         *backRef = NULL;  
  77.     }  
  78.     else  
  79.     {  
  80.         slow = source;  
  81.         fast = source->next;  
  82.   
  83.         /* Advance 'fast' two nodes, and advance 'slow' one node */   
  84.         while(fast != NULL)  
  85.         {  
  86.             fast = fast->next;  
  87.             if( fast != NULL )  
  88.             {  
  89.                 slow = slow->next;  
  90.                 fast = fast->next;  
  91.             }  
  92.         }  
  93.   
  94.         *frontRef = source;  
  95.         *backRef = slow->next;  
  96.         slow->next = NULL;  
  97.     }  
  98. }  
  99.       
  100. /*Function to print nodes in a given linked list*/  
  101. void printList(struct node* node)  
  102. {  
  103.     while( node != NULL )  
  104.     {  
  105.         printf("%d  ", node->data);  
  106.         node = node->next;  
  107.     }  
  108. }  
  109.   
  110. /* Function to insert a node at the begining of the linked list*/  
  111. void push(struct node** head_ref, int new_data)  
  112. {  
  113.     /*allocate node*/  
  114.     struct node* new_node = (struct node*)malloc(sizeof(struct node));  
  115.       
  116.     /*put in the data*/  
  117.     new_node->data = new_data;  
  118.       
  119.     /*link the old list off the new node*/  
  120.     new_node->next = (*head_ref);  
  121.       
  122.     /*move the head to point to the new node*/  
  123.     (*head_ref) = new_node;  
  124. }  
  125.       
  126. /* Drier program to test above functions*/  
  127. int main()  
  128. {  
  129.     /* Start with the empty list */  
  130.     struct node* res = NULL;  
  131.     struct node* a = NULL;  
  132.   
  133.     /* Let us create a unsorted linked lists to test the functions 
  134.        Created lists shall be a: 2->3->20->5->10->15 */  
  135.     push(&a, 15);  
  136.     push(&a, 10);  
  137.     push(&a, 5);  
  138.     push(&a, 20);  
  139.     push(&a, 3);  
  140.     push(&a, 2);   
  141.   
  142.     /* Sort the above created Linked List */  
  143.     MergeSort(&a);  
  144.   
  145.     printf("\n Sorted Linked List is: \n");  
  146.     printList(a);             
  147.   
  148.     return 0;  
  149. }  
時間複雜度爲O(nLogn)。
貌似MergeSort的時間複雜度爲O(nLogn),Split的時間複雜度也爲O(nLogn)?當然了,總的時間複雜度還是O(nLogn),但是肯定沒有對數組進行歸併排序快。
http://www.geeksforgeeks.org/archives/7740

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章