直接插入排序、希尔排序、归并排序的区别与联系

53 篇文章 2 订阅

    直接插入排序、希尔排序,都属于插入排序,即每一趟选择一个关键字,把它插入到已排序序列的适当位置,直到整个序列都有序为止。而归并排序,比如,2路归并,是将2个子有序表,合并成一个新的有序表,这个新的有序表再跟其他字表合并,循环往复,两两归并,直到整个序列都成有序的。
    对比它们的时间复杂度、空间复杂度、稳定性,如下:

算法对比直接插入排序希尔排序归并排序
平均时间复杂度O(n^2)O(n^1.5)O(nlogn)
最坏情况O(n^2)O(n^2)O(nlogn)
最好情况O(n)O(n^1.3)O(nlogn)
空间复杂度O(1)O(1)O(n)
属于稳定算法属于不属于属于

1、直接插入排序

    基本思路:依次将每个记录插入到一个有序的序列里。假设记录存放在R[0,n-1]之中,R[0,i-1]是已排好序的记录区(也叫有序区),R[i,n-1]是未排序的记录区(无序区)。每次将R[i]插入到R[0,i-1]之中,使得R[0,i]成为有序的,直到i=n-1为止。
    //插入排序源码

//直接插入排序
void InsertSort(vector<int> &list) {
	for (int i = 1; i < list.size();i++)
	{
		int tmp = list[i];
		int j = 0;
		for (j = i - 1; j >= 0 && tmp < list[j];j--)
		{
			list[j + 1] = list[j];
		}
		list[j + 1] = tmp;
	}
}

2、希尔排序

    希尔排序,又称"缩小增量排序"方法,它是一种改良版的插入排序。
    基本思路:将记录按下标的一定增量d分组,对每组记录采用直接插入排序方法进行排序,随着增量逐渐减小,所分成的组包含的记录越来越多。当增量的值减小到1时,整个数据合成一组,变成一组有序序列。
    //希尔排序的源码:

//希尔排序
void ShellSort(vector<int> &list) {
	int step = list.size() / 2;
	while (step >= 1)
	{
		for (int i = step; i < list.size();i++)
		{
			int tmp = list[i];
			int j = 0;
			for (j = i - step; j >= 0 && tmp < list[j];j = j - step)
			{
				list[j + step] = list[j];
			}
			list[j + step] = tmp;
		}
		step = step / 2;
	}
}

3、归并排序

    基本思路:将R[0,n-1]看成是n个长度为1的有序表,把相邻的有序表成对合并,得到n/2长度为2的有序表;然后,将这些长度为2的有序表,继续成对合并,得到n/4个长度为4的有序表,如此反复进行下去,最终得到一个长度为n的有序表。
    如果在归并的过程中,以2位基数进行合并,则称为二路归并排序;若以n为基数进行合并,则称为n路归并排序。

    //二路归并排序源码:


//------------------- 归并排序 ---------------------
//合并
void merge(vector<int> &list, vector<int> &tmplist, int left, int mid, int right){
	int leftEnd = mid - 1;
	int rightStart = mid;
	int tmpIndex = left;
	int tmpLength = right - left + 1;
	while ((left <= leftEnd)&&(rightStart <= right))
	{
		if (list[left] < list[rightStart])
		{
			tmplist[tmpIndex] = list[left];
			tmpIndex++;
			left++;
		}
		else {
			tmplist[tmpIndex] = list[rightStart];
			tmpIndex++;
			rightStart++;
		}
	}

	//判断左子区间
	while (left <= leftEnd) {
		tmplist[tmpIndex] = list[left];
		tmpIndex++;
		left++;
	}

	//判断右子区间
	while (rightStart <= right) {
		tmplist[tmpIndex] = list[rightStart];
		tmpIndex++;
		rightStart++;
	}

	//交换数据
	for (int i = 0; i < tmpLength; i++){
		list[right] = tmplist[right];
		right--;
	}

}

//排序
void MergeSort(vector<int> &list, vector<int> &tmplist, int left, int right) {
	if (left < right)
	{
		int mid = (left + right) / 2;
		//划分左区间
		MergeSort(list, tmplist, left, mid);
		//划分右区间
		MergeSort(list, tmplist, mid + 1, right);
		//数组合并
		merge(list, tmplist, left, mid + 1, right);
	}
}

4、完整代码

//sort.cpp

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

//直接插入排序
void InsertSort(vector<int> &list) {
	for (int i = 1; i < list.size();i++)
	{
		int tmp = list[i];
		int j = 0;
		for (j = i - 1; j >= 0 && tmp < list[j];j--)
		{
			list[j + 1] = list[j];
		}
		list[j + 1] = tmp;
	}
}


//希尔排序
void ShellSort(vector<int> &list) {
	int step = list.size() / 2;
	while (step >= 1)
	{
		for (int i = step; i < list.size();i++)
		{
			int tmp = list[i];
			int j = 0;
			for (j = i - step; j >= 0 && tmp < list[j];j = j - step)
			{
				list[j + step] = list[j];
			}
			list[j + step] = tmp;
		}
		step = step / 2;
	}
}


//------------------- 归并排序 ---------------------
//合并
void merge(vector<int> &list, vector<int> &tmplist, int left, int mid, int right){
	int leftEnd = mid - 1;
	int rightStart = mid;
	int tmpIndex = left;
	int tmpLength = right - left + 1;
	while ((left <= leftEnd)&&(rightStart <= right))
	{
		if (list[left] < list[rightStart])
		{
			tmplist[tmpIndex] = list[left];
			tmpIndex++;
			left++;
		}
		else {
			tmplist[tmpIndex] = list[rightStart];
			tmpIndex++;
			rightStart++;
		}
	}

	//判断左子区间
	while (left <= leftEnd) {
		tmplist[tmpIndex] = list[left];
		tmpIndex++;
		left++;
	}

	//判断右子区间
	while (rightStart <= right) {
		tmplist[tmpIndex] = list[rightStart];
		tmpIndex++;
		rightStart++;
	}

	//交换数据
	for (int i = 0; i < tmpLength; i++){
		list[right] = tmplist[right];
		right--;
	}

}

//排序
void MergeSort(vector<int> &list, vector<int> &tmplist, int left, int right) {
	if (left < right)
	{
		int mid = (left + right) / 2;
		//划分左区间
		MergeSort(list, tmplist, left, mid);
		//划分右区间
		MergeSort(list, tmplist, mid + 1, right);
		//数组合并
		merge(list, tmplist, left, mid + 1, right);
	}
}



//输出所有的元素
void printList(vector<int> list){
	for (int i = 0; i < list.size(); i++){
		printf("%d ", list[i]);
		if ((i + 1) % 10 == 0)
			printf("\n");
	}
	printf("\n");
}


int main() {

	int arry[6] = { 40,20,80,50,30,60 };
	vector<int> dataVec(arry, arry + 6);


	//1)直接插入排序
	//InsertSort(dataVec);
	//printList(dataVec);

	//2)希尔排序
	//ShellSort(dataVec);
	//printList(dataVec);

	//3)归并排序
	vector<int> dataTmp;
	dataTmp.resize(6);

	MergeSort(dataVec, dataTmp, 0, dataVec.size() - 1);
	printList(dataVec);

	
	system("pause");
	return 0;
}

5、参考文献

    李春葆.数据结构习题与解析B级.2006

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sanqima

一键三连,多多益善

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值