排序与搜索
冒泡排序
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190214153816738.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjMwNzAzNA==,size_16,color_FFFFFF,t_70
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190214155820408.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjMwNzAzNA==,size_16,color_FFFFFF,t_70
def bubble_sort(alist):
'''冒泡法排序'''
n=len(alist)
for j in range(n-1):
count=0
for i in range(n-1-j):
# 班长从头走到尾
if alist[i]>alist[i+1]:
alist[i],alist[i+1]=alist[i+1],alist[i]
count+=1
if count==0:
return
if __name__ == '__main__':
li=[54,26,93,17,77,31,44,55,20]
print(li)
bubble_sort(li)
print(li)
时间复杂度:
最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束)。
最坏时间复杂度:O(n2)
稳定性:稳定
选择排序
将顺序表分为两部分,一部分是已经排好序的,一部分是未排序的,每次都从为排序的序列里选择最小的那个放入已经排好序的里面,直到最后所有的都已经排好序了。
时间复杂度:
最优时间复杂度:O(n2)
最坏时间复杂度:O(n2)
稳定性:不稳定(考虑升序每次取最大值的情况)。
def select_sort(alist):
'''选择排序'''
n=len(alist)
for j in range(n-1):
min_index=j
for i in range(j+1,n):
if alist[min_index]>alist[i]:
min_index=i
alist[j],alist[min_index]=alist[min_index],alist[j]
if __name__ == '__main__':
li=[54,26,93,17,77,31,44,55,20]
print(li)
select_sort(li)
print(li)
插入排序
def insert_sort(alist):
'''插入排序'''
n=len(alist)
for j in range(1,n):
#从右边的无序序列中取出多少个元素执行这样的插入过程
for i in range(j,0,-1):
#i代表内存循环起始值,执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
if alist[i]<alist[i-1]:
alist[i],alist[i-1]=alist[i-1],alist[i]
else:
break
if __name__ == '__main__':
li=[54,26,93,17,77,31,44,55,20]
print(li)
insert_sort(li)
print(li)
时间复杂度
最优时间复杂度:O(n)
最坏时间复杂度:O(n2)
稳定性:稳定性
希尔排序
def shell_sort(alist):
'''希尔排序'''
#n=9
n=len(alist)
gap=n//2
#n=4
#gap变化到0之前,插入算法执行的次数
while gap>=1:
for j in range(gap,n):
#gap之后的所有元素都要执行
for i in range(j,0,-gap):
if alist[i]<alist[i-gap]:
alist[i],alist[i-gap]=alist[i-gap],alist[i]
else:
break
#缩短gap步长
gap //= 2
时间复杂度
最优时间复杂度:根据步长的不同而不同
最坏时间复杂度:O(n2)
稳定性:不稳定
快速排序(必须要掌握!!!)
def quick_sort(alist,first,last):
'''快速排序'''
if first>=last:
return
mid_value=alist[first]
low=first
high=last
while low<high:
#high左移,遇到比基准值小的退出循环
while low<high and alist[high]>=mid_value:
high-=1
alist[low]=alist[high]
#low右移,遇到比基准值大的退出循环
while low<high and alist[low]<mid_value:
low+=1
alist[high]=alist[low]
#从循环退出时,low=high
alist[low]=mid_value
#对low左边的列表执行快速排序
quick_sort(alist,first,low-1)
#对low右边的列表执行快速排序
quick_sort(alist,low+1,last)
时间复杂度
最优时间复杂度:nlog2(n)
最坏时间复杂度:O(n2)
稳定性:不稳定
归并排序
先对半分,再合并
def merge_sort(alist):
'''归并排序'''
n=len(alist)
if n<=1:
return alist
mid=n//2
#left采用归并排序后形成的有序的新的列表
left_li=merge_sort(alist[:mid])
#right采用归并排序后形成的有序的新的列表
right_li=merge_sort(alist[mid:])
#merge left和right,将两个有序的子序列合并
#拆分和n无关,时间复杂度O(1)
left_pointer,right_pointer=0,0
result=[]
while (left_pointer<len(left_li)) and (right_pointer<len(right_li)):
if left_li[left_pointer]<=right_li[right_pointer]:
result.append(left_li[left_pointer])
left_pointer+=1
else:
result.append(right_li[right_pointer])
right_pointer+=1
result+=left_li[left_pointer:]
result+=right_li[right_pointer:]
return result
时间复杂度
前面拆分部分与n无关,时间复杂度O(1),合并的时候每一级的时间复杂度为O(n),合并的级数为log2n, 因此时间复杂度为nlog2n。
最坏时间复杂度:nlog2n
稳定性:稳定
归并算法是排序算法中时间复杂度最小的,但是它有一个返回值,也就是说它需要一个新的空间来保存排序后的,空间上消耗了。