前言
众所周知,我皮皮安最近在苦学数据结构和算法,前面的栈和队列的访问量还可以,昨天的算法与复杂度为什么就拉了跨呢。这着实不行,但这个数据结构和算法确实难理解,正片之前,先要给大家一个学习数据结构的网站,答应我,就算有了它,也要回来看皮皮安的博客,帮皮皮安学习。
这离有最常见的数据结构等方面的知识,什么?看皮皮安的博客也行。低调低调,有一说一,这里面有最全的数据结构图解,注意!是图解。我皮某人看大段的官方解释也头疼,但是看图就不一样了,那叫一个...嘿嘿嘿...
今天给大家分享常用排序。
常用排序?有多常用。
别打岔,主要介绍插入,冒泡,选择三大常用排序。
咋就这三个?我可记得有八大排序。你皮皮安框我们?
确实,在数据结构中有八大排序
1.冒泡排序
2.选择排序
3.插入排序
4.归并排序
5.快速排序
6.随机快速排序
7.计数排序
8.基数排序
这八大排序估计让我要啃一个月,接下来就看我今天的学习成果吧。
一、什么是排序?
首先,什么是排序?所谓排序,就是指将数据按照重新排列为升序或者降序的处理。但往往我们的数据都是具有多个属性的表,在排序的时候需要以某种特定属性为基准。今天在这里我们不考虑其他属性,只考虑值的大小
二、常用排序
在排序之前,给出题目。
题目很简单,就是将数组按照升序或者降序排列。
1.插入排序
插入排序的思想就是,找出最小的那个放在一边,如此反复,直到排序完成。难理解?就你打扑克的时候,要将大牌一个一个抽出来放在一边。具体还是看不懂的话,去打开上面的链接,把动画好好看看。
给出算法代码
void INS(int a[],int N)//参数为数组和数组长度
{
for(int i = 1;i < N;i++)//这里我们从第二个数(数组下标为1),默认第一个数已经被排序
{
int v = a[i];
printf("v = %d,\ta[i] = %d\n",v,a[i]);
int j = i - 1;
while(j >= 0 && a[j]>v)//如果a[j]>a[i],比a[i]的数均向后移动
{
a[j+1] = a[j];//a[j] = a[j-1]不建议,这里j>=0
j--;
}
a[j+1] = v;//当a[j]<a[i]时a[i]就排在比它小的后面
printf("v = %d,\ta[i] = %d\n",v,a[i]);
}
}
从代码上可以看出,总共需要1+2+3+...+N-1次,算法的复杂度为O(n^2)。
2.冒泡排序
这个和选择排序应该是老朋友了,之前看过皮皮安的博客应该知道,我专门为这两个排序写了各自的博客,有兴趣的小伙伴可以在去看看哦。如果说插入排序是逐一比较的话,那么冒泡排序就是两两之间比较了。
大小关系相反就交换位置,如此反复,直到排序完成。
算法代码如下:
void BUB(int a[],int N)
{
int b;
for(int i = 1;i<N;i++)
{
for(int j = 0;j < N-i;j++)
{
if(a[j+1] < a[j])
{
b = a[j];
a[j] = a[j+1];
a[j+1] = b;
}
}
}
}
看代码可以知道,在两次for循环的加持下,冒泡排序的算法复杂度也达到了O(n^2)。 这里提一句,如果将a[j+1] < a[j]改成a[j+1] <= a[j]的话,该算法将失去了稳定性。
至于什么是稳定排序,在以后的博客中会给大家介绍。
3.选择排序
选择排序是一种最直观的排序,在每一步中都选出一个最小值,然后完成排序。和插入排序很像?
这么说确实有那么一点哈,快去上面网站去看看就知道了。
给出算法代码:
void SEL(int a[],int N)
{
int b;
for(int i = 0;i<N;i++)
{
int max = i;
for(int j = 0;j<N;j++)
{
if(a[max]<a[j])
max = j;
b = a[i];
a[i] = a[max];
a[max] = b;
}
}
}
同样,选择排序的算法复杂度也是O(n^2)。
总结
让我们重新看一看这三种排序算法,冒泡排序和选择排序相比,一个从局部入手,减少逆序元素,一个放眼大局,逐个选则最小值。虽然思路完全不一样,但是都有"通过i次外层循环,从数据中顺次求出i个最小值"的方法。
相对于,插入排序是通过i次外层循环,直接将原数组的i个元素重新排序。
最后,我想说的是,无论看的在多,一定要动手!!! 只有自己亲自动手了,你才会知道,这里为什么要用i,那里为什么要用j,这里为什么要+1,那里为什么要-1.
点个赞在走呗。