Tìm kiếm nào là tốt nhất trong Python?

Thuật toán tìm kiếm nhị phân hiệu quả hơn nhiều so với thuật toán tìm kiếm tuyến tính. Ta cần sắp xếp mảng cho thuật toán tìm kiếm nhị phân không phải trường hợp trong thuật toán tìm kiếm tuyến tính. Sắp xếp mất một thời gian. Tuy nhiên, sử dụng thuật toán sắp xếp hiệu quả sẽ tạo thành một sự kết hợp tốt với thuật toán tìm kiếm nhị phân

Tìm kiếm nhị phân là một thuật toán cổ điển trong khoa học máy tính. Nó thường xuất hiện trong các cuộc thi lập trình và phỏng vấn kỹ thuật. Thực hiện tìm kiếm nhị phân hóa ra là một nhiệm vụ đầy thách thức, ngay cả khi bạn hiểu khái niệm này. Trừ khi bạn tò mò hoặc có nhiệm vụ cụ thể, bạn phải luôn tận dụng các thư viện hiện có để thực hiện tìm kiếm nhị phân bằng Python hoặc bất kỳ ngôn ngữ nào khác

Trong hướng dẫn này, bạn sẽ học cách

  • Sử dụng mô-đun
    def find_index(elements, value):
        for index, element in enumerate(elements):
            if element == value:
                return index
    
    8 để thực hiện tìm kiếm nhị phân trong Python
  • Thực hiện tìm kiếm nhị phân trong Python cả đệ quy và lặp lại
  • Nhận biết và sửa lỗi trong triển khai Python tìm kiếm nhị phân
  • Phân tích độ phức tạp không gian thời gian của thuật toán tìm kiếm nhị phân
  • Tìm kiếm thậm chí còn nhanh hơn tìm kiếm nhị phân

Hướng dẫn này giả định bạn là sinh viên hoặc lập trình viên trung cấp quan tâm đến thuật toán và cấu trúc dữ liệu. Ít nhất, bạn nên làm quen với các kiểu dữ liệu có sẵn của Python, chẳng hạn như danh sách và bộ dữ liệu. Ngoài ra, một số hiểu biết về đệ quy, lớp, lớp dữ liệu và lambda sẽ giúp bạn hiểu rõ hơn về các khái niệm mà bạn sẽ thấy trong hướng dẫn này

Bên dưới, bạn sẽ tìm thấy một liên kết đến mã mẫu mà bạn sẽ thấy trong suốt hướng dẫn này, yêu cầu Python 3. 7 trở lên để chạy

Nhận mã mẫu. Nhấp vào đây để lấy mã mẫu mà bạn sẽ sử dụng để tìm hiểu về tìm kiếm nhị phân trong Python trong hướng dẫn này

điểm chuẩn

Trong phần tiếp theo của hướng dẫn này, bạn sẽ sử dụng một tập hợp con của Cơ sở dữ liệu phim trên Internet (IMDb) để đánh giá hiệu suất của một vài thuật toán tìm kiếm. Bộ dữ liệu này miễn phí cho mục đích sử dụng cá nhân và phi thương mại. Nó được phân phối dưới dạng một loạt các tệp giá trị được phân tách bằng tab (TSV) được nén, được cập nhật hàng ngày

Để làm cho cuộc sống của bạn dễ dàng hơn, bạn có thể sử dụng tập lệnh Python có trong mã mẫu. Nó sẽ tự động lấy tệp có liên quan từ IMDb, giải nén nó và trích xuất các phần thú vị

$ python download_imdb.py
Fetching data from IMDb...
Created "names.txt" and "sorted_names.txt"

Được cảnh báo rằng điều này sẽ tải xuống và giải nén khoảng 600 MB dữ liệu, cũng như tạo ra hai tệp bổ sung, có kích thước bằng một nửa. Quá trình tải xuống cũng như xử lý dữ liệu này có thể mất một hoặc hai phút để hoàn tất

Loại bỏ các quảng cáo

Tải xuống IMDb

Để lấy dữ liệu theo cách thủ công, hãy điều hướng trình duyệt web của bạn đến https. // bộ dữ liệu. imdbws. com/ và lấy tệp có tên

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
9, chứa hồ sơ của các diễn viên, đạo diễn, biên kịch, v.v. Khi bạn giải nén tập tin, bạn sẽ thấy nội dung sau

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)

Nó có một tiêu đề với các tên cột trong dòng đầu tiên, theo sau là các bản ghi dữ liệu trong mỗi dòng tiếp theo. Mỗi bản ghi chứa một mã định danh duy nhất, tên đầy đủ, năm sinh và một số thuộc tính khác. Tất cả đều được phân cách bằng ký tự tab

Có hàng triệu bản ghi, vì vậy đừng cố mở tệp bằng trình soạn thảo văn bản thông thường để tránh làm hỏng máy tính của bạn. Ngay cả phần mềm chuyên dụng như bảng tính cũng có thể gặp sự cố khi mở nó. Thay vào đó, bạn có thể tận dụng trình xem lưới dữ liệu hiệu suất cao có trong JupyterLab chẳng hạn

Đọc các giá trị được phân tách bằng tab

Có một số cách để phân tích tệp TSV. Ví dụ: bạn có thể đọc nó bằng Pandas, sử dụng ứng dụng chuyên dụng hoặc tận dụng một số công cụ dòng lệnh. Tuy nhiên, bạn nên sử dụng tập lệnh Python đơn giản có trong mã mẫu

Ghi chú. Theo nguyên tắc thông thường, bạn nên tránh phân tích cú pháp tệp theo cách thủ công vì bạn có thể bỏ qua các trường hợp cạnh. Ví dụ: ở một trong các trường, ký tự tab phân tách có thể được sử dụng theo nghĩa đen bên trong dấu ngoặc kép, điều này sẽ phá vỡ số lượng cột. Bất cứ khi nào có thể, hãy cố gắng tìm một mô-đun có liên quan trong thư viện tiêu chuẩn hoặc bên thứ ba đáng tin cậy

Cuối cùng, bạn muốn kết thúc với hai tệp văn bản theo ý của bạn

  1. >>> fruits = ['orange', 'plum', 'banana', 'apple']
    >>> fruits.index('banana')
    2
    >>> fruits.index('blueberry')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'blueberry' is not in list
    
    0
  2. >>> fruits = ['orange', 'plum', 'banana', 'apple']
    >>> fruits.index('banana')
    2
    >>> fruits.index('blueberry')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'blueberry' is not in list
    
    1

Một sẽ chứa danh sách các tên có được bằng cách cắt bỏ cột thứ hai khỏi tệp TSV gốc

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...

Cái thứ hai sẽ là phiên bản được sắp xếp của cái này

Khi cả hai tệp đã sẵn sàng, bạn có thể tải chúng vào Python bằng chức năng này

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')

Mã này trả về một danh sách các tên được lấy từ tệp đã cho. Lưu ý rằng việc gọi

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
2 trên chuỗi kết quả sẽ xóa ký tự dòng mới ở cuối mỗi dòng. Thay vào đó, bạn có thể gọi
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
3, nhưng điều đó sẽ giữ lại các dòng mới không mong muốn

Đo thời gian thực hiện

Để đánh giá hiệu suất của một thuật toán cụ thể, bạn có thể đo thời gian thực hiện của thuật toán đó dựa trên bộ dữ liệu IMDb. Điều này thường được thực hiện với sự trợ giúp của các mô-đun

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
4 hoặc
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
5 tích hợp sẵn, rất hữu ích để định thời gian cho một khối mã

Bạn cũng có thể xác định một trình trang trí tùy chỉnh để tính thời gian cho một chức năng nếu bạn muốn. Mã mẫu được cung cấp sử dụng, được giới thiệu trong Python 3. 7, vì nó mang lại độ chính xác cao tính bằng nano giây

Hiểu các thuật toán tìm kiếm

Tìm kiếm là phổ biến và nằm ở trung tâm của khoa học máy tính. Bạn có thể đã thực hiện một số tìm kiếm trên web ngày hôm nay, nhưng bạn đã bao giờ tự hỏi tìm kiếm thực sự có nghĩa là gì chưa?

Các thuật toán tìm kiếm có nhiều dạng khác nhau. Ví dụ, bạn có thể

  • Thực hiện tìm kiếm toàn văn
  • Kết hợp các chuỗi với tìm kiếm mờ
  • Tìm đường đi ngắn nhất trong đồ thị
  • Truy vấn cơ sở dữ liệu
  • Tìm giá trị nhỏ nhất hoặc lớn nhất

Trong hướng dẫn này, bạn sẽ tìm hiểu về cách tìm kiếm một phần tử trong danh sách các mục được sắp xếp, chẳng hạn như danh bạ điện thoại. Khi bạn tìm kiếm một yếu tố như vậy, bạn có thể hỏi một trong những câu hỏi sau

Câu hỏi Trả lời Có ở đó không? Có Nó ở đâu? Ở trang thứ 42. Đó là ai? Một người tên là John Doe

Câu trả lời cho câu hỏi đầu tiên cho bạn biết liệu một phần tử có trong bộ sưu tập hay không. Nó luôn đúng hoặc sai. Câu trả lời thứ hai là vị trí của một phần tử trong bộ sưu tập, có thể không khả dụng nếu phần tử đó bị thiếu. Cuối cùng, câu trả lời thứ ba là chính yếu tố đó hoặc thiếu yếu tố đó

Ghi chú. Đôi khi có thể có nhiều hơn một câu trả lời đúng do các mục trùng lặp hoặc tương tự. Ví dụ: nếu bạn có một vài địa chỉ liên hệ có cùng tên thì tất cả chúng sẽ phù hợp với tiêu chí tìm kiếm của bạn. Vào những thời điểm khác, có thể chỉ có một câu trả lời gần đúng hoặc không có câu trả lời nào cả

