1、78.9 µs冒泡
2、61 µs选择
3、32.5 µs插入
4、33.4 µs希尔
5、82.4 µs归并
6、38.1 µs快速
7、135 µs堆
8、25.1 µs计数
9、29 µs桶
10、87.7 µs基数
以上是我全部写完后,在目前新换的NUC上跑的结果,虽然性能不及开始时i3的一半,但是运行时长并没有增加多少。
1、最快的计数、桶,是不稳定的,计数:当序列是均匀挨着的时候,最强。桶,需要均匀。
2、希尔比较难理解,但是确实是把一个大的内容拆分了
3、归并死板,快速算是归并的实用版
4、插入是我一开始的思路,而且用上二分法后,更能提升效率,也很容易理解
B站上有个视频,他将各个算法的时间复杂度列了出来,一目了然,忘了收藏,找不到了!
因为之前的代码中使用了大量的语法技巧来提升效率,导致失去了算法的效率参考性,于是这次重写代码,只是用最基础的指令,不使用任何可提升效率的语法。
废弃文,已写完希尔
十大经典排序算法(动图演示)
十大经典排序算法动画与解析
B站搜索:排序动画
在堆中,%%timeit的跑分不正常,经过import time后,确定他可能有些地方不对劲,可能是自定义函数的变量global调用下的问题。
所以我尝试使用import time的方式去换算,例如冒泡排序中,%%timeit是73.8 µs,import time range(1000)是0.12592077255249023秒。
目标timeit/目标importtime=73.8/0.12592077255249023=586.0828082930987
目标timeit=586.0828082930987*目标importtime,但准不准是一回事,然后我尝试把所有的global去掉,这换算的数值和%%timeit不一样,大致就是1:1000的节奏,而且还有比%%timeit更低的时候,毕竟跑一次%%timeit,时间太长,变数太多
1、73.8 µs,冒泡排序,循环325次,交换115次
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
site=len(list1)-1
while 1:
if site<1:break
i=0
while 1:
if list1[i]>list1[i+1]:
t=list1[i+1]
list1[i+1]=list1[i]
list1[i]=t
i=i+1
if i==site:break
site=site-1
2、52.9,选择,325,25
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
site=0
lenl=len(list1)
while 1:
if site>=lenl-1:break
mini=site
i=site+1
while 1:
if list1[mini]>list1[i]:mini=i
if i==lenl-1:break
i=i+1
temp=list1[site]
list1[site]=list1[mini]
list1[mini]=temp
site=site+1
3、31.5/28.2µs,插入,138,140
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
site=1
lenl=len(list1)
while 1:
if site>=lenl:break
temp=list1[site]
seat=site
while 1:
if temp>list1[seat-1]:seat=seat-1;break
list1[seat]=list1[seat-1]
seat=seat-1
if seat==-1:break
list1[seat+1]=temp
site=site+1
不可思议,发生什么事了,写的时候还卡在了这个标记为该怎么去记的麻烦情况,可能我是不喜欢去记录标记位这么麻烦的东西的,我想得到一个万能的结果,于是就有了上面一些比较奇怪的地方,但是我觉得是麻烦了些,于是我打算反优化下
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
site=1
lenl=len(list1)
while 1:
if site>=lenl:break
temp=list1[site]
i=site-1
while 1:
if temp>list1[i]:seat=i+1;break
list1[i+1]=list1[i]
if i==0:seat=0;break
i=i-1
list1[seat]=temp
site=site+1
这里多引入了个变量,对象应该插入的位置,其实还是有一个地方可以再优化或者说还原,在倒数第三行加入if seat==site:pass,但其实加不加结果都一样,加了反而没有得出更好的结果
4、32.7,希尔,97,106
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
lenl=len(list1)
half=lenl//2
i=0
while 1:
if i>=half:break
if list1[i]>list1[i+half]:
temp=list1[i+half]
list1[i+half]=list1[i]
list1[i]=temp
i=i+1
i=0
while 1:
if i+2>=lenl:break
if list1[i]>list1[i+2]:
temp=list1[i+2]
list1[i+2]=list1[i]
list1[i]=temp
i=i+2
i=1
while 1:
if i+2>=lenl:break
if list1[i]>list1[i+2]:
temp=list1[i+2]
list1[i+2]=list1[i]
list1[i]=temp
i=i+2
site=1
while 1:
if site>=lenl:break
temp=list1[site]
i=site-1
while 1:
if temp>list1[i]:seat=i+1;break
list1[i+1]=list1[i]
if i==0:seat=0;break
i=i-1
list1[seat]=temp
site=site+1
5、89.9/71.5 归并,按照索引,把问题一分为二,248,248
这个算法几乎每次都要动,只有个别真不要动的才不懂,而且动起来惊天动地,思路是加深了对递归的认识,有的大佬也确实写出了406ns的时长,但是是借助list的方法下,之后我记得的话,可能会挑战下,但是这个算法真的就只是学学归并,如果用来做排序的话…
肯定是哪里搞错了,写的很辛苦,主要还是没有画图,以及之前之后抄错改错写错的一些变量,别的归并没有这么长啊。
那归并究竟是什么呢,目前我的理解和他的定义中,归并就是大问题分解成小问题,那如果去除这些前摇,是不是就溜了,但是这样就跟演示的动画不一样了,或者说演示的动画误导了我!?
果然是演示动画与算法精髓不符,不过我的这个实现效果确实和动画一样的,强行同步
是我理解错了,我完全以动画为思路,结果他是正好15的元素,以至于…
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
def f(left,lens,n=-1,last=0):
if lens<=1:return
if lens>1:
if last==1:
n=0
while 1:
if 2**n>=lens:break
n=n+1
half=2**(n-1)
right=left+half
if lens==2**n:
lefts=half
rights=half
f(left,half,n-1,0)
f(right,half,n-1,0)
else:
lefts=half
rights=lens-half
f(left,half,n-1,0)
f(right,lens-half,last=1)
if last==0:
half=2**(n-1)
lefts=half
rights=half
right=left+half
f(left,half,n-1,0)
f(right,half,n-1,0)
i=lefti=righti=0
list2=['']*lens
while 1:
if lefti==lefts:
while 1:
if righti==rights:break
list2[i]=list1[right+righti]
righti=righti+1
i=i+1
i=0
while 1:
if i==lens:return
list1[left+i]=list2[i]
i=i+1
if righti==rights:
while 1:
if lefti==lefts:break
list2[i]=list1[left+lefti]
lefti=lefti+1
i=i+1
i=0
while 1:
if i==lens:return
list1[left+i]=list2[i]
i=i+1
if list1[left+lefti]>list1[right+righti]:
list2[i]=list1[right+righti]
righti=righti+1
else:
list2[i]=list1[left+lefti]
lefti=lefti+1
i=i+1
lenl=len(list1)
f(0,lenl,last=1)
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
def f(left,lens):
if lens<=1:return
half=lens//2
right=left+half
lefts=half
rights=lens-half
f(left,lefts)
f(right,rights)
i=lefti=righti=0
list2=['']*lens
while 1:
if lefti==lefts:
while 1:
if righti==rights:break
list2[i]=list1[right+righti]
righti=righti+1
i=i+1
i=0
while 1:
if i==lens:return
list1[left+i]=list2[i]
i=i+1
if righti==rights:
while 1:
if lefti==lefts:break
list2[i]=list1[left+lefti]
lefti=lefti+1
i=i+1
i=0
while 1:
if i==lens:return
list1[left+i]=list2[i]
i=i+1
if list1[left+lefti]>list1[right+righti]:
list2[i]=list1[right+righti]
righti=righti+1
else:
list2[i]=list1[left+lefti]
lefti=lefti+1
i=i+1
lenl=len(list1)
f(0,lenl)
还是总觉得哪里不大对,抄大佬们的代码跑个分看看
6、31.4,快速,进阶归并,按照基准,一分为二,循环91次,交换21次,挤兑13次
在混沌中比较顺利的写出来了,之后修改了几个之前写错的和漏赋值的几个变量,总体思路,我是看了并对比了两篇文章中的演示动画后,才了解了的
上面的归并,是固定化的,这个快速排序也是一种归并,却是动态的,更有内涵,也具备了实用性!
def f(start,end):
if start+1>end:return
standard=list1[start]
insert=start
i=start+1
while 1:
if list1[i]<standard:
insert=insert+1
if insert!=i:
temp=list1[i]
list1[i]=list1[insert]
list1[insert]=temp
i=i+1
else:i=i+1
if insert==end or i>end:break
if insert!=start:
i=start
while 1:
list1[i]=list1[i+1]
i=i+1
if i==insert:break
list1[insert]=standard
f(start,insert-1)
f(insert+1,end)
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
f(0,len(list1)-1)
7、173.3/(1.47)/76.8/107,堆,142,80
后记:
上面的中间的结果是%%timeit得出来的,但是我觉得他有猫腻,于是我用time跑了下,并且对照之前冒泡排序的时长算出来个大致结果,总之,不算好,但是堆这个东西确实好玩
目前表现好的:
插入,一开始我就这样想的;
快速,我还记得他是怎么回事
希尔,这个我要回头再看一下ta是什么意思,嗯,使用了一些方法,让之后的插入等方法,往前推算的没那么多。
前文:
这个写的有点困难,我是看图后没有其他知识基础的情况下,莽过来的,而且%%timeit居然不能运行该段,所以用time运行了下
回头又看了下已有的代码,大佬们没有设置那么复杂的东西,其实我也知道的,但是那个推算出来,原理还是一样的,嘛,试着写下吧!
先再多看些关于堆的代码!
这里出现过几次问题,主要是堆比较复杂,在里面迷路了,其他的就是数值的逻辑推导错误的问题!
莽出来的版本,弄巧成拙,大家可以看第二个代码,那个是正确的版本,虽然和大佬们写的不一样的样子!
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
list2=[]
def HeapCreate():
global rows,lists,i
if i==lenl:return
else:list2.append([list1[i],rows,lists]);i=i+1;lists=lists+1
if i==lenl:return
else:list2.append([list1[i],rows,lists]);i=i+1;lists=lists+1
if lists==2**rows:rows=rows+1;lists=0
HeapCreate()
def SortHeap():
global rows,lists
if rows==0:return
v1=list2[2**(rows-1)+lists//2-1][0]
v2=list2[2**rows+lists-2][0]
v3=list2[2**rows+lists-1][0]
if v2>v3 and v2>v1:
list2[2**(rows-1)+lists//2-1][0]=v2
list2[2**rows+lists-2][0]=v1
LDHeap(rows,lists-1)
elif v3>v2 and v3>v1:
list2[2**(rows-1)+lists//2-1][0]=v3
list2[2**rows+lists-1][0]=v1
LDHeap(rows,lists)
lists=lists-2
if lists==-1:
rows=rows-1
lists=2**rows-1
SortHeap()
def LDHeap(rowi,listi):#little down
if 2**(rowi+1)+listi*2-1>=out:return
v1=list2[2**rowi+listi-1][0]
v2=list2[2**(rowi+1)+listi*2-1][0]
v3=list2[2**(rowi+1)+listi*2][0]
if v3=='':
if v2>v1:
list2[2**rowi+listi-1][0]=v2
list2[2**(rowi+1)+listi*2-1][0]=v1
return
if v2>v3 and v2>v1:
list2[2**rowi+listi-1][0]=v2
list2[2**(rowi+1)+listi*2-1][0]=v1
LDHeap(rowi+1,listi*2)
elif v3>v2 and v3>v1:
list2[2**rowi+listi-1][0]=v3
list2[2**(rowi+1)+listi*2][0]=v1
LDHeap(rowi+1,listi*2+1)
else:return
def MaxHeap():
global rows,lists
list3.insert(0,list2[0][0])
if rows==0:return
list2[0][0]=list2[2**rows+lists-1][0]
list2[2**rows+lists-1][0]=''
lists=lists-1
if lists==-1:
rows=rows-1
lists=2**rows-1
LDHeap(0,0)
MaxHeap()
lenl=len(list1)
if lenl>0:
rows=lists=i=0
list2.append([list1[i],rows,lists])
rows=i=1
HeapCreate()
rows=rowm=list2[-1][1]
lists=listm=list2[-1][2]
out=2**rows+lists
if lists%2==0:
list2.append(['','',''])
v1=list2[2**rows+lists-1][0]
v2=list2[2**(rows-1)+lists//2-1][0]
if v1>v2:
list2[2**(rows-1)+lists//2-1][0]=v1
list2[2**rows+lists-1][0]=v2
lists=lists-1
if lists==-1:
rows=rows-1
lists=2**rows-1
SortHeap()
rows=rowm
lists=listm
list3=[]
MaxHeap()
print(list3)
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
lenl=len(list1) # i:index lenl:len list1 lent:len true
i=lenl-1
def HeapCreate():
global i
if i==0:return
v1=list1[i//2-1]
v2=list1[i-1]
v3=list1[i]
if v2>v1 and v2>v3:
list1[i//2-1]=v2
list1[i-1]=v1
HeapSort(i-1,lenl-1)
elif v3>v1 and v3>v2:
list1[i//2-1]=v3
list1[i]=v1
HeapSort(i,lenl-1)
i=i-2
HeapCreate()
def HeapSort(site,i):
if site*2>=i:return
v1=list1[site]
v2=list1[site*2+1]
if site*2+1==i:
if v2>v1:
list1[site]=v2
list1[site*2+1]=v1
return
else:
v3=list1[site*2+2]
if v2>v1 and v2>v3:
list1[site]=v2
list1[site*2+1]=v1
HeapSort(site*2+1,i)
elif v3>v1 and v3>v2:
list1[site]=v3
list1[site*2+2]=v1
HeapSort(site*2+2,i)
def MaxOut():
global i
list2.append(list1[0])
if i==0:return
list1[0]=list1[i]
i=i-1
HeapSort(0,i)
MaxOut()
if lenl>1:
if lenl%2==0:
v1=list1[i//2]
v2=list1[i]
if v2>v1:
list1[i//2]=v2
list1[i]=v1
i=i-1
HeapCreate()
list2=[]
i=lenl-1
MaxOut()
这串代码中在最终完成前,有个bug,HeapSort是向下对比的排序,本来他只是为了之后出堆顶时设计的,无奈开始形成堆结构时,也会用到这个功能,所以增加了一个索引位置的传递,而且把最初判断堆低的数值由全局i,变成了这个传递的变量并一直传递下去,直至return
什么鬼,1.47 µs,是不是哪里搞错了?
优化1,在每组三个的对比中,if y>x:if y>z:x,y=y,x else x,z=z,x
优化2,每次堆顶出去,不是从堆底上来,是从二层堆上去
但自从知道堆其实本质仍是二维态,我就放弃了上面两行
在以上两段代码中,我都犯过的错误,第一次创建堆时,要上下对应的排序,不然会出现其中的一个小堆,小的在上面,大的在下面,而上面的小的是从上面被交换下来的,所以需要再把它排序了。
而这个效率可能是真的,那么堆就是目前我见过的最快的排序了。
看似老长的代码,这次的计数把一开始就return的都算进去了,还是不高,而且交换次数也不高,就此看,比以前低是一定的,但是为什么这么低,会不会是%%timeit又遇上了什么bug不能准确得出结果!我重启服务后,直接跑%%timeit,报错。
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
lenl=len(list1) # i:index lenl:len list1 lent:len true
def HeapCreate(i):
if i<=0:return
v1=list1[i//2-1]
v2=list1[i-1]
v3=list1[i]
if v2>v1 and v2>v3:
list1[i//2-1]=v2
list1[i-1]=v1
HeapSort(i-1)
elif v3>v1 and v3>v2:
list1[i//2-1]=v3
list1[i]=v1
HeapSort(i)
HeapCreate(i-2)
def HeapSort(i):
if i*2+2>lenl:return
v1=list1[i]
v2=list1[i*2+1]
v3=list1[i*2+2]
if list1[i*2+1]=='' and list1[i*2+2]=='':return
elif list1[i*2+1]=='':
if v3>v1:
list1[i]=v3
list1[i*2+2]=v1
HeapSort(i*2+2)
elif list1[i*2+2]=='':
if v2>v1:
list1[i]=v2
list1[i*2+1]=v1
HeapSort(i*2+1)
elif v3>v2 and v3>v1:
list1[i]=v3
list1[i*2+2]=v1
HeapSort(i*2+2)
elif v2>v3 and v2>v1:
list1[i]=v2
list1[i*2+1]=v1
HeapSort(i*2+1)
def MaxOut():
if list1[0]=='':return
list2.append(list1[0])
list1[0]=''
HeapSort(0)
MaxOut()
if lenl>1:
if lenl%2==0:list1.append('');lenl=lenl+1
i=lenl-1
HeapCreate(i)
list2=[]
i=lenl-1
MaxOut()
反优化版,这个是我按照堆本应该出现的一提一大串的想法写的,结果效果是反优化。可能是判断的条件太多了,而之前的判断条件只需要一个列表长度或者说末尾索引值即可。所以这次反优化了
8、22.6µs/5.78ms,计数,80 -
这个效率真是喵,全程并没有元素交换的操作,第一步仅仅是找到最大最小值,只要数值符合条件,就把参照数值换掉,相当于两个用于对比、替换的变量和一个只读的列表。最大替换次数也不过是25次。
第二次,虽然用到了只读和写入,但是也最多26次。
第三次,只读,修改,增加,也最多26次。但如果要对比的数据不是连贯的,是个超大跨度的,也不过是在最后一步读入了过多的0,试一下!例如加一个‘香’。话说这时我发现我写漏了一行,因为一开始时,list2的长度和list1的一样,所以并未表现出来错误!
一旦加上’香’:ord(‘香’)-ord(‘z’)=39199,就会多出39198个无意义的0来读取。多出来的时长就是这一串的时长。去掉这一串,那就确实目前最速!
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
maxv=minv=list1[0]
lenl=len(list1)
if lenl>=2:
i=1
while 1:
if i==lenl:break
v=list1[i]
if v>maxv:
maxv=v
elif v<minv:
minv=v
i=i+1
if type(list1[0])==str:
lenl2=ord(maxv)-ord(minv)+1
list2=[0]*lenl2
i=0
minv=ord(minv)
while 1:
if i==lenl:break
v=list1[i]
i2=ord(v)-minv;
list2[i2]=list2[i2]+1
i=i+1
i=0
lenl=len(list2)
list3=[]
while 1:
if i==lenl:break
if list2[i]!=0:
v=chr(minv+i)
c=list2[i]
while 1:
if c==0:break
list3.append(v)
c=c-1
i=i+1
9、桶排序(Bucket Sort)
def f(list1):
site=1
lenl=len(list1)
while 1:
if site>=lenl:return list1
temp=list1[site]
seat=site
while 1:
if temp>list1[seat-1]:seat=seat-1;break
list1[seat]=list1[seat-1]
seat=seat-1
if seat==-1:break
list1[seat+1]=temp
site=site+1
return list1
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
lenl=len(list1)
if lenl>1:
minv=maxv=list1[0]
i=1
while 1:
if list1[i]> maxv:maxv=list1[i]
elif list1[i]<minv:minv=list1[i]
i=i+1
if i==lenl:break
lista=[]
listb=[]
listc=[]
listd=[]
i=0
minv=ord(minv)
maxv=ord(maxv)
b=chr(minv+(maxv-minv)//4)
c=chr(minv+(maxv-minv)//2)
d=chr(minv+(maxv-minv)//4*3)
while 1:
v=list1[i]
if v>=d:listd.append(v)
elif v>=c:listc.append(v)
elif v>=b:listb.append(v)
else:lista.append(v)
i=i+1
if i==lenl:break
f(lista)
f(listb)
f(listc)
f(listd)
list2=lista+listb+listc+listd
换电脑了,这次代码,排序部分使用了插入法,改了两个失误写错的bug,基本顺利
因为换了电脑以及学会了限制cpu性能,所以之后会从头来过一次timeit
另外这个桶排序只是了解下理念,使用起来绝对没有这么简单,毕竟元素序列不一定是均匀的
10、基数排序(Radix Sort)
这次也顺利的完成了,至于思维上的弯弯绕绕,我是理解了的,但是觉得还没有吃透!
list1=['e', 'k', 'b', 'g', 'd', 'o', 'p', 'h', 'i', 'm', 'l', 's', 'n', 'x', 'y', 't', 'j', 'r', 'z', 'a', 'u', 'v', 'w', 'q', 'c', 'f']
lenl=len(list1)
i=0
maxv=ord(list1[0])
list2=[]
while 1:
if i==lenl:break
v=ord(list1[i])
list2.append(v)
if v>maxv:maxv=v
i=i+1
bit=0
while 1:
if maxv//10==0:break
maxv=maxv//10
bit=bit+1
j=1
while 1:
if j==bit+2:break
i=0
list00=[]
list01=[]
list02=[]
list03=[]
list04=[]
list05=[]
list06=[]
list07=[]
list08=[]
list09=[]
while 1:
if i==lenl:break
v=list2[i]
b=v%(10**j)//(10**(j-1))
if b==0:list00.append(v)
elif b==1:list01.append(v)
elif b==2:list02.append(v)
elif b==3:list03.append(v)
elif b==4:list04.append(v)
elif b==5:list05.append(v)
elif b==6:list06.append(v)
elif b==7:list07.append(v)
elif b==8:list08.append(v)
else:list09.append(v)
i=i+1
list2=list00+list01+list02+list03+list04+list05+list06+list07+list08+list09
j=j+1
i=0
list3=[]
while 1:
if i==lenl:break
v=chr(list2[i])
list3.append(v)
i=i+1