《数据结构与算法》6-排序

排序是一种对线性数据结构做的数据顺序调整,获得从大到小或者从小到大的有序的结果。

比如 1 6 4 3 9 0 从小到大排序之后是 0 1 3 4 6 9 。从大到小排序的顺序是 9 6 4 3 1 0

排序有很多方法,一般的排序算法的两个基本操作是比较和位移

  • 比较

比较是排序的基础,如果线性表里面的数据无法相互比较大小,就没有排序的概念。上面的例子是比较的数字,开发环境中有很多场景,列表里面的数据可能是对象,有很多属性,这样的话就要开发自己指定排序的方法,或者扩展数据类型继承Comparable<T>接口,或者是在Arrays.sort(T[] ts,Comparator<T> comparator>传入Comparator的接口实现。

  • 位移

上面的比较之后,根据比较的结果调整元素的位置,才能使得原始打乱的数据重新变成有序的。

根据比较的的算法叫比较排序,常规的有冒泡排序,插入排序,选择排序;

  • 冒泡排序

冒泡排序大家都经常使用,正常从小到大排序过程中,从前往后比较相邻的两个数据,如果前面的数据大于后面的数据,则交换位置。那么经过n-1次循环遍历,最终完成排序。

 1 6 4 3 9 0 
// 第一次冒泡
 1 4 3 6 0 9
// 第二次冒泡
 1 3 4 0 6 9
//第三次
 1 3 0 4 6 9
//第四次
 1 0 3 4 6 9
// 第五次
 0 1 3 4 6 0
 

所以第一次冒泡会选出最大值,第二次会选出倒数第二大的值,这样遍历 n-1次就能得倒正常的顺序

  • 插入排序

把列表分为已排序部分和未排序两部分。选择无序部分的第一个元素,插入到有序部分的合适位置

1|6 4 3 9 0
//原始有序数据为1,无序部分为 6 4 3 9 0
//然后选择无序部分的第一个元素,放在有序部分的合适的位置
1 6| 4 3 9 0
//第二次插入排序
1 4 6|3 9 0
//第三次插入排序
1 3 4 6|9 0
//第四次插入排序
0 1 3 4 6|9
  • 选择排序,分为有序无序两部分,选择无序部分的最小值插入到有序部分的最后
1 6 4 3 9 0

//一开始有序部分为空,无序部分为全部原始数据
//第一次排序,找出最小的元素插入队列的第一位,其余的元素后移
0 1 6 4 3 9
//这样子,有序部分为1 无序部分为6 4 3 9 0
//第二次排序 找到无序部分的最小值 1 ,放在有序元素的后面,
0 1 6 4 3 9
// 第三次排序,找到无序部分的最小值3 ,放在有序元素的后面
0 1 3 6 4 9
//第四次排序,找到无序部分最小值 4 ,放在有序元素的后面
0 1 3 4 6 9
//最终
0 1 3 4 6 9

上面三种排序是比较基本的算法。那么怎么评估三种算法的优劣呢

  • 时间复杂度分析法

冒泡排序:

  1. 最好情况时间复杂度,原始数据有序,比较次数n*n,位移次数0
  2. 最坏情况时间复杂度,原始数据完全无序,比较次数n*n,位移次数n*n
  3. 平均情况时间复杂度,n*n

插入排序:

  1. 最好情况时间复杂度,原始数据有序,比较次数n*n,位移次数0
  2. 最坏情况时间复杂度,原始数据完全无序,比较次数n*n,位移次数n
  3. 平均情况时间复杂度 n*n

选择排序:

  1. 最好情况时间复杂度,原始数据有序,比较次数n*n,位移次数0
  2. 最坏情况时间复杂度,原始数据完全无序,比较次数n*n,位移次数n*n
  3. 平均情况时间复杂度 n*n

除此之外,衡量一个排序算法是否优秀还有另外两个纬度:

  • 稳定性,比如原始数据 1 6 4 5 5 3 9,经过排序之后,两个5的位置不会发生变化,那么就说排序算法稳定
  • 原地排序,即空间性上,如果需要额外的空间,且空间大小不会随着数据的增加而增大,那么就说排序算法是原地排序

所以上面的三个排序算法中,冒泡排序-插入排序-选择排序都是原地排序算法,

但是选择排序算法不是稳定排序算法

猜你喜欢

转载自blog.csdn.net/David_lou/article/details/108658126