1.1翻转一个字符串

切蛋糕思维
image.png

  1. def str_reverse(str,end):
  2. end-=1
  3. if end==0:
  4. return str
  5. t=list(str) #str[i]是错误的,和其他语言不一样
  6. return t[end]+str_reverse(str[:-1],end) #str[:-1]表示切取0至倒数第1个字符(不包括),所以就是丢掉最后一个字符
  7. str='abc'
  8. print(str_reverse(str,3))

1.2斐波拉契数

递推公式或者等价转换
image.png

  1. def fei(n):
  2. if n==1 or n==2:
  3. return 1
  4. return fei(n-1)+fei(n-2)
  5. print(fei(5))

1.3求两个整数的最大公约数

递推公式
image.png

  1. def max_com_divisor(m,n):
  2. if(n==0):
  3. return m
  4. return max_com_divisor(n,m%n)
  5. print(max_com_divisor(8,3))

1.4插入排序(o(n^2))

RPReplay_Final1575811816.mp4 (244.17KB)

  1. import random
  2. import time
  3. def insert_sort(alist):
  4. for i in range(1,len(alist)):
  5. j=i
  6. while j>0:
  7. if alist[j]<alist[j-1]:
  8. alist[j-1],alist[j]=alist[j],alist[j-1] #交换使得赋值次数为3
  9. j-=1
  10. else:
  11. break
  12. alist=random.sample(range(0,10000),10000)
  13. start=time.clock()
  14. insert_sort(alist)
  15. end=time.clock()
  16. print(end-start)

改进的插入排序

  1. import random
  2. import time
  3. def insert_sort(alist):
  4. for i in range(1,len(alist)):
  5. j=i
  6. e=alist[j] #将每次要插入的数赋给e
  7. while j>0:
  8. if e<alist[j-1]:
  9. alist[j]=alist[j-1] #不做交换,只做一次赋值
  10. j-=1
  11. else:
  12. break
  13. alist=random.sample(range(0,10000),10000)
  14. start=time.clock()
  15. insert_sort(alist)
  16. end=time.clock()
  17. print(end-start)

用递归插入升序排序数组

  1. def insert_sort(alist,n):
  2. n=n-1
  3. if n==0:
  4. return
  5. if n>0:
  6. insert_sort(alist,n)
  7. k=n
  8. while (k>0)and(alist[k]<alist[k-1]):
  9. alist[k],alist[k-1]=alist[k-1],alist[k] #交换
  10. k=k-1
  11. return alist
  12. alist=[1,4,5,3,7,9,8,0,11,10,2,14]
  13. insert_sort(alist,len(alist))
  14. print(alist)

1.5 汉诺塔

image.png

  1. def hannota(N,start,distination,assistance):
  2. count=0
  3. N=int(N)
  4. if N<=1:
  5. print("move"+str(N)+"from"+start+"to"+distination)
  6. return 1
  7. count+=hannota(N-1,start,assistance,distination)
  8. print("move"+str(N)+"from"+start+"to"+distination)
  9. count+=1
  10. count+=hannota(N-1,assistance,distination,start)
  11. return count
  12. a='A'
  13. b='B'
  14. c='C'
  15. print(hannota(3,a,b,c))
  16. move1fromAtoB
  17. move2fromAtoC
  18. move1fromBtoC
  19. move3fromAtoB
  20. move1fromCtoA
  21. move2fromCtoB
  22. move1fromAtoB
  23. 7

1.7二分查找

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列

  1. def erfensearch(alist,low,high,key):
  2. if low>high:
  3. return -1
  4. elif low==high:
  5. if alist[low]==key:
  6. return low
  7. else:
  8. mid = (low+high)>>1
  9. if alist[mid]>key:
  10. return erfensearch(alist,low,mid-1,key)
  11. elif alist[mid]<key:
  12. return erfensearch(alist,mid+1,high,key)
  13. else:
  14. return mid
  15. alist=[1,2,3,4,5,6,7,8]
  16. print(erfensearch(alist,0,len(alist)-1,4))

1.8归并排序

借助辅助空间,时间复杂度为nlogn

