1.直接插入排序
平均時間複雜度O(n^2),最好情況O(n),穩定。
思想:每次迭代確保前2, 3, ...., n個爲排序好的,每次排序從後往前比較
待排序: [49,38,65,97,76,13,27,49]
第一次比較後: [38,49,65,97,76,13,27,49] 第二個元素(38)與之前的元素進行比較,發現38較小,進行交換
第二次比較後: [38,49,65,97,76,13,27,49] 第三個元素(65)大於前一個元素(49),所以不進行交換操作,直接到下一個元素比較
第三次比較後: [38,49,65,97,76,13,27,49] 和第二次比較類似
第四次比較後: [38,49,65,76,97,13,27,49] 當前元素(76)比前一元素(97)小,(97)後移,(76)繼續與(65)比較,發現當前元素比較大,執行插入
第五次比較後: [13,38,49,65,76,97,27,49]
第六次比較後: [13,27,38,49,65,76,97,49]
第七次比較後: [13,27,38,49,49,65,76,97]
def InsertSort(myList):
#獲取列表長度
length = len(myList)
for i in range(1,length):
#設置當前值前一個元素的標識
j = i - 1
#如果當前值小於前一個元素,則將當前值作爲一個臨時變量存儲,將前一個元素後移一位
if(myList[i] < myList[j]):
temp = myList[i]
myList[i] = myList[j]
#繼續往前尋找,如果有比臨時變量大的數字,則後移一位,直到找到比臨時變量小的元素或者達到列表第一個元素
j = j-1
while j>=0 and myList[j] > temp:
myList[j+1] = myList[j]
j = j-1
#將臨時變量賦值給合適位置
myList[j+1] = temp
myList = [49,38,65,97,76,13,27,49]
InsertSort(myList)
print(myList)
2. 希爾排序
最壞情況時間複雜度O(n^2),最好情況O(n),不穩定。
1. 選取增量 2.確保最後增量爲1
3. 快速排序
不穩定,
def parttion(v, left, right):
key = v[left]
low = left
high = right
while low < high:
while (low < high) and (v[high] >= key):
high -= 1
v[low] = v[high]
while (low < high) and (v[low] <= key):
low += 1
v[high] = v[low]
v[low] = key
return low
def quicksort(v, left, right):
if left < right:
p = parttion(v, left, right)
quicksort(v, left, p-1)
quicksort(v, p+1, right)
return v
s = [6, 8, 1, 4, 3, 9, 5, 4, 11, 2, 2, 15, 6]
print("before sort:",s)
s1 = quicksort(s, left = 0, right = len(s) - 1)
print("after sort:",s1)
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) / 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
print quicksort([3,6,8,10,1,2,1])
4. 冒泡排序
穩定,每次循環確保前i個數爲最小且遞增。
第一次循環,第一個數對開始比較並替換直到到底,然後最後一個數全局最大(增序排列時)
與直接選擇排序相比,它通過對比數對並交換使得第一次循環最後一個數全局最大,而直接選擇排序對比min與後面所有元素最終找到後續最小值從而第一次循環後第一個數全局最小;直接插入排序每次迭代將n個數依次與前面(倒序)元素比較,第一次循環兩端未必有全局極值。
def bubbleSort(nums):
for i in range(len(nums)-1): # 這個循環負責設置冒泡排序進行的次數
for j in range(len(nums)-i-1): # j爲列表下標,倒序可以使得每次迭代得到第n小的
if nums[j] > nums[j+1]:
nums[j], nums[j+1] = nums[j+1], nums[j]
return nums
5. 直接選擇排序
不穩定,每次循環將第n個位置數值與它之後的最小值的位置交換。
第一次循環,比較第一個位置與所有後面位置數值,結束後第一個位置的數值直接與後面最小數值對應位置對換。與冒泡排序區別,每次循環時直接選擇排序找到最小值後才與第i位置交換一次,而冒泡排序循環是不斷把第i個與後面每個分別比較,如果大則立刻交換。
思想:每次迭代確保前n個數爲排序好的,每次迭代用第n個數與後面所有數依次比較取最小(大)值放在位置n上。
def sort(a):
for i in range(len(a)):
min = i
for j in range(i+1,len(a)):
if a[min] > a[j]:
min = j
a[i], a[min] = a[min], a[i]
a =[49,38,65,97,76,13,27,49,55,4]
sort(a)
print(a)
6. 堆排序
選擇排序,不穩定排序。先確保每個非葉子節點值比其葉子大,然後得到根節點最大值,並從第一個位置放到最後一個位置,再0 - n-1循環。
利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。
其基本思想爲(大頂堆):
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]同該區間的最後一個記錄交換,然後將新的無序區調整爲新的堆。
def adjust_heap(lists, i, size):
lchild = 2 * i + 1
rchild = 2 * i + 2
max = i
if i < size / 2:
if lchild < size and lists[lchild] > lists[max]:
max = lchild
if rchild < size and lists[rchild] > lists[max]:
max = rchild
if max != i:
lists[max], lists[i] = lists[i], lists[max]
adjust_heap(lists, max, size)
def build_heap(lists, size):
for i in range(0, (size/2))[::-1]:
adjust_heap(lists, i, size)
def heap_sort(lists):
size = len(lists)
build_heap(lists, size)
for i in range(0, size)[::-1]:
lists[0], lists[i] = lists[i], lists[0]
adjust_heap(lists, 0, i)
7.歸類排序
穩定
把數組從中間位置拆分得到第二層,然後反覆如此拆分,分到底後葉子節點層比較兩個數大小,排序後遞歸歸併組合。
def mergesort(seq):
if len(seq)<=1:
return seq
mid=int(len(seq)/2)
left=mergesort(seq[:mid])
right=mergesort(seq[mid:])
return merge(left,right)
def merge(left,right):
result=[]
i,j=0,0
while i<len(left) and j<len(right):
if left[i]<=right[j]:
result.append(left[i])
i+=1
else:
result.append(right[j])
j+=1
result+=left[i:]
result+=right[j:]
return result
if __name__=='__main__':
seq=[4,5,7,9,7,5,1,0,7,-2,3,-99,6]
print(mergesort(seq))
8. 基數排序
穩定
for i in range(d): #循環 位數
建立10個桶
根據list中對應位數大小放入桶中
順序取出桶中元素形成list
from random import randint
def RadixSort(list,d):
for k in range(d):#d輪排序
s=[[] for i in range(10)]#因爲每一位數字都是0~9,故建立10個桶
'''對於數組中的元素,首先按照最低有效數字進行
排序,然後由低位向高位進行。'''
for i in list:
'''對於3個元素的數組[977, 87, 960],第一輪排序首先按照個位數字相同的
放在一個桶s[7]=[977],s[7]=[977,87],s[0]=[960]
執行後list=[960,977,87].第二輪按照十位數,s[6]=[960],s[7]=[977]
s[8]=[87],執行後list=[960,977,87].第三輪按照百位,s[9]=[960]
s[9]=[960,977],s[0]=87,執行後list=[87,960,977],結束。'''
s[int(i/(10**k)%10)].append(i) #保留指定位數
list=[j for i in s for j in i] #總集中取出第i個桶,桶中取出第j個數,循環加入list
return list
if __name__ == '__main__':
a=[randint(1,999) for i in range(10)]#最多是三位數,因此d=3
print(a)
a=RadixSort(a,3)#將排好序的數組再賦給a!!!!
print(a)
8. 最長公共子串
LCS問題就是求兩個字符串最長公共子串的問題。解法就是用一個矩陣來記錄兩個字符串中所有位置的兩個字符之間的匹配情況,若是匹配則爲1,否則爲0。然後求出對角線最長的1的序列,其對應的位置就是最長匹配子串的位置。
def find_lcsubstr(s1, s2):
m=[[0 for i in range(len(s2)+1)] for j in range(len(s1)+1)] #生成0矩陣,爲方便後續計算,比字符串長度多了一列
mmax=0 #最長匹配的長度
p=0 #最長匹配對應在s1中的最後一位
for i in range(len(s1)):
for j in range(len(s2)):
if s1[i]==s2[j]:
m[i+1][j+1]=m[i][j]+1
if m[i+1][j+1]>mmax:
mmax=m[i+1][j+1]
p=i+1
return s1[p-mmax:p],mmax #返回最長子串及其長度
print find_lcsubstr('abcdfg','abdfg')
9. 二分查找
def find(a,b):
min = 0
max = len(a)-1
if b in a:
while True:
centre = int((max + min)/2)
if a[centre] > b:
max = centre - 1
elif a[centre] < b:
min = centre + 1
elif a[centre] == b:
return centre
break
else:
return('b in not in a')
ex = find([1,2,3,4,5,6],5)
print(ex)