目录
此次博客中的简单选择排序、堆排序都是属于选择排序。博客代码是博主想复习下排序算法然后手打的,已经过调试。若还有错误请指出!
一、直接插入排序
算法思想:
简单选择排序是一种选择排序。每趟选出最小关键字
平均 最坏 最好 空间 稳定性 复杂性
O(n²) O(n²) O(n²) O(1) 稳定 简单
简单选择排序的比较次数与序列的初始排序无关。 假设待排序的序列有 N 个元素,则比较次数总是N (N - 1) / 2。
而移动次数与序列的初始排序有关。当序列正序时,移动次数最少,为 0.
当序列反序时,移动次数最多,为3N (N - 1) / 2。
所以,综合以上,简单排序的时间复杂度为 O(N^2)。
算法稳定性
排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。
Python代码
def select_sort(input_list):
if len(input_list) <= 1:
return input_list
for i in range(len(input_list)-1):
min_index = i
for j in range(i+1,len(input_list)):
if input_list[j] < input_list[min_index]:
min_index = j
if min_index == i:
continue
input_list[i],input_list[min_index] = input_list[min_index],input_list[i]
return input_list
print(select_sort([10,9,8,7,6,5,3,2,1]))
二、堆排序
算法思想:
'''
堆排序
平均 最坏 最好 空间 稳定性 复杂性
O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定 较复杂
build_big_heap() 耗时 logn,共 n 次,故排序时间为 O(nlogn)。
堆是一棵顺序存储的完全二叉树。
其中每个结点的关键字都不大于其孩子结点的关键字,这样的堆称为小根堆。
其中每个结点的关键字都不小于其孩子结点的关键字,这样的堆称为大根堆。
举例来说,对于n个元素的序列{R0, R1, ... , Rn}当且仅当满足下列关系之一时,称之为堆:
Ri <= R2i+1 且 Ri <= R2i+2 (小根堆)
Ri >= R2i+1 且 Ri >= R2i+2 (大根堆)
其中i=1,2,…,n/2向下取整;
设当前元素在数组中以R[i]表示,那么,
(1) 它的左孩子结点是:R[2*i+1];
(2) 它的右孩子结点是:R[2*i+2];
(3) 它的父结点是:R[(i-1)/2];
(4) R[i] <= R[2*i+1] 且 R[i] <= R[2i+2]。
以上思想可归纳为两个操作:
(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。
(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。
如何确定最后一个非叶子结点?
设二叉树结点总数为 n,则最后一个非叶子结点是第 n/2 个。
ps:当想得到一个序列中第k个最小的元素之前的部分排序序列,最好采用堆排序。topK问题,冒泡也可以
'''
算法稳定性
因为在堆的调整过程中,关键字进行比较和交换所走的是该结点到叶子结点的一条路径,因此对于相同的关键字就可能出现排在后面的关键字被交换到前面来的情况。(不稳定)
Python代码
def build_big_heap(input_list,parent_index,last_index):
'''
:param input_list: # 待排序列表
:param parent_index: # 父节点索引
:param last_index: # 数组最后一个数的索引
'''
child_index = 2 * parent_index + 1
temp = input_list[parent_index] # 存储最开始父节点的值
while child_index < last_index: # 索引不得超出数组
if child_index + 1 < last_index and input_list[child_index] < input_list[child_index+1]: # 如果有第二个子节点且第二子节点大于第一子节点
child_index += 1 # 换成第二个子节点的索引
if temp >= input_list[child_index]: # 如果最开始父节点的值大于此时的子节点
break # 不用做什么操作,break
else: # 如果最开始父节点的值小于此时的子节点
input_list[parent_index] = input_list[child_index] # 将此时父节点的值换成此时的子节点
parent_index = child_index # 将此时的子节点看成父节点
child_index = 2 * parent_index + 1 # 求出它第一个子节点的值
input_list[parent_index] = temp # 将此时父节点的值换成最开始父节点的值
def heap_sort(input_list):
if len(input_list) <= 1:
return input_list
for i in range(0,len(input_list) // 2)[::-1]: # 从最后一个非叶子结点开始到根节点构建大根堆
build_big_heap(input_list,i,len(input_list))
for j in range(1,len(input_list))[::-1]:# 渐渐缩小数组直到数组长度为1
input_list[0],input_list[j] = input_list[j],input_list[0] # 每次都交换第一个数和最后一个数
build_big_heap(input_list,0,j) # 每次的最大数被换到数组最后,构建过程已经被排除
print(f'第{len(input_list)-j}躺排序:',input_list)
return input_list