排序算法之归并排序的递归与迭代实现方法

归并排序简述:

归并排序是排序算法的一种新的思路,旨在把两个或以上有序的数列归并一个有序的数列,是为归并。

假如有一个含有n个元素的数组,将其看作n个有序列,然后两两归并,最终得到一个有序列。

排序前的准备:

#define MAXSIZE 10
//顺序表结构
template <class T>
struct SqList
{
	T s[MAXSIZE + 1] = { NULL, 98, 24, 55, 81, 32, 77, 48, 60, 14 ,8};          //数组s,s[0]用作哨兵
	int length = MAXSIZE;              //s长度
	void PrintArray();
};
typedef SqList<int> SList;

//交换l中的数组中下标为i和j的值
void Swap(SList *L, int i, int j)
{
	int temp = L->s[i];
	L->s[i] = L->s[j];
	L->s[j] = temp;
}

template <class T>
void SqList<T>::PrintArray()
{
	for (int i = 1; i <= MAXSIZE; i++)
	{
		cout << s[i] << " ";
	}
	cout << endl;
}

准备了一个默认元素的数组用于排序。

递归实现归并排序:

C++实现代码如下:

//归并排序主函数
void MSort(int array[], int res[], int m, int n)
{
	int pivot;                 //临时变量
	int tempArray[MAXSIZE + 1];      //临时数组    这里的MAXSIZE默认为10
	if (m == n)
	{
		res[m] = array[m];
	}
	else
	{
		pivot = (m + n) / 2;       //中间下标,把数组array平分为[m...pivot]和[pivot+1...n]
		MSort(array, tempArray,m, pivot);         //先把数组[m...pivot]递归归并到有序数组tempArray[m,pivot]
		MSort(array, tempArray, pivot + 1, n);    //把数组[pivot+1,n]递归归并到有序数组tempArray[pivot+1,n]
		Merge(tempArray, res, m, pivot, n);//把有序数组tempArray[m,pivot]和有序数组tempArray[pivot+1,n]归并为一个新的有序数组
	}
}
这个函数的作用在于把一个无序数列,不断递归分割为两半,最终得到n个单个元素,然后单个元素分别递归归并成有序数列。

其中的Merge函数实现如下:

//归并
//两个有序数组归并为一个有序数组
void Merge(int tempArray[], int res[], int m, int pivot, int n)
{
	int i, r;       //临时变量用于遍历
	//不断比较,将较小的数放到目标数组的前面
	for (i = pivot + 1,r = m;i <= n && m <= pivot; r++)   //i从pivot+1开始遍历,r一开始等于m并作为res数组的下标
	{
		if (tempArray[m]<tempArray[i])         //比较临时数组的第1位[m]和[pivot+1]位的元素大小
		{
			res[r] = tempArray[m++];         //小于的话,就把m下标元素放在res第一位,并且m+1
		}
		else
		{
			res[r] = tempArray[i++];
		}
	}
	//上述比较后,会有剩余的数组元素
	//把剩余数组元素复制到res数组
	if (m<=pivot)
	{
		for (int l = 0; l <= pivot-m; l++)
		{
			res[r + l] = tempArray[m + l];
		}
	}
	if (i<=n)
	{
		for (int l = 0; l <= n-i; l++)
		{
			res[r + l] = tempArray[i + l];
		}
	}
}
最后可以用一个函数来调用主函数,作为最终的函数方便使用:

//归并排序
void MergeSort(SList *L)
{
	MSort(L->s, L->s, 1, L->length);
}

迭代实现归并排序:

迭代仍然使用到了上面的Merge函数,用于归并。

//归并排序迭代实现
void MergeSort2(SList *L)
{
	int *resA = new int[L->length];     //用于存放最终得到的有序表
	int pivot = 1;             //变量记录有序表长度
	while (pivot < L->length)       //不断循环直到有序表长度大于原表
	{
		MergeIterate(L->s,resA,pivot,L->length);
		pivot *= 2;       //自乘两倍
		MergeIterate(resA,L->s,pivot,L->length);
		pivot *= 2;
	}
}

//将array[]中长度为pivot的序列,两两进行归并,结果放到res[]
void MergeIterate(int array[], int res[], int pivot, int length)
{
	int i = 1,j;
	while (i<= length-2*pivot+1)
	{
		Merge(array, res, i, i + pivot - 1, i + 2 * pivot - 1);
		i = i + 2 * pivot;
	}
	if (i<length - pivot + 1)
	{
		Merge(array, res, i, i + pivot - 1, length);
	}
	else
	{
		for (j = i; j <= length; j++)
		{
			res[j] = array[j];
		}
	}
}

归并排序的时间复杂度:

归并排序的最好最坏和平均时间复杂度都为O(nlogn),迭代方法的空间复杂度为O(n)

迭代方法的效率要比递归更高,并且归并排序是一种稳定的的排序算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值