Trong trường hợp phổ biến nhất, bạn sẽ tìm kiếm theo giá trị, so sánh các phần tử trong bộ sưu tập với phần tử chính xác mà bạn cung cấp làm tham chiếu. Nói cách khác, tiêu chí tìm kiếm của bạn là toàn bộ phần tử, chẳng hạn như một số, một chuỗi hoặc một đối tượng như một người. Ngay cả sự khác biệt nhỏ nhất giữa hai yếu tố được so sánh cũng không dẫn đến kết quả trùng khớp

Mặt khác, bạn có thể chi tiết hơn với các tiêu chí tìm kiếm của mình bằng cách chọn một số thuộc tính của một phần tử, chẳng hạn như họ của một người. Điều này được gọi là tìm kiếm theo khóa vì bạn chọn một hoặc nhiều thuộc tính để so sánh. Trước khi bạn đi sâu vào tìm kiếm nhị phân trong Python, hãy xem nhanh các thuật toán tìm kiếm khác để có được bức tranh toàn cảnh hơn và hiểu cách chúng hoạt động

Loại bỏ các quảng cáo

Tìm kiếm ngẫu nhiên

Làm thế nào bạn có thể tìm kiếm một cái gì đó trong ba lô của bạn? . Nếu bạn không may mắn, thì bạn đặt món đồ trở lại, rửa sạch và lặp lại. Ví dụ này là một cách hay để hiểu tìm kiếm ngẫu nhiên, đây là một trong những thuật toán tìm kiếm kém hiệu quả nhất. Sự kém hiệu quả của cách tiếp cận này xuất phát từ thực tế là bạn có nguy cơ chọn sai cùng một thứ nhiều lần.

Ghi chú. Thật thú vị, về mặt lý thuyết, chiến lược này có thể là chiến lược hiệu quả nhất nếu bạn rất may mắn hoặc có một số lượng nhỏ các yếu tố trong bộ sưu tập

Nguyên tắc cơ bản của thuật toán này có thể được diễn đạt bằng đoạn mã Python sau

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element

Hàm lặp lại cho đến khi một số phần tử được chọn ngẫu nhiên khớp với giá trị đã cho làm đầu vào. Tuy nhiên, điều này không hữu ích lắm vì hàm trả về

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
7 hoàn toàn hoặc chính giá trị mà nó đã nhận được trong một tham số. Bạn có thể tìm thấy cách triển khai đầy đủ trong mã mẫu có sẵn để tải xuống tại liên kết bên dưới

Nhận mã mẫu. Nhấp vào đây để lấy mã mẫu mà bạn sẽ sử dụng để tìm hiểu về tìm kiếm nhị phân trong Python trong hướng dẫn này

Đối với các bộ dữ liệu vi mô, thuật toán tìm kiếm ngẫu nhiên dường như đang thực hiện công việc của nó khá nhanh

>>>

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'

Tuy nhiên, hãy tưởng tượng bạn phải tìm kiếm như vậy qua hàng triệu phần tử. Dưới đây là tóm tắt nhanh về thử nghiệm hiệu suất đã được thực hiện đối với bộ dữ liệu IMDb

Search TermElement IndexBest TimeAverage TimeWorst TimeFred Astaire

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
8
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
9
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
0
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
1Alicia Monica
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
2
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
3
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
4
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
5Baoyin Liu
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
6
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
7
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
8
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
9missing
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
0
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
1
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
2
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
3

Các yếu tố duy nhất tại các vị trí bộ nhớ khác nhau được chọn cụ thể để tránh sai lệch. Mỗi thuật ngữ được tìm kiếm mười lần để tính đến tính ngẫu nhiên của thuật toán và các yếu tố khác, chẳng hạn như các quy trình hệ thống đang chạy trong nền

Ghi chú. Nếu bạn muốn tự mình tiến hành thử nghiệm này, hãy tham khảo lại hướng dẫn trong phần giới thiệu của hướng dẫn này. Để đo lường hiệu suất mã của bạn, bạn có thể sử dụng các mô-đun

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
4 và
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
5 tích hợp sẵn hoặc bạn có thể tính thời gian cho các chức năng bằng một bộ trang trí tùy chỉnh

Thuật toán có hiệu suất không xác định. Mặc dù thời gian trung bình để tìm một phần tử không phụ thuộc vào vị trí của nó, nhưng thời điểm tốt nhất và tồi tệ nhất cách nhau từ hai đến ba bậc độ lớn. Nó cũng bị hành vi không nhất quán. Cân nhắc việc có một bộ sưu tập các phần tử chứa một số bản sao. Vì thuật toán chọn các phần tử một cách ngẫu nhiên nên chắc chắn nó sẽ trả về các bản sao khác nhau trong các lần chạy tiếp theo

Làm thế nào bạn có thể cải thiện về điều này?

Tìm kiếm tuyến tính

Khi quyết định ăn gì cho bữa trưa, bạn có thể nhìn quanh thực đơn một cách hỗn loạn cho đến khi có thứ gì đó thu hút sự chú ý của bạn. Ngoài ra, bạn có thể thực hiện một cách tiếp cận có hệ thống hơn bằng cách quét menu từ trên xuống dưới và xem xét kỹ lưỡng từng mục theo trình tự. Tóm lại đó là tìm kiếm tuyến tính. Để triển khai nó trong Python, bạn có thể

>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
6 phần tử để theo dõi chỉ mục của phần tử hiện tại

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index

Hàm lặp qua một tập hợp các phần tử theo thứ tự được xác định trước và nhất quán. Nó dừng lại khi tìm thấy phần tử hoặc khi không còn phần tử nào để kiểm tra. Chiến lược này đảm bảo rằng không có phần tử nào được truy cập nhiều hơn một lần vì bạn đang duyệt qua chúng theo thứ tự trước

>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
7

Hãy xem tìm kiếm tuyến tính đối phó tốt như thế nào với bộ dữ liệu IMDb bạn đã sử dụng trước đây

Search TermElement IndexBest TimeAverage TimeWorst TimeFred Astaire

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
8
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
9
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
00
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
01Alicia Monica
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
2
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
03
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
04
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
05Baoyin Liu
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
6
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
07
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
08
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
09missing
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
0
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
08
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
12
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
13

Hầu như không có bất kỳ sự khác biệt nào trong thời gian tra cứu của một phần tử riêng lẻ. Thời gian trung bình hầu như giống như thời gian tốt nhất và tồi tệ nhất. Vì các phần tử luôn được duyệt theo cùng một thứ tự nên số lần so sánh cần thiết để tìm cùng một phần tử không thay đổi

Tuy nhiên, thời gian tìm kiếm tăng lên với chỉ mục tăng dần của một phần tử trong bộ sưu tập. Phần tử càng xa đầu danh sách thì càng phải chạy nhiều phép so sánh hơn. Trong trường hợp xấu nhất, khi thiếu một phần tử, phải kiểm tra toàn bộ tập hợp để đưa ra câu trả lời chắc chắn

Khi bạn chiếu dữ liệu thử nghiệm lên một biểu đồ và kết nối các dấu chấm, thì bạn sẽ thấy ngay mối quan hệ giữa vị trí phần tử và thời gian cần thiết để tìm thấy nó

Tìm kiếm nào là tốt nhất trong Python?

Tất cả các mẫu nằm trên một đường thẳng và có thể được mô tả bằng một hàm tuyến tính, đó là nguồn gốc của tên thuật toán. Bạn có thể giả định rằng, trung bình, thời gian cần thiết để tìm bất kỳ phần tử nào bằng cách sử dụng tìm kiếm tuyến tính sẽ tỷ lệ thuận với số lượng tất cả các phần tử trong tập hợp. Chúng không mở rộng tốt khi lượng dữ liệu để tìm kiếm tăng lên

Ví dụ: máy quét sinh trắc học có sẵn tại một số sân bay sẽ không nhận ra hành khách chỉ trong vài giây nếu chúng được triển khai bằng tìm kiếm tuyến tính. Mặt khác, thuật toán tìm kiếm tuyến tính có thể là một lựa chọn tốt cho các tập dữ liệu nhỏ hơn vì thuật toán này không yêu cầu tiền xử lý dữ liệu. Trong trường hợp như vậy, lợi ích của tiền xử lý sẽ không hoàn lại chi phí của nó

Python đã đi kèm với tìm kiếm tuyến tính, vì vậy không có ích gì khi bạn tự viết nó. Ví dụ, cấu trúc dữ liệu

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
14 hiển thị một phương thức sẽ trả về chỉ mục của một phần tử hoặc đưa ra một ngoại lệ nếu không

>>>

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list

Điều này cũng có thể cho bạn biết nếu phần tử có trong bộ sưu tập, nhưng một cách Pythonic hơn sẽ liên quan đến việc sử dụng toán tử

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
15 linh hoạt

>>>

>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False

Điều đáng chú ý là mặc dù sử dụng tìm kiếm tuyến tính ẩn, nhưng các hàm và toán tử tích hợp sẵn này sẽ thổi bay quá trình triển khai của bạn. Đó là bởi vì chúng được viết bằng C thuần túy, biên dịch thành mã máy gốc. Trình thông dịch Python tiêu chuẩn không phù hợp với nó, cho dù bạn có cố gắng thế nào

Một thử nghiệm nhanh với mô-đun

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
5 cho thấy rằng việc triển khai Python có thể chạy chậm hơn gần mười lần so với mô-đun gốc tương đương

>>>

>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614

Tuy nhiên, đối với các bộ dữ liệu đủ lớn, ngay cả mã gốc cũng sẽ đạt đến giới hạn của nó và giải pháp duy nhất là suy nghĩ lại về thuật toán

