[算法]

您所在的位置:网站首页 merge和mergesort [算法]

[算法]

#[算法]| 来源: 网络整理| 查看: 265

归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序;然后将已经有序的两个子部分进行合并,最终完成排序。其时间复杂度与快速排序均为O(nlogn),但是归并排序除了递归调用间接使用了辅助空间栈,还需要额外的O(n)空间进行临时存储。从此角度归并排序略逊于快速排序,但是归并排序是一种稳定的排序算法,快速排序则不然。

所谓稳定排序,表示对于具有相同值的多个元素,其间的先后顺序保持不变。对于基本数据类型而言,一个排序算法是否稳定,影响很小,但是对于结构体数组,稳定排序就十分重要。例如对于student结构体按照关键字score进行非降序排序:

// A structure data definition typedef struct __Student { char name[16]; int score; }Student; // Array of students name : A B C D score: 80 70 75 70 Stable sort in ascending order: name : B D C A score: 70 70 75 80 Unstable sort in ascending order: name : D B C A score: 70 70 75 80

其中稳定排序可以保证B始终在D之前;而非稳定排序,则无法保证。

1)数组的归并排序

归并排序的思想实际上是一种分治法,即将待排序数据分成两部分,分别对两部分排序,然后将这两部分合并。下面以非降序排序为例:

// Split arr[] into two parts [begin,mid), [mid,end) // and using merge_core to merge this two parts // Total Time O(nlogn) void merge_sort(int arr[], int begin, int end) { if (end-begin < 2) return; int mid = (begin+end)>>1; merge_sort(arr,begin,mid); merge_sort(arr,mid,end); merge_core(arr,begin,mid,end); } // Time O(logn)

其中arr[]为待排序数组,对于一个长度为N的数组,直接调用merge_sort(arr,0,N);则可以排序。

归并排序总体分为两步,首先分成两部分,然后对每个部分进行排序,最后合并。当然也可以分成三部分或其他,然而通常是分成两部分,因此又称为二路归并。merge_core可以将两个有序数组合并成一个,具体操作如图所示:

/* merge core: combine two parts which are sorted in ascending order * arr[]: ..., 1, 4, 8, 2, 3, 7, 9, ... * begin__| |__mid |__end * part1: 1, 4, 8 part2: 2, 3, 7, 9 * * combination: * part1:[1] [4] [8] * part2: | [2] [3] | [7] | [9] * | | | | | | | * tmp :[1] [2] [3] [4] [7] [8] [9] * * at last, copyback tmp to arr[begin,end) * */

合并的前提是,两个数组已经是有序的。其代码为:

void merge_core(int arr[], int begin, int mid, int end) { int i=begin, j=mid, k=0; int *tmp = (int*)malloc(sizeof(int)*(end-begin)); for(; inext; mid->next = NULL; // cut down mid part from head list mid = fast; head = merge_sort(head); mid = merge_sort(mid); return merge_core(head,mid); }

注意,找到链表的中间节点后,务必将其指向NULL,以保证确实将链表分成两部分。然后将两个链表head与mid进行合并。由于合并后可能会修改链表头结点,因此要返回新的链表头结点。下面是合并操作:

// merge single list without head node (ascending order) ListNode *merge_core(ListNode *i, ListNode *j) { ListNode H, *p; for (p=&H; i && j; p=p->next){ if (i->val < j->val){ p->next = i; i = i->next; } else{ p->next = j; j = j->next; } } p->next = (i ? i:j); return H.next; }

链表合并时,不需要像数组那样,直接可以将链表尾部p->next指向剩余的i或j,即可完成合并。可以看出,归并排序更适合于对链表排序,而快速排序适合于数组排序。

 注:本文涉及的源码:merge sort : https://git.oschina.net/eudiwffe/codingstudy/blob/master/src/sort/mergesort.c



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3