RPReplay_Final1575979198.mp4 (195.78KB)

  1. import random
  2. import time
  3. def merge(alist,left,mid,right):
  4. blist=[0]
  5. blist[0]=alist[left]
  6. for i in range(left+1,right+1):
  7. blist.append(alist[i]) #创建辅助数组
  8. i=left
  9. j=mid+1
  10. for k in range(left,right+1):
  11. if i>mid: #i>mid,j>right都是溢出情况
  12. alist[k]=blist[j-left]
  13. j+=1
  14. elif j>right:
  15. alist[k]=blist[i-left]
  16. i+=1
  17. else:
  18. if blist[i-left]<blist[j-left]:
  19. alist[k]=blist[i-left]
  20. i+=1
  21. else:
  22. alist[k]=blist[j-left]
  23. j+=1
  24. def MergeSort(alist,left,right):
  25. if right>left:
  26. mid=(left+right)>>1
  27. MergeSort(alist,left,mid)
  28. MergeSort(alist,mid+1,right)
  29. merge(alist,left,mid,right)
  30. alist=random.sample(range(0,30000),30000)
  31. left=1000 #可以从alist中的任何索引开始排序
  32. right=len(alist)-1
  33. start=time.clock()
  34. MergeSort(alist,left,right)
  35. end=time.clock()
  36. print(end-start)
  37. #优化后的归并排序
  38. def MergeSort(alist,left,right):
  39. if right>left:
  40. mid=(left+right)>>1
  41. MergeSort(alist,left,mid)
  42. MergeSort(alist,mid+1,right)
  43. if alist[mid]>alist[mid+1]:
  44. merge(alist,left,mid,right)
  45. #当递归到数据量比较小的时候,可以采用插入排序,此时数据近乎有序的几率比较大,对于近乎有序的数据,
  46. #插入排序的时间比归并排序的时间短
  47. def MergeSort(alist,left,right):
  48. if right-left<=15:
  49. insert_sort(alist,left,right)
  50. return
  51. mid=(left+right)>>1
  52. MergeSort(alist,left,mid)
  53. MergeSort(alist,mid+1,right)
  54. if alist[mid]>alist[mid+1]:
  55. merge(alist,left,mid,right)
  56. #自底向上的的归并排序
  57. def MergeSort(alist,n):
  58. sz=1
  59. i=0
  60. while sz<=n:
  61. while i+sz<n:
  62. #对alist[i...i+sz-1]和alist[i+sz...i+2*sz-1]进行归并
  63. merge(alist,i,i+sz-1,min(i+sz+sz-1,n-1))
  64. i+=sz^2
  65. sz+=sz

利用归并排序求逆序对

  1. import random
  2. import time
  3. def merge(alist,left,mid,right):
  4. blist=[0]
  5. blist[0]=alist[left]
  6. for i in range(left+1,right+1):
  7. blist.append(alist[i]) #创建辅助数组
  8. global n
  9. i=left
  10. j=mid+1
  11. for k in range(left,right+1):
  12. if i>mid:
  13. alist[k]=blist[j-left]
  14. j+=1
  15. elif j>right:
  16. alist[k]=blist[i-left]
  17. i+=1
  18. else:
  19. if blist[i-left]<blist[j-left]:
  20. alist[k]=blist[i-left]
  21. i+=1
  22. else:
  23. alist[k]=blist[j-left]
  24. j+=1
  25. n=n+(mid-i+1) #求逆序对数
  26. print(alist)
  27. def MergeSort(alist,left,right):
  28. global n
  29. if right>left:
  30. mid=(left+right)>>1
  31. MergeSort(alist,left,mid)
  32. MergeSort(alist,mid+1,right)
  33. merge(alist,left,mid,right)
  34. alist=random.sample(range(0,8),8)
  35. n=0
  36. print(alist)
  37. print("----------")
  38. left=0
  39. right=len(alist)-1
  40. start=time.clock()
  41. MergeSort(alist,left,right)
  42. print(n)
  43. end=time.clock()
  44. print(end-start)

1.9快速排序