Ghi chú. Toán tử

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
15 không phải lúc nào cũng thực hiện tìm kiếm tuyến tính. Ví dụ: khi bạn sử dụng nó trên
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
18, nó sẽ thực hiện tìm kiếm dựa trên hàm băm thay thế. Toán tử có thể làm việc với bất kỳ iterable nào, bao gồm
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
19,
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
14,
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
18,
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
22 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
23. Bạn thậm chí có thể hỗ trợ các lớp tùy chỉnh của mình với nó bằng cách triển khai
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
24 để xác định logic cơ bản

Trong các tình huống thực tế, thường nên tránh sử dụng thuật toán tìm kiếm tuyến tính. Ví dụ, đã có lúc tôi không thể đăng ký con mèo của mình tại phòng khám thú y vì hệ thống của họ liên tục gặp sự cố. Bác sĩ nói với tôi rằng cuối cùng anh ấy phải nâng cấp máy tính của mình vì thêm nhiều bản ghi vào cơ sở dữ liệu khiến nó chạy ngày càng chậm hơn

Tôi nhớ mình đã nghĩ vào thời điểm đó rằng người viết phần mềm đó rõ ràng không biết về thuật toán tìm kiếm nhị phân

Loại bỏ các quảng cáo

Tìm kiếm nhị phân

Từ nhị phân thường được liên kết với số 2. Trong ngữ cảnh này, nó đề cập đến việc chia một tập hợp các phần tử thành hai nửa và loại bỏ một trong số chúng ở mỗi bước của thuật toán. Điều này có thể làm giảm đáng kể số lần so sánh cần thiết để tìm một phần tử. Nhưng có một nhược điểm—các phần tử trong bộ sưu tập phải được sắp xếp trước

Ý tưởng đằng sau nó giống như các bước tìm trang trong một cuốn sách. Lúc đầu, bạn thường mở cuốn sách đến một trang hoàn toàn ngẫu nhiên hoặc ít nhất một trang gần với nơi bạn nghĩ có thể có trang bạn muốn.

Đôi khi, bạn sẽ đủ may mắn để tìm thấy trang đó trong lần thử đầu tiên. Tuy nhiên, nếu số trang quá thấp, thì bạn biết trang phải ở bên phải. Nếu bạn vượt quá trong lần thử tiếp theo và số trang hiện tại cao hơn trang bạn đang tìm kiếm, thì bạn biết chắc chắn rằng nó phải ở đâu đó ở giữa

Bạn lặp lại quy trình, nhưng thay vì chọn ngẫu nhiên một trang, bạn kiểm tra trang nằm ngay giữa phạm vi mới đó. Điều này giảm thiểu số lần thử. Một cách tiếp cận tương tự có thể được sử dụng trong trò chơi đoán số. Nếu bạn chưa nghe nói về trò chơi đó, thì bạn có thể tra cứu nó trên Internet để có rất nhiều ví dụ được triển khai trong Python

Ghi chú. Đôi khi, nếu các giá trị được phân phối đồng đều, bạn có thể tính chỉ số ở giữa bằng phép nội suy tuyến tính thay vì lấy giá trị trung bình. Biến thể này của thuật toán sẽ yêu cầu ít bước hơn

Số trang hạn chế phạm vi trang để tìm kiếm được gọi là giới hạn dưới và giới hạn trên. Trong tìm kiếm nhị phân, bạn thường bắt đầu với trang đầu tiên là giới hạn dưới và trang cuối cùng là giới hạn trên. Bạn phải cập nhật cả hai giới hạn khi bạn đi. Ví dụ: nếu trang bạn chuyển đến thấp hơn trang bạn đang tìm kiếm, thì đó là giới hạn dưới mới của bạn

Giả sử bạn đang tìm kiếm một quả dâu tây trong bộ sưu tập các loại trái cây được sắp xếp theo thứ tự tăng dần theo kích cỡ

Tìm kiếm nào là tốt nhất trong Python?

Trong lần thử đầu tiên, phần tử ở giữa là một quả chanh. Vì nó to hơn quả dâu tây nên bạn có thể loại bỏ tất cả các yếu tố sang bên phải, bao gồm cả quả chanh. Bạn sẽ di chuyển cận trên đến vị trí mới và cập nhật chỉ mục ở giữa

Tìm kiếm nào là tốt nhất trong Python?

Bây giờ, bạn chỉ còn lại một nửa số trái cây mà bạn đã bắt đầu. Yếu tố ở giữa hiện tại thực sự là quả dâu tây bạn đang tìm kiếm, kết thúc tìm kiếm. Nếu không, thì bạn chỉ cần cập nhật các giới hạn cho phù hợp và tiếp tục cho đến khi chúng vượt qua nhau. Ví dụ: tìm kiếm một quả mận bị thiếu, nằm giữa quả dâu tây và quả kiwi, sẽ có kết quả như sau

Tìm kiếm nào là tốt nhất trong Python?

Lưu ý rằng không có nhiều so sánh phải được thực hiện để tìm phần tử mong muốn. Đó là sự kỳ diệu của tìm kiếm nhị phân. Ngay cả khi bạn đang xử lý hàng triệu yếu tố, bạn chỉ cần tối đa một số lần kiểm tra. Con số này sẽ không vượt quá logarit cơ số hai của tổng số phần tử do giảm một nửa. Nói cách khác, số phần tử còn lại giảm đi một nửa ở mỗi bước

Điều này là có thể bởi vì các yếu tố đã được sắp xếp theo kích thước. Tuy nhiên, nếu bạn muốn tìm trái cây theo một phím khác, chẳng hạn như màu sắc, thì bạn phải sắp xếp lại toàn bộ bộ sưu tập một lần nữa. Để tránh chi phí sắp xếp tốn kém, bạn có thể thử tính toán trước các chế độ xem khác nhau của cùng một bộ sưu tập. Điều này hơi giống với việc tạo chỉ mục cơ sở dữ liệu

Xem xét điều gì sẽ xảy ra nếu bạn thêm, xóa hoặc cập nhật một phần tử trong bộ sưu tập. Để tìm kiếm nhị phân tiếp tục hoạt động, bạn cần duy trì thứ tự sắp xếp phù hợp. Điều này có thể được thực hiện với mô-đun

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
8 mà bạn sẽ đọc trong phần sắp tới

Bạn sẽ thấy cách triển khai thuật toán tìm kiếm nhị phân trong Python sau trong hướng dẫn này. Hiện tại, hãy đối đầu với bộ dữ liệu IMDb. Lưu ý rằng có những người khác nhau để tìm kiếm so với trước đây. Đó là bởi vì tập dữ liệu phải được sắp xếp để tìm kiếm nhị phân, giúp sắp xếp lại các phần tử. Các yếu tố mới được định vị gần giống với các chỉ số như trước đây, để giữ cho các phép đo có thể so sánh được

Search TermElement IndexAverage TimeComparisons(…) Berendse

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
8
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
2723Jonathan Samuangte
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
28
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
2924Yorgos Rahmatoulin
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
30
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
3123missing
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
0
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
3323

Các câu trả lời gần như ngay lập tức. Trong trường hợp trung bình, chỉ mất vài phần triệu giây để tìm kiếm nhị phân tìm thấy một phần tử trong số chín phần triệu. Ngoài ra, số lượng so sánh cho các phần tử được chọn gần như không đổi, trùng khớp với công thức sau

Tìm kiếm nào là tốt nhất trong Python?

Tìm hầu hết các phần tử sẽ yêu cầu số lần so sánh cao nhất, có thể được lấy từ logarit của kích thước của bộ sưu tập. Ngược lại, chỉ có một yếu tố ở giữa có thể được tìm thấy trong lần thử đầu tiên với một phép so sánh

Tìm kiếm nhị phân là một ví dụ tuyệt vời về kỹ thuật phân chia và chinh phục, phân chia một vấn đề thành một loạt các vấn đề nhỏ hơn cùng loại. Các giải pháp riêng lẻ sau đó được kết hợp để tạo thành câu trả lời cuối cùng. Một ví dụ nổi tiếng khác của kỹ thuật này là thuật toán Quicksort

Ghi chú. Đừng nhầm lẫn giữa chia để trị với lập trình động, đây là một kỹ thuật hơi giống nhau

Không giống như các thuật toán tìm kiếm khác, tìm kiếm nhị phân có thể được sử dụng ngoài việc chỉ tìm kiếm. Ví dụ: nó cho phép kiểm tra tư cách thành viên đã đặt, tìm giá trị lớn nhất hoặc nhỏ nhất, tìm hàng xóm gần nhất của giá trị đích, thực hiện truy vấn phạm vi, v.v.

Nếu tốc độ là ưu tiên hàng đầu, thì tìm kiếm nhị phân không phải lúc nào cũng là lựa chọn tốt nhất. Thậm chí còn có các thuật toán nhanh hơn có thể tận dụng cấu trúc dữ liệu dựa trên hàm băm. Tuy nhiên, các thuật toán đó yêu cầu nhiều bộ nhớ bổ sung, trong khi tìm kiếm nhị phân mang lại sự cân bằng tốt giữa không gian và thời gian

Loại bỏ các quảng cáo

Tìm kiếm dựa trên hàm băm

Để tìm kiếm nhanh hơn, bạn cần thu hẹp không gian vấn đề. Tìm kiếm nhị phân đạt được mục tiêu đó bằng cách giảm một nửa số lượng ứng viên ở mỗi bước. Điều đó có nghĩa là ngay cả khi bạn có một triệu phần tử, thì chỉ cần tối đa hai mươi lần so sánh để xác định xem phần tử đó có tồn tại hay không, với điều kiện là tất cả các phần tử đều được sắp xếp

Cách nhanh nhất để tìm kiếm là biết nơi để tìm những gì bạn đang tìm kiếm. Nếu bạn biết chính xác vị trí bộ nhớ của một phần tử, thì bạn sẽ truy cập trực tiếp vào phần tử đó mà không cần phải tìm kiếm ngay từ đầu. Ánh xạ một phần tử hoặc (phổ biến hơn) một trong các khóa của nó tới vị trí phần tử trong bộ nhớ được gọi là băm

