数据结构 - 归并排序

45 篇文章 0 订阅
43 篇文章 0 订阅

归并排序(Merge sort,合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。

归并操作的过程如下:

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针达到序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾

时间复杂度:n*logn 空间复杂度:n

#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值