C/C++ 插入排序、希尔排序、选择排序、冒泡排序、快速排序及其复杂度计算

目录

插入排序

希尔排序

选择排序

冒泡排序

快速排序


插入排序

思想

 数组下标end,从0开始到数组总数n-1,依次遍历数组中的数字。

以end为分界线,0-end+1为有序,end+2-n为无序

注意事项

记得保留第end+1个数字的值,因为end在不断改变,end+1所指代的值也会改变。要记住的是,插入排序是在0--end+1个数字中给end+1找到一个合适的位置。

代码

void InsertSort(int* a, int n) {
	//遍历第一个到倒数第一的前一个数字
	for(int i=0;i<n-1;i++)
	{
		int end = i;
		//默认0-end有序,把end+1插入进去
		//记录下数据
		int tmp = a[end + 1];

		//遍历end前的所有数据,直到有序或者到头
		while (end >= 0) {
			//为什么是end>=0
			//最坏情况下tmp可能是0-end中最小的那个数
			if (a[end] > tmp) {
				a[end + 1] = a[end];
				end--;
			}
			else {
				break;
			}
		}

		//更新tmp
		a[end + 1] = tmp;
	}
}

复杂度计算

最坏的情况

外层for循环走n-1次,内层while循环走1+2+3+…+n-1次

总共为O(N^2)

最好的情况

不用调O(N)

希尔排序

思想

 

希尔排序是插入排序的变形,插入排序的排序间隔是不变的,也就是从0至n-1每个数都遍历,而希尔排序以gap为间隔,将n个数字分组,每个组有序,整个数组也就有序了。

gap的值也是在不断缩小的

gap越大,大的数据可以越快跳到后面,gap越小,跳的越慢越接近有序

其实就是一个调整gap的循环套上一个gap为间隔的插入循环

注意事项

gap值的确定:

gap==1时为插入排序,gap>1为希尔排序

代码

void ShellSort(int* a, int n) {
	//原理就是将0-gap的数字都遍历一遍,不断调整gap的大小
	//gap越大,大的数据可以越快跳到后面
	//gap越小,跳的越慢越接近有序

	//给gap赋值
	int gap = n;
	while (gap > 1) {
		//调整gap
		gap = gap / 2;

		//这是以gap为间距的插入排序
		for (int i = 0; i < n-gap; i ++) {
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0) {
				if (a[end] > tmp) {
					a[end + gap] = a[end];
					end-=gap;
				}
				else {
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

复杂度计算

选择排序

思想

 begin、end为数组的下标。begin代表起始位置,end代表最后位置

选出最小的数字放在begin位置,选出最大的数字放在end位置

注意事项

最大数字在第一位时需要调整

代码

void SelectSort(int* a, int n) {
	int begin = 0, end = n - 1;
	while (begin < end) {
		int mini = begin, maxi = begin;
		for (int i = begin + 1; i <= end; i++) {
			//记录从begin+1至end的最小值和最大值
			if (a[i] > a[maxi]) {
				maxi = i;
			}
			if (a[i] < a[mini]) {
				mini = i;
			}
		}
		//交换最小值
		Swap(&a[begin], &a[mini]);
		//如果最大值在首位
		if (maxi == begin) {
			maxi = mini;
		}
		//交换最大值
		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

复杂度计算

n/2次循环

第一次循环,第一次循环…… 第n/2次循环,

n-1                +n-3+        ……  +1

O(N^2)

冒泡排序

思想

 

与希尔排序类似,冒泡排序最后面的数字是有序的,以n-i为分界线,0- n-i为无序,n-i  -n为有序

第一个for循环遍历所有的数字

第二个for循环遍历从1至n-i个数字,每次循环将数字与它前面的数相比较

代码

void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n; ++j)
	{
		int exchange = 0;
		for (int i = 1; i < n - j; ++i)
		{
			if (a[i - 1] > a[i])
			{
				Swap(&a[i - 1], &a[i]);
				exchange = 1;
			}
		}
		if (exchange == 0)
		{
			break;
		}
	}
}

复杂度计算

O(N^2)

快速排序

思想

设定一个key,通常是数组的第一个或者是最后一个。作为比较的依据。

两个指针 left 寻找比key大,right寻找比key小的数字

其中一个找到即停下

直到两个都找到才进行交换

在left--right中交换过之后,将最后两个指针相遇的地方同key 交换

最后达到的结果为key左边的数都比key小,key右边的数都比key大

在递归中不断改变key,

注意事项

两个指针相遇的地方同key 交换

当key是起始位置第一个数时,right先走,相遇位置的数字一定比key小吗?

当left与right停下有两种情况

1、left 停下(表示已经找到比key大的数,且已经交换过,此时left的数比key小),right走,right遇到left(此时right没有找到比key小的数字,但是已经不满足条件left<right了所以终止循环),相遇位置的数字比key小

2、right停下(表示已经找到比key小的数),left走,left遇到right,相遇位置的数字比key小

left与right谁先走谁后走也是很重要滴

代码

int PartSort(int* a, int left, int right)
{
	int keyi = left;
	while (left < right)
	{
		// R找小
        //两个条件一个不能少,必须带上=号
		while (left < right && a[right] >= a[keyi])
		{
			--right;
		}

		// L找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}

		if (left < right)
			Swap(&a[left], &a[right]);
	}

	int meeti = left;

	Swap(&a[meeti], &a[keyi]);

	return meeti;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
	{
		return;
	}

	int keyi = PartSort(a, begin, end);
	//[begin, keyi-1] keyi [keyi+1, end]

	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

复杂度计算

O(logN)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值