九大排序算法原理图解

九大排序算法图解

  • 0、稳定性和复杂度
  • 1、直接插入排序(插入类)
  • 2、折半插入排序(插入类)
  • 3、冒泡排序(交换类)
  • 4、简单选择排序(选择类)
  • 5、希尔排序(插入类)
  • 6、快速排序(交换类)
  • 7、堆排序(选择类)
  • 8、2路归并排序
  • 9、基数排序

0、稳定性和复杂度

开始之前,先简单介绍一下排序算法的几个重要指标,这里,我尽量用自己理解的傻瓜式方法解读:

(1)稳定性:当序列中存在两个或两个以上的关键字相等的时候,如果排序前序列中r1领先于r2,那么排序后r1如果仍旧领先r2的话,则是稳定的。(相等的元素排序后相对位置不变)

(2)不稳定性:当序列中存在两个或两个以上的关键字相等的时候,如果排序前序列中r1领先于r2,那么排序后r1如果落后r2的话,则是不稳定的。(相等的元素排序后相对位置发生改变)

(3)时间复杂度:算法的时间开销是衡量其好坏的最重要的标志。高效率的算法应该具有更少的比较次数和记录移动次数。

(4)空间复杂度:即执行算法所需要的辅助存储的空间。

排序算法小结表
九大排序算法原理图解_第1张图片

1、直接插入排序(插入类)

流程描述:遍历序列中的关键字,每次取一个待排序的关键字,从待排序关键字的前一个关键字逐次向前扫描,如果扫描到的关键字大于待排序关键字,则把扫描到的关键字往后移一个位置。最后找到插入位置,将待排序关键字插入。

