最重要的快排和归并啃下来之后,其他的就相对简单了,就一个堆排序稍微复杂一点。
一、冒泡排序
两两比较,顺序错误就进行交换,形似冒泡
一次冒泡循环结束时,应该是一个最大值浮到最上面
然后再一次循环,倒数第二大上浮,依次类推。本质还是一个双循环法
void bubble(int a[], int lens)
{
int i,j = 0;
for (i=0;i<lens;i++)
{
for (j=0;j<lens-i-1;j++)
{
if (a[j]>a[j+1]) swap(a[j],a[j+1]);
}
}
}
注意,冒泡是左右左右两两比较
二、选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序其实就是最符合我们人类惯常思维的排序,简单来说就是遍历一遍找到一个最大值,放末尾,然后依次类推
void select_sort(int a[],int n){
int temp;
for(int i=0;i<n-1;i++){
temp=i; //利用一个中间变量temp来记录需要交换元素的位置
for(int j=i+1;j<n;j++){
if(a[temp]>a[j]){ //选出待排数据中的最小值
temp=j;
}
}
swap(a[i],a[temp]); //交换函数
}
}
需要注意,由于是需要交换数组中的两个数,所以不能像普通求最值那样用temp记录最大值,而是要记录temp的位置。
相比冒泡排序的不断交换,简单选择排序(simple selection sort)是等到合适的关键字出现后再进行交换,并且移动(交换)一次就可以达到一次冒泡的效果。
三、直接插入排序
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到 {\displaystyle O(1)} {\displaystyle O(1)}的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
关键点在于每次插入的时候,插入位置往后的数要进行一次挪位。
void insert(int a[],int n)
{
int i,j=0;
int temp = 0;
//要怎么构造循环来遍历插入,我们要插入的对象每次往后数一位就是了,所以这里可以当作是一层循环
//因为我们前面的都是按照小到大拍好序了,因此,每次比较排好序的最后一位和下一位就行
for (i=1;i<n;i++)
{
if (a[i-1]>a[i}) //下一个值比较小时
{
int temp = a[i]; //由于挪位的范围为0——i,实际上就是i和前面的某个位置交换,挪位会影响a[i]
for (j=i-1;j>=0&&a[i]<a[j];j--) //秒处便在于此,寻找合适位置的同时,也完成了挪位的操作
{
a[j+1]=a[j];
}
a[j+1] = temp;
}
}
}
四、希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
其本质就是利用查排序当最终数组比较有序时,处理起来比较简单的道理。
写希尔排序的时候怎么写,本质上就是增量逐渐变化的过程
//先写个插入排序,然后再插入排序的基础上加上gap变化并把原增量1改为gap
for (int gap=n/2;gap>0;gap=gap/2)
{
for (i=gap;i<n;i++)
{
int temp = a[i]; //由于挪位的范围为0——i,实际上就是i和前面的某个位置交换,挪位会影响a[i]
for (j=i-gap;j>=0&&temp<a[j];j-=gap) //秒处便在于此,寻找合适位置的同时,也完成了挪位的操作
{
a[j+gap]=a[j];
}
a[j+gap] = temp;
}
}
五、堆排序
待补充
六、各排序总结
1、冒泡邻居两两换,每次找最大值
2、选择排序记录下标,每次找最小换
3、插入排序找位置挪位置,每次找小值
4、希尔排序直接插入排序换增量
5、归并排序,3个while循环
6、快排,挖坑填数,左小右大
参考https://www.dotcpp.com/course/166