常见的经典排序算法有10种,可以分为两大类:
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
冒泡排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 |
希尔排序 | O(n^1.3) | O(n^2) | O(n) | O(1) | 不稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
快速排序 | O(nlogn) | O(n^2) | O(nlogn) | O(nlogn) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 稳定 |
桶排序 | O(n+k) | O(n^2) | O(n) | O(n+k) | 稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
注:
插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
# 直接插入排序
def Direct_Insertion_Sort(ary):
for i in range(1, len(ary)): # 第一个元素认为已排序,从第二个元素开始遍历
if ary[i] < ary[i-1]: # 取出已经排好序的元素的下一个元素,与排好序的最后一个元素对比
tmp = ary[i] # 如果小于最后一个元素,则将待排序元素的值赋给临时变量tmp
index = i # 下标赋给index,待插入下标
for j in range(i-1, -1, -1): # 从排好序的元素的最后一个元素开始向前遍历,循环到0
if ary[j] > tmp: # 若之前有序的元素大于待排序元素
ary[j+1] = ary[j] # 将该元素后移
index = j # 待插入位置为j
else: # 若大于之前排好序的元素则终止循环
break
ary[index] = tmp
return ary
if __name__ == '__main__':
ary = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] # 待排序数组
correct_ary = [2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 9, 12, 15, 44, 45, 54, 64] # 排好序数组
print("正确排序后的结果:")
print(correct_ary)
# 直接插入排序结果
insert_sort_result = Direct_Insertion_Sort(ary)
print("直接插入排序后的结果:")
print(insert_sort_result)
原始待排序数组:
[2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44]
正确排序后的结果:
[2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 9, 12, 15, 44, 45, 54, 64]
直接插入排序后的结果:
[2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 9, 12, 15, 44, 45, 54, 64]
插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
折半插入排序是在一组有序数列中插入新的元素,找到插入位置是高半区还是低半区。折半插入排序所需附加存储空间和直接插入排序相同,从时间上比较,折半插入排序减少了关键字间的比较次数,而记录的移动次数不变。
区别:在插入到已排序的数据时采用来折半查找(二分查找),取已经排好序的数组的中间元素,与插入的数据进行比较,如果比插入的数据大,那么插入的数据肯定属于前半部分,否则属于后半部分,依次不断缩小范围,确定要插入的位置。
# 折半插入排序
def Binary_Insertion_Sort(ary):
for i in range(1, len(ary)): # 从数组第二个元素开始
if ary[i] < ary[i - 1]: # 如果小于前一个元素
x = ary[i] # 值赋给临时变量x
low = 0
high = i - 1
while low <= high:
m = int((low + high) / 2)
if x < ary[m]: # 与排好序的中间值比较,找到需要插入的位置
high = m - 1
else:
low = m + 1
for j in range(i - 1, high, -1):
ary[j + 1] = ary[j] # 统一移动该移动元素
ary[high + 1] = x # 插入到正确位置
return ary
先折半查找元素的应该插入的位置,然后统一移动应该移动的元素,再将这个元素插入到正确的位置。
优点 : 稳定,相对于直接插入排序元素减少了比较次数;
缺点 : 相对于直接插入排序元素的移动次数不变;
时间复杂度:可以看出,折半插入排序减少了比较元素的次数,约为O(nlogn),比较的次数取决于表的元素个数n。因此,折半插入排序的时间复杂度仍然为O(n²),但它的效果还是比直接插入排序要好。
空间复杂度:排序只需要一个位置来暂存元素,因此空间复杂度为O(1)。
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
某一趟遍历如果没有数据交换,则说明已经排好序了,因此不用再进行迭代了。用一个标记记录这个状态即可。
# 冒泡排序
def Bubble_Sort(ary):
for i in range(len(ary) - 1, 0, -1):
flag = 1 # 用状态判断本次循环是否改变,flag=1表示没有改变
for j in range(0, i):
if ary[j] > ary[j + 1]: # 如果前者比后者大
ary[j], ary[j + 1] = ary[j + 1], ary[j] # 则交换位置
flag = 0
if flag:
break
return ary
进一步优化:
记录某次遍历时最后发生数据交换的位置,这个位置之后的数据显然已经有序了。因此通过记录最后发生数据交换的位置就可以确定下次循环的范围了。
def bubble_sort(ary):
n = len(ary)
k = n #k为循环的范围,初始值n
for i in range(n):
flag = 1
for j in range(1,k): #只遍历到最后交换的位置即可
if ary[j-1] > ary[j] :
ary[j-1],ary[j] = ary[j],ary[j-1]
k = j #记录最后交换的位置
flag = 0
if flag :
break
return ary
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:
# 选择排序
def Selection_Sort(ary):
n = len(ary)
for i in range(0, n):
min = i # 最小元素下标标记
for j in range(i + 1, n):
if ary[j] < ary[min]:
min = j # 找到最小值的下标
ary[min], ary[i] = ary[i], ary[min] # 交换两者
return ary
希尔排序,也称递减增量排序算法,实质是分组插入排序。由 Donald Shell 于1959年提出。希尔排序是非稳定排序算法。
希尔排序的基本思想是:将数组列在一个表中并对列分别进行插入排序,重复这过程,不过每次用更长的列(步长更长了,列数更少了)来进行。最后整个表就只有一列了。将数组转换至表是为了更好地理解这算法,算法本身还是使用数组进行排序。
【从大范围到小范围进行比较-交换】类似冒泡和插入的联合
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
注:步长分别为5,3,1
# 希尔排序
def Shell_Sort(ary):
n = len(ary)
gap = round(n / 2) # 初始步长 , 用round四舍五入取整
while gap > 0:
for i in range(gap, n): # 每一列进行插入排序 , 从gap 到 n-1
temp = ary[i]
j = i
while (j >= gap and ary[j - gap] > temp): # 插入排序
ary[j] = ary[j - gap] # 交换位置
j = j - gap # 改变下标
ary[j] = temp # 交换位置
gap = round(gap / 2) # 重新设置步长
return ary
注:上面源码的步长的选择是从n/2开始,每次再减半,直至为0。步长的选择直接决定了希尔排序的复杂度。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
归并排序的思想就是先递归分解数组,再合并数组。
分治法-2-4-8插入排序:
# 归并排序
def Merge_Sort(ary):
if len(ary) <= 1:
return ary
num = int(len(ary) / 2) # 二分分解
left = Merge_Sort(ary[:num]) # 递归
right = Merge_Sort(ary[num:])
return merge(left, right) # 合并数组
def merge(left, right):
# 合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组
l, r = 0, 0 # left与right数组的下标指针
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]: # 按顺序加入到最终数组
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result
快速排序通常明显比同为Ο(n log n)的其他算法更快,因此常被采用,而且快排采用了分治法的思想,所以在很多笔试面试中能经常看到快排的影子。
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
# 快排序
def Quick_Sort(ary):
return qsort(ary, 0, len(ary)-1)
def qsort(ary, left, right):
# 快排函数,ary为待排序数组,left为待排序的左边界,right为右边界
if left >= right:
return ary
key = ary[left] # 取最左边的为基准数
lp = left # 左指针
rp = right # 右指针
while lp < rp:
while ary[rp] >= key and lp < rp:
rp -= 1
while ary[lp] <= key and lp < rp:
lp += 1
ary[lp], ary[rp] = ary[rp], ary[lp] # 交换位置
ary[left], ary[lp] = ary[lp], ary[left]
qsort(ary, left, lp-1) # 递归左部分
qsort(ary, rp+1, right) # 递归右部分
return ary
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
堆排序在 top K 问题中使用比较频繁。堆排序是采用二叉堆的数据结构来实现的,虽然实质上还是一维数组。
二叉堆具有以下性质:
构造最大堆(Build_Max_Heap):若数组下标范围为0~n,考虑到单独一个元素是大根堆,则从下标n/2开始的元素均为大根堆。于是只要从n/2-1开始,向前依次构造大根堆,这样就能保证,构造到某个节点时,它的左右子树都已经是大根堆。
堆排序(HeapSort):由于堆是用数组模拟的。得到一个大根堆后,数组内部并不是有序的。因此需要将堆化数组有序化。思想是移除根节点,并做最大堆调整的递归运算。第一次将heap[0]与heap[n-1]交换,再对heap[0…n-2]做最大堆调整。第二次将heap[0]与heap[n-2]交换,再对heap[0…n-3]做最大堆调整。重复该操作直至heap[0]和heap[1]交换。由于每次都是将最大的数并入到后面的有序区间,故操作完后整个数组就是有序的了。
最大堆调整(Max_Heapify):该方法是提供给上述两个过程调用的。目的是将堆的末端子节点作调整,使得子节点永远小于父节点 。
# 堆排序
def Heap_Sort(ary):
n = len(ary)
first = int(n / 2 - 1) # 最后一个非叶子节点
for start in range(first, -1, -1): # 构造大根堆
max_heapify(ary, start, n - 1)
for end in range(n - 1, 0, -1): # 堆排,将大根堆转换成有序数组
ary[end], ary[0] = ary[0], ary[end]
max_heapify(ary, 0, end - 1)
return ary
# 最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
# start为当前需要调整最大堆的位置,end为调整边界
def max_heapify(ary, start, end):
root = start
while True:
child = root*2 + 1 # 调整节点的子节点
if child > end:
break
if child+1 <= end and ary[child] < ary[child+1]:
child = child+1 # 取较大的子节点
if ary[root] < ary[child]: # 较大的子节点成为父节点
ary[root], ary[child] = ary[child], ary[root] # 交换
root = child
else:
break
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
# 计数排序
def Count_Sort(ary):
max = 0 # 最大值
min = 0 # 最小值
for i in ary: # 计算最值
if max < i:
max = i
if min > i:
min = i
dict_value = {} # 字典存储次数
for i in ary:
if i in dict_value.keys():
dict_value[i] += 1
else:
dict_value[i] = 1
result = [] # 存储排序结果
for i in range(min, max+1):
if i in dict_value.keys():
for j in range(dict_value[i]):
result.append(i)
return result
计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。
计数排序的缺点:
当数值中有非整数时,计数数组的索引无法分配
计数排序是以牺牲空间换时间,虽然很快,但由于可能产生大量的空位置导致内存增大。
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
桶排序与计数排序类似,但可以解决非整数的排序。
# 桶排序(可以处理非整数)
def Bucket_Sort(ary):
min_num = min(ary)
max_num = max(ary)
# 桶的大小
bucket_range = (max_num - min_num) / len(ary)
# 桶数组
count_list = [[] for i in range(len(ary) + 1)]
# 向桶数组填数
for i in ary:
count_list[int((i - min_num) // bucket_range)].append(i)
result = []
# 回填,这里桶内部排序直接调用了sorted,可以选用不同的排序方法
for i in count_list:
for j in sorted(i):
result.append(j)
return result
桶排序最好情况下使用线性时间O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。
桶排序中尽量使每个桶中的元素个数均匀分布最好。
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
这里将列表进行基数排序,默认列表中的元素都是正整数
# 基数排序
def Radix_Sort(ary):
n = len(str(max(ary))) # 记录最大值的位数
for k in range(n): # n轮排序
# 每一轮生成10个列表
bucket_list = [[] for i in range(10)] # 因为每一位数字都是0~9,故建立10个桶
for i in ary:
# 按第k位放入到桶中
bucket_list[i // (10 ** k) % 10].append(i)
# 按当前桶的顺序重排列表
ary = [j for i in bucket_list for j in i]
return ary
基数排序基于分别排序,分别收集,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要O(n)的时间复杂度。假如待排数据可以分为d个关键字,则基数排序的时间复杂度将是O(d*2n) ,当然d要远远小于n,因此基本上还是线性级别的。
基数排序的空间复杂度为O(n+k),其中k为桶的数量。一般来说n>>k,因此额外空间需要大概n个左右。
桶排序与基数排序常作为桶式排序出现,基数排序进行了多轮的桶排序。桶式排序不再是一种基于比较的排序方法,它是一种比较巧妙的排序方式,但这种排序方式需要待排序的序列满足以下两个特征:待排序列所有的值处于一个可枚举的范围之类;待排序列所在的这个可枚举的范围不应该太大,否则排序开销太大。
参考文档:
十大经典排序算法(动图演示)
经典排序算法总结与实现—Python
计数排序与桶排序的python实现
十大经典排序算法(python实现)(原创)
附录:
完整代码
"""
下面是10种经典排序的简单python实现
Date: 2020/11/1
By: Zhugangya
"""
# 直接插入排序
def Direct_Insertion_Sort(ary):
for i in range(1, len(ary)): # 第一个元素认为已排序,从第二个元素开始遍历
if ary[i] < ary[i-1]: # 取出已经排好序的元素的下一个元素,与排好序的最后一个元素对比
tmp = ary[i] # 如果小于最后一个元素,则将待排序元素的值赋给临时变量tmp
index = i # 下标赋给index,待插入下标
for j in range(i-1, -1, -1): # 从排好序的元素的最后一个元素开始向前遍历,循环到0
if ary[j] > tmp: # 若之前有序的元素大于待排序元素
ary[j+1] = ary[j] # 将该元素后移
index = j # 待插入位置为j
else: # 若大于之前排好序的元素则终止循环
break
ary[index] = tmp
return ary
# 折半插入排序
def Binary_Insertion_Sort(ary):
for i in range(1, len(ary)): # 从数组第二个元素开始
if ary[i] < ary[i - 1]: # 如果小于前一个元素
x = ary[i] # 值赋给临时变量x
low = 0
high = i - 1
while low <= high:
m = int((low + high) / 2)
if x < ary[m]: # 与排好序的中间值比较,找到需要插入的位置
high = m - 1
else:
low = m + 1
for j in range(i - 1, high, -1):
ary[j + 1] = ary[j] # 统一移动该移动元素
ary[high + 1] = x # 插入到正确位置
return ary
# 冒泡排序
def Bubble_Sort(ary):
for i in range(len(ary) - 1, 0, -1):
flag = 1 # 用状态判断本次循环是否改变,flag=1表示没有改变
for j in range(0, i):
if ary[j] > ary[j + 1]: # 如果前者比后者大
ary[j], ary[j + 1] = ary[j + 1], ary[j] # 则交换位置
flag = 0
if flag:
break
return ary
# 选择排序
def Selection_Sort(ary):
n = len(ary)
for i in range(0, n):
min = i # 最小元素下标标记
for j in range(i + 1, n):
if ary[j] < ary[min]:
min = j # 找到最小值的下标
ary[min], ary[i] = ary[i], ary[min] # 交换两者
return ary
# 希尔排序
def Shell_Sort(ary):
n = len(ary)
gap = round(n / 2) # 初始步长 , 用round四舍五入取整
while gap > 0:
for i in range(gap, n): # 每一列进行插入排序 , 从gap 到 n-1
temp = ary[i]
j = i
while (j >= gap and ary[j - gap] > temp): # 插入排序
ary[j] = ary[j - gap] # 交换位置
j = j - gap # 改变下标
ary[j] = temp # 交换位置
gap = round(gap / 2) # 重新设置步长
return ary
# 归并排序
def Merge_Sort(ary):
if len(ary) <= 1:
return ary
num = int(len(ary) / 2) # 二分分解
left = Merge_Sort(ary[:num]) # 递归
right = Merge_Sort(ary[num:])
return merge(left, right) # 合并数组
def merge(left, right):
# 合并操作,将两个有序数组left[]和right[]合并成一个大的有序数组
l, r = 0, 0 # left与right数组的下标指针
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result
# 快排序
def Quick_Sort(ary):
return qsort(ary, 0, len(ary)-1)
def qsort(ary, left, right):
# 快排函数,ary为待排序数组,left为待排序的左边界,right为右边界
if left >= right:
return ary
key = ary[left] # 取最左边的为基准数
lp = left # 左指针
rp = right # 右指针
while lp < rp:
while ary[rp] >= key and lp < rp:
rp -= 1
while ary[lp] <= key and lp < rp:
lp += 1
ary[lp], ary[rp] = ary[rp], ary[lp] # 交换位置
ary[left], ary[lp] = ary[lp], ary[left]
qsort(ary, left, lp-1) # 递归左部分
qsort(ary, rp+1, right) # 递归右部分
return ary
# 堆排序
def Heap_Sort(ary):
n = len(ary)
first = int(n / 2 - 1) # 最后一个非叶子节点
for start in range(first, -1, -1): # 构造大根堆
max_heapify(ary, start, n - 1)
for end in range(n - 1, 0, -1): # 堆排,将大根堆转换成有序数组
ary[end], ary[0] = ary[0], ary[end]
max_heapify(ary, 0, end - 1)
return ary
# 最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
# start为当前需要调整最大堆的位置,end为调整边界
def max_heapify(ary, start, end):
root = start
while True:
child = root*2 + 1 # 调整节点的子节点
if child > end:
break
if child+1 <= end and ary[child] < ary[child+1]:
child = child+1 # 取较大的子节点
if ary[root] < ary[child]: # 较大的子节点成为父节点
ary[root], ary[child] = ary[child], ary[root] # 交换
root = child
else:
break
# 计数排序
def Count_Sort(ary):
max = 0 # 最大值
min = 0 # 最小值
for i in ary: # 计算最值
if max < i:
max = i
if min > i:
min = i
dict_value = {} # 字典存储次数
for i in ary:
if i in dict_value.keys():
dict_value[i] += 1
else:
dict_value[i] = 1
result = [] # 存储排序结果
for i in range(min, max+1):
if i in dict_value.keys():
for j in range(dict_value[i]):
result.append(i)
return result
# 计数排序升级版桶排序
def bucketSort(nums):
# 选择一个最大的数
max_num = max(nums)
# 创建一个元素全是0的列表, 当做桶
bucket = [0] * (max_num + 1)
# 把所有元素放入桶中, 即把对应元素个数加一
for i in nums:
bucket[i] += 1
# 存储排序好的元素
sort_nums = []
# 取出桶中的元素
for j in range(len(bucket)):
if bucket[j] != 0:
for y in range(bucket[j]):
sort_nums.append(j)
return sort_nums
# 桶排序(可以处理非整数)
def Bucket_Sort(ary):
min_num = min(ary)
max_num = max(ary)
# 桶的大小
bucket_range = (max_num - min_num) / len(ary)
# 桶数组
count_list = [[] for i in range(len(ary) + 1)]
# 向桶数组填数
for i in ary:
count_list[int((i - min_num) // bucket_range)].append(i)
result = []
# 回填,这里桶内部排序直接调用了sorted,可以选用不同的排序方法
for i in count_list:
for j in sorted(i):
result.append(j)
return result
# 基数排序
def Radix_Sort(ary):
n = len(str(max(ary))) # 记录最大值的位数
for k in range(n): # n轮排序
# 每一轮生成10个列表
bucket_list = [[] for i in range(10)] # 因为每一位数字都是0~9,故建立10个桶
for i in ary:
# 按第k位放入到桶中
bucket_list[i // (10 ** k) % 10].append(i)
# 按当前桶的顺序重排列表
ary = [j for i in bucket_list for j in i]
return ary
if __name__ == '__main__':
ary = [2, 15, 5, 9, 7, 6, 4, 12, 5, 4, 2, 64, 5, 6, 4, 2, 3, 54, 45, 4, 44] # 待排序数组
correct_ary = [2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 9, 12, 15, 44, 45, 54, 64] # 排好序数组
print("原始待排序数组:")
print(ary)
print("正确排序后的结果:")
print(correct_ary)
# 直接插入排序结果
#insert_sort_result = Direct_Insertion_Sort(ary)
print("直接插入排序后的结果:")
#print(insert_sort_result)
# 折半插入排序结果
#binary_insert_sort_result = Binary_Insertion_Sort(ary)
print("折半插入排序后的结果:")
#print(binary_insert_sort_result)
# 冒泡排序结果
#bubble_sort_result = Bubble_Sort(ary)
print("冒泡排序后的结果:")
#print(bubble_sort_result)
# 选择排序结果
#selection_sort_result = Selection_Sort(ary)
print("选择排序后的结果:")
#print(selection_sort_result)
# 希尔排序结果
#shell_sort_result = Shell_Sort(ary)
print("希尔排序后的结果:")
#print(shell_sort_result)
# 归并排序结果
#merge_sort_result = Merge_Sort(ary)
print("归并排序后的结果:")
#print(merge_sort_result)
# 快速排序结果
#quick_sort_result = Quick_Sort(ary)
print("快速排序后的结果:")
#print(quick_sort_result)
# 堆排序结果
#heap_sort_result = Heap_Sort(ary)
print("堆排序后的结果:")
#print(heap_sort_result)
# 计数排序结果
#count_sort_result = Count_Sort(ary)
print("计数排序后的结果:")
#print(count_sort_result)
# 计数排序结果
#bucket_sort_result = Bucket_Sort(ary)
print("桶排序后的结果:")
#print(bucket_sort_result)
# 计数排序结果
radix_sort_result = Radix_Sort(ary)
print("基数排序后的结果:")
print(radix_sort_result)