algorithm - 链表归并排序解释

标签 algorithm sorting linked-list mergesort

有人可以向我解释一下这段代码是如何工作的吗:

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

我不明白这篇文章中使用的算法。谢谢

最佳答案

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

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

合并排序(headRef)

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

2) 否则将链表分成两半。 FrontBackSplit(头, &a, &b);/* a 和 b 是两半 */

3) 对两半a和b进行排序。 归并排序(a); 归并排序(b);

4) 合并已排序的 a 和 b(使用此处讨论的 SortedMerge()) 并使用 headRef 更新头指针。 *headRef = SortedMerge(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;
    }


关于algorithm - 链表归并排序解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9406719/

相关文章:

Python:如何按值和索引对字典列表进行排序

c++ - 为什么此代码无法反转双向链表

java - 如果对象包含在列表中,为什么 LinkedList.indexOf() 返回 -1?

使用固定半径的圆二等分一组点的算法

PostgreSQL:乌克兰语文本排序错误

c++ - 不使用合并排序的倒置计数算法 (c++)

创建具有多种元素类型的链表

c# - 矩阵的左上象限的最大和可以通过反转行和列来形成

algorithm - 是否有任何正在使用的并发算法可以在没有任何同步的情况下正常工作?

algorithm - Javascript 数据结构库