1. 插入排序
def insertsort(a):
if len(a)==1:
return a
for i in range(1,len(a)):
j=i-1
insert=a[i]
while j>=0 and a[j]>insert:
a[j+1]=a[j]
j=j-1
a[j+1]=insert
return a
插入排序首先认为第一个元素是排好序的,然后将之后的元素往排好序的元素里插入,这里用了一个while循环来替代了swap的交换,可以提高效率。
时间复杂的:
最好情况下数组已经排好序,每次while循环里只比较一次,所以是
最坏情况下数组倒序,每次while循环里要比较i次,i从1到n,比较,所以是
2. 堆排序
堆排序首先构造一个堆,堆分为大顶堆和小顶堆。以大顶堆为例,大顶堆是一个完全二叉树,每一个节点都要大于它的左右孩子节点,所以根节点是最大的。排序的方法就是先构造一个大顶堆,然后将根与最后一个节点交换,剩余的节点再调成为大顶堆,选出最大的根节点再交换,依次选出树中最大的节点来。时间复杂度是nlogn,虽然看上去是简单的每次选最大的,但是用树形结构相当于记录了每次比较的结果,在算法中可以看到每次循环只比较了树高次的节点。
def adject_heap(ls,i,size):
lchild=2*i+1
rchild=2*i+2
max=i
if i<size/2:
if lchild<size and ls[lchild]>ls[max]:
max=lchild
if rchild<size and ls[rchild]>ls[max]:
max=rchild
if max!=i:
ls[max],ls[i]=ls[i],ls[max]
adject_heap(ls,max,size)
def build_heap(ls,size):
for i in range(0,int(size/2))[::-1]:
adject_heap(ls,i,size)
ls=[49,38,65,97,76,13,27,49]
size=len(ls)
build_heap(ls,size)
for i in range(0,size)[::-1]:
ls[0],ls[i]=ls[i],ls[0]
adject_heap(ls,0,i)
print(ls)
首先构造大顶堆,build_heap。在数组上没有显式的构造树,而是假设数组是从前到后排成一个树,49是根,38,65是它的子节点,依次往后。所以构造大顶堆的过程就是调整数组让它成为一个大顶堆,也就是adject_heap。注意build_heap里我们是从size/2开始到0的,这样做是因为叶节点没有子节点所以不用调整,而且调整要从下到上。
通过分析数组下标可以发现,49是根,标号是0,它的左右孩子分别是1和2,也就是lchild=2*i+1,rchild=2*i+2。有的博客会在最前面加一个0辅助,这样是没有必要的。调整的方法就是先记录三个下标,max=当前节点,lchild,rchild是左右孩子,比较max的节点和孩子比哪个大,大的话将max赋值给哪个节点的下标。注意要判别child的下标<size and i<size/2。比较完了交换节点,交换之后的话原先的i节点的数字被交换到下面去了,可能会影响下面的树不满足堆,所以要接着调整下面,此时当前节点是max.
经过build_heap之后现在是一个大顶堆了,根是数组中最大的元素,将根与数组最后一个元素交换,此时再对除最后一个元素之外的元素调整成堆,获得根就是最大值再添加到末尾,依次从大到小排序。
3. 快速排序
def quick(ls,start,end):
if not ls:
return
i,j=start,end
key=ls[start]
if start<end:
while i<j:
while i<j and ls[j]>=key:
j=j-1
ls[i]=ls[j]
while i<j and ls[i]<=key:
i=i+1
ls[j]=ls[i]
ls[i]=key
quick(ls,start,i-1)
quick(ls,j+1,end)
return ls
#ls=[49,38,65,97,76,13,27,49]
ls=[1,3]
quick(ls,0,len(ls)-1)
print(ls)
快速排序就是选取数组中的一个数为key,然后将比key大的数都移到右边,比key小的数都移到左边,然后再递归用这种方法排序左边和右边。这种方法还可以用来求数组中第k大的数。
快速排序有各种方法,不同在排序的方法上,我这里使用的是挖坑法。先记录下key的值,然后右指针往左扫到小于key的数的时候将数赋给之前挖的坑,这里就变成了新坑,然后左指针向右扫描到大于key的数填到坑里又出现新坑,最后剩下的坑填入我们之前保存的key值。