python实现排序算法(二)
希尔排序
希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
插入排序在对几乎已经排好序的数据操作时,效率高,既可以达到线性排序的效率。
但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
算法原理
希尔排序基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
- 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
- 按增量序列的个数 k,对序列进行 k 趟排序;
- 每趟排序,根据对应的增量 ti,将待排序序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
复杂度分析
- 最坏复杂度: 时间复杂度为 O(n(logn)^2)
- 最好复杂度:时间复杂度为 O(nlogn)
- 平均复杂度: 取决于间隔序列
算法实现
def shell_sort(sequence):
#获取列表的长度
gap=len(sequence)
while gap>1:
#除2取整数
gap=gap//2
for i in range(gap,len(sequence)):
for j in range(i%gap,gap):
if sequence[i]<sequence[j]:
#print(i,j,sequence[i],sequence[j])
sequence[i],sequence[j]=sequence[j],sequence[i]
return sequence
if __name__ == '__main__':
sequence = [12, 27, 46, 16, 25, 37, 22, 29, 15, 47, 48, 34]
print(sequence)
print(shell_sort(sequence))
归并排序
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2-路归并。
算法原理
归并排序基本思想是:
- 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
归并排序演示
复杂度分析
- 最坏复杂度: 时间复杂度为 O(nlogn)
- 最好复杂度:时间复杂度为 O(nlogn)
- 平均复杂度: 时间复杂度为 O(nlogn)
算法实现
import math
def merge_sort(sequence):
if(len(sequence)<2):
return sequence
#取中间值,除2取整数
mid=math.floor(len(sequence)/2)
#以中间值为界限,分为左右两个列表
left,right=sequence[0:mid],sequence[mid:]
#返回分开后的两个列表
return merge(merge_sort(left),merge_sort(right))
def merge(left,right):
#存储处理后的列表
result=[]
#左右列表存在不为空
while left and right:
#如果左的第一个元素小于右的第一个元素
if left[0]<=right[0]:
#添加左列表弹出的第一个元素
result.append(left.pop(0))
else:
#添加右列表弹出的第一个元素
result.append(right.pop(0))
#当左右列表有一个为空时,将列表剩余的元素依次弹出添加到结果列表
while left:
result.append(left.pop(0))
while right:
result.append(right.pop(0))
#返回结果列表
return result
if __name__ == '__main__':
sequence = [12, 27, 46, 16, 25, 37, 22, 29, 15, 47, 48, 34]
print(sequence)
print(merge_sort(sequence))
快速排序
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
算法原理
- 归并排序基本思想是:使用分治法来把一个串(list)分为两个子串(sub-lists)
- 从数列中挑出一个元素,称为"基准"(pivot)。
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
复杂度分析
- 最坏复杂度: 时间复杂度为 O(n^2)
- 最好复杂度:时间复杂度在 O(n) 和 O(nlogn)中间
- 平均复杂度: 时间复杂度为 O(nlogn)
算法实现
def quick_select(sequence):
def recursive(begin,end):
#
if begin>end:
return
#左右分别取开始索引与结束索引
left,right=begin,end
#基准取数列首个元素
pivot=sequence[left]
#当左的索引值小于右索引值
while left<right:
#右索引所表示的值大于基准值,索引-1,向前移动
while left<right and sequence[right]>pivot:
right=right-1
#左索引所表示的值大于基准值,索引+1,向后移动
while left<right and sequence[left]<=pivot:
left=left+1
#交换找到的两个不符合判断条件值
sequence[left],sequence[right]=sequence[right],sequence[left]
#将基准值填充进去,并重新赋值开始索引
sequence[left],sequence[begin]=pivot,sequence[left]
#左右两侧递归使用快速排序
recursive(begin,left-1)
recursive(right+1,end)
recursive(0,len(sequence)-1)
return sequence
if __name__ == '__main__':
sequence = [12, 27, 46, 16, 25, 37, 22, 29, 15, 47, 48, 34]
print(sequence)
print(quick_select(sequence))