几种常用排序算法的python实现
1:快速排序
思想:
任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted s = [] for i in range(0,100): s.append(random.randint(1,100)) print(s[i]), # print("\nbegin") def partition(inlist,start,end): i = start j = end k = inlist[i] while i<j: while i<j and inlist[j]>=k: j = j-1 inlist[i]=inlist[j] while i<j and inlist[i]<=k: i = i+1 inlist[j]=inlist[i] inlist[i]=k return i def quickSort(inlist,start,end): if start>=end: return middle = partition(inlist,start,end) quickSort(inlist,start,middle-1) quickSort(inlist,middle+1,end) quickSort(s,0,len(s)-1) for i in s: print "%d " %i, print("done")
2:直接插入排序
思想:
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted s = [] for i in range(0,100): s.append(random.randint(1,100)) print(s[i]), # print("\nbegin") j=0 for i in range(1,len(s)): if s[i]<s[i-1]: temp = s[i] j=i-1 while j>=0 and s[j]>temp: s[j+1]=s[j] s[j]=temp j=j-1 for i in s: print "%d " %i, print("\ndone")
3:冒泡排序
思想:
-
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
python 代码:
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted s = [] for i in range(0,100): s.append(random.randint(1,100)) print(s[i]), # print("\nbegin") i = len(s)-1 while i>0: j=0 for j in range(0,i): if s[j+1]<s[j]: temp = s[j] s[j]=s[j+1] s[j+1]=temp j = j+1 i = i-1 for i in s: print "%d " %i, print("\ndone")
4:桶排序
思想:
假定:输入是由一个随机过程产生的[0, 1)区间上均匀分布的实数。将区间[0, 1)划分为n个大小相等的子区间(桶),每桶大小1/n:[0, 1/n), [1/n, 2/n), [2/n, 3/n),…,[k/n, (k+1)/n ),…将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1..n] <1辅助数组B[0..n-1]是一指针数组,指向桶(链表)。
太难懂了,举个简单的例子:
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted #10000 numbers,range in (0,100) s = [] for i in range(0,10000): s.append(random.randint(0,100)) #print(s[i]), # print("\nbegin") r = {} for i in range(0,101): r[i]=[] for i in s: r[i].append(i) f = file("r.txt","w") for i in range(0,101): for j in r[i]: f.write(str(j)+‘,‘) print("\ndone")
5:归并排序
思想:
归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。
python代码:
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted s = [] for i in range(0,100): s.append(random.randint(1,100)) print(s[i]),print("\nbegin") def spli(inlist): if len(inlist)<=1: return inlist num = len(inlist)/2 left = spli(inlist[0:num]) right = spli(inlist[num:]) return sor(left,right) def sor(left,right): #print(left) #print(right) l = 0 r = 0 result =[] while l<len(left) and r <len(right): if left[l]<right[r]: result.append(left[l]) l =l+1 else: result.append(right[r]) r = r+1 result = result+right[r:] result = result+left[l:] return result s=spli(s) for i in s: print "%d " %i, print("\ndone")
6:堆排序
思想:
1.什么是堆?
堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:
Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]或者Key[i]>=Key[2i+1]&&key>=key[2i+2]
即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。
堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。
2.堆排序的思想
利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
其基本思想为(大顶堆):
1)将初始待排序关键字序列(R1,R2....Rn)构建成大顶堆,此堆为初始的无序区;
2)将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,......Rn-1)和新的有序区(Rn),且满足R[1,2...n-1]<=R[n];
3)由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,......Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2....Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
操作过程如下:
1)初始化堆:将R[1..n]构造为堆;
2)将当前无序区的堆顶元素R[1]同该区间的最后一个记录交换,然后将新的无序区调整为新的堆。
python 代码:
#*-* coding: utf-8 *-* import random # produce random numbers to be sorted s = [] count=0 for i in range(0,100): s.append(random.randint(1,100)) print(s[i]), # print("\nbegin") def heap_sort(inlist): for start in range((len(inlist)-2)/2,-1,-1):#1:初始化堆:从最底层开始建树,并且保证是堆 sift_down(inlist,start,len(inlist)-1) for end in range(len(inlist)-1,0,-1):#2:将堆顶元素与最后一个元素交换,调整 inlist[0],inlist[end]=inlist[end],inlist[0] sift_down(inlist,0,end-1) return inlist def sift_down(inlist,start,end): """调整算法:从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换 (交换之后可能造成被交换的孩子节点不满足堆的性质, 因此每次交换之后要重新对被交换的孩子节点进行调整)""" root = start while True: global count count=count+1 child = 2*root +1#左节点 if child>end: break if child+1<=end and inlist[child]<inlist[child+1]:#左节点比右节点小 child = child+1#保证child对应的是左右节点中最大的 if inlist[root]<inlist[child]:#如果root不是最大,交换 inlist[root],inlist[child]=inlist[child],inlist[root] root=child else: break heap_sort(s) for i in s: print (i), print("\ndone") print(count)
6种算法比较次数的比较
随机生成10000的数据
快速排序 | 直接插入排序 | 冒泡排序 | 桶排序 | 归并排序 | 堆排序 | |
比较次数 | 512689 | 24795124 | 24934964 | 10000 | 120275 | 128265 |
效率 | NlogN | N*N | N*N | N | NlogN | NlogN |
很容易可以看出:
1:桶排序是最快的,但使用范围有限,排序的标准和数据的属性是一致的
2:快速排序、归并排序和堆排序都是NlogN的,但具体还是差别的,随机数据来看,比较次数:归并《堆《快速
有序序列的影响:
快速排序:有序》》》》(远大于)无序
直接插入:有序《无序
冒泡:有序《无序
桶排序:无差别
归并:有序《无序
堆排序:有序》无序
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。