Bạn có thể nghĩ về việc băm không phải là tìm kiếm phần tử cụ thể, mà thay vào đó tính toán chỉ mục dựa trên chính phần tử đó. Đó là công việc của một , cái cần giữ một số tính chất toán học nhất định. Một hàm băm tốt nên

  • Lấy đầu vào tùy ý và biến nó thành đầu ra có kích thước cố định
  • Có phân phối giá trị thống nhất để giảm thiểu va chạm băm
  • Tạo ra kết quả xác định
  • Là hàm một chiều
  • Khuếch đại các thay đổi đầu vào để đạt được hiệu ứng tuyết lở

Đồng thời, nó không nên quá tốn kém về mặt tính toán, nếu không thì chi phí của nó sẽ lớn hơn lợi ích thu được. Hàm băm cũng được sử dụng để xác minh tính toàn vẹn của dữ liệu cũng như trong mật mã

Cấu trúc dữ liệu sử dụng khái niệm này để ánh xạ khóa thành giá trị được gọi là bản đồ, bảng băm, từ điển hoặc mảng kết hợp

Ghi chú. Python có hai cấu trúc dữ liệu tích hợp là

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
18 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
22, dựa vào hàm băm để tìm các phần tử. Trong khi
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
18 băm các phần tử của nó, thì một
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
22 sử dụng hàm băm đối với các khóa phần tử. Để tìm hiểu chính xác cách một
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
22 được triển khai trong Python, hãy xem bài nói chuyện tại hội nghị của Raymond Hettinger trên Modern Python Dictionaries

Một cách khác để hình dung quá trình băm là tưởng tượng cái gọi là nhóm các phần tử tương tự được nhóm theo các khóa tương ứng của chúng. Ví dụ: bạn có thể thu hoạch trái cây vào các thùng khác nhau dựa trên màu sắc

Tìm kiếm nào là tốt nhất trong Python?

Quả dừa và quả kiwi được cho vào thùng có nhãn màu nâu, trong khi quả táo được cho vào thùng có nhãn màu đỏ, v.v. Điều này cho phép bạn lướt qua một phần của các phần tử một cách nhanh chóng. Lý tưởng nhất là bạn chỉ muốn có một quả trong mỗi thùng. Nếu không, bạn sẽ nhận được cái gọi là xung đột, dẫn đến phải làm thêm

Ghi chú. Các thùng, cũng như nội dung của chúng, thường không theo thứ tự cụ thể

Hãy đặt các tên từ bộ dữ liệu IMDb vào một từ điển để mỗi tên trở thành một khóa và giá trị tương ứng trở thành chỉ mục của nó

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
0

Sau khi tải các tên văn bản vào một danh sách cố định, bạn có thể

>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
6 nó bên trong a để tạo ánh xạ. Bây giờ, việc kiểm tra sự hiện diện của phần tử cũng như lấy chỉ mục của nó rất đơn giản

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
1

Nhờ hàm băm được sử dụng ở hậu trường, bạn hoàn toàn không phải thực hiện bất kỳ tìm kiếm nào

Đây là cách thuật toán tìm kiếm dựa trên hàm băm hoạt động đối với bộ dữ liệu IMDb

Search TermElement IndexBest TimeAverage TimeWorst TimeFred Astaire

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
8
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
41
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
42
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
43Alicia Monica
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
2
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
45
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
42
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
47Baoyin Liu
>>> 'banana' in fruits
True
>>> 'blueberry' in fruits
False
6
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
45
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
42
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
51missing
>>> import timeit
>>> from search.linear import contains
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> timeit.timeit(lambda: contains(fruits, 'blueberry'))
1.8904765040024358
>>> timeit.timeit(lambda: 'blueberry' in fruits)
0.22473459799948614
0
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
53
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
42
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
55

Không chỉ thời gian trung bình nhanh hơn một bậc so với triển khai Python tìm kiếm nhị phân vốn đã nhanh, mà tốc độ còn được duy trì trên tất cả các phần tử bất kể chúng ở đâu

Giá cho mức tăng đó là khoảng 0. Quá trình Python tiêu thụ thêm 5 GB bộ nhớ, thời gian tải chậm hơn và nhu cầu giữ dữ liệu bổ sung đó phù hợp với nội dung từ điển. Đổi lại, tra cứu rất nhanh, trong khi cập nhật và chèn chậm hơn một chút khi so sánh với danh sách

Một hạn chế khác mà từ điển áp đặt cho các khóa của họ là chúng phải có thể băm được và giá trị băm của chúng không thể thay đổi theo thời gian. Bạn có thể kiểm tra xem một loại dữ liệu cụ thể có thể băm được trong Python hay không bằng cách gọi số

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
56 trên đó

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
2

Các bộ sưu tập có thể thay đổi—chẳng hạn như

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
14,
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
18 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
22—không thể băm được. Trong thực tế, các khóa từ điển phải là bất biến vì giá trị băm của chúng thường phụ thuộc vào một số thuộc tính của khóa. Nếu một bộ sưu tập có thể thay đổi có thể băm được và có thể được sử dụng làm khóa, thì giá trị băm của nó sẽ khác mỗi khi nội dung thay đổi. Xem xét điều gì sẽ xảy ra nếu một loại trái cây cụ thể đổi màu do chín. Bạn sẽ tìm nó trong thùng sai

Hàm băm có nhiều công dụng khác. Ví dụ: nó được sử dụng trong mật mã để tránh lưu trữ mật khẩu ở dạng văn bản thuần túy, cũng như để xác minh tính toàn vẹn của dữ liệu

Loại bỏ các quảng cáo

Sử dụng Mô-đun def find_index(elements, value): for index, element in enumerate(elements): if element == value: return index 8

Tìm kiếm nhị phân trong Python có thể được thực hiện bằng cách sử dụng mô-đun

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
8 tích hợp, điều này cũng giúp duy trì danh sách theo thứ tự được sắp xếp. Nó dựa trên phương pháp chia đôi để tìm nghiệm nguyên của các hàm. Mô-đun này đi kèm với sáu chức năng được chia thành hai loại

Find IndexInsert Element

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
62
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
63
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
64
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
65
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
66
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
67

Các hàm này cho phép bạn tìm chỉ mục của một phần tử hoặc thêm một phần tử mới vào đúng vị trí. Những người ở hàng đầu tiên chỉ là bí danh của

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
66 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
67, tương ứng. Trên thực tế, bạn chỉ đang xử lý bốn chức năng

Ghi chú. Bạn có trách nhiệm sắp xếp danh sách trước khi chuyển nó đến một trong các chức năng. Nếu các phần tử không được sắp xếp, thì rất có thể bạn sẽ nhận được kết quả không chính xác

Còn chần chừ gì nữa, hãy cùng xem hoạt động của mô-đun

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
8

Tìm một phần tử

Để tìm chỉ mục của một phần tử hiện có trong danh sách được sắp xếp, bạn muốn

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
64

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
3

Đầu ra cho bạn biết rằng chuối là loại trái cây thứ hai trong danh sách vì nó được tìm thấy ở chỉ mục

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
72. Tuy nhiên, nếu một phần tử bị thiếu, thì bạn vẫn nhận được vị trí mong đợi của nó

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
4

Mặc dù những loại trái cây này chưa có trong danh sách nhưng bạn có thể biết được nên đặt chúng ở đâu. Ví dụ, quả mơ nên nằm giữa quả táo và quả chuối, trong khi quả dưa hấu nên là thành phần cuối cùng. Bạn sẽ biết liệu một phần tử có được tìm thấy hay không bằng cách đánh giá hai điều kiện

  1. Là chỉ mục trong kích thước của danh sách?

  2. Giá trị của phần tử có phải là giá trị mong muốn không?

Điều này có thể được dịch thành một chức năng phổ quát để tìm các phần tử theo giá trị

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
5

Khi khớp hàm sẽ trả về chỉ số phần tử tương ứng. Nếu không, nó sẽ trả về

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
7 hoàn toàn

Để tìm kiếm theo khóa, bạn phải duy trì một danh sách khóa riêng. Vì điều này phát sinh thêm chi phí nên bạn nên tính toán trước các phím và tái sử dụng chúng càng nhiều càng tốt. Bạn có thể định nghĩa một lớp trình trợ giúp để có thể tìm kiếm bằng các khóa khác nhau mà không cần sao chép nhiều mã

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
6

Khóa là một hàm được truyền dưới dạng tham số đầu tiên cho

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
74. Sau khi có nó, bạn tạo một danh sách sắp xếp các cặp khóa-giá trị để có thể truy xuất một phần tử từ khóa của nó sau này. Biểu diễn các cặp bằng các bộ đảm bảo rằng phần tử đầu tiên của mỗi cặp sẽ được sắp xếp. Trong bước tiếp theo, bạn trích xuất các khóa để tạo một danh sách phẳng phù hợp với việc triển khai Python tìm kiếm nhị phân của bạn

Sau đó, có phương pháp thực tế để tìm các phần tử theo khóa

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
7

Mã này chia đôi danh sách các khóa đã sắp xếp để lấy chỉ mục của một phần tử theo khóa. Nếu một khóa như vậy tồn tại, thì chỉ mục của nó có thể được sử dụng để lấy cặp tương ứng từ danh sách các cặp khóa-giá trị được tính toán trước đó. Phần tử thứ hai của cặp đó là giá trị mong muốn

Ghi chú. Đây chỉ là một ví dụ minh họa. Bạn sẽ tốt hơn nếu sử dụng công thức được đề xuất, được đề cập trong tài liệu chính thức

Nếu bạn có nhiều chuối, thì

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
64 sẽ trả về phiên bản ngoài cùng bên trái

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
8

