p2_1归并排序O(nlogn)
题目:
给定你一个长度为 n 的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在 1∼109 范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
#Python使用缩进对齐组织代码的执行,所有没有缩进的代码(非函数定义和类定义),
# 都会在载入时自动执行,这些代码,可以认为是Python的main函数。
#2路归并:把两个已经有序的序列合并成一个,可以把一列数的每一个数字看成是一个独立是子序列,直接合并就行
#但是因为输入的序列所以先得把他们一一分割成独立的数字,所以归并函数先分割!
#每次合并都是相邻的序列!!!!(因为mid一分为二啊!!!!想象一下)
#见百度云第八章9-12min
#快排是先分左右,再递归;归并是先递归再合二为一
#快排不稳定,归并稳定:当两个对比数相等时候,取第一个数,第一个指针后移---为了稳定
#快排是【从长到短】,归并是【从短到长】
#时间复杂度为O(nlogn):因为整个序列长n,递归的第二层为:两个n/2的,,第三层为4个n/4, 。。。,n个长度为1的序列
#所以一共递归logn次,每次复杂度为n 【n = 2^x,解得x = log 2 n(2为底数)】
#对每个序列从中间一分为二,再对比合并
#选数mid=(l+r)/2
#递归排序
#将有序的列合二为一
def merge_sort(nums,l,r):#每次这个lr都直接想成某一个序列的左右端点,而不只是初始的lr
if l>=r: return
mid=(l+r)//2
merge_sort(nums,l,mid)#感受这句话!!!:对左边递归的排序使得有序!!递归到头就是一个独立的数字,再相邻两个归并
merge_sort(nums,mid+1,r)
i = l
j = mid + 1
k=0
while i<=mid and j<=r:
if nums[i]<=nums[j]:
tmp[k]=nums[i]
k+=1
i+=1
else:
tmp[k]=nums[j]
k+=1
j+=1 #大的while循环结束必有i=mid+1且j<=r 或者j=r+1且i<=mid
while i<=mid:#都扫尾肯定没错
tmp[k]=nums[i]
k+=1
i+=1
while j<=r:#都扫尾肯定没错
tmp[k]=nums[j]
k+=1
j+=1
# 将排序好的tmp数组存到nums对应部分中, 因为这个已经在函数里面,所以要注意不能直接等!
i = l
k = 0#每个循环里面生成的tmp都是从k=0开始的,充当的是nums里面从l开始的到r结束的
while i <= r:
nums[i] = tmp[k]
i += 1
k += 1
if __name__=="__main__":#这个和main()不一样,这里面定义的变量可用于其他函数中,main则不行不,而且个如果这个要调用某个函数则只能放在该函数后
length=int(input("n\n").strip())
nums = list(map(int,input("nums\n").split()))
tmp = [0] * length# 一维数组可以这么生成,二维数组不行
merge_sort(nums,0,length-1)
print(' '.join(map(str, nums)))#nums不需要再split