链表合并排序放大



有人能向我解释一下这个代码是如何工作的吗:

http://www.chiark.greenend.org.uk/~sgtatham/agorithms/listsort.c

我不理解这篇文章中使用的算法。感谢

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

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

MergeSort(headRef)

1) 如果head为NULL或链表中只有一个元素然后返回。

2) 否则,将链表一分为二。前后拆分(head,&a,&b);/*a和b是两半*/

3) 对a和b的两半进行排序。MergeSort(a);MergeSort(b);

4) 合并已排序的a和b(使用此处讨论的SortedMerge())并使用headRef更新头指针。*headRef=排序合并(a,b);



    /* Link list node */
    struct node
    {
        int data;
        struct node* next;
    };
    /* function prototypes */
    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);
    }
    /* See http://geeksforgeeks.org/?p=3622 for details of this
       function */
    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, and recur */
      if (a->data 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 reference parameters.
         If the length is odd, the extra node should 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)
      {
        /* length 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;
          }
        }
        /* 'slow' is before the midpoint in the list, so split it in two
          at that point. */
        *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 beginging 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;
      struct node* b = 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); 
      /* Remove duplicates from linked list */
      MergeSort(&a);
      printf("n Sorted Linked List is: n");
      printList(a);           
      getchar();
      return 0;
    }

试着对数组上正常合并排序中执行的所有合并进行成像:首先,元素配对并合并到长度为2的排序子数组中,然后这些长度为二的子数组配对并合并成长度为四的排序子阵列,依此类推。注意子数组的长度:1、2、4等等,让我们称之为instep,它在每次迭代中都会翻倍。

在任何时候,p指向长度为instep的列表,q指向长度为instep或更小的列表(我们可能会到达列表的末尾),并且q紧跟在p之后。它们形成一对子阵列,如上所述。我们对pq进行合并,得到从p开始的长度为psize + qsize的排序列表。然后,我们将pq移到下一对,依此类推。一旦我们处理完整个列表,我们就将instep加倍,并开始合并更长排序的列表。

相关内容

  • 没有找到相关文章

最新更新