Có thể dự đoán, để lấy được quả chuối ngoài cùng bên phải, bạn cần gọi tới số

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
66 hoặc bí danh của nó là
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
62. Tuy nhiên, hai hàm đó trả về một chỉ mục xa hơn từ quả chuối ngoài cùng bên phải thực tế, rất hữu ích để tìm điểm chèn của phần tử mới

>>>

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
9

Khi bạn kết hợp mã, bạn có thể xem bạn có bao nhiêu chuối

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
0

Nếu một phần tử bị thiếu, thì cả

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
64 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
66 sẽ trả về cùng một chỉ mục, không mang lại quả chuối nào

Loại bỏ các quảng cáo

Chèn một phần tử mới

Một ứng dụng thực tế khác của mô-đun

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
8 là duy trì thứ tự của các phần tử trong danh sách đã được sắp xếp. Rốt cuộc, bạn sẽ không muốn sắp xếp toàn bộ danh sách mỗi khi bạn phải chèn thứ gì đó vào đó. Trong hầu hết các trường hợp, cả ba chức năng có thể được sử dụng thay thế cho nhau

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
1

Bạn sẽ không thấy bất kỳ sự khác biệt nào cho đến khi có các bản sao trong danh sách của bạn. Nhưng ngay cả khi đó, nó sẽ không trở nên rõ ràng miễn là những bản sao đó là những giá trị đơn giản. Thêm một quả chuối khác vào bên trái sẽ có tác dụng tương tự như thêm nó vào bên phải

Để nhận thấy sự khác biệt, bạn cần một kiểu dữ liệu mà các đối tượng có thể có các đặc điểm nhận dạng duy nhất mặc dù có các giá trị bằng nhau. Hãy định nghĩa một loại

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
81 bằng cách sử dụng trình trang trí @dataclass, được giới thiệu trong Python 3. 7

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
2

Một người có một

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
82 và một
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
83 tùy ý được gán cho nó. Bằng cách loại trừ trường
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
83 khỏi bài kiểm tra đẳng thức, bạn làm cho hai người bằng nhau ngay cả khi họ có các giá trị khác nhau của thuộc tính đó

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
3

Mặt khác, hai biến đó đề cập đến các thực thể hoàn toàn riêng biệt, cho phép bạn phân biệt giữa chúng

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
4

Các biến

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
85 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
86 thực sự là các đối tượng khác nhau

Lưu ý rằng các phiên bản của một lớp dữ liệu không thể so sánh được theo mặc định, điều này ngăn cản bạn sử dụng thuật toán chia đôi trên chúng

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
5

Python không biết đặt hàng

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
87 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
88, vì chúng là đối tượng của một lớp tùy chỉnh. Theo truyền thống, bạn sẽ triển khai phương pháp ma thuật
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
89 trong lớp của mình, viết tắt của less than, để cho trình thông dịch biết cách so sánh các phần tử đó. Tuy nhiên, trình trang trí
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
90 chấp nhận một vài cờ Boolean tùy chọn. Một trong số đó là
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
91, dẫn đến việc tạo tự động các phương pháp ma thuật để so sánh khi được đặt thành
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
92

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
6

Đổi lại, điều này cho phép bạn so sánh hai người và quyết định ai đến trước

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
7

Cuối cùng, bạn có thể tận dụng các thuộc tính

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
82 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
83 để quan sát vị trí các hàm khác nhau chèn người mới vào danh sách

>>>

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
8

Các số trong ngoặc đơn sau tên cho biết thứ tự chèn. Ban đầu, chỉ có một

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
95, người đã nhận được số
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
72. Sau đó, bạn đã thêm bản sao của nó vào bên trái và sau đó thêm một bản sao nữa vào bên phải

Loại bỏ các quảng cáo

Thực hiện tìm kiếm nhị phân trong Python

Hãy nhớ rằng bạn có thể không nên triển khai thuật toán trừ khi bạn có lý do chính đáng để. Bạn sẽ tiết kiệm thời gian và không cần phải phát minh lại bánh xe. Cơ hội là mã thư viện đã trưởng thành, đã được kiểm tra bởi người dùng thực trong môi trường sản xuất và có chức năng mở rộng được cung cấp bởi nhiều người đóng góp

Điều đó nói rằng, có những lúc bạn nên xắn tay áo và tự mình làm điều đó. Công ty của bạn có thể có chính sách cấm một số thư viện mã nguồn mở do vấn đề cấp phép hoặc bảo mật. Có thể bạn không đủ khả năng phụ thuộc khác do hạn chế về bộ nhớ hoặc băng thông mạng. Cuối cùng, tự viết mã có thể là một công cụ học tập tuyệt vời

Bạn có thể thực hiện hầu hết các thuật toán theo hai cách

  1. lặp đi lặp lại
  2. đệ quy

Tuy nhiên, có những ngoại lệ cho quy tắc đó. Một ví dụ đáng chú ý là hàm Ackermann, hàm này chỉ có thể biểu diễn dưới dạng đệ quy

Trước khi bạn tiến xa hơn, hãy đảm bảo rằng bạn nắm vững thuật toán tìm kiếm nhị phân. Bạn có thể tham khảo một phần của hướng dẫn này để làm mới nhanh

lặp đi lặp lại

Phiên bản lặp của thuật toán bao gồm một vòng lặp, vòng lặp này sẽ lặp lại một số bước cho đến khi đáp ứng điều kiện dừng. Hãy bắt đầu bằng cách triển khai một hàm sẽ tìm kiếm các phần tử theo giá trị và trả về chỉ mục của chúng

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
9

Bạn sẽ sử dụng lại chức năng này sau

Giả sử rằng tất cả các phần tử đã được sắp xếp, bạn có thể đặt ranh giới dưới và trên ở hai đầu đối diện của chuỗi

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
0

Bây giờ, bạn muốn xác định phần tử ở giữa để xem nó có giá trị mong muốn không. Tính toán chỉ số giữa có thể được thực hiện bằng cách lấy trung bình của cả hai ranh giới

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
1

Lưu ý cách một phép chia số nguyên giúp xử lý cả số lượng phần tử chẵn và lẻ trong phạm vi giới hạn bằng cách làm sàn kết quả. Tùy thuộc vào cách bạn cập nhật ranh giới và xác định điều kiện dừng, bạn cũng có thể sử dụng chức năng trần

Tiếp theo, bạn hoàn thành hoặc chia chuỗi thành hai và tiếp tục tìm kiếm ở một trong các nửa kết quả

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
2

Nếu phần tử ở giữa trùng khớp, thì bạn trả về chỉ mục của nó. Ngược lại, nếu nó quá nhỏ, thì bạn cần di chuyển đường viền dưới lên trên. Nếu nó quá lớn, thì bạn cần di chuyển ranh giới trên xuống

Để tiếp tục, bạn phải đặt hầu hết các bước trong một vòng lặp, vòng lặp này sẽ dừng lại khi ranh giới phía dưới vượt qua ranh giới phía trên

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
3

Nói cách khác, bạn muốn lặp lại miễn là ranh giới dưới thấp hơn hoặc bằng ranh giới trên. Mặt khác, không có kết quả khớp và hàm trả về

>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
7 hoàn toàn

Tìm kiếm theo khóa rút gọn lại để xem xét các thuộc tính của đối tượng thay vì giá trị theo nghĩa đen của nó. Ví dụ, khóa có thể là số ký tự trong tên của một loại trái cây. Bạn có thể điều chỉnh

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
98 để chấp nhận và sử dụng tham số
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
99

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
4

Tuy nhiên, bạn cũng phải nhớ sắp xếp danh sách bằng cách sử dụng cùng một

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
99 mà bạn sẽ tìm kiếm

>>>

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
5

Trong ví dụ trên,

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
01 được chọn vì tên của nó dài chính xác mười ký tự, trong khi không có loại trái cây nào trong danh sách có tên gồm ba chữ cái

Điều đó thật tuyệt, nhưng đồng thời, bạn vừa mất khả năng tìm kiếm theo giá trị. Để khắc phục điều này, bạn có thể gán cho

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
99 một giá trị mặc định là
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> fruits.index('banana')
2
>>> fruits.index('blueberry')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'blueberry' is not in list
7 và sau đó kiểm tra xem nó có được cung cấp hay không. Tuy nhiên, trong một giải pháp hợp lý hơn, bạn luôn muốn gọi số
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
99. Theo mặc định, nó sẽ là một hàm nhận dạng trả về chính phần tử đó

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
6

Ngoài ra, bạn có thể xác định nội tuyến hàm nhận dạng bằng biểu thức lambda ẩn danh

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
7

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
98 chỉ trả lời một câu hỏi. Vẫn còn hai câu hỏi khác, đó là "Có ở đó không?"

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
8

Với ba chức năng này, bạn có thể nói hầu hết mọi thứ về một phần tử. Tuy nhiên, bạn vẫn chưa giải quyết các trùng lặp trong quá trình triển khai của mình. Điều gì sẽ xảy ra nếu bạn có một nhóm người và một số người trong số họ có chung tên hoặc họ?

def load_names(path):
    with open(path) as text_file:
        return text_file.read().splitlines()

names = load_names('names.txt')
sorted_names = load_names('sorted_names.txt')
9

Để mô hình hóa loại

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
81, bạn có thể sửa đổi lớp dữ liệu đã xác định trước đó

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
0

Lưu ý việc sử dụng thuộc tính

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
91 để cho phép tự động tạo các phương thức ma thuật để so sánh các thể hiện của lớp theo tất cả các trường. Ngoài ra, bạn có thể muốn tận dụng lợi thế của
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
10, có cú pháp ngắn hơn

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
1

Cả hai định nghĩa đều tốt và có thể hoán đổi cho nhau. Mỗi người có một thuộc tính

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
82 và một thuộc tính
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
12. Để sắp xếp và tìm kiếm theo một trong số chúng, bạn có thể xác định chức năng chính một cách thuận tiện bằng một
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
13 có sẵn trong mô-đun
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
14 tích hợp

