Python练手之6种经典排序算法

 在入手了python之后,确实被它简单的特性和上手容易度震惊过。不过python和c语言什么的又确实存在很大的差别,习惯了c语言,使用python的时候多少还是有些不习惯。

  入手python一周左右了,为了熟悉和深化对python的理解,就把几种经典的排序算法拿来练手,顺便强化一下自己的基础知识。开始写了,才发现自己写出来的代码问题还真不少,排序的结果总是有各种问题,看来真的是很久没有用这些算法写过东西了,都忘了一些细节的东西了,汗哪。。。

 

  废话不多说,开始练手吧。

  排序前需要给定一个数据集,这个用随机数生成就好:

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename:randata.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import random  
  7. ''''' 
  8. 随机生成0~10000000之间的数值 
  9. '''  
  10. def getrandata(num):  
  11.     a=[]  
  12.     i=0  
  13.     while i<num:  
  14.         a.append(random.randint(0,10000000))  
  15.         i+=1  
  16.     return a  
 

  经典算法之冒泡排序(Bubble sort):

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename:bubble_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import randata  
  7. ''''' 
  8. 算法思想:每次从最后开始往前滚,邻接元素两两相比,小元素交换到前面 
  9. 第一轮循环把最小的元素上浮至第一个位置,第二小的元素上浮至第二个位置,依次类推 
  10. '''  
  11. def bubbleSort(a):  
  12.     l=len(a)-2  
  13.     i=0  
  14.     while i<l:  
  15.         j=l  
  16.         while j>=i:  
  17.             if(a[j+1]<a[j]):  
  18.                 a[j],a[j+1]=a[j+1],a[j]  
  19.             j-=1  
  20.         i+=1  
 

  经典算法之直接插入排序(Insert sort):

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename: insert_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import randata  
  7. ''''' 
  8. 被注释掉的部分是c语言数组普通的插入方式 
  9. 未被注释的部分则是使用python列表的插入和删除特性改善的 
  10. '''  
  11. def insertSort(arr):  
  12.     for i in range(1,len(arr)):  
  13.         ''''' 
  14.         tmp=arr[i] 
  15.         j=i 
  16.         while j>0 and tmp<arr[j-1]: 
  17.             arr[j]=arr[j-1] 
  18.             j-=1 
  19.         arr[j]=tmp 
  20.         '''  
  21.         j=i  
  22.         while j>0 and arr[j-1]>arr[i]:  
  23.             j-=1  
  24.         arr.insert(j,arr[i])  
  25.         arr.pop(i+1)  
 

  经典算法之希尔排序(Shell sort):

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename: shell_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import randata  
  7. def shellSort(arr):  
  8.     dist=len(arr)/2  
  9.     while dist>0:  
  10.         for i in range(dist,len(arr)):  
  11.             tmp=arr[i]  
  12.             j=i  
  13.             while j>=dist and tmp<arr[j-dist]:  
  14.                 arr[j]=arr[j-dist]  
  15.                 j-=dist  
  16.             arr[j]=tmp  
  17.         dist/=2  
 

  希尔排序的名称源于它的发明者Donald Shell,该算法是冲破二次时间屏障的第一批算法之一,不过,直到它最初被发现的若干年后才被证明了它的亚二次时间界。它通过比较相距一定间隔的元素来工作;各趟比较所用的距离随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止。

 

  经典算法之归并排序(Merge sort):

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename: merge_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import randata  
  7. ''''' 
  8. 使用新分配的空间存储合并得到的新列表 
  9. arr:  原始列表(数组) 
  10. s:    需合并的第一段空间起始点 
  11. m:    需合并的第二段空间起始点 
  12. e:    需合并的第二段空间结束点 
  13. '''  
  14. def mergeWithNewSpace(arr,s,m,e):  
  15.     i,j=s,m  
  16.     t=0  
  17.     newArr=[]  
  18.     while i<m and j<=e:  
  19.         if(arr[i]<arr[j]):  
  20.             newArr.append(arr[i])  
  21.             i+=1  
  22.             t+=1  
  23.         else:  
  24.             newArr.append(arr[j])  
  25.             j+=1  
  26.             t+=1  
  27.     if i>=m:  
  28.         t=0  
  29.         for i in range(s,j):  
  30.             arr[i]=newArr[t]  
  31.             t+=1  
  32.     else:  
  33.         t=0  
  34.         for i in range(i,m):  
  35.             newArr.append(arr[i])  
  36.         for i in range(s,e+1):  
  37.             arr[i]=newArr[t]  
  38.             t+=1  
  39.     del newArr  
  40. def mergePassWithNewSpace(arr, n, d):  
  41.     i=0  
  42.     while i<(n-d) and i<(n+1-2*d):  
  43.         mergeWithNewSpace(arr,i,i+d,i+2*d-1)  
  44.         i=i+2*d  
  45.     if i<n-d:  
  46.         mergeWithNewSpace(arr,i,i+d,n-1)  
  47.     else:  
  48.         mergeWithNewSpace(arr,i-2*d,i,n-1)  
  49. def mergeSortWithNewSpace(arr):  
  50.     d=1  
  51.     while d<len(arr):  
  52.         mergePassWithNewSpace(arr,len(arr),d)  
  53.         d*=2  
  54. ''''' 
  55. 不分配新的空间存储合并得到的列表 
  56. 而是使用原列表使用插入方式存储 
  57. arr:  原始列表(数组) 
  58. s:    需合并的第一段空间起始点 
  59. m:    需合并的第二段空间起始点 
  60. e:    需合并的第二段空间结束点 
  61. 被注释掉的部分是c语言数组普通的插入方式 
  62. 未被注释的部分则是使用python列表的插入和删除特性改善的 
  63. '''  
  64. def mergeWithoutNewSpace(arr,s,m,e):  
  65.     i,j=s,m  
  66.     while i<m and j<=e:  
  67.         if arr[i]>arr[j]:  
  68.             ''''' 
  69.             tmp=arr[j] 
  70.             k=j 
  71.             while k>i: 
  72.                 arr[k]=arr[k-1] 
  73.                 k-=1 
  74.             arr[i]=tmp 
  75.             '''  
  76.             arr.insert(i,arr[j])  
  77.             arr.pop(j+1)  
  78.             j+=1  
  79.             m+=1  
  80.         else:  
  81.             i+=1  
  82. ''''' 
  83. arr:  原始列表(数组) 
  84. n:    数组大小 
  85. d:    区间大小 
  86. '''  
  87. def mergePassWithoutNewSpace(arr, n, d):  
  88.     i=0  
  89.     while i<(n-d) and i<(n+1-2*d):  
  90.         mergeWithoutNewSpace(arr,i,i+d,i+2*d-1)  
  91.         i=i+2*d  
  92.     if i<n-d:  
  93.         mergeWithoutNewSpace(arr,i,i+d,n-1)  
  94.     else:  
  95.         mergeWithoutNewSpace(arr,i-2*d,i,n-1)  
  96. def mergeSortWithoutNewSpace(arr):  
  97.     d=1  
  98.     while d<len(arr):  
  99.         mergePassWithoutNewSpace(arr,len(arr),d)  
  100.         d*=2  
 

  归并排序算法中,在合并两个已排序的表时,通常的做法是新建一个大小等于它们之和的新表,用于存储这两个表合并的结果,然后把把合并后的表在拷贝回这两个连续的表中。另外一个做法,也可以不分配新的空间存储结果,而是使用插入排序的思想进行合并。

  使用分配空间合并的方式,时间复杂度为O(nlogn),使用插入合并的方式,时间复杂度为O(n^2),这里采用python列表的插入和删除机制,比c语言中数组整体往后挪动的插入方式(见注释部分)要高效不少。

 

  经典算法之堆排序:

 

