一、算法思想
选择排序的基本思想是:第一次从待排序的记录中选出最小(最大)的一个记录,存放在序列的起始位置,然后再从剩余的未排序记录中寻找到最小(大)元素,然后放到已排序的序列的末尾,以此类推。这里主要简单展开介绍简单选择排序、树形排序和堆排序。
![2c90a24012a64d6f325b4589b9590cde.png](https://i-blog.csdnimg.cn/blog_migrate/8fbf1818af257c8d2b40f73ce74c1fe0.jpeg)
二、简单选择排序
原理:
1、从待排序的记录中逐个比较第一个与其后记录的大小,选出最小(最大)的一个记录,与第一个位置的记录互换。
2、然后再从剩余的未排序记录中寻找到最小(大)元素,即重复1过程。
算法推演:
简单选择排序类似于冒泡排序(冒泡排序中相邻两个记录可以交换),直观简单。
简单选择排序是待排序列表的第一个值与后面的值比较,选择这一趟比较的最大值或最小值。
例如,排序列表{10,78,5,80,3}
![786fa54444b68a5f066609b0f8cf1b56.png](https://i-blog.csdnimg.cn/blog_migrate/c3f8f4f5ac3394a08080da1a3a468111.jpeg)
简单选择排序简单示意图
进一步的算法执行过程
![9aa741306db79bf39020f69327ea37d2.png](https://i-blog.csdnimg.cn/blog_migrate/a85159841ef9d1839ed0e0ed44bb0636.jpeg)
算法执行示意明细
python3代码实现
def selection_sort(sort_list): for i in range(len(sort_list)-1): #起始元素位置索引 min_index = i print("--记录开始比较位置"+str(i)+"值为:"+str(sort_list[i])) #逐步两两比较 for j in range(i + 1, len(sort_list)): print("----记录"+str(sort_list[j])+"与"+str(sort_list[min_index])+"比较大小") if sort_list[j] < sort_list[min_index]: print("--------最小值发生改变,"+str(sort_list[j])+"为临时最小值") min_index = j if i!=min_index: print("----最小值索引发生改变,索引位置互换,即"+str(sort_list[i])+"与"+str(sort_list[min_index])+"互换") sort_list[min_index], sort_list[i] = sort_list[i], sort_list[min_index] print("--第"+str(i+1)+"趟排序的结果:",sort_list)sort_list=[10, 78 , 5,80,3]print("排序前:",sort_list)selection_sort(sort_list)print("排序后:",sort_list)
三、树形选择排序
原理:首先对 n 个记录的关键字进行两两比较,然后在其中 不大于 n/2 的整数个较小者之间再进行两两比较,直到选出最小关键字的记录为止。可以用一棵有 n 个叶子结点的完全二叉树表示。
例如,排序列表【10, 78, 5, 80, 3,12】
![8ca0aa9ee17c444e1b5b7300fb15ebe6.png](https://i-blog.csdnimg.cn/blog_migrate/915ec1f2a1e34513102bc6d63b07e2d7.jpeg)
第1轮两两比较结果,取出最小值3
![b64a7ab8e31c8db4de5109e5475e92ec.png](https://i-blog.csdnimg.cn/blog_migrate/70b7ae08de90c32713b153597927f50e.jpeg)
第2轮两两比较结果,取出最小值5,原取值的节点值为None
![22aa304cffaa9ec957eab60aa05ad3b7.png](https://i-blog.csdnimg.cn/blog_migrate/aa9d86640f17e12e04055ef03a4cd65c.jpeg)
第3轮两两比较结果,取出最小值10,原取值的节点值为None
![1f0bec91ffc43ee02916d0780d4ac874.png](https://i-blog.csdnimg.cn/blog_migrate/254a0054aa4320a8363d2eba0ba1f9f3.jpeg)
第4轮两两比较结果,取出最小值12,原取值的节点值为None
![81e6d9095de5d6575cf46d0c01ccbea6.png](https://i-blog.csdnimg.cn/blog_migrate/5138c2665fdda21c45aefe7dad1713f4.jpeg)
第5轮两两比较结果,取出最小值78,原取值的节点值为None
第6轮,剩余一个节点,直接取出。
最后取出排序结果:
【3, 5, 10, 12, 78,80】
树形选择排序算法缺点有:
1、与None的比较多余
2、辅助空间使用多(以空间换时间)
四、构建堆与堆排序
1、构建堆
一般我们使用数组来存放最大堆,通过二叉树进行分析的。
它们满足的性质为:
二叉树中所有的父节点的值都不大于/不小于其子节点;根节点的值必定是所有节点中最小/最大的。数组的保存形式为:
父亲节点:i
左孩子节点:2∗i2∗i
右孩子节点:2∗i+1
二维数组初始堆
例如,排序列表【10, 78, 5, 80, 3,12】
![c6bd827033bf3fa04416ecdb9e10e93f.png](https://i-blog.csdnimg.cn/blog_migrate/b5d9d3f2d73306bf426284aefe16db2c.jpeg)
开始构建堆一般从二叉树的倒数第一个叶子节点开始,n//2(python语法),n为二叉树的节点数量,在本例中是从5开始,节点往上开始构建。
![1c27b7b549c911a00fdf5e016a0751ee.png](https://i-blog.csdnimg.cn/blog_migrate/a33404e0157a93e6d763b1adcf1fbf6d.jpeg)
构建完成的二叉树(小根堆)如下图所示:
![cef111b29e2f21adee82af84a951b4c5.png](https://i-blog.csdnimg.cn/blog_migrate/e9dc7abb914a66ce3c19d954d9288d59.jpeg)
2、堆排序
堆排序基本思路为:
- 构建最小堆(最大堆)
- 取出最小值(最大值)、将剩余n-1个记录重新构建新堆
- 重复2.过程,进行n-1次筛选
经过n-1次筛选结果如下图:
![bc729d8a01c6148b4fa3070f22578510.png](https://i-blog.csdnimg.cn/blog_migrate/3a375b909ed101140d41fed2e81e8390.jpeg)
3、堆构建和堆排序的python实现
def heapify(arr, n, idx): min = idx left = 2 * idx + 1 right = 2 * idx + 2 #如果父节点值大于LEFT节点值,则记录LEFT节点为最小值, if left < n and arr[idx] > arr[left]: min = left #如果最小值大于RIGHT节点值,则记录RIGHT节点为最小值 if right < n and arr[min] > arr[right]: min = right #比较索引是否改变 if min != idx: # 交换 arr[idx],arr[min] = arr[min],arr[idx] #递归构建堆 heapify(arr, n, min) def heapSort(arr): n = len(arr) # 构建最小值堆. 正常为n-1开始倒序,又索引从零0开始,则为n-1-1开始构建 for i in range((n-1-1)//2, -1, -1): heapify(arr, n, i) print("构建后:",arr) # 取出最小值,放在数组尾 for i in range(n-1, 0, -1): #交换 arr[i], arr[0] = arr[0], arr[i] #重新构建堆,因为根节点已经是最小值了,数组arr中索引位置i的值不再参与运算(传递的i为数组的长度,每次循环都-1) heapify(arr, i, 0) arr = [ 10, 78, 5, 80, 3,12] print ("排序前:",arr) heapSort(arr) print ("排序后:",arr)
代码亲测可行!
水平有限,若有不足,还望批评指正!
![b27ef6d43c7d6499811512254a7512c5.png](https://i-blog.csdnimg.cn/blog_migrate/f27c8b904a0929820e98d2a8de988c5b.jpeg)