时间复杂度为nlogn

  1. def sure_k(alist,low,high):
  2. k=low
  3. x=alist[low]
  4. for i in range(low+1,high+1):
  5. if alist[i]<=x:
  6. k+=1
  7. if k!=i:
  8. alist[k],alist[i]=alist[i],alist[k]
  9. alist[low],alist[k]=alist[k],alist[low]
  10. print(alist,"---",alist[k])
  11. return k
  12. def quicksort(alist,low,high):
  13. if high-low<=15:
  14. insert_sort(alist,low,high)
  15. k=sure_k(alist,low,high)
  16. quicksort(alist,low,k-1)
  17. quicksort(alist,k+1,high)
  18. else:
  19. return
  20. alist=[5,1,3,8,0,4,7,2,7,9,6,10,14,13]
  21. print(alist)
  22. quicksort(alist,0,len(alist)-1)

快速二路排序
**

  1. #采用赋值而不是交换的方式
  2. import random
  3. import time
  4. def partition(alist,left,right):
  5. e=alist[left]
  6. if left>right:
  7. return
  8. while (left<right):
  9. while (alist[right]>e)&(right>left):
  10. right-=1
  11. if (alist[right]<e)&(left<right):
  12. alist[left]=alist[right]
  13. while (alist[left]<e)&(left<right):
  14. left+=1
  15. if (alist[left]>e)&(left<right):
  16. alist[right]=alist[left]
  17. alist[left]=e
  18. k=left
  19. return k
  20. def partition_sort(alist,left,right):
  21. if left>right:
  22. return
  23. k=partition(alist,left,right)
  24. partition_sort(alist,left,k-1)
  25. partition_sort(alist,k+1,right)
  26. alist=random.sample(range(0,10000),10000)
  27. print(alist)
  28. start=time.clock()
  29. partition_sort(alist,0,9999)
  30. end=time.clock()
  31. print(end-start)

三路快速排序:当一个数组中有比较多的相同数时适用

  1. import random
  2. import time
  3. import sys
  4. sys.setrecursionlimit(1000000)
  5. def quick_sort(alist,left,right):
  6. if right-left<1:
  7. return
  8. v=alist[left]
  9. lt=left
  10. gt=right
  11. i=left+1
  12. while i<gt:
  13. if alist[i]>v:
  14. alist[i],alist[gt]=alist[gt],alist[i]
  15. gt-=1
  16. elif alist[i]<v:
  17. alist[i],alist[lt+1]=alist[lt+1],alist[i]
  18. i+=1
  19. lt+=1
  20. else:
  21. i+=1
  22. alist[left],alist[lt]=alist[lt],alist[left]
  23. quick_sort(alist,left,lt-1)
  24. quick_sort(alist,gt,right)
  25. alist=random.sample(range(0,10000),10000)
  26. x=1000
  27. while x:
  28. alist.append(alist[0])
  29. x-=1
  30. start=time.clock()
  31. quick_sort(alist,0,len(alist)-1)
  32. end=time.clock()
  33. print(end-start)

利用快速排序查找数组中第k大的数

  1. import random
  2. import time
  3. import sys
  4. sys.setrecursionlimit(1000000)
  5. def partition(alist,left,right):
  6. e=alist[left]
  7. while (left<right):
  8. while (alist[right]>e)&(right>left):
  9. right-=1
  10. if (alist[right]<e)&(left<right):
  11. alist[left]=alist[right]
  12. while (alist[left]<e)&(left<right):
  13. left+=1
  14. if (alist[left]>e)&(left<right):
  15. alist[right]=alist[left]
  16. alist[left]=e
  17. k=left
  18. return k
  19. def partition_sort(alist,left,right,v):
  20. if (left>=right) & (left == v):
  21. return alist[v]
  22. k=partition(alist,left,right)
  23. if k>v:
  24. return partition_sort(alist,left,k-1,v)
  25. elif k<v:
  26. return partition_sort(alist,k+1,right,v)
  27. else:
  28. return alist[k]
  29. alist=random.sample(range(0,30000),30000)
  30. k=partition_sort(alist,0,len(alist)-1,10000)
  31. print(k)

1.10优先队列

概念

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。
image.png
image.png

实现

通常采用堆数据结构来实现。

image.png

堆的定义

