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

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

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

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

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

 

  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

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

 

  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):

 

  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):

 

  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):

 

  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语言中数组整体往后挪动的插入方式(见注释部分)要高效不少。

  经典算法之堆排序:

 

  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) 

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

  经典算法之快速排序:

 

  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

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

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

 

  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
  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
  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
  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
  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
  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
  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
  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
  96. f.close() 

  这是某次执行的结果:

 

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

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

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值