做了一道跟二級排序相關的筆試題,不用sorted函數,手擼Python歸併排序,一直忙着做項目學習,擼了很久纔出來,最後被參數傳遞坑了一道,太菜了我~~~
懷念C++,參數傳遞很清晰,想傳值傳引用都是自己說了算。我用Python在賦值、傳參、返回值的時候,總是忍不住去想,這個賦值、參數或者返回是不是又開闢空間了?我的原變量會不會被修改掉?我要不要傳引用?怎麼節省內存?畢竟是以前寫C++留下來的病。
言歸正傳。
問題描述
給出一個n*m的列表,先按第二列進行升序排序,第二列值相同的,按第一列的值進行升序排序。
輸入:
[[4, 88], [1, 33], [2, 88], [5, 43], [1, 68], [4, 22], [3, 22], [5, 41], [4, 42], [2, 22]]
輸出:
[[2, 22], [3, 22], [4, 22], [1, 33], [5, 41], [4, 42], [5, 43], [1, 68], [2, 88], [4, 88]]
輸入:
[[4, 88, 999], [1, 33, 199], [2, 88, 111], [5, 43, 123], [1, 68, 144], [4, 22, 232], [3, 22, 566], [5, 41, 0], [4, 42, 234], [2, 22, 555]]
輸出:
[[2, 22, 555], [3, 22, 566], [4, 22, 232], [1, 33, 199], [5, 41, 0], [4, 42, 234], [5, 43, 123], [1, 68, 144], [2, 88, 111], [4, 88, 999]]
Python的sorted函數
if __name__ == '__main__':
l = [[4, 88], [1, 33], [2, 88], [5, 43], [1, 68], [4, 22], [3, 22], [5, 41], [4, 42], [2, 22]]
l1 = [[4, 88, 999], [1, 33, 199], [2, 88, 111], [5, 43, 123], [1, 68, 144], [4, 22, 232], [3, 22, 566], [5, 41, 0], [4, 42, 234], [2, 22, 555]]
print(sorted(l, key=lambda x: (x[1], x[0]), reverse=False))
print(sorted(l1, key=lambda x: (x[1], x[0]), reverse=False))
無返回值的歸併排序代碼:
def merge_sort(l):
length = len(l)
if length <= 1:
return
p = int(length / 2)
l1 = l[:p]
l2 = l[p:]
merge_sort(l1) # 前半段會排序
merge_sort(l2) # 後半段也會排序
merge(l1, l2, l) # 傳入排序後的前後半段,併合並
# 這種方法是錯誤的,思考爲什麼?
# merge_sort(l[:p]) # 切片返回的是一個新對象
# merge_sort(l[p:])
# merge(l[:p], l[p:], l) # 錯誤在於,又傳遞新對象,前半段未改變,後半段也未改變,合併的時候還是無序的
def merge(l1, l2, l):
len_l1, len_l2 = len(l1), len(l2)
i = j = 0
while i != len_l1 and j != len_l2:
# 此處是排序規則,按第二位升序,若第二位相同,按第一位升序
if l1[i][1] < l2[j][1] or (l1[i][1] == l2[j][1] and l1[i][0] <= l2[j][0]):
l[i+j] = l1[i]
i += 1
else:
l[i+j] = l2[j]
j += 1
# 剩餘元素
while i != len_l1:
l[i+j] = l1[i]
i += 1
while j != len_l2:
l[i+j] = l2[j]
j += 1
if __name__ == '__main__':
l = [[4, 88], [1, 33], [2, 88], [5, 43], [1, 68], [4, 22], [3, 22], [5, 41], [4, 42], [2, 22]]
merge_sort(l)
print(l)
l1 = [[4, 88, 999], [1, 33, 199], [2, 88, 111], [5, 43, 123], [1, 68, 144], [4, 22, 232], [3, 22, 566], [5, 41, 0], [4, 42, 234], [2, 22, 555]]
merge_sort(l1)
print(l1)
有返回值的歸併排序
def merge_sort(l):
length = len(l)
if length <= 1:
return l
p = length // 2
l1 = l[:p]
l2 = l[p:]
left = merge_sort(l1)
right = merge_sort(l2)
res = merge(left, right)
return res
def merge(l1, l2):
len_l1 = len(l1)
len_l2 = len(l2)
l = []
i = j = 0
while i != len_l1 and j != len_l2:
if l1[i][1] < l2[j][1] or (l1[i][1] == l2[j][1] and l1[i][0] <= l2[j][0]):
l.append(l1[i])
i += 1
else:
l.append(l2[j])
j += 1
while i != len_l1:
l.append(l1[i])
i += 1
while j != len_l2:
l.append(l2[j])
j += 1
return l
if __name__ == '__main__':
l = [[4, 88], [1, 33], [2, 88], [5, 43], [1, 68], [4, 22], [3, 22], [5, 41], [4, 42], [2, 22]]
l1 = [[4, 88, 999], [1, 33, 199], [2, 88, 111], [5, 43, 123], [1, 68, 144], [4, 22, 232], [3, 22, 566], [5, 41, 0], [4, 42, 234], [2, 22, 555]]
# print(sorted(l, key=lambda x: (x[1], x[0]), reverse=False))
print(merge_sort(l))
# print(sorted(l1, key=lambda x: (x[1], x[0]), reverse=False))
print(merge_sort(l1))