归并排序(Merge sort,合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
归并操作的过程如下:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针达到序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
#include <stdio.h>
#include <stdlib.h>
void Merge(int a[], int low, int mid, int high)
{
//将两个有序的子区间a[low, mid]和a[mid+1, high]归并成一个有序的区间a[low, high]
int i = low, j = mid + 1, k = 0; //置初始值
int *b = (int *) malloc ( (high - low + 1) * sizeof(int) );
//申请空间失败判断
if (!b)
{
return;
}
//两子区间非空时取其小者输出到b[k]上
while (i <= mid && j <= high)
{
b[k++] = a[i] <= a[j] ? a[i++] : a[j++];
}
//若第1个子区间非空,则复制剩余记录到b中
while (i <= mid)
{
b[k++] = a[i++];
}
//若第2个子区间非空,则复制剩余记录到b中
while (j <= high)
{
b[k++] = a[j++];
}
//归并完成后将结果复制回a[low, high]
for (i = low, k = 0; i <= high; i++, k++)
{
a[i] = b[k];
}
}
void MergeSort(int a[], int low, int high)
{
//用分治法对a[low, high]进行二路归并排序
int mid;
if (low < high)
{
mid = (low + high) / 2;
MergeSort(a, low, mid); //递归地对a[low, mid]排序
MergeSort(a, mid + 1, high); //递归地对a[mid+1, high]排序
Merge(a, low ,mid, high); //将两个有序区间归并为一个有序区间
}
}
int main()
{
//none of the numbers is same
int a[] = {4, 2, 7, 5, 3, 8, 9, 0, 6, 1};
MergeSort(a, 0, 9);
for (int i = 0; i < 10; i++)
printf("%d\t", a[i]);
printf("\n");
//some of the numbers are same
int b[] = {7, 1, 0, 0, 3, 0, 6, 6, 3};
MergeSort(b, 0, 8);
for (int j = 0; j < 9; j++)
printf("%d\t", b[j]);
printf("\n");
return 0;
}
链表的归并排序
对于单链表,如果需要对其排序,你会选择哪一种排序的算法了?
当然是归并排序了。相比于数组的归并需要辅助空间,链表只需要操作指针即可。
Node *linkedListMergeSort(Node *pHead){
int len = getLen(pHead);
return mergeSort(pHead,len);
}
Node*mergeSort(Node*p,int len) {
if (len==1){p->next=NULL;returnp;}
Node*pmid=p;
for(inti=0; i<len/2; i++) {
pmid=pmid->next;
}
Node*p1=mergeSort(p,len/2);
Node*p2=mergeSort(pmid,len -len/2);
returnmerge(p1,p2);
}
Node*merge(Node*p1,Node*p2){
Node*p=NULL,*ph=NULL;
while(p1!=NULL&&p2!=NULL){
if (p1->data<p2->data){
if (ph ==NULL){ph=p=p1;}
else{p->next=p1;p1=p1->next;p=p->next;}
}else{
if (ph ==NULL){ph=p=p2;}
else{p->next=p2;p2=p2->next;p=p->next;}
}
}
p->next=(p1==NULL)?p2: p1;
returnph;
}