做了一道跟二级排序相关的笔试题,不用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))