Skip to content

排序與搜尋

a = [5, 1, 3, 6, 3, 4, 8, 2, 1]
b = sorted(a)   # 不改 a
a.sort()        # 改 a

sorted(a) 是在不改變 a 的情況下回傳 a 排序後的 list

寫排序規則

a.sort(key=lambda x: x[1])

上述指令的意思是排序用的 key 值是對於每一個元素 x(自己隨便取名字),取出 x[1]當作比較對象。當
然可以用各種欄位運算的結果來排序,例如:

a.sort(key=lambda x: x[1]+x[0])

例如:

a = [[1,3], [2,1], [2,4], [2,6]]
a.sort(key=lambda x : x[0] + x[1])
print(a) # [[2, 1], [1, 3], [2, 4], [2, 6]]

也可以由大排到小

a = [[1, 3], [2, 1], [2, 4], [2, 6]]
a.sort(key=lambda x: x[0] + x[1], reverse=True)
print(a) # [[2, 6], [2, 4], [1, 3], [2, 1]]

cmp(a, b) 回傳規則

Python 的 cmp 回傳和 C++ 不一樣,C++ 裡面 cmp(a, b) 回傳 true,代表 a 應該排在 b 前面。

而 Python 是像下面這樣。

def cmp(a, b):
    return 負數   # a 排在 b 前面
    return 0      # a 和 b 順序相同
    return 正數   # a 排在 b 後面

可以記成:

回傳值 意思
< 0 a 在前(左)
0 一樣(不動)
> 0 b 在前(左)

Danger | 注意

return 0 盡量要寫。
然後 reutrn 0 有時候放最後面就好

會這樣是因為最基本的由小到大寫法是:

from functools import functools

def cmp(a, b):
    return a - b

arr = [5, 2, 9, 1]
arr.sort(key=cmp_to_key(cmp))

print(arr)

所以負數是代表 a 在前面。

範例:

from functools import cmp_to_key

def cmp(a, b):      # 依照前面的排序
    if a[0] < b[0]:
        return -1
    elif a[0] > b[0]:
        return 1
    
    return 0 # 放最後面

points = [(1, 3), (5, 2), (9, 1), (2, 5)]
points.sort(key=cmp_to_key(cmp))

print(points) # [(1, 3), (2, 5), (5, 2), (9, 1)]

線性搜尋

在沒有順序的資料中搜尋只能一個一個慢慢找

a = [5, 1, 3, 4, 1, 8, 2, 3, 3, 7]
x = 6

for i in range(len(a)):
    if a[i] == x:
        break

print('end with i =', i)

if a[i] == x:
    print(x, 'found at', i)
else:
    print(x, 'not found')

如果只要知道在或不在,可以用 in 來檢查。

if x in a:
    print('yes')
else:
    print('no')

如果確定 xa 中,可以用內建函數 index 來找位置。

i = a.index(3)      # 可以找到第一個 3 的位置
i = a.index(3, i+1) # i+1 開始找

list.index(x)x 不存在時會引發錯誤,所以使用上要小心。

Python 可以用錯誤處理的方式做,但初學者不太容易使用,可以用 in 搭配 index 來做。

a = [5, 1, 3, 4, 1, 8, 2, 3, 3, 7]
x = 9

if x in a:
    print('yes, found at', a.index(x))
else:
    print('no')

二分搜尋的 lower_bound / upper_bound

import bisect # 或是寫 from bisect import bisect_left, bisect_right

a = [1, 4, 5, 6, 6, 6, 7, 9, 10]
i = bisect.bisect_left(a, 6)        # lower_bound
print(i)
i = bisect.bisect_right(a, 6)       # upper_bound
print(i)