"""归并排序"""
'''
假设现在的列表分两段有序,如何将其合成为一个有序列表:[2]578|9|[1]346 ,其中指针i指向2,j指向1,中间mid=9。这种操作称为一次归并
第1步:2和1比较,1小存入ltmp=[1],j指针移动+1;
第2步:i指向2,j指向3,2和3比较,2小,2存入列表litmp=[1,2],i指针移动+1;
第3步:i指向5,j指向3,5和3比较,3小,3存入列表litmp=[1,2,3],j指针移动+1;
第4步:i指向5,j指向4,5和4比较,4小,4存入列表litmp=[1,2,3,4],j指针移动+1;
第5步:i指向5,j指向6,5和6比较,5小,5存入列表litmp=[1,2,3,4,5],i指针移动+1;
第6步:i指向7,j指向6,6和7比较,6小,6存入列表litmp=[1,2,3,4,5,6],j指针移动+1,
第7步:i指向7,j指向空,右边无元素,无需比较,则剩下左边部分都出来7、8、9,即7、8、9存入列表litmp=[1,2,3,4,5,6,7,8,9];
'''
def merge(li,low,mid,high):
i=low
j=mid+1
ltmp=[]
while i <=mid and j<=high:#只要左右两边都有数
if li[i]<li[j]:
ltmp.append(li[i])
i+=1
else:
ltmp.append(li[j])
j+=1
#执行完while,肯定有一部分没数了
#如果右半部分无数字结束
while i<=mid:
ltmp.append(li[i])
i+=1
# 如果左半部分无数字结束
while j<=high:
ltmp.append(li[j])
j+=1
#将存入ltmp中排好序的数值写回去li 因为li函数参数截出来就是从low到high
li[low:high+1]=ltmp
def mergesort(li,low,high):
if low<high:#至少有两个元素,递归
mid=(low+high)//2
mergesort(li,low,mid)
mergesort(li,mid+1,high)
merge(li,low,mid,high)
#时间复杂度
###---------------------归并排序的使用-----------------------------
"""
归并排序
分解:将列表越分越小,直至分成一个元素
终止条件:一个元素是有序的
合并:将两个有序列表归并,列表越来越大。
"""
def merge(li,low,mid,high):
i=low
j=mid+1
ltmp=[]
while i <mid and j<=high:#只要左右两边都有数
if li[i]<li[j]:
ltmp.append(li[i])
i+=1
else:
ltmp.append(li[j])
j+=1
#执行完while,肯定有一部分没数了
while i<=mid:
ltmp.append(li[i])
i+=1
while j<=high:
ltmp.append(li[j])
j+=1
li[low:high+1]=ltmp
def merge_sort(li,low,high):
if low<high:#至少有两个元素,递归
mid=(low+high)//2
merge_sort(li,low,mid)
merge_sort(li,mid+1,high)
merge(li,low,mid,high)
#测试
import random
li=list(range(1000))
random.shuffle(li)
print(li)
merge_sort(li,0,len(li)-1)
print(li)
##########NB三人组#################
'''
三种排序算法的事件复杂度都是O(nlogn)
一般情况下,就运行时间而言:
快速排序<归并排序<堆排序
三种排序算法的缺点:
快速排序:极端情况下排序效率低
归并排序:需要额外的内存开销
堆排序:在快的排序算法中相对较慢
快速排列
优点:虽然三种算法的时间复杂度都是O(nlogn),但是三者速度仍然有微小区别,快排是NB三人组算法中最快的一个
缺点:快排算法可能出现最坏情况,这个情况的出现在每次要归位的数是所有剩余数中最大(或者最小的数)时,此时快速排列的时间复杂度是O(n**2)
归并排序
优点:归并排序速度第二
缺点:空间复杂度为O(n),消耗内存
堆排序
优点:可以实现部分排序
缺点:速度是三者中最慢的,代码复杂,逻辑复杂
运行时间装饰器
'''
#####快速排序、归并排序、堆排序时间运行比较代码实现######
# 运行时间装饰器
import time
def tell_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return res
return wrapper
##————————————————————————————————————————————————————————————————###########
import random
from common import *
li = [i for i in range(100000)]
random.shuffle(li)
li1 = li.copy() # 将列表拷贝三份
li2 = li.copy()
li3 = li.copy()
def position(li, head, end): # 一次归位函数
tmp = li[head]
while head < end:
while head < end and li[end] >= tmp:
end -= 1
li[head] = li[end]
while head < end and li[head] <= tmp:
head += 1
li[end] = li[head]
li[head] = tmp
return head
def _quick_sort(li, head, end): # 快速排列由外到内
if head < end:
mid = position(li, head, end)
_quick_sort(li, head, mid-1)
_quick_sort(li, mid+1, head)
@tell_time
def quick_sort(li, head, end): # 为了避免递归对装饰器的影响
_quick_sort(li, head, end)
def sift(li, head, end): # 向下调整函数
tmp = li[head]
i = head
j = head * 2 + 1
while j <= head:
if j+1 <= head and li[j+1] > li[j]:
j += 1
if li[j] > tmp:
li[i] = li[j]
i = j
j = j * 2 + 1
else:
break
li[i] = tmp
@tell_time
def heap_sort(li): # 堆排序
end = len(li) - 1
for i in range((end - 1) // 2, -1, -1):
sift(li, i, end)
for i in range(end, 0, -1):
li[0], li[i] = li[i], li[0]
sift(li, 0, i-1)
def merge(li, head, mid, end): # 一次归并函数
i = head
j = mid + 1
tmp_li = []
while i <= mid and j <= end:
if li[i] <= li[j]:
tmp_li.append(li[i])
i += 1
else:
tmp_li.append(li[j])
j += 1
while i <= mid:
tmp_li.append(li[i])
i += 1
while j <= end:
tmp_li.append(li[j])
j += 1
li[head:end+1] = tmp_li
def _merge_sort(li, head, end):
if head < end: # 归并排序由内到外
mid = (head + end) // 2
_merge_sort(li, head, mid)
_merge_sort(li, mid+1, end)
merge(li, head, mid, end)
@tell_time
def merge_sort(li, head, end):
_merge_sort(li, head, end)
quick_sort(li1, 0, len(li1) - 1)
merge_sort(li2, 0, len(li2) - 1)
heap_sort(li3)
#测试堆排序、快速排序、归并排序时间运行
print('-----------------------------','测试堆排序、快速排序、归并排序时间运行')
import random,copy
li=list(range(100000))
random.shuffle(li)
li1=copy.deepcopy(li)
li2=copy.deepcopy(li)
li3=copy.deepcopy(li)
quick_sort(li1)
heap_sort(li2)
merge_sort(li3)
'''
基础算法总结
算法名称 时间复杂度——最好——平均——最坏 空间复杂度 稳定性
冒泡排序 O(n) O(n**2) O(n**2) O(1) 稳定
选择排序 O(n**2) O(n**2) O(n**2) O(1) 不稳定
插入排序 O(n**2) O(n**2) O(n**2) O(1) 稳定
快速排序 O(nlogn) O(nlogn) O(n**2) O(1) 不稳定
归并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 稳定
堆排序 O(nlogn) O(nlogn) O(nlogn) O(1) 不稳定
'''