>>>

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
2

Lưu ý cách mọi người hiện được sắp xếp theo họ theo thứ tự tăng dần. Có

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
15 và
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
16, nhưng tìm kiếm nhị phân cho họ
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
06 hiện chỉ cho bạn một kết quả tùy ý

>>>

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
3

Để bắt chước các tính năng của mô-đun

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
8 được hiển thị trước đây, bạn có thể viết phiên bản của riêng mình của
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
64 và
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
66. Trước khi tìm phiên bản ngoài cùng bên trái của phần tử trùng lặp, bạn muốn xác định xem có phần tử nào như vậy không

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
4

Nếu một số chỉ mục đã được tìm thấy, thì bạn có thể nhìn sang bên trái và tiếp tục di chuyển cho đến khi bạn gặp một phần tử có khóa khác hoặc không còn phần tử nào nữa

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
5

Khi bạn đi qua phần tử ngoài cùng bên trái, bạn cần di chuyển chỉ mục về bên phải một vị trí

Tìm trường hợp ngoài cùng bên phải cũng khá giống nhau, nhưng bạn cần lật điều kiện

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
6

Thay vì đi sang trái, bây giờ bạn sẽ sang phải cho đến hết danh sách. Sử dụng cả hai chức năng cho phép bạn tìm tất cả các lần xuất hiện của các mục trùng lặp

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
7

Hàm này luôn trả về một tập hợp. Nếu phần tử không được tìm thấy thì tập hợp sẽ trống. Nếu phần tử là duy nhất, thì tập hợp sẽ chỉ được tạo thành từ một chỉ mục duy nhất. Nếu không, sẽ có nhiều chỉ số trong tập hợp

Để kết thúc, bạn có thể xác định các hàm trừu tượng hơn nữa để hoàn thành thư viện Python tìm kiếm nhị phân của mình

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
8

Điều này không chỉ cho phép bạn xác định chính xác vị trí của các phần tử trong danh sách mà còn truy xuất các phần tử đó. Bạn có thể đặt câu hỏi rất cụ thể

Is it there?Where is it?What is it?

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
21
nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
98
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
23
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
24
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
25
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
26
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
27
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
28
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
29

Có thể tìm thấy mã hoàn chỉnh của thư viện Python tìm kiếm nhị phân này tại liên kết bên dưới

Nhận mã mẫu. Nhấp vào đây để lấy mã mẫu mà bạn sẽ sử dụng để tìm hiểu về tìm kiếm nhị phân trong Python trong hướng dẫn này

Loại bỏ các quảng cáo

đệ quy

Để đơn giản, bạn sẽ chỉ xem xét phiên bản đệ quy của

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
21, phiên bản này sẽ cho bạn biết nếu một phần tử được tìm thấy

Ghi chú. Định nghĩa đệ quy yêu thích của tôi đã được đưa ra trong một tập của loạt bài Fun Fun Function về lập trình hàm trong JavaScript

“Đệ quy là khi một hàm gọi chính nó cho đến khi nó không. ”

— Mattias Petter Johansson

Cách tiếp cận đơn giản nhất là sử dụng phiên bản lặp lại của tìm kiếm nhị phân và sử dụng toán tử cắt để cắt danh sách

import random

def find(elements, value):
    while True:
        random_element = random.choice(elements)
        if random_element == value:
            return random_element
9

Thay vì lặp, bạn kiểm tra điều kiện một lần và đôi khi gọi hàm tương tự trong danh sách nhỏ hơn. Điều gì có thể đi sai với điều đó?

Để tránh sao chép, bạn có thể sử dụng lại cùng một danh sách nhưng chuyển các ranh giới khác nhau vào hàm bất cứ khi nào cần thiết

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
0

Nhược điểm là mỗi khi bạn muốn gọi hàm đó, bạn phải vượt qua các ranh giới ban đầu, đảm bảo rằng chúng chính xác

>>>

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
1

Nếu bạn mắc lỗi, thì có khả năng sẽ không tìm thấy phần tử đó. Bạn có thể cải thiện điều này bằng cách sử dụng các đối số hàm mặc định hoặc bằng cách giới thiệu một hàm trợ giúp ủy quyền cho hàm đệ quy

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
2

Going further, you might prefer to nest one function in another to hide the technical details and to take advantage of variable reuse from outer scope

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
3

The

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
31 inner function can access both
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
32 and
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
33 parameters even though they’re defined in the enclosing scope. The life cycle and visibility of variables in Python is dictated by the so-called LEGB rule, which tells the interpreter to look for symbols in the following order

  1. Local scope
  2. Enclosing scope
  3. Global scope
  4. Built-in symbols

This allows variables that are defined in outer scope to be accessed from within nested blocks of code

The choice between an iterative and a recursive implementation is often the net result of performance considerations, convenience, as well as personal taste. However, there are also certain risks involved with recursion, which is one of the subjects of the next section

Covering Tricky Details

Here’s what the author of The Art of Computer Programming has to say about implementing the binary search algorithm

“Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky, and many good programmers have done it wrong the first few times they tried. ”

— Donald Knuth

If that doesn’t deter you enough from the idea of writing the algorithm yourself, then maybe this will. The standard library in Java had a subtle bug in their implementation of binary search, which remained undiscovered for a decade. But the bug itself traces its roots much earlier than that

Note. I once fell victim to the binary search algorithm during a technical screening. There were a couple of coding puzzles to solve, including a binary search one. Guess which one I failed to complete? Yeah

The following list isn’t exhaustive, but at the same time, it doesn’t talk about common mistakes like forgetting to sort the list

Loại bỏ các quảng cáo

Integer Overflow

This is the Java bug that was just mentioned. If you recall, the binary search Python algorithm inspects the middle element of a bounded range in a sorted collection. But how is that middle element chosen exactly? Usually, you take the average of the lower and upper boundary to find the middle index

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
4

This method of calculating the average works just fine in the overwhelming majority of cases. However, once the collection of elements becomes sufficiently large, the sum of both boundaries won’t fit the integer data type. It’ll be larger than the maximum value allowed for integers

Some programming languages might raise an error in such situations, which would immediately stop program execution. Unfortunately, that’s not always the case. Ví dụ, Java âm thầm bỏ qua vấn đề này, để giá trị đảo ngược và trở thành một số dường như ngẫu nhiên. You’ll only know about the problem as long as the resulting number happens to be negative, which throws an

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
34

Here’s an example that demonstrates this behavior in jshell, which is kind of like an interactive interpreter for Java

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
5

A safer way to find the middle index could be calculating the offset first and then adding it to the lower boundary

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
6

Even if both values are maxed out, the sum in the formula above will never be. There are a few more ways, but the good news is that you don’t need to worry about any of these, because Python is free from the integer overflow error. Không có giới hạn trên về số nguyên lớn có thể khác với bộ nhớ của bạn

>>>

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
7

However, there’s a catch. When you call functions from a library, that code might be subject to the C language constraints and still cause an overflow. There are plenty of libraries based on the C language in Python. You could even build your own C extension module or load a dynamically-linked library into Python using

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
35

tràn ngăn xếp

Về mặt lý thuyết, vấn đề tràn ngăn xếp có thể liên quan đến việc triển khai đệ quy tìm kiếm nhị phân. Hầu hết các ngôn ngữ lập trình đều áp đặt giới hạn về số lần gọi hàm lồng nhau. Mỗi cuộc gọi được liên kết với một địa chỉ trả lại được lưu trữ trên ngăn xếp. Trong Python, giới hạn mặc định là vài nghìn cấp độ của các cuộc gọi như vậy

>>>

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
8

Điều này sẽ không đủ cho nhiều hàm đệ quy. Tuy nhiên, rất khó có khả năng tìm kiếm nhị phân trong Python sẽ cần nhiều hơn do tính chất logarit của nó. Bạn sẽ cần một bộ sưu tập từ hai đến ba nghìn phần tử. Đó là một số có hơn chín trăm chữ số

Tuy nhiên, vẫn có thể xảy ra lỗi đệ quy vô hạn nếu điều kiện dừng được nêu không chính xác do lỗi. Trong trường hợp như vậy, đệ quy vô hạn cuối cùng sẽ gây ra tràn ngăn xếp

Ghi chú. Lỗi tràn ngăn xếp rất phổ biến ở các ngôn ngữ có quản lý bộ nhớ thủ công. Mọi người thường google những lỗi đó để xem liệu có ai khác đã gặp sự cố tương tự hay không, điều này đã đặt tên cho một trang web Hỏi & Đáp phổ biến dành cho các lập trình viên

Bạn có thể tạm thời tăng hoặc giảm giới hạn đệ quy để mô phỏng lỗi tràn ngăn xếp. Lưu ý rằng giới hạn hiệu quả sẽ nhỏ hơn do các chức năng mà môi trường thời gian chạy Python phải gọi

>>>

>>> from search.random import *  # Sample code to download
>>> fruits = ['orange', 'plum', 'banana', 'apple']
>>> contains(fruits, 'banana')
True
>>> find_index(fruits, 'banana')
2
>>> find(fruits, key=len, value=4)
'plum'
9

Hàm đệ quy được gọi ba lần trước khi bão hòa ngăn xếp. Bốn cuộc gọi còn lại phải được thực hiện bởi trình thông dịch tương tác. Nếu bạn chạy cùng mã đó trong PyCharm hoặc trình bao Python thay thế, thì bạn có thể nhận được kết quả khác

Loại bỏ các quảng cáo

Các yếu tố trùng lặp

Bạn nhận thức được khả năng có các yếu tố trùng lặp trong danh sách và bạn biết cách xử lý chúng. Điều này chỉ để nhấn mạnh rằng tìm kiếm nhị phân thông thường trong Python có thể không tạo ra kết quả xác định. Tùy thuộc vào cách danh sách được sắp xếp hoặc có bao nhiêu phần tử mà bạn sẽ nhận được câu trả lời khác nhau

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
0

