经典算法梳理-排序算法

排序算法

在这里插入图片描述

为了测试各个算法的复杂度,直接用以下程序生成10000个数字的列表进行排序:

import random
lis = [random.randint(1,1000) for ii in range(10000)]

首先测试内置排序算法sorted()函数的运行时间,sorted()函数使用的是归并排序,后面也会复现。

import time
start=time.time()
base_sort=sorted(lis)
end=time.time()
interval=end-start
print(interval)
## 0.0016279220581054688

冒泡排序

冒泡排序实际上就是第i个元素不断的与ii+1的元素两两比较,将最大值往后移,例如:

[6, 9, 10, 5, 7, 7, 8, 8]
[6, 9, 5, 10, 7, 7, 8, 8]
[6, 9, 5, 7, 10, 7, 8, 8]
[6, 9, 5, 7, 7, 10, 8, 8]
[6, 9, 5, 7, 7, 8, 10, 8]
[6, 9, 5, 7, 7, 8, 8, 10]
[6, 5, 9, 7, 7, 8, 8, 10]
[6, 5, 7, 9, 7, 8, 8, 10]
[6, 5, 7, 7, 9, 8, 8, 10]
[6, 5, 7, 7, 8, 9, 8, 10]
[6, 5, 7, 7, 8, 8, 9, 10]
[5, 6, 7, 7, 8, 8, 9, 10]
实现代码如下:

## 冒泡排序
def bubble_sort(lis):
    switch=True
    while switch:
        cc=0
        for ii in range(len(lis)-1):
            if lis[ii]>lis[ii+1]:
                cc+=1
                lis[ii],lis[ii+1]=lis[ii+1],lis[ii]
        if cc==0:
            switch=False 
    return lis

从代码就可以看出,最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)最坏时间复杂度:O(n2)(while的地方循环次数也为列表的的长度)。稳定性:稳定
10000个随机数字测试:

start=time.time()
sort_def_bubble=bubble_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 13.968239068984985

选择排序

先从所有的序列中找到最小的,放在第一位,再从除了第一个位置的序列中找到最小的放在第二位置,再从除了第一位置和第二位置的序列中找到最小的放在第三个位置,以此类推。
代码实现:

def sel_sort(lis):
	for ii in range(len(lis)-1):
		min_pos=ii # 先假设最小值在第ii位置,后面发现比他更小的就替换掉
		for jj in range(ii,len(lis)):
			if lis[jj]<lis[min_pos]:
				min_pos=jj
		if min_pos!=ii:
			lis[ii],lis[min_pos]=lis[min_pos],lis[ii]
	return lis

最优时间复杂度:O(n2);最坏时间复杂度:O(n2);稳定性:不稳定
测试:

start=time.time()
sort_def_sel=sel_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 3.3619589805603027

插入排序

如果第二个位置的数小于第一个位置的数,则第二个数与第一个数交换,第三个数如果小于第一和第二个数,则第三个数依次与第二个数,第一个数交换直到挪到第一个位置,以此类推。例如:
1,5,3,2,6
1,3,5,2,6
1,3,2,5,6
1,2,3,5,6
代码实现:

def inset_sort(lis):
	for ii in range(1,len(lis)):
		for jj in range(ii,0,-1):
			if lis[jj]<lis[jj-1]:
				lis[jj-1],lis[jj]=lis[jj],lis[jj-1]
	return lis

最优时间复杂度:O(n) (升序排列,序列已经处于升序状态);最坏时间复杂度:O(n2);稳定性:稳定
测试:

start=time.time()
sort_def_sel=insert_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 4.615377902984619

希尔排序(插入排序衍生)

插入算法的升级版本,每次按照一定的步长把原始列表变成一个数组,对数组的列进行排序,在进一步缩小步长,直到步长为1,即为传统的插入排序。
代码实现:

def shell_sort(lis):
	gap=len(lis)//2
	while gap>=1:
		for ii in range(len(lis)):
			jj=ii
			while jj>=gap and lis[jj]<lis[jj-gap]:
				lis[jj],lis[jj-gap]=lis[jj-gap],lis[jj]
				jj-=gap
		gap=gap//2	

最优时间复杂度:根据步长序列的不同而不同;最坏时间复杂度:O(n2);稳定性:不稳定
测试:

start=time.time()
sort_def_sel=shell_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 0.026904821395874023

快速排序(分而治之策略,递归算法)

随便选一个baseline,比如列表中的第一个数,找到比第一个数小的数们放在第一个数左边,找到比第一个数大的数们,放在第一个数右边,然后再对【比第一个数小的数们】和【比第一个数大的数们】形成的列表分别进行快速排序。直到列表被拆分成只含有一个元素的列表,则返回列表本身。
代码如下:

def quick_sort(lis):
    if len(lis) < 2:
        return lis
    baseline=lis[0]
    big_lis=[ii for ii in lis[1:] if ii>baseline]
    small_lis=[ii for ii in lis[1:] if ii<=baseline]
    return quick_sort(small_lis)+[baseline]+quick_sort(big_lis)

最优时间复杂度:O(nlogn),最坏时间复杂度:O(n2);稳定性:不稳定
测试:

start=time.time()
sort_def_sel=quick_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 0.0341188907623291

归并排序(分而治之策略,递归算法)

将数组从中间的位置分成两组,分别进行归并排序得到两个有序序列A和B,然后A和B分别取第一个数作比较,比如A[0]<B[0],A[0]放进新数组,B[0]继续与A[1]比较,直到所有的数都写进新数组。核心思想还是递归,比较难写的部分是如何合并?代码如下

def merge_sort(lis):
	if len(lis)<2:
		return lis
	middle_pos=len(lis)//2
	head_lis=merge_sort(lis[:middle_pos])
	tail_lis=merge_sort(lis[middle_pos:])
	# 合并head_lis和tail_lis
	ii=0 # 标记head_lis各个元素位置
	jj=0 # 标记tail_lis各个元素位置
	merge_lis=[] # 写进一个新列表
	while ii<len(head_lis) and jj<len(tail_lis):
		if head_lis[ii]<tail_lis[jj]:
			merge_lis.append(head_lis[ii])
			ii+=1
		else:
			merge_lis.append(tail_lis[jj])
			jj+=1
	# head_lis和tail_lis一定会有一个优先遍历完,留下还没有遍历的
	if ii != len(head_lis):
		merge_lis.extend(head_lis[ii:])
	else: # jj != len(tail_lis)
		merge_lis.extend(tail_lis[jj:])
	return merge_lis

最优时间复杂度:O(nlogn);最坏时间复杂度:O(nlogn);稳定性:稳定
测试:

start=time.time()
sort_def_sel=merge_sort(lis)
end=time.time()
interval=end-start
print(interval)
## 0.04941534996032715
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值