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)