堆其实就是一棵完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边),
定义为:具有n个元素的序列(h1,h2,…hn),当且仅当满足(hi>=h2i,hi>=h2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆

image.png

堆排序

  1. import random
  2. import time
  3. class MaxHeap(object):
  4. def __init__(self):
  5. self._data = []
  6. self._count = len(self._data)
  7. def size(self):
  8. return self._count
  9. def isEmpty(self):
  10. return self._count == 0
  11. def add(self, item):
  12. # 插入元素入堆
  13. self._data.append(item)
  14. self._count += 1
  15. self._shiftup(self._count-1) #堆的序号从0开始
  16. def pop(self):
  17. # 出堆
  18. if self._count > 0:
  19. ret = self._data[0]
  20. self._data[0] = self._data[self._count-1] #移除堆的最顶的元素
  21. self._count -= 1
  22. self._shiftDown(0) #对移除之后的堆进行排序,使之成为最大堆
  23. return ret
  24. def _shiftup(self, index):
  25. # 上移self._data[index],以使它不大于父节点
  26. parent = (index-1)>>1
  27. while index > 0 and self._data[parent] < self._data[index]:
  28. # swap
  29. self._data[parent], self._data[index] = self._data[index], self._data[parent]
  30. index = parent
  31. parent = (index-1)>>1
  32. def _shiftDown(self, index):
  33. # 上移self._data[index],以使它不小于子节点
  34. j = (index << 1) + 1
  35. while j < self._count :
  36. # 有子节点
  37. if j+1 < self._count and self._data[j+1] > self._data[j]:
  38. # 有右子节点,并且右子节点较大
  39. j += 1
  40. if self._data[index] >= self._data[j]:
  41. # 堆的索引位置已经大于两个子节点,不需要交换了
  42. break
  43. self._data[index], self._data[j] = self._data[j], self._data[index]
  44. index = j
  45. j = (index << 1) + 1
  46. def MaxHeap1(self,alist,n): #n表示alist的长度
  47. self._data=n*[0]
  48. for i in range(0,n):
  49. self._data[i]=alist[i]
  50. self._count=n
  51. i=(self._count-1)>>2
  52. while i>=0:
  53. self._shiftDown(i)
  54. i-=1
  55. #通过将数组的数一个一个添加到堆中然后在移出堆的操作实现逆序
  56. def Heapsort1(alist):
  57. maxheap=MaxHeap()
  58. for i in range(0,len(alist)):
  59. maxheap.add(alist[i])
  60. i=maxheap._count-1
  61. while i>=0:
  62. alist[i]=maxheap.pop()
  63. i-=1
  64. #通过开辟一个与数组同长度的堆,然后赋值->shitfdown使得成为最大堆,最后移出堆操作实现逆序
  65. def Heapsort2(alist):
  66. #开辟新空间maxheap
  67. maxheap=MaxHeap()
  68. maxheap.MaxHeap1(alist,len(alist))
  69. i=len(alist)-1
  70. while i>=0:
  71. alist[i]=maxheap.pop()
  72. i-=1
  73. #直接对alist逆排序,不创建堆空间
  74. def Heapsort3(alist):
  75. #对数组heapify
  76. i=(len(alist)-1)>>1
  77. while i>=0:
  78. shiftdown(alist,len(alist),i)
  79. i-=1
  80. #对数组进行逆序
  81. k=len(alist)-1
  82. while k>0:
  83. #交换
  84. alist[k],alist[0]=alist[0],alist[k]
  85. shiftdown(alist,k,0)
  86. k-=1
  87. def shiftdown(alist,n,k):
  88. while 2*k+1<n: #当左孩子没有越界
  89. j=2*k+1
  90. if j+1<n and alist[j+1]>alist[j]:
  91. j+=1
  92. if alist[k]>=alist[j]:
  93. break
  94. alist[k],alist[j]=alist[j],alist[k]
  95. k=j
  96. if __name__ == '__main__':
  97. alist=random.sample(range(0,10000),10000)
  98. start=time.clock()
  99. Heapsort3(alist)
  100. end=time.clock()
  101. print(end-start)

索引堆

image.png

  1. import math
  2. class IndexMaxHeap(object):
  3. def __init__(self,capacity):
  4. self._indexes =capacity*[0]
  5. self._data=capacity*[0]
  6. self._reverse=capacity*[0]
  7. self._count = 0
  8. def size(self):
  9. return self._count
  10. def isEmpty(self):
  11. return self._count == 0
  12. def IndexMaxHeap1(self,alist):
  13. for i in range(0,len(alist)):
  14. self._data[i]=alist[i]
  15. self._indexes[i]=i
  16. self._reverse[i]=i
  17. self._count+=1
  18. #进行最大堆排序
  19. i=(self._count-2)>>1 #求第一个不是叶子节点的元素的序号
  20. while i>=0:
  21. self._shiftDown(i)
  22. i-=1
  23. #传入的i对用户而言,是从0索引的
  24. def add(self, i,item):
  25. # 插入元素入堆
  26. self._data.append(item)
  27. self._indexes.append(i)
  28. self._reverse.append(self._count)
  29. self._count += 1
  30. self._shiftup(self._count-1) #堆的序号从0开始
  31. def pop(self):
  32. # 出堆,返回的是堆的最大元素
  33. if self._count > 0:
  34. ret = self._data[self._indexes[0]]
  35. self._indexes[0],self._indexes[self._count-1]= self._indexes[self._count-1],self._indexes[0] #移除堆的最顶的元素
  36. self._reverse[self._indexes[0]]=0
  37. self._reverse[self._indexes[count-1]]=0
  38. self._count -= 1
  39. self._shiftDown(0) #对移出之后的堆进行排序,使之成为最大堆
  40. return ret
  41. def popindex(self):
  42. #返回最大元素的索引
  43. if self._count>0:
  44. ret=self._indexes[0] #对于用户来说,返回的是从0开始列表最大元素的索引
  45. self._indexes[0],self._indexes[self._count-1]= self._indexes[self._count-1],self._indexes[0] #移除堆的最顶的元素
  46. self._count-=1
  47. self._shiftDown(0)
  48. return ret
  49. def contain(self,i):
  50. #验证用户传进的i(以0开始)的参数是不是在索引堆中
  51. if i>=0 and i+1<=self._count:
  52. return self._reverse[i]!=0
  53. def getItem(self,i):
  54. if self.contain(i):
  55. return self._data[i]
  56. def change(self,i,item): #将列表中的data[i]改为item
  57. if self.contain(i):
  58. self._data[i]=item
  59. #找到indexes[j]=i,j表示data[i]在堆中的位置
  60. # for j in range(0,self._count):
  61. # if self._indexes[j]==i:
  62. # _shiftup(j)
  63. # _shiftDown(j)
  64. # return
  65. j=self._reverse[i]
  66. self._shiftup(j)
  67. self._shiftDown(j)
  68. #上浮和下沉都是入堆与出堆的操作,与用户无关,可以设为私有方法
  69. def _shiftup(self, k):
  70. # 上移self._indexes[k],以使它不大于父节点
  71. while k > 0 and self._data[self._indexes[(k-1)>>1]] < self._data[self._indexes[k]]:
  72. # swap
  73. self._indexes[(k-1)>>1], self._indexes[k] = self._indexes[k], self._indexes[(k-1)>>1]
  74. self._reverse[self._indexes[(k-1)>>1]]=(k-1)>>1
  75. self._reverse[self._indexes[k]]=k
  76. k=(k-1)>>1
  77. def _shiftDown(self, k):
  78. # 上移self._data[index],以使它不小于子节点
  79. while (k <<1+1) <= self._count :
  80. j = k << 1 + 1
  81. # 有子节点
  82. if j+1 < self._count and self._data[self._indexes[j+1]] > self._data[self._indexes[j]]:
  83. # 有右子节点,并且右子节点较大
  84. j += 1
  85. if self._data[self._indexes[k]] >= self._data[self._indexes[j]]:
  86. # 堆的索引位置已经大于两个子节点,不需要交换了
  87. break
  88. self._indexes[k],self._indexes[j]=self._indexes[j],self._indexes[k]
  89. self._reverse[self._indexes[k]]=k
  90. self._reverse[self._indexes[j]]=j
  91. k = j
  92. indexheap=IndexMaxHeap(5)
  93. alist=[30,90,3,6,40]
  94. indexheap.IndexMaxHeap1(alist)
  95. print(indexheap._indexes)
  96. indexheap.add(5,80)
  97. print(indexheap._indexes)
  98. print(indexheap.getItem(5)) #80

运行结果:
image.png

排序总结

image.png

排序的稳定性

image.png