【Python】List 二級歸併排序(不使用sorted)

做了一道跟二級排序相關的筆試題,不用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))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章