[读书笔记]算法(Sedgewick著)·第二章.初级排序算法
2014-05-26 15:35
337 查看
本章开始学习排序算法
1.初级排序算法
先从选择排序和插入排序这两个简单的算法开始学习排序算法。选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序。
而插入排序就像打poker一样,找到每个元素在小数组中的位置。
算法思路相当简单,而本节比较有趣的地方是可视化排序算法。我们就实现这个可视化。
我们分为三个步骤。第一步,将一个数组的元素(这里我们选用double数据类型)用长条表示,并依次罗列在屏幕上。第二步,按照各个算法的思路将有序数组排序,画出一张可视轨迹图。第三步,将轨迹图动画化。
接下来的重头戏是比较选择排序和插入排序。通过下图的例子,我们可以看出第i个元素都进行一次交换和N-1-i次比较。对于长度为N的数组,选择排序要进行N^2/2次比较和N次交换。
而对于插入排序呢?情况比选择排序复杂。最坏情况(完全逆序)下,需要~N^2/2次比较和~N^2/2次交换;而最好情况(已经顺序)下,需要N-1次比较和0次交换。就如同例子中第3次插入时,S、T已经是有序的了,所以不存在交换的需要。对于随机排序的数组,在平均情况下每个元素都可能向后移动半个数组的长度,因此交换总数是~N^2/4,而比较次数是交换次数加上一个额外的项(相比N^2,可以忽略)。
而排序前数组的倒置(比如E-A)个数越少,插入排序就越快。接下来我们用随机数组来比较两种算法。
重复一百次的1000个随机数排序比较结果:
重复一百次的10000个随机数排序比较结果:
最后,我们可以得出:对于随机数组,插入排序和选择排序的运行时间是平方级别的,两者之比是一个较小的常数(本机测试为1.3~1.4)。
希尔排序的思想是使数组中任意减个为h的元素有序,也就是将插入排序的元素移动距离由1改变为逐渐增大的h。
这么做的原因是因为部分有序数组更适合插入排序。那么,我们就比较一下这两种算法的执行速度。
1.初级排序算法
先从选择排序和插入排序这两个简单的算法开始学习排序算法。选择排序就是依次找到当前数组中最小的元素,将其和第一个元素交换位置,直到整个数组有序。
public static void sort(Comparable a[]){ int N = a.length; for(int i = 0; i < N; i ++){ int min = i; //最小元素索引 for(int j = i + 1; j < N; j++){ if(less(a[j], a[min])) min = j; } exch(a, i, min); } }
而插入排序就像打poker一样,找到每个元素在小数组中的位置。
public static void sort(Comparable a[]){ int N = a.length; for(int i = 1; i < N; i ++){ //将a[i]插入a[i-1]、a[i-2]、a[i-3]...之中 for(int j = i; j > 0 && less(a[j], a[j-1]); j--){ exch(a, j, j-1); } } }
算法思路相当简单,而本节比较有趣的地方是可视化排序算法。我们就实现这个可视化。
我们分为三个步骤。第一步,将一个数组的元素(这里我们选用double数据类型)用长条表示,并依次罗列在屏幕上。第二步,按照各个算法的思路将有序数组排序,画出一张可视轨迹图。第三步,将轨迹图动画化。
接下来的重头戏是比较选择排序和插入排序。通过下图的例子,我们可以看出第i个元素都进行一次交换和N-1-i次比较。对于长度为N的数组,选择排序要进行N^2/2次比较和N次交换。
而对于插入排序呢?情况比选择排序复杂。最坏情况(完全逆序)下,需要~N^2/2次比较和~N^2/2次交换;而最好情况(已经顺序)下,需要N-1次比较和0次交换。就如同例子中第3次插入时,S、T已经是有序的了,所以不存在交换的需要。对于随机排序的数组,在平均情况下每个元素都可能向后移动半个数组的长度,因此交换总数是~N^2/4,而比较次数是交换次数加上一个额外的项(相比N^2,可以忽略)。
而排序前数组的倒置(比如E-A)个数越少,插入排序就越快。接下来我们用随机数组来比较两种算法。
重复一百次的1000个随机数排序比较结果:
重复一百次的10000个随机数排序比较结果:
最后,我们可以得出:对于随机数组,插入排序和选择排序的运行时间是平方级别的,两者之比是一个较小的常数(本机测试为1.3~1.4)。
希尔排序的思想是使数组中任意减个为h的元素有序,也就是将插入排序的元素移动距离由1改变为逐渐增大的h。
public static void sort(Comparable a[]){ int N = a.length; int h = 1; while(h < N/3) h = 3*h + 1; while(h >= 1){ for(int i = h; i < N; i++){ for(int j = i; j >= h && less(a[j], a[j-h]); j -= h){ exch(a, j, j-h); } } h = h/3; } }
这么做的原因是因为部分有序数组更适合插入排序。那么,我们就比较一下这两种算法的执行速度。
相关文章推荐
- 编程珠玑第二章读书笔记 第二章 Aha!算法 (手摇法)
- 《大话数据结构》读书笔记 第二章 算法
- 机器学习实战第二章——学习KNN算法,读书笔记
- 读书笔记-《大话数据结构》第二章算法
- 大话数据结构 第二章 算法(读书笔记)
- 啊哈!算法读书笔记 | 第二章 栈、队列、链表
- 【编程珠玑】读书笔记 第二章 算法
- 《大话数据结构》读书笔记 第二章 算法 函数的渐近增长
- 【转】读书笔记:“集体智慧编程”之第二章:推荐算法——协同滤波
- 算法初级02——荷兰国旗问题、随机快速排序、堆排序、桶排序、相邻两数的最大差值问题、工程中的综合排序算法
- 《机器学习实战》读书笔记:第二章 k-近邻算法
- 《算法》阅读笔记-2.1初级排序算法
- 算法手记(5)初级排序算法
- 《算法导论》读书笔记--第二章 2.2 分析算法
- 用 Python 学习算法:初级排序算法
- (算法)初级排序算法
- 数据结构与算法(C语言) 第二章 算法分析 读书笔记
- 『算法』之 初级排序算法总结
- 算法第四版学习笔记之初级排序算法
- 《算法导论》读书笔记--第二章 2.3 设计算法