Có hai quả chuối trong danh sách. Lúc đầu, lệnh gọi tới

nconst     primaryName      birthYear  deathYear  (...)
nm0000001  Fred Astaire     1899       1987       (...)
nm0000002  Lauren Bacall    1924       2014       (...)
nm0000003  Brigitte Bardot  1934       \N         (...)
nm0000004  John Belushi     1949       1982       (...)
98 trả về giá trị bên trái. Tuy nhiên, việc thêm một yếu tố hoàn toàn không liên quan vào cuối danh sách sẽ khiến cùng một cuộc gọi mang lại cho bạn một
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
37 khác

Nguyên tắc tương tự, được gọi là tính ổn định của thuật toán, áp dụng cho các thuật toán sắp xếp. Một số ổn định, nghĩa là chúng không thay đổi vị trí tương đối của các phần tử tương đương. Những người khác không đảm bảo như vậy. Nếu bạn cần sắp xếp các phần tử theo nhiều tiêu chí, thì bạn phải luôn bắt đầu từ khóa ít quan trọng nhất để duy trì sự ổn định

Làm tròn dấu phẩy động

Cho đến nay, bạn chỉ tìm kiếm trái cây hoặc người, nhưng còn các con số thì sao?

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
1

Danh sách phải chứa các số một phần mười, hai phần mười và ba phần mười. Đáng ngạc nhiên, chỉ có thể tìm thấy hai trong số ba số đó

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
2

Đây không phải là vấn đề liên quan chặt chẽ đến tìm kiếm nhị phân trong Python, vì tìm kiếm tuyến tính tích hợp phù hợp với nó

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
3

Nó thậm chí không phải là một vấn đề liên quan đến Python mà là cách các số dấu phẩy động được biểu diễn trong bộ nhớ máy tính. Điều này được xác định bởi tiêu chuẩn IEEE 754 cho số học dấu phẩy động. Không đi sâu vào chi tiết, một số số thập phân không có biểu diễn hữu hạn ở dạng nhị phân. Do bộ nhớ hạn chế, những con số đó được làm tròn, gây ra lỗi làm tròn dấu phẩy động

Ghi chú. Nếu bạn yêu cầu độ chính xác tối đa, thì hãy tránh xa các số có dấu phẩy động. Chúng tuyệt vời cho các mục đích kỹ thuật. Tuy nhiên, đối với các hoạt động tiền tệ, bạn không muốn tích lũy lỗi làm tròn. Bạn nên giảm quy mô tất cả giá và số tiền xuống đơn vị nhỏ nhất, chẳng hạn như xu hoặc xu và coi chúng là số nguyên

Ngoài ra, nhiều ngôn ngữ lập trình có hỗ trợ cho số điểm cố định, chẳng hạn như kiểu thập phân trong Python. Điều này giúp bạn kiểm soát thời gian và cách thức làm tròn đang diễn ra

Nếu bạn cần làm việc với các số dấu phẩy động, thì bạn nên thay thế đối sánh chính xác bằng so sánh gần đúng. Hãy xem xét hai biến có giá trị hơi khác nhau

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
4

So sánh thông thường cho kết quả âm tính, mặc dù cả hai giá trị gần giống nhau. May mắn thay, Python đi kèm với một chức năng sẽ kiểm tra xem hai giá trị có gần nhau trong một số vùng lân cận nhỏ không

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
5

Vùng lân cận đó, là khoảng cách tối đa giữa các giá trị, có thể được điều chỉnh nếu cần

>>>

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
6

Bạn có thể sử dụng chức năng đó để thực hiện tìm kiếm nhị phân trong Python theo cách sau

def find_index(elements, value):
    for index, element in enumerate(elements):
        if element == value:
            return index
7

Mặt khác, việc triển khai tìm kiếm nhị phân trong Python này chỉ dành riêng cho các số dấu phẩy động. Bạn không thể sử dụng nó để tìm kiếm bất kỳ thứ gì khác mà không gặp lỗi

Phân tích độ phức tạp thời gian-không gian của tìm kiếm nhị phân

Phần sau sẽ không chứa mã và một số khái niệm toán học

Trong điện toán, bạn có thể tối ưu hóa hiệu suất của hầu hết mọi thuật toán với chi phí sử dụng bộ nhớ tăng lên. Chẳng hạn, bạn thấy rằng tìm kiếm dựa trên hàm băm của bộ dữ liệu IMDb cần thêm 0. Bộ nhớ 5 GB để đạt được tốc độ vô song

Ngược lại, để tiết kiệm băng thông, bạn sẽ nén luồng video trước khi gửi qua mạng, làm tăng khối lượng công việc phải hoàn thành. Hiện tượng này được gọi là sự đánh đổi không-thời gian và rất hữu ích trong việc đánh giá độ phức tạp của thuật toán

Độ phức tạp thời gian-không gian

Độ phức tạp tính toán là thước đo tương đối về số lượng tài nguyên mà thuật toán cần để thực hiện công việc của nó. Các tài nguyên bao gồm thời gian tính toán cũng như dung lượng bộ nhớ mà nó sử dụng. So sánh độ phức tạp của các thuật toán khác nhau cho phép bạn đưa ra quyết định sáng suốt về thuật toán nào tốt hơn trong một tình huống nhất định

Ghi chú. Các thuật toán không cần phân bổ nhiều bộ nhớ hơn dữ liệu đầu vào đã tiêu thụ của chúng được gọi là thuật toán tại chỗ hoặc tại chỗ. Điều này dẫn đến việc thay đổi dữ liệu gốc, đôi khi có thể có tác dụng phụ không mong muốn

Bạn đã xem xét một vài thuật toán tìm kiếm và hiệu suất trung bình của chúng đối với một tập dữ liệu lớn. Rõ ràng từ các phép đo đó rằng tìm kiếm nhị phân nhanh hơn tìm kiếm tuyến tính. Bạn thậm chí có thể nói theo yếu tố nào

Tuy nhiên, nếu bạn thực hiện các phép đo tương tự trong một môi trường khác, bạn có thể nhận được kết quả hơi khác hoặc có thể hoàn toàn khác. Có những yếu tố vô hình đang diễn ra có thể ảnh hưởng đến bài kiểm tra của bạn. Bên cạnh đó, các phép đo như vậy không phải lúc nào cũng khả thi. Vì vậy, làm thế nào bạn có thể so sánh sự phức tạp về thời gian một cách nhanh chóng và khách quan?

Bước đầu tiên là chia nhỏ thuật toán thành các phần nhỏ hơn và tìm ra phần hoạt động hiệu quả nhất. Nó có thể sẽ là một hoạt động cơ bản nào đó được gọi rất nhiều và luôn mất khoảng thời gian như nhau để chạy. Đối với các thuật toán tìm kiếm, một hoạt động như vậy có thể là so sánh hai yếu tố

Sau khi thiết lập điều đó, bây giờ bạn có thể phân tích thuật toán. Để tìm độ phức tạp về thời gian, bạn muốn mô tả mối quan hệ giữa số lượng thao tác cơ bản được thực hiện so với kích thước của đầu vào. Chính thức, một mối quan hệ như vậy là một chức năng toán học. Tuy nhiên, bạn không quan tâm đến việc tìm kiếm công thức đại số chính xác của nó mà là ước tính hình dạng tổng thể của nó

Có một vài lớp hàm nổi tiếng mà hầu hết các thuật toán đều phù hợp. Khi bạn phân loại một thuật toán theo một trong số chúng, bạn có thể đặt nó lên thang điểm

Tìm kiếm nào là tốt nhất trong Python?
Các lớp phổ biến của thời gian phức tạp

Các lớp này cho bạn biết số lượng thao tác cơ bản tăng lên như thế nào khi kích thước đầu vào ngày càng tăng. Họ là, từ trái sang phải

  • Hằng số
  • logarit
  • tuyến tính
  • chuẩn tuyến tính
  • bậc hai
  • số mũ
  • yếu tố

Điều này có thể cung cấp cho bạn ý tưởng về hiệu suất của thuật toán mà bạn đang xem xét. Độ phức tạp không đổi, bất kể kích thước đầu vào là gì, là mong muốn nhất. Độ phức tạp logarit vẫn còn khá tốt, cho thấy kỹ thuật chia để trị đang được sử dụng. Càng xa về bên phải trên thang đo này, thuật toán càng phức tạp vì nó có nhiều việc phải làm hơn

Khi bạn đang nói về độ phức tạp của thời gian, điều bạn thường muốn nói là độ phức tạp tiệm cận, mô tả hành vi trong các tập dữ liệu rất lớn. Điều này giúp đơn giản hóa công thức hàm bằng cách loại bỏ tất cả các số hạng và hệ số trừ số hạng và hệ số tăng nhanh nhất (ví dụ: n bình phương)

Tuy nhiên, một chức năng duy nhất không cung cấp đủ thông tin để so sánh chính xác hai thuật toán. Độ phức tạp về thời gian có thể khác nhau tùy thuộc vào khối lượng dữ liệu. Ví dụ: thuật toán tìm kiếm nhị phân giống như một động cơ tăng áp, tạo ra áp suất trước khi nó sẵn sàng cung cấp năng lượng. Mặt khác, thuật toán tìm kiếm tuyến tính nhanh ngay từ đầu nhưng nhanh chóng đạt đến công suất cực đại và cuối cùng thua cuộc

Tìm kiếm nào là tốt nhất trong Python?

Về tốc độ, thuật toán tìm kiếm nhị phân bắt đầu vượt qua tìm kiếm tuyến tính khi có một số phần tử nhất định trong tập hợp. Đối với các bộ sưu tập nhỏ hơn, tìm kiếm tuyến tính có thể là lựa chọn tốt hơn