[python] view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename:heap_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. ''''' 
  7. 大根堆:在一棵完全二叉树中,对于任意节点,满足性质arr[i]>=arr[2*i], arr[i]>=arr[2*i+1] 
  8. 小根堆:在一棵完全二叉树中,对于任意节点,满足性质arr[i]<=arr[2*i], arr[i]<=arr[2*i+1] 
  9. '''  
  10. import randata  
  11. ''''' 
  12. 假定除了start位置的顶点外,以start位置为root的这棵二叉树是一个大根堆 
  13. 向下调整start位置的节点至合适的位置,是的这棵树重新恢复为一个大根堆 
  14. '''  
  15. def adjust(arr,start,size):  
  16.     tmp=arr[start]  
  17.     j=2*start+1  
  18.     while j<size:  
  19.         if j<size-1 and arr[j]<arr[j+1]:  
  20.             j+=1  
  21.         if tmp>=arr[j]:  
  22.             break  
  23.         arr[start]=arr[j]  
  24.         start=j  
  25.         j=2*j+1  
  26.     arr[start]=tmp  
  27. ''''' 
  28. 从一堆乱序的元素列表中建立大根堆 
  29. '''  
  30. def buildHeap(arr):  
  31.     size=len(arr)  
  32.     for i in range(size/2-1,-1,-1):  
  33.         adjust(arr,i,size)  
  34. def heapSort(arr):  
  35.     size=len(arr)  
  36.     buildHeap(arr)  
  37.     ''''' 
  38.     建立大根堆后,第一个元素为列表的最大元素,将它跟最后一个元素交换,列表大小-1 
  39.     重新调整列表为大根堆,重复此操作直到最后一个元素 
  40.     '''  
  41.     for i in range(size-1,0,-1):  
  42.         arr[i],arr[0]=arr[0],arr[i]  
  43.         adjust(arr,0,i)  

  堆排序的思路是建立在大根堆和小根堆的基础上,具体步骤可以参见网上解释以及上面的源码。

 

  经典算法之快速排序:

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename:quick_sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import randata  
  7. import sys  
  8. ''''' 
  9. 这个函数的作用是,从区间的第一个,最后一个和最中间的位置上选出一个中间大小的值,并把它放置在区间的第一个位置上 
  10. 这样有效消除预排序的最坏情况 
  11. '''  
  12. def median(a,start,end):  
  13.     center=(start+end)/2  
  14.     if a[start]>a[center]:  
  15.         a[start],a[center]=a[center],a[start]  
  16.     if a[start]>a[end]:  
  17.         a[start],a[end]=a[end],a[start]  
  18.     if a[center]>a[end]:  
  19.         a[center],a[end]=a[end],a[center]  
  20.     a[start],a[center]=a[center],a[start]  
  21. def doSwap(a,start,end):  
  22.     if start>=end:  
  23.         return  
  24.     i,j=start,end  
  25.     median(a,start,end)  
  26.     tmp=a[start]  
  27.     while(True):  
  28.         while(a[j]>tmp and i<j):  
  29.             j-=1  
  30.         if i<j:  
  31.             a[i]=a[j]  
  32.             i+=1  
  33.         while(a[i]<tmp and i<j):  
  34.             i+=1  
  35.         if i<j:  
  36.             a[j]=a[i]  
  37.             j-=1  
  38.         else:  
  39.             break  
  40.     a[i]=tmp  
  41.     doSwap(a,start,i-1)  
  42.     doSwap(a,j+1,end)  
  43. def quickSort(a):  
  44.     #设置递归深度为10000000,放置数据量过大时超出递归最大深度发生exception  
  45.     sys.setrecursionlimit(1000000)  
  46.     doSwap(a,0,len(a)-1)  
 

  在这里,快速排序算法在选择参考值的时候,采用了中值选取的方式,即从区间的第一个,最后一个和最中间的元素,这三个中选择一个中间大小的作为参考值,把这个元素挪动至第一个位置。这个算法可以有效消除快速排序中的最坏时间复杂度。

 

  写出了算法,总要有个东西来验证,写一个单独的部分来执行这些算法,输出个算法花费的时间值,并将他们的执行结果输出至文件中,用于检验执行结果是否正确。

 

