排序算法小全《下》

接着上一篇:排序算法小全《上》
长话短说,直奔主题吧。

目录:
一:插入类
1.直接插入排序
2.希尔排序
二:选择类
1.直接选择排序
2.堆排序
小结
本篇内容如下

三,交换类

和选择类差别是,交换意味着,每个数一边比较时,一边互换位置。

1.直接交换排序

共n个数需要排序,储存于数组中。
步骤:
1.相邻两数比较,0:1,1:2,2:3等等(满足条件交换位置)
,比较到最后一个数(n-2:n-1)

2.总数变为n-1,执行第1步.如此循环直至,排序成功。
注意:不一定需要等到n变为1,可以检测某一次排序时,只进行了比较,没有一次交换,这时就可以退出循环了。

动画演示:

在这里插入图片描述代码如下:

void swapSort(int *ar, int count) {
	int i;
	int j;
	int temp;
	char isSwap;
	

	for (i = 0; i < count; i++) {
		for (isSwap = 0, j = 0; j < count - i - 1 ; j++) {  //每次循环isSwap都是赋值为0
			if (ar[j] > ar[j + 1]) {
				temp = ar[j];
				ar[j] = ar[j + 1];
				ar[j + 1] = temp;
				isSwap = 1; 		//如果存在交换,isSwap为1
			}
		}
		if (isSwap == 0) {     //内循环结束后,如果isSwap为0,即上次已经排序成功了,所以可以退出。
			return;
		}
	}
}

在这里插入图片描述

2.快速排序

快速排序是基于交换排序的改良。
基本思路:对于每一组数据,总是以第一个数为基准,将小于它的数交换至其左侧,大于它的数保留在其右侧。
步骤:
1.取出数据中第一个数(temp保存),用头、尾指针遍历数组。
从尾指针(t)开始(头指针(h)指向的事第一个数取出的空空间),如果ar[t] > temp;那么不交换,t–;,直至ar[t] > temp,不成立。若不成立,则该数(ar[t])和ar[h]交换。且h++;
接着比较ar[h]和temp;如果小于成立,下一个数比较(h++),如果不成立,交换ar[h]和ar[t],且,t–;

2.重复以上两个操作,直至h == t;停止,且ar[h] = temp;完成一轮操作

3.此时数据分为两个部分,分别对这两个数据组进行上述操作,直至排序成功。

动画演示:

在这里插入图片描述
代码如下:

static void quickOnce(int *ar, int startIndex, int endIndex) {
	int head = startIndex;
	int tail = endIndex;
	int tmp;

	if (head > tail) {  //递归必须先给出结束。
		return;
	}

	tmp = ar[head];
	while (head < tail) {
		while (ar[tail] > tmp && head < tail) {
			--tail;
		}
		if (head < tail) {
			ar[head++] = ar[tail];
		}
		while (ar[head] < tmp && head < tail) {
			++head;
		}
		if (head < tail) {
			ar[tail--] = ar[head];
		}
	}
	ar[head] = tmp;

	quickOnce(ar, startIndex, head - 1); //前半部分排序
	quickOnce(ar, head + 1, endIndex);   //后半部分排序
}

void quickSort(int *ar, int count) {
	quickOnce(ar, 0, count - 1);
}

四,特殊范围类

1.简单桶排序

步骤:
1.遍历数组,找到最大值,最小值,等间距设置固定数量的空桶。

2.将每个数据放入对应范围的桶中。
3.对每个桶进行排序。

4.将每个桶按顺序链接,得到最终结果

动画演示:
在这里插入图片描述

代码暂时没有。

2.优化一点的桶排序–计数排序

基本思想:空间换时间
步骤:
1.遍历数组,找到最大值,最小值。
2.遍历的同时,用另一个频度数组freq[max ](初始全为零),将每一个数值做为下标,出现一次,频度加1
3.遍历频度数组,频度值为多少,就输出几次这个下标几次。排序成功。

在这里插入图片描述代码暂无:

3.特殊桶排序–基排序

特殊在哪?
桶分别为0-9,10-99,100-999等等
步骤:
1.取出最大数。
2.取出每个数的个位上的数,如果为1,就放如1桶里,例如(11,161,5981,61不排序),一次取出
3.再取出每个数的十位上的数,如果为1,就放入1桶里,如(11,115,6415不排序),注意*此时0桶里的都是小于10的数,且排好序,*一次取出
4.再取出每个数的百位上的数,那么100之前已经排好。
5.继续进行千位,万位。。。直至排序完成

动画演示:
在这里插入图片描述代码暂无

4.变化的桶–归并排序

基本思路:指数爆炸
步骤:
1.从第一个数开始,排序。
2.排序前两个数,同时排序第三、第四个数。(此时,相对于将这组数分为两个两个的)
3.归并前四个数(排序归并),同时排序5–8个数(此时,相当于把之前两个为一组的合成4个为一组。所有的都合成。)
4.继续归并前16个数,排序16至32个数
5.如此继续归并加排序,直至结束。

在这里插入图片描述代码如下:

static void merge(int* array, int left, int right, int mid, int* temp) {
	int i = left;
	int j = mid + 1;
	int tempLeft = left;
	int t = 0;
	
	while (i <= mid && j <= right) {
		temp[t] = array[i] <= array[j] ? array[i++] : array[j++];
		t++;
	}
	while (i <= mid) {
		temp[t++] = array[i++];
	}
	while (j <= right) {
		temp[t++] = array[j++];
	}								//以上三个循环的目的是将整个数组排好序再存入temp数组中

	t = 0;
	while (tempLeft <= right) {		//这个循环的目的是将排好序的数组内的值赋值给原数组
		array[tempLeft++] = temp[t++];
	}
}

static void mSort(int* array, int left, int right, int* temp) {
	int mid;

	if (left >= right) {
		return;
	}
	
	mid = (left + right) / 2;
	mSort(array, left, mid, temp);
	mSort(array, mid + 1, right, temp);
	merge(array, left, right, mid, temp);

}

void mergeSort(int* array, int count) {
	int *temp;
	
	temp = (int *)calloc(sizeof(int), count);
	mSort(array, 0, count-1, temp);
}

五、小结

个人最喜欢的堆排序。

关于排序的算法,
首先,一定得理清每一个的思路,明白各自算法的优缺点;不同排序方法适用于场景各有差异。
接着,根据思路,找到每个方法的重复单元,做好手工过程。
然后,根据手工过程,开始编程,一定得变量跟踪,不然往往会结尾时出错。
最后,总结分析,每种方法的共同点,不同点,归类。

每一行代码可能会遗忘,但每一个自己遇到的错误,自己总结出的经验都会生根在我们心中。

感谢指导文章:五分钟学算法
感谢指导老师:铁血教主

笔者水平有限,目前只能描述以上问题,如果有其他情况,可以留言,有错误,请指教,有继续优化的,请分享,谢谢!

2019年12.22 图书馆

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值