Ghi chú. Lưu ý rằng cùng một thuật toán có thể có độ phức tạp thời gian lạc quan, bi quan và trung bình khác nhau. Ví dụ: trong trường hợp tốt nhất, thuật toán tìm kiếm tuyến tính sẽ tìm phần tử ở chỉ mục đầu tiên, sau khi chỉ chạy một lần so sánh

Ở đầu kia của quang phổ, nó sẽ phải so sánh một giá trị tham chiếu với tất cả các phần tử trong bộ sưu tập. Trong thực tế, bạn muốn biết độ phức tạp bi quan của một thuật toán

Có một vài ký hiệu toán học về độ phức tạp tiệm cận, được sử dụng để so sánh các thuật toán. Cho đến nay, phổ biến nhất là ký hiệu Big O

Ký hiệu O lớn

Ký hiệu Big O đại diện cho trường hợp xấu nhất về độ phức tạp tiệm cận. Mặc dù điều này nghe có vẻ khá đáng sợ, nhưng bạn không cần phải biết định nghĩa chính thức. Theo trực giác, đó là thước đo rất sơ bộ về tốc độ tăng trưởng ở phần đuôi của hàm mô tả độ phức tạp. Bạn phát âm nó là “big oh” của một cái gì đó

Tìm kiếm nào là tốt nhất trong Python?

“Cái gì đó” đó thường là một hàm của kích thước dữ liệu hoặc chỉ là chữ số “một” tượng trưng cho một hằng số. Ví dụ: thuật toán tìm kiếm tuyến tính có độ phức tạp thời gian là

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
39, trong khi tìm kiếm dựa trên hàm băm có độ phức tạp
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
40

Ghi chú. Khi bạn nói rằng một thuật toán nào đó có độ phức tạp

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
41, trong đó
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
42 là kích thước của dữ liệu đầu vào, thì điều đó có nghĩa là hàm
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
43 là cận trên của đồ thị có độ phức tạp đó. Nói cách khác, độ phức tạp thực tế của thuật toán đó sẽ không tăng nhanh hơn
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
43 nhân với một hằng số nào đó, khi
Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
42 tiến đến vô cùng

Trong thực tế, ký hiệu Big O được sử dụng ít trang trọng hơn với cả giới hạn trên và giới hạn dưới. Điều này rất hữu ích cho việc phân loại và so sánh các thuật toán mà không phải lo lắng về các công thức hàm chính xác

Sự phức tạp của tìm kiếm nhị phân

Bạn sẽ ước tính độ phức tạp về thời gian tiệm cận của tìm kiếm nhị phân bằng cách xác định số phép so sánh trong trường hợp xấu nhất—khi một phần tử bị thiếu—như một hàm của kích thước đầu vào. Bạn có thể tiếp cận vấn đề này theo ba cách khác nhau

  1. dạng bảng
  2. đồ họa
  3. Phân tích

Phương pháp dạng bảng là về việc thu thập dữ liệu thực nghiệm, đặt nó vào một bảng và cố gắng đoán công thức bằng cách đánh dấu các giá trị được lấy mẫu

Số phần tửSố phép so sánh001122324353637384

Số lượng phép so sánh tăng lên khi bạn tăng số lượng phần tử trong tập hợp, nhưng tốc độ tăng trưởng chậm hơn so với khi đó là một hàm tuyến tính. Đó là dấu hiệu của một thuật toán tốt có thể mở rộng quy mô với dữ liệu

Nếu điều đó không giúp ích cho bạn, bạn có thể thử phương pháp đồ họa, phương pháp này trực quan hóa dữ liệu được lấy mẫu bằng cách vẽ biểu đồ

Tìm kiếm nào là tốt nhất trong Python?

Các điểm dữ liệu dường như phủ một đường cong, nhưng bạn không có đủ thông tin để đưa ra câu trả lời kết luận. Nó có thể là một đa thức, có đồ thị tăng giảm đối với các đầu vào lớn hơn

Sử dụng phương pháp phân tích, bạn có thể chọn một số mối quan hệ và tìm kiếm các mẫu. Ví dụ: bạn có thể nghiên cứu cách số lượng phần tử co lại trong mỗi bước của thuật toán

Số phần tử so sánh-n1stn/22ndn/43rdn/8⋮⋮k-thn/2 k

Ban đầu, bạn bắt đầu với toàn bộ tập hợp n phần tử. Sau lần so sánh đầu tiên, bạn chỉ còn lại một nửa trong số họ. Tiếp theo, bạn có một phần tư, v.v. Mô hình phát sinh từ quan sát này là sau khi so sánh thứ k, có n/2 k phần tử. Biến k là số phép toán cơ bản dự kiến

Sau khi so sánh hết k còn phần tử nào nữa. Tuy nhiên, khi bạn lùi lại một bước, tức là k - 1, sẽ còn lại đúng một phần tử. Điều này mang lại cho bạn một phương trình thuận tiện

Tìm kiếm nào là tốt nhất trong Python?

Nhân cả hai vế của phương trình với mẫu số, sau đó lấy logarit cơ số hai của kết quả và di chuyển hằng số còn lại sang phải. Bạn vừa tìm thấy công thức cho độ phức tạp tìm kiếm nhị phân, theo thứ tự của

Fred Astaire
Lauren Bacall
Brigitte Bardot
John Belushi
Ingmar Bergman
...
46

Phần kết luận

Bây giờ bạn đã biết thuật toán tìm kiếm nhị phân từ trong ra ngoài. Bạn có thể tự triển khai nó một cách hoàn hảo hoặc tận dụng thư viện chuẩn trong Python. Sau khi khai thác khái niệm về độ phức tạp của không gian-thời gian, bạn có thể chọn thuật toán tìm kiếm tốt nhất cho tình huống nhất định

Bây giờ bạn có thể

  • Sử dụng mô-đun
    def find_index(elements, value):
        for index, element in enumerate(elements):
            if element == value:
                return index
    
    8 để thực hiện tìm kiếm nhị phân trong Python
  • Thực hiện tìm kiếm nhị phân trong Python theo cách đệ quy và lặp lại
  • Nhận biết và sửa lỗi trong triển khai Python tìm kiếm nhị phân
  • Phân tích độ phức tạp không gian thời gian của thuật toán tìm kiếm nhị phân
  • Tìm kiếm thậm chí còn nhanh hơn tìm kiếm nhị phân

Với tất cả những kiến ​​thức này, bạn sẽ làm rung chuyển cuộc phỏng vấn lập trình của mình. Thuật toán tìm kiếm nhị phân có phải là giải pháp tối ưu cho một vấn đề cụ thể hay không, bạn có các công cụ để tự tìm ra giải pháp đó. Bạn không cần bằng khoa học máy tính để làm như vậy

Bạn có thể lấy tất cả mã bạn đã thấy trong hướng dẫn này tại liên kết bên dưới

Nhận mã mẫu. Nhấp vào đây để lấy mã mẫu mà bạn sẽ sử dụng để tìm hiểu về tìm kiếm nhị phân trong Python trong hướng dẫn này

Đánh dấu là đã hoàn thành

Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Tạo Tìm kiếm nhị phân trong Python

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Tìm kiếm nào là tốt nhất trong Python?

Gửi cho tôi thủ thuật Python »

Giới thiệu về Bartosz Zaczyński

Tìm kiếm nào là tốt nhất trong Python?
Tìm kiếm nào là tốt nhất trong Python?

Bartosz là người hướng dẫn bootcamp, tác giả và lập trình viên đa ngôn ngữ yêu thích Python. Anh ấy giúp sinh viên của mình tiếp cận công nghệ phần mềm bằng cách chia sẻ kinh nghiệm thương mại hơn một thập kỷ trong ngành CNTT

» Thông tin thêm về Bartosz


Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Tìm kiếm nào là tốt nhất trong Python?

Aldren

Tìm kiếm nào là tốt nhất trong Python?

Geir Arne

Tìm kiếm nào là tốt nhất trong Python?

Jaya

Tìm kiếm nào là tốt nhất trong Python?

Jon

Tìm kiếm nào là tốt nhất trong Python?

Joanna

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Chuyên gia Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Thuật toán tìm kiếm nhanh nhất trong python là gì?

Tìm kiếm nhị phân là một trong những thuật toán tìm kiếm nhanh nhất. Chúng ta có thể triển khai tìm kiếm nhị phân cả lặp và đệ quy. Độ phức tạp thời gian trung bình của tìm kiếm nhị phân trong python là O (log n) và độ phức tạp không gian của tìm kiếm nhị phân trong python là O(1).

Phương pháp tìm kiếm nào là tốt nhất?

Loại thuật toán tìm kiếm này được sử dụng để tìm vị trí của một giá trị cụ thể có trong một mảng được sắp xếp. Thuật toán tìm kiếm nhị phân hoạt động theo nguyên tắc chia để trị và nó được coi là thuật toán tìm kiếm tốt nhất vì chạy nhanh hơn

Thuật toán tìm kiếm nào sau đây là nhanh nhất?

8. Thuật toán tìm kiếm nào sau đây là nhanh nhất? . Tìm kiếm theo hàm mũ có độ phức tạp về thời gian ít nhất (bằng log n) trong số các thuật toán tìm kiếm đã cho. Điều này làm cho tìm kiếm theo cấp số nhân thích hợp hơn trong hầu hết các trường hợp.

Tìm kiếm nào là rất hiệu quả và tại sao?

Tìm kiếm khoảng thời gian . Các thuật toán này được thiết kế đặc biệt để tìm kiếm trong cấu trúc dữ liệu được sắp xếp. Các loại thuật toán tìm kiếm này hiệu quả hơn nhiều so với Tìm kiếm tuyến tính vì chúng liên tục nhắm mục tiêu vào trung tâm của cấu trúc tìm kiếm và chia đôi không gian tìm kiếm. Ví dụ. Tìm kiếm nhị phân.