[python]  view plain copy
  1. #-*- coding: utf-8 -*-  
  2. #!/usr/bin/python  
  3. #Filename:sort.py  
  4. #Author: Boyce  
  5. #Email:  boyce.ywr@gmail.com  
  6. import time  
  7. import randata  
  8. import bubble_sort  
  9. import quick_sort  
  10. import heap_sort  
  11. import shell_sort  
  12. import merge_sort  
  13. import insert_sort  
  14. fileName='sort.dat'  
  15. size=10000  
  16. print '/nStart generate randam data...'  
  17. arr=randata.getrandata(size)  
  18. print 'Data generation finished.'  
  19. print 'Data size is %d, result will be save to file %s'%(size,fileName)  
  20. f=file(fileName,'w')  
  21. f.write("/nOriginal data:/n")  
  22. f.write(str(arr))  
  23. #使用python内置的timSort排序算法  
  24. a=arr[:]  
  25. print '/nStart internal sort...'  
  26. t1=time.clock()  
  27. a.sort()  
  28. t2=time.clock()  
  29. print 'Internal sort finisehd. Time used=%fs'%(t2-t1)  
  30. f.write('/n/nInternal sort [Time used=%fs]/n'%(t2-t1))  
  31. f.write(str(a))  
  32. del a  
  33. a=arr[:]  
  34. print '/nStart quick sort...'  
  35. t1=time.clock()  
  36. quick_sort.quickSort(a)  
  37. t2=time.clock()  
  38. print 'Quick sort finished. Time used=%fs'%(t2-t1)  
  39. f.write('/n/nQuick sort [Time used=%fs]/n'%(t2-t1))  
  40. f.write(str(a))  
  41. del a  
  42. a=arr[:]  
  43. print '/nStart heap sort...'  
  44. t1=time.clock()  
  45. heap_sort.heapSort(a)  
  46. t2=time.clock()  
  47. print 'Heap sort finished. Time used=%fs'%(t2-t1)  
  48. f.write('/n/nHeap sort [Time used=%fs]/n'%(t2-t1))  
  49. f.write(str(a))  
  50. del a  
  51. a=arr[:]  
  52. print '/nStart shell sort...'  
  53. t1=time.clock()  
  54. shell_sort.shellSort(a)  
  55. t2=time.clock()  
  56. print 'Shell sort finished. Time used=%fs'%(t2-t1)  
  57. f.write('/n/nShell sort [Time used=%fs]/n'%(t2-t1))  
  58. f.write(str(a))  
  59. del a  
  60. a=arr[:]  
  61. print '/nStart merge sort with new space...'  
  62. t1=time.clock()  
  63. merge_sort.mergeSortWithNewSpace(a)  
  64. t2=time.clock()  
  65. print 'Merge sort with new space finished. Time used=%fs'%(t2-t1)  
  66. f.write('/n/nMerge sort with new space [Time used=%fs]/n'%(t2-t1))  
  67. f.write(str(a))  
  68. del a  
  69. a=arr[:]  
  70. print '/nStart merge sort without new space...'  
  71. t1=time.clock()  
  72. merge_sort.mergeSortWithoutNewSpace(a)  
  73. t2=time.clock()  
  74. print 'Merge sort without new space finished. Time used=%fs'%(t2-t1)  
  75. f.write('/n/nMerge sort without new space [Time used=%fs]/n'%(t2-t1))  
  76. f.write(str(a))  
  77. del a  
  78. a=arr[:]  
  79. print '/nStart insert sort...'  
  80. t1=time.clock()  
  81. insert_sort.insertSort(a)  
  82. t2=time.clock()  
  83. print 'Insert sort finished. Time used=%fs'%(t2-t1)  
  84. f.write('/n/nInsert sort [Time used=%fs]/n'%(t2-t1))  
  85. f.write(str(a))  
  86. del a  
  87. a=arr[:]  
  88. print '/nStart bubble sort...'  
  89. t1=time.clock()  
  90. bubble_sort.bubbleSort(a)  
  91. t2=time.clock()  
  92. print 'Bubble sort finished. Time used=%fs'%(t2-t1)  
  93. f.write('/n/nBubble sort [Time used=%fs]/n'%(t2-t1))  
  94. f.write(str(a))  
  95. del a  
  96. f.close()  
 

 

  这是某次执行的结果:

  

 

  输出结果被保存在当前目录的sort.dat文件中,用记事本打开即可看到。

  (看看人家python内置的timSort排序算法,根本就不是一个数量级的,真牛,好快呀。。。)

 

  这就是输出文件的内容显示:

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值