void InsertSort(int R[],int n)
{
int i,j
int temp;
for(i=1;i {
temp=R[i]; //将待排关键字暂时存放在temp中
j=i-1; //待排关键字的前一个关键字序号
while(j>=0&&temp //从待排关键字的前一个关键字开始扫描,如果大于待排关键字,则往后移一个位置
{
R[j+1]=R[j];
–j;
}
R[j+1]=temp; //找到插入位置,将temp中暂存的待排关键字插入
}
}

最坏情况:整个序列是逆序的时候,则内层循环的条件temp

最好情况:整个序列为正序的时候。内层循环条件始终不成立,所以内层循环始终不执行,始终执行语句R[j+1]=temp。所以时间复杂度为O(n)。

空间复杂度:算法所需的辅助存储空间不随待排序列的规模变化而变化,是个常量,所以为O(1)。
九大排序算法原理图解_第2张图片

2、折半插入排序(插入类)

过程描述:过程同直接插入排序,只是不同于直接插入排序时用顺序查找,这里用的是折半查找。所以折半插入排序在查找过程上比直接插入排序节约不少时间。但是关键字移动次数和直接插入排序一样。

3、冒泡排序(交换类)

过程描述:通过一系列的交换动作实现排序。首先第一个关键字和第二个关键字比较,如果第一个关键字大,二者交换;然后第二个关键字和第三个关键字比较,如果第二个关键字大,二者交换,否则不交换。一直进行下去,知道最终最大的哪个关键字被交换到了最后,一趟冒泡排序完成。

void BubbleSort(int R[],int n)
{
int i,j,flag;
int temp;
for(i=n-1;i>=1;–i)
{
flag=0; //flag用来标记本趟排序是否发生了交换
for(j=1;j<=i;++j)
{
if(R[j-1]>R[j])
{
temp=R[j];
R[j-1]=R[j];
R[j]=temp;
flag=1; //flag=1表示本次排序发生了交换
}
if(flag==0)//如果没有发生交换,说明序列有序,排序结束
return;
}
}

最坏情况:序列逆序,此时内层循环if语句的条件始终成立,基本操作执行的次数为n-i。i取值为1~n-1,所以总的执行次数为(n-1+1)(n-1)/2=n(n-1)/2,所以时间复杂度为O(n^2)。

最好情况:序列正序。此时内层循环的条件比较语句始终不成立,不发生交换,内层循环执行n-1次,所以时间复杂度为O(n)。

平均情况:时间复杂度O(n^2)。
九大排序算法原理图解_第3张图片

4、简单选择排序(选择类)

选择排序就是不断地从未排序的元素中选择最大(或者最小)的元素放入已经排好序的元素集合中,直到未排序中仅剩一个元素为止
void SelectSort(int R[],int n)
{
int i,j,k;
int temp;
for(i=0;i {
k=i;
for(j=i+1;j {
if(R[k]>R[j])
k=j; //
temp=R[i];
R[i]=R[k];
R[k]=temp;
}
}
}

5、希尔排序(插入类)

首先它把较大的数据集合分割成若干个小组(逻辑上分组),然后对每一个小组分别进行插入排序,此时,插入排序所作用的数据量比较小(每一个小组),插入的效率比较高
九大排序算法原理图解_第4张图片九大排序算法原理图解_第5张图片
可以看出,他是按下标相隔距离为4分的组,也就是说把下标相差4的分到一组,比如这个例子中a[0]与a[4]是一组、a[1]与a[5]是一组…,这里的差值(距离)被称为增量
九大排序算法原理图解_第6张图片
每个分组进行插入排序后,各个分组就变成了有序的了(整体不一定有序)
九大排序算法原理图解_第7张图片

此时,整个数组变的部分有序了(有序程度可能不是很高)
九大排序算法原理图解_第8张图片

然后缩小增量为上个增量的一半:2,继续划分分组,此时,每个分组元素个数多了,但是,数组变的部分有序了,插入排序效率同样比高
九大排序算法原理图解_第9张图片

同理对每个分组进行排序(插入排序),使其每个分组各自有序

九大排序算法原理图解_第10张图片

最后设置增量为上一个增量的一半:1,则整个数组被分为一组,此时,整个数组已经接近有序了,插入排序效率高

九大排序算法原理图解_第11张图片

同理,对这仅有的一组数据进行排序,排序完成

6、快速排序(交换类)

过程描述:每一趟选择当前子序列中的一个关键字作为枢轴(一般选择第一个关键字作为枢轴),将子序列中比枢轴小的移到枢轴前面,比枢轴大的移到枢轴后面,本趟交换完成后得到新的更短的子序列,成为下一趟交换的初始序列。一趟排序之后可以确定枢轴的最终位置。比枢轴小的全部在枢轴左边,比枢轴大的全部在枢轴右边。

void QuickSort(int R[],int high,int low)
{
int temp;
int i=low,j=high;
if(low {
temp=R[low];
while(i!=j)
{
while(j>i&&R[j]>=temp) --j; //从右往左扫描,找到一个小于枢轴temp的关键字
if(i {
R[i]=R[j]; //将右边小于枢轴temp的关键字放在temp的左边
++i; //左边序列号向右移一位
}
while(i if(i {
R[j]=R[i];//将左边大于枢轴temp的关键字放在temp的右边
–j; //右边序号向左移动一位
}
}
R[i]=temp;
QuickSort(R,low,i-1);
QuickSort(R,i+1,high);
}
}

最好情况:时间复杂度为[公式] ,待排序列越接近无序,本算法效率越高。

最坏情况:时间复杂度为 [公式] ,待排序列越接近有序,本算法效率越低。

平均情况:时间复杂度 [公式] 。

空间复杂度:从头到尾只用了temp这一个辅助存储,所以为O(1)。
九大排序算法原理图解_第12张图片

7、堆排序(选择类)

把堆看成完全二叉树,大根堆—父亲大孩子小;小根堆—父亲小孩子大。

过程描述:整个排序的过程就是不断地将序列调整为堆。

以原始序列:49 38 65 97 76 13 27 49为例,调整为大根堆。

(1)调整97,97>49,不需要调整

(2)调整65,65>13,65>27,不需要调整
九大排序算法原理图解_第13张图片
(3)调整38,38<97,38<76。需要调整,38和97交换,交换后38成为49的根节点,,继续将38和49交换。
九大排序算法原理图解_第14张图片
(4)调整49,49<97,49<65,所以49和较大者97交换,交换后,49<76,仍然不满足大根堆,将49与76交换。
九大排序算法原理图解_第15张图片

8、2路归并排序

void mergeSort(int A[],int low,int high)
{
if(low {
int mid=(low+high)/2;
mergeSort(A,low,mid); //归并排序前半段
mergeSort(A,mid+1,high);//归并排序后半段
merge(A,low,mid,high); //把数组中的low到mid 和 mid+1到high的两段有序序列归并成一段有序序列
}
}
九大排序算法原理图解_第16张图片

9、基数排序

“多关键字排序”,(1)最高位优先(2)最低位优先。例如最高位优先:先按最高位排成若干子序列,再对每个子序列按次高位进行排序。

如下图,低位优先的排序过程:每个桶相当于一个队列,先进先出规则。
九大排序算法原理图解_第17张图片
最后得到的结果:最高为有序,最高位相同的关键字次高位有序,次高位相同的关键字最低位有序,所以整个序列有序。

你可能感兴趣的:(排序,算法)