第十五章 算法
“”"
- 衡量算法的好坏
时间复杂度
空间复杂度 - 查找
顺序查找
折半查找 - 排序
冒泡排序
选择排序
插入排序
希尔排序
快速排序
归并排序
算法
解决特定问题的方案
一、衡量算法的好坏
(1) 时间复杂度
算法运行的时候执行规模、频度。
最好执行次数、平均执行次数、最坏执行次数(为准)
常数时间复杂度:在任何时刻访问时间复杂度都是一致的。O(1)
x=1
y=2
O(n): 根据n的大小变化的时间复杂度
一层循环就是O(n)
n=5
for i in range(n):
pass
O(n^2):嵌套循环
for i in range(n):
for j in range(n-2):
pass
O(logn):log2为底 n的对数 ,当循环的次数在循环中折半
while n!=0:
print(n)
n=n//2
常用时间复杂度的排序
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)
(2)空间复杂度:
用空间换时间的方式。
二、查找
查找:顺序查找、折半查找
(1) 顺序查找
从前到后,顺序进行与关键字相匹配的查找
时间复杂度O(n)
def search(li,key):
for index,i in enumerate(li):
if i==key:
return index
return -1
print(search([1,2,3,44,5,77,88],44))
(2) 折半查找
选择中间的元素进行比较,每次排除一半的元素
时间复杂度 O(logn)
折半查找必须要在已排序的基础上进行
"""
key比较中间的元素mid
if key >mid: 舍弃左半部分,取右半部分,继续查找
else : 舍弃右半部分,区左半部分,继续查找
"""
"""
舍弃左半部分: start: mid+1 end 不变
舍弃右半部分: start: 不变 end mid-1
"""
def middleSearch(li,key):
start=0
end=len(li)-1
while start<=end:
mid=(start+end)//2
if key>li[mid]:
start=mid+1
elif key<li[mid]:
end=mid-1
else:
return mid
return -1
print(middleSearch([1,2,4,77,88,99,100],3))
思考:折半查找一定顺序查找吗?
折半查找需要先排序
当查找次数较多的时候,可以选择使用折半查找。
查找分几种?
折半查找怎么找?
折半是不是一定比顺好?
三、排序
按照稳定性上:稳定排序和不稳定排序
3 4 5(1) 6 -9 -1 5(2) -9 -1 3 4 5(1) 5(2) 6
1. 冒泡排序
最重要的排序方法
思路:将相邻的两个元素进行比较 i i+1 , 通过比较来决定是否交换位置。
每一次排序都会选出一个(最大)最小值。
li=[23,-8,29,2,6,18,33]
内循环---外循环
def bublesort(li):
n=len(li)-1
for j in range(n):
for i in range(n-j):
if li[i]>li[i+1]:
li[i],li[i+1]=li[i+1],li[i]
print(li)
bublesort(li)
时间复杂度:O(n^2) 最佳时间复杂度(O(n))
稳定性:稳定排序
2. 选择排序
思路:每次选择一个最小或者最大的的元素放在前面,排好序。
li=[23,-8,29,2,6,18,33]
min_value=0
li_temp=[]
for i in li:
if i==0:
min_value=li[0]
else:
if i<min_value:
min_value=i
print(min_value)
"""
1. 不取最小值 ,而是使用索引
min设置成最小值的索引
2. 外循环
"""
li=[-9 ,-20 , -100, 10 , 3 ,11 , 7 , 5]
第一轮
def choosesort(li):
n=len(li)
min_index=0 假定第0个元素是最小值的索引
使用for遍历从1个元素到最后一个元素,找到真正 最小值的索引
for i in range(1,n):
if li[i]<li[min_index]:
min_index=i
for循环结束之后,min_index是真正的最小值索引
li[min_index],li[0]=li[0],li[min_index]
print(li)
min_index = 1 假定第1个元素是最小值的索引
使用for遍历从2个元素到最后一个元素,找到真正 最小值的索引
for i in range(2, n):
if li[i] < li[min_index]:
min_index = i
for循环结束之后,min_index是真正的最小值索引
li[min_index], li[1] = li[1], li[min_index]
print(li)
choosesort(li)
def choosesort(li):
n=len(li)
for j in range(n-1):
min_index=j 假定第j个元素是最小值的索引
使用for遍历从j+1个元素到最后一个元素,找到真正 最小值的索引
for i in range(j+1,n):
if li[i]<li[min_index]:
min_index=i
for循环结束之后,min_index是真正的最小值索引
li[min_index],li[j]=li[j],li[min_index]
print(li)
choosesort(li)
li=[-9 ,-20 , -100, 10 , 3 ,11 , 7 , 5]
[-100, -20, -9, 3, 5, 7, 10, 11]
时间复杂度:O(n^2) 没有最佳排序。
稳定性: 不稳定排序
3. 插入排序
像大小个排队
思路:从第二个元素开始,插入先有的已排好序的列表中。
li=[-9 ,-20 , -100, 10 , 3 ,11 , 7 , 5]
n=len(li)
for i in range(1,n):
第一次
i=1 6
temp=li[i] 7
拿着-20跟前面排好队[-9]的元素比较,插入的到[-9]的列表中
j=i-1
while j>=0 and temp<li[j]:
li[j+1]=li[j]
j-=1
li[j+1]=temp
print(li)
时间复杂度:O(n^2) 最佳O(n) 排好序。
稳定性:稳定排序
4.希尔排序
缩小增量排序。
以插入排序为基础,设置一系列增量,按照增量进行分组,将组内的元素进行排序,
再取其他的增量。增量(大---小1)
对于增量没有固定的值。 11 6 3 2 1
li=[-9 ,-20 , -100, 10 , 3 ,-110 , 7 , -5]
increment=[3,2,1]
def shell(li,increment):
n=len(li)
for inc in increment:3 2 1
for k in range(inc): 0 1 2
for i in range(k+inc,n,inc):
temp=li[i]
j=i-inc
while j>=0 and temp<li[j]:
li[j+inc]=li[j]
j-=inc
li[j+inc]=temp
print(li)
shell(li,increment)
时间复杂度:跟增量设置有关 最差的情况:O(n^2)
稳定性:不稳定
5. 快速排序
从列表中选取一个中心点。使得中心点左侧的元素都小于该元素,中心点右侧的元素都大于该元素
def quicksort(li):
n=len(li)
if n<=1:
return li
else:
mid_index=0
small=[]
big=[]
for i in range(1,n):
if li[mid_index]>li[i]:
small.append(li[i])
else:
big.append(li[i])
return quicksort(small)+[li[mid_index]]+quicksort(big)
li=[-9 ,-20 , -100, 10 , 3 ,-110 , 7 , -5,7]
print(quicksort(li))
时间复杂度:O(n^2)
稳定性:稳定
6.归并排序
分久必合,合久必分。
def merage(li,low,high):
if low <high:
mid=(low+high)//2
merage(li,low,mid)
merage(li,mid+1,high)
_merage_sort(li,low,mid,high)
return li
def _merage_sort(li,low,mid,high):
i=low i是左半部分的第一个元素
j= mid+1 j是右半部分的第一个元素
temp=[]
while i<=mid and j<=high:
if li[i]<=li[j]:
temp.append(li[i])
i+=1
else:
temp.append(li[j])
j+=1
while j<=high: 左边被取完了
temp.append(li[j])
j+=1
while i<=mid: 右边被取完
temp.append(li[i])
i+=1
li[low:high+1]=temp
li=[-9 ,-20 , -100, 10 , 3 ,-110 , 7 , -5,7]
print(merage(li,0,len(li)-1))
时间复杂度:O(nlogn)
稳定性:稳定排序
“”"