Hướng dẫn how does python implement binary search? - python thực hiện tìm kiếm nhị phân như thế nào?
Xem bây giờ hướng dẫn này có một khóa học video liên quan được tạo bởi nhóm Python thực sự. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn về sự hiểu biết của bạn: Tạo một tìm kiếm nhị phân trong Python This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Creating a Binary Search in Python Show
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à các cuộc phỏng vấn kỹ thuật. Việc 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ó một bài tập cụ thể, bạn nên 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. is a classic algorithm in computer science. It often comes up in programming contests and technical interviews. Implementing binary search turns out to be a challenging task, even when you understand the concept. Unless you’re curious or have a specific assignment, you should always leverage existing libraries to do a binary search in Python or any other language. Trong hướng dẫn này, bạn sẽ học cách:
Hướng dẫn này giả định rằng bạn là một sinh viên hoặc một lập trình viên trung cấp với sự quan tâm đến các thuật toán và cấu trúc dữ liệu. Ít nhất, bạn nên quen thuộc với các loại dữ liệu tích hợp Python, chẳng hạn như danh sách và bộ dữ liệu. Ngoài ra, một số sự quen thuộc với đệ quy, các lớp, lớp dữ liệu và lambdas 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.intermediate programmer with an interest in algorithms and data structures. At the very least, you should be familiar with Python’s built-in data types, such as lists and tuples. In addition, some familiarity with recursion, classes, data classes, and lambdas will help you better understand the concepts you’ll see in this tutorial. Dưới đây 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: Điểm chuẩnTrong 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 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 việc 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 tab (TSV) nén, nhận được các bản 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 tìm nạp tệp có liên quan từ IMDB, giải nén nó và trích xuất các phần thú vị:
Được cảnh báo rằng điều này sẽ tải xuống và trích xuất khoảng 600 MB dữ liệu, cũng như tạo hai tệp bổ sung, có kích thước khoảng một nửa. Việc 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 thành. Tải xuống IMDBĐể có được 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://datasets.imdbws.com/ và lấy tệp có tên 9, chứa hồ sơ của các tác nhân, đạo diễn, nhà văn, v.v. Khi bạn giải nén tệp, bạn sẽ thấy nội dung sau:
Nó có một tiêu đề với các tên cột trong dòng đầu tiên, tiếp theo 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 định danh duy nhất, một tên đầy đủ, năm sinh và một vài thuộc tính khác. Tất cả đều được phân định với một ký tự tab.header with the column names in the first line, followed by data records in each of the subsequent lines. Each record contains a unique identifier, a full name, birth year, and a few other attributes. These are all delimited with a tab character. Có hàng triệu hồ sơ, vì vậy don don cố gắng mở tệp với một trình soạn thảo văn bản thông thường để tránh bị sập máy tính của bạn. Ngay cả các phần mềm chuyên dụng như bảng tính cũng có thể có vấn đề 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 bao gồm trong Jupyterlab chẳng hạn. Đọc các giá trị phân tách tabCó một vài cách để phân tích tệp TSV. Ví dụ: bạn có thể đọc nó bằng gấu trúc, sử dụng một ứng dụng chuyên dụng hoặc tận dụng một vài công cụ dòng lệnh. Tuy nhiên, nó khuyên bạn nên sử dụng tập lệnh Python không rắc rối có trong mã mẫu. 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:
Một người sẽ chứa một danh sách các tên thu được bằng cách cắt cột thứ hai khỏi tệp TSV gốc:
Cái thứ hai sẽ là phiên bản 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:
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 2 trên chuỗi kết quả sẽ loại bỏ ký tự dòng mới ra khỏi mỗi dòng. Thay vào đó, bạn có thể gọi 3, nhưng điều đó sẽ giữ cho 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 nó so với 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 4 hoặc 5 tích hợp, rất hữu ích cho việc định thời gian một khối mã.Bạn cũng có thể xác định một người trang trí tùy chỉnh theo thời gian một chức năng nếu bạn muốn. Mã mẫu được cung cấp sử dụng 6, được giới thiệu trong Python 3.7, bởi vì nó cung cấp độ chính xác cao trong nano giây.Hiểu thuật toán tìm kiếmTìm kiếm có mặt khắp nơi 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 việc tìm kiếm thực sự có nghĩa là gì?searching really means? Thuật toán tìm kiếm có nhiều hình thức khác nhau. Ví dụ: bạn có thể:
Trong hướng dẫn này, bạn sẽ tìm hiểu về việc tìm kiếm một yếu tố trong danh sách các mục được sắp xếp, như một 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 trả lời cho câu hỏi đầu tiên cho bạn biết liệu một yếu tố có mặt trong bộ sưu tập hay không. Nó luôn giữ đú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 có sẵn 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 nó.present in the collection. It always holds either true or false. The second answer is the location of an element within the collection, which may be unavailable if that element was missing. Finally, the third answer is the element itself, or a lack of it. 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 yếu tố trong bộ sưu tập với cái chính xác bạn cung cấp làm tài liệu tham khảo. Nói cách khác, tiêu chí tìm kiếm của bạn là toàn bộ yếu tố, chẳng hạn như số, chuỗi hoặc một đối tượng giống như một người. Ngay cả sự khác biệt nhỏ nhất giữa hai yếu tố so sánh cũng giành được kết quả trong một trận đấu.searching by value, which compares elements in the collection against the exact one you provide as a reference. In other words, your search criteria are the entire element, such as a number, a string, or an object like a person. Even the tiniest difference between the two compared elements won’t result in a match. Mặt khác, bạn có thể có nhiều tiêu chí tìm kiếm hơn bằng cách chọn một số thuộc tính của một yếu tố, chẳng hạn như một người tên cuối cùng. Điều này được gọi là tìm kiếm bởi 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 ở Python, hãy để xem nhanh các thuật toán tìm kiếm khác để có được một bức tranh lớn hơn và hiểu cách chúng hoạt động.searching by key because you pick one or more attributes to compare. Before you dive into binary search in Python, let’s take a quick look at other search algorithms to get a bigger picture and understand how they work. Tìm kiếm ngẫu nhiênLàm thế nào bạn có thể tìm kiếm thứ gì đó trong ba lô của bạn? Bạn có thể chỉ cần đào tay vào đó, chọn một vật phẩm một cách ngẫu nhiên và xem nó có phải là thứ bạn muốn không. Nếu bạn không gặp may, thì bạn đặt vật phẩm trở lại, rửa sạch và lặp lại. Ví dụ này là một cách tốt để 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 ít hiệu quả nhất. Sự kém hiệu quả của phương pháp này bắt nguồn từ thực tế là bạn đang có nguy cơ chọn điều tương tự nhiều lần.random search, which is one of the least efficient search algorithms. The inefficiency of this approach stems from the fact that you’re running the risk of picking the same wrong thing multiple times. Nguyên tắc cơ bản của thuật toán này có thể được thể hiện với đoạn mã Python sau:
Các vòng lặp hàm cho đến khi một số phần tử được chọn ngẫu nhiên khớp với giá trị được đưa ra dưới dạng đầu vào. Tuy nhiên, điều này rất hữu ích vì hàm trả về 7 ngầm hoặc cùng một giá trị mà nó đã nhận được trong một tham số. Bạn có thể tìm thấy việc 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:Đối với các bộ dữ liệu bằng kính hiển vi, 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 mình nhanh chóng: >>>
Tuy nhiên, hãy tưởng tượng phải tìm kiếm như vậy thông qua hàng triệu yếu tố! Tại đây, một bản tóm tắt nhanh chóng của một bài kiểm tra hiệu suất đã được thực hiện dựa trên bộ dữ liệu IMDB:
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 như thu thập rác hoặc quy trình hệ thống chạy trong nền. 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 yếu tố không phụ thuộc vào nơi ở của nó, thời gian tốt nhất và tồi tệ nhất là hai đến ba bậc độ lớn. Nó cũng bị hành vi không nhất quán. Cân nhắc có một bộ sưu tập các yếu tố chứa một số bản sao. Bởi vì thuật toán chọn các yếu tố một cách ngẫu nhiên, nên nó chắc chắn sẽ trả lại các bản sao khác nhau khi chạy tiếp theo.non-deterministic performance. While the average time to find an element doesn’t depend on its whereabouts, the best and worst times are two to three orders of magnitude apart. It also suffers from inconsistent behavior. Consider having a collection of elements containing some duplicates. Because the algorithm picks elements at random, it’ll inevitably return different copies upon subsequent runs. Làm thế nào bạn có thể cải thiện về điều này? Một cách để giải quyết cả hai vấn đề cùng một lúc là sử dụng tìm kiếm tuyến tính.linear search. Tìm kiếm tuyến tínhKhi bạn quyết định những gì cần có cho bữa trưa, bạn có thể nhìn xung quanh thực đơn một cách hỗn loạn cho đến khi một cái gì đó bắt mắt 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 mọi mục trong một chuỗi. Đó là tìm kiếm tuyến tính một cách ngắn gọn. Để thực hiện nó trong Python, bạn có thể 4 các yếu tố để theo dõi chỉ số phần tử hiện tại:sequence. That’s linear search in a nutshell. To implement it in Python, you could
4 elements to keep track of the current element’s index:
Các vòng lặp chức năng trên 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 phần tử được tìm thấy, hoặc khi không có nhiều yếu tố để kiểm tra. Chiến lược này đảm bảo rằng không có yếu tố nào được truy cập nhiều lần vì bạn đã đi qua chúng theo thứ tự bởi 5.Hãy để xem các cảnh sát tìm kiếm tuyến tính với bộ dữ liệu IMDB bạn đã sử dụng tốt như thế nào trước đây:
0 10 11Có hầu như không có bất kỳ phương sai nào trong thời gian tra cứu của một yếu tố riêng lẻ. Thời gian trung bình gần như giống như tốt nhất và tồi tệ nhất. Vì các yếu tố luôn được duyệt theo cùng một thứ tự, số lượng so sánh cần thiết để tìm cùng một yếu tố không thay đổi.linear function, which is where the name of the algorithm comes from. You can assume that, on average, the time required to find any element using a linear search will be proportional to the number of all elements in the collection. They don’t scale well as the amount of data to search increases. Tuy nhiên, thời gian tra cứu tăng lên với chỉ số ngày càng tăng của một yếu tố trong bộ sưu tập. Phần tử càng xa từ đầu danh sách, càng nhiều so sánh phải chạy. Trong trường hợp xấu nhất, khi thiếu phần tử, toàn bộ bộ sưu tập phải được kiểm tra để đưa ra câu trả lời xác định.preprocessing the data. In such a case, the benefits of preprocessing wouldn’t pay back its cost. Khi bạn chiếu dữ liệu thử nghiệm lên một lô và kết nối các dấu chấm, thì bạn sẽ ngay lập tức thấy mối quan hệ giữa vị trí phần tử và thời gian cần tìm nó: Tất cả các mẫu nằm trên một đường thẳng và có thể được mô tả bởi một hàm tuyến tính, đó là nơi tên của thuật toán đến từ. Bạn có thể giả định rằng, trung bình, thời gian cần thiết để tìm bất kỳ yếu tố nào sử dụng tìm kiếm tuyến tính sẽ tỷ lệ thuận với số lượng của tất cả các phần tử trong bộ sưu tập. Họ không có quy mô tốt như số lượng dữ liệu để tìm kiếm tăng.
Ví dụ, máy quét sinh trắc học có sẵn tại một số sân bay sẽ nhận ra hành khách trong vài giây, nếu họ được thực hiện bằng cách sử dụ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 bộ dữ liệu nhỏ hơn, bởi vì nó 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 việc tiền xử lý sẽ trả lại chi phí của nó. Tất cả các mẫu nằm trên một đường thẳng và có thể được mô tả bởi một hàm tuyến tính, đó là nơi tên của thuật toán đến từ. Bạn có thể giả định rằng, trung bình, thời gian cần thiết để tìm bất kỳ yếu tố nào sử dụng tìm kiếm tuyến tính sẽ tỷ lệ thuận với số lượng của tất cả các phần tử trong bộ sưu tập. Họ không có quy mô tốt như số lượng dữ liệu để tìm kiếm tăng.
Ví dụ, máy quét sinh trắc học có sẵn tại một số sân bay sẽ nhận ra hành khách trong vài giây, nếu họ được thực hiện bằng cách sử dụ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 bộ dữ liệu nhỏ hơn, bởi vì nó 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 việc tiền xử lý sẽ trả lại chi phí của nó. Python đã được vận chuyển với tìm kiếm tuyến tính, vì vậy, không có điểm nào trong việc tự viết nó. Ví dụ, cấu trúc dữ liệu 12 hiển thị một phương thức sẽ trả về chỉ mục của một phần tử hoặc nêu ra một ngoại lệ khác:Tất cả các mẫu nằm trên một đường thẳng và có thể được mô tả bởi một hàm tuyến tính, đó là nơi tên của thuật toán đến từ. Bạn có thể giả định rằng, trung bình, thời gian cần thiết để tìm bất kỳ yếu tố nào sử dụng tìm kiếm tuyến tính sẽ tỷ lệ thuận với số lượng của tất cả các phần tử trong bộ sưu tập. Họ không có quy mô tốt như số lượng dữ liệu để tìm kiếm tăng.
Ví dụ, máy quét sinh trắc học có sẵn tại một số sân bay sẽ nhận ra hành khách trong vài giây, nếu họ được thực hiện bằng cách sử dụ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 bộ dữ liệu nhỏ hơn, bởi vì nó 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 việc tiền xử lý sẽ trả lại chi phí của nó. Python đã được vận chuyển với tìm kiếm tuyến tính, vì vậy, không có điểm nào trong việc tự viết nó. Ví dụ, cấu trúc dữ liệu 12 hiển thị một phương thức sẽ trả về chỉ mục của một phần tử hoặc nêu ra một ngoại lệ khác:>>>binary search algorithm! Điều này cũng có thể cho bạn biết nếu phần tử có mặt 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 (...) 13 đa năng:Điều đáng chú ý là mặc dù sử dụng tìm kiếm tuyến tính dưới mui xe, các chức năng và nhà khai thác tích hợp này sẽ thổi bay việc thực hiện của bạn ra khỏi nước. Điều đó bởi vì chúng được viết bằng C Pure C, biên dịch cho mã máy gốc. Trình thông dịch Python tiêu chuẩn không phù hợp với nó, bất kể bạn cố gắng thế nào.binary is generally associated with the number 2. In this context, it refers to dividing a collection of elements into two halves and throwing away one of them at each step of the algorithm. This can dramatically reduce the number of comparisons required to find an element. But there’s a catch—elements in the collection must be sorted first. Một thử nghiệm nhanh với mô -đun 5 cho thấy việc triển khai Python có thể chạy chậm hơn gần gấp mười lần so với bản địa tương đương:Tuy nhiên, đối với các bộ dữ liệu đủ lớn, ngay cả mã gốc sẽ đạt đến giới hạn của nó và giải pháp duy nhất sẽ là suy nghĩ lại về thuật toán. Trong các kịch bản thực tế, thuật toán tìm kiếm tuyến tính thường nên tránh. Ví dụ, có một thời gian tôi không thể đăng ký con mèo của mình tại phòng khám bác sĩ thú y vì hệ thống của họ liên tục bị sập. Bác sĩ nói với tôi rằng cuối cùng anh ta phải nâng cấp máy tính của mình vì thêm nhiều hồ sơ vào cơ sở dữ liệu khiến nó chạy chậm hơn và chậm hơn.middle of that new range. This minimizes the number of tries. A similar approach can be used in the number guessing game. If you haven’t heard of that game, then you can look it up on the Internet to get a plethora of examples implemented in Python. Tôi nhớ mình đã nghĩ cho bản thân mình 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!lower bound and the upper bound. In binary search, you commonly start with the first page as the lower bound and the last page as the upper bound. You must update both bounds as you go. For example, if the page you turn to is lower than the one you’re looking for, then that’s your new lower bound. Hãy nói rằng bạn đang tìm kiếm một quả dâu trong một 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 thước: Trong lần thử đầu tiên, phần tử ở giữa xảy ra là một quả chanh. Vì nó lớn hơn một quả dâu tây, bạn có thể loại bỏ tất cả các yếu tố ở bên phải, bao gồm cả chanh. Bạn sẽ di chuyển ràng buộc trên đến một vị trí mới và cập nhật chỉ số giữa: Bây giờ, bạn đã rời đi chỉ với một nửa số trái cây mà bạn bắt đầu. Yếu tố trung gian hiện tại thực sự là quả dâu tây mà bạn đang tìm kiếm, kết luận tìm kiếm. Nếu đó không phải là người, thì bạn chỉ cần cập nhật giới hạn cho đến khi họ vượt qua nhau. Ví dụ, tìm kiếm một mận còn thiếu, sẽ đi giữa dâu tây và kiwi, sẽ kết thúc với kết quả sau: Lưu ý rằng có nhiều so sánh phải được thực hiện để tìm ra yếu 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ý một triệu yếu tố, bạn cũng chỉ yêu cầu nhiều nhất một số kiểm tra. Con số này đã giành được vượt quá cơ sở logarit hai trong tổng số phần tử do giảm một nửa. Nói cách khác, số lượng các yếu tố còn lại được giảm một nửa ở mỗi bước.logarithm base two of the total number of elements due to halving. In other words, the number of remaining elements is reduced by half at each step. Đ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 bằng một chìa khóa khác, chẳng hạn như một màu, thì bạn phải sắp xếp toàn bộ bộ sưu tập một lần nữa. Để tránh chi phí đắt tiền của việc phân loại, bạn có thể cố gắng tính toán các chế độ xem khác nhau của cùng một bộ sưu tập trước. Điều này có phần giống với việc tạo một chỉ mục cơ sở dữ liệu.database index. Xem xét những gì 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 phải duy trì thứ tự sắp xếp thích hợp. Điều này có thể được thực hiện với mô -đun 8 mà bạn sẽ đọc trong phần sắp tới.Bạn sẽ thấy cách thực hiện thuật toán tìm kiếm nhị phân trong Python sau này trong hướng dẫn này. Hiện tại, hãy để đối mặt với nó với bộ dữ liệu IMDB. Lưu ý rằng có những người khác nhau để tìm kiếm hơn trước. Điều đó bởi vì bộ dữ liệu phải được sắp xếp để tìm kiếm nhị phân, sắp xếp lại các yếu tố. Các yếu tố mới được đặt gần đúng với các chỉ số như trước đây, để giữ cho các phép đo có thể so sánh được:
Các câu trả lời gần như tức thời. Trong trường hợp trung bình, chỉ mất một vài micro giây để tìm kiếm nhị phân để tìm một yếu tố trong số chín triệu! Ngoài ra, số lượng so sánh cho các phần tử được chọn vẫn gần như không đổi, trùng với công thức sau: Tìm hầu hết các yếu tố sẽ yêu cầu số lượng so sánh cao nhất, có thể được lấy từ logarit có kích thước của bộ sưu tập. Ngược lại, 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 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 để hình thành câu trả lời cuối cùng. Một ví dụ nổi tiếng khác về kỹ thuật này là thuật toán Quicksort.divide-and-conquer technique, which partitions one problem into a bunch of smaller problems of the same kind. The individual solutions are then combined to form the final answer. Another well-known example of this technique is the Quicksort algorithm. 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 đặt thử nghiệm thành viên, tìm giá trị lớn nhất hoặc nhỏ nhất, tìm người hàng xóm gần nhất của giá trị mục tiêu, thực hiện các truy vấn phạm vi và hơn thế nữa. 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ó các thuật toán nhanh hơn có thể tận dụng các cấu trúc dữ liệu dựa trên băm. Tuy nhiên, các thuật toán đó đòi hỏi rất nhiều bộ nhớ bổ sung, trong khi tìm kiếm nhị phân cung cấp một sự đánh đổi không gian tốt. Tìm kiếm dựa trên 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 cử viên ở mỗi bước. Điều đó có nghĩa là ngay cả khi bạn có một triệu yếu tố, phải mất nhiều nhất hai mươi so sánh để xác định xem phần tử có mặt hay không, với điều kiện là tất cả các yếu tố được sắp xếp.problem space. Binary search achieves that goal by halving the number of candidates at each step. That means that even if you have one million elements, it takes at most twenty comparisons to determine if the element is present, provided that all elements are sorted. 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 vị trí bộ nhớ chính xác của một phần tử, thì bạn sẽ truy cập trực tiếp vào nó mà không cần 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 phím của nó vào vị trí phần tử trong bộ nhớ được gọi là băm.hashing. Bạn có thể nghĩ rằng 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 hàm băm, cần giữ các thuộc tính toán học nhất định. Một hàm băm tốt nên:hash function, which needs to hold certain mathematical properties. A good hash function should:
Đồ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ẽ vượt xa lợi nhuận. Chức năng băm cũng được sử dụng để xác minh tính toàn vẹn 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ạ các phím thành các giá trị được gọi là bản đồ, bảng băm, từ điển hoặc mảng kết hợp.map, a hash table, a dictionary, or an associative array. Một cách khác để trực quan hóa băm là tưởng tượng cái gọi là xô của các yếu tố tương tự được nhóm lại dưới các khóa tương ứng của chúng. Ví dụ: bạn có thể thu hoạch trái cây thành các thùng khác nhau dựa trên màu sắc:buckets of similar elements grouped under their respective keys. For example, you may be harvesting fruits into different buckets based on color: Dừa và trái cây kiwi đi đến xô có nhãn màu nâu, trong khi một quả táo kết thúc trong một cái xô với nhãn màu đỏ, v.v. Điều này cho phép bạn liếc qua một phần của các yếu tố một cách nhanh chóng. Lý tưởng nhất, bạn muốn chỉ có một quả trong mỗi thùng. Nếu không, bạn có được những gì mà người Viking gọi là va chạm, dẫn đến công việc làm thêm.collision, which leads to extra work. Hãy để Lừa đặt tên từ bộ dữ liệu IMDB vào 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ó: >>> 0Sau khi tải tên văn bản vào một danh sách phẳng, bạn có thể 4 nó bên trong một sự hiểu biết từ điển để 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ư nhận chỉ số của nó là đơn giản:>>> 1Sau khi tải tên văn bản vào một danh sách phẳng, bạn có thể 4 nó bên trong một sự hiểu biết từ điển để 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ư nhận chỉ số của nó là đơn giản:Nhờ chức năng băm được sử dụng đằng sau hậu trường, bạn không phải thực hiện bất kỳ tìm kiếm nào!
28Alicia Monica 2hashable, and their hash values can’t change over time. You can check if a particular data type is hashable in Python by calling 41 on it:>>> 2Sau khi tải tên văn bản vào một danh sách phẳng, bạn có thể 4 nó bên trong một sự hiểu biết từ điển để 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ư nhận chỉ số của nó là đơn giản:immutable because their hash value often depends on some attributes of the key. If a mutable collection was hashable and could be used as a key, then its hash value would be different every time the contents changed. Consider what would happen if a particular fruit changed color due to
ripening. You’d be looking for it in the wrong bucket!Nhờ chức năng băm được sử dụng đằng sau hậu trường, bạn không phải thực hiện bất kỳ tìm kiếm nào! Tại đây, cách thức thuật toán tìm kiếm dựa trên băm thực hiện đối với bộ dữ liệu IMDB:Thuật ngữ tìm kiếm
28Alicia Monica >>> 'banana' in fruits True >>> 'blueberry' in fruits False 2 30>>> 3Sau khi tải tên văn bản vào một danh sách phẳng, bạn có thể 4 nó bên trong một sự hiểu biết từ điển để 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ư nhận chỉ số của nó là đơn giản:
>>> 4Sau khi tải tên văn bản vào một danh sách phẳng, bạn có thể 4 nó bên trong một sự hiểu biết từ điển để 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ư nhận chỉ số của nó là đơn giản:
Điều này có thể được dịch sang một hàm phổ quát để tìm các yếu tố theo giá trị: 5Khi có một trận đấu, hàm sẽ trả về chỉ mục phần tử tương ứng. Nếu không, nó sẽ trả lại 7 ngầm.Để tìm kiếm theo khóa, bạn phải duy trì một danh sách các khóa riêng. Vì điều này phải chịu thêm một chi phí, nên nó có giá trị để tính toán các phím lên phía trước và tái sử dụng chúng càng nhiều càng tốt. Bạn có thể xác định một lớp trợ giúp để có thể tìm kiếm bằng các khóa khác nhau mà không cần giới thiệu nhiều sao chép mã: 6Khóa là một hàm được truyền dưới dạng tham số đầu tiên cho 59. Khi bạn có nó, bạn lập một danh sách các cặp giá trị khóa để có thể lấy một phần tử từ khóa của nó sau đó. Đại diện cho các cặp với các bộ dữ liệu đả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 mà 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 yếu tố theo khóa: 7Mã này chia đôi danh sách các khóa được 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 tính toán trước đó các cặp giá trị khóa. Yếu tố thứ hai của cặp đó là giá trị mong muốn. Nếu bạn có nhiều chuối, thì 49 sẽ trả lại phiên bản ngoài cùng bên trái:>>> 8Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:>>> 9Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:>>> 0Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:Khi bạn kết hợp mã, bạn có thể thấy bạn có bao nhiêu chuối:Nếu một phần tử bị thiếu, thì cả 49 và 51 sẽ trả lại cùng một chỉ số mang lại chuối bằng không.>>> 1Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:duplicates in your list. But even then, it won’t become apparent as long as
those duplicates are simple values. Adding another banana to the left will have the same effect as adding it to the right.Khi bạn kết hợp mã, bạn có thể thấy bạn có bao nhiêu chuối:unique identities despite having equal values. Let’s define a 66 type using the @dataclass decorator,
which was introduced in Python 3.7: 2Nếu một phần tử bị thiếu, thì cả 49 và 51 sẽ trả lại cùng một chỉ số mang lại chuối bằng không.>>> 3Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:>>> 4Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:Khi bạn kết hợp mã, bạn có thể thấy bạn có bao nhiêu chuối: >>> 5Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:less than, to tell the interpreter how to compare such elements. However, the 75 decorator accepts a few optional Boolean flags. One of them is 76, which results in an automatic generation of the magic methods for comparison when set to 77: 6Khi bạn kết hợp mã, bạn có thể thấy bạn có bao nhiêu chuối: >>> 7Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:>>> 8Có thể dự đoán, để có được quả chuối ngoài cùng bên phải, bạn cần phải gọi 51 hoặc bí danh 47 của nó. Tuy nhiên, hai chức năng đó trả về một chỉ mục từ chuối ngoài cùng bên phải thực tế, rất hữu ích cho việc tìm điểm chèn của một yếu tố mới:Khi bạn kết hợp mã, bạn có thể thấy bạn có bao nhiêu chuối:Nếu một phần tử bị thiếu, thì cả 49 và 51 sẽ trả lại cùng một chỉ số mang lại chuối bằng không.Điều đó nói rằng, có những lúc nó có ý nghĩa khi cuộn tay áo lên và tự làm điều đó. Công ty của bạn có thể có một chính sách cấm một số thư viện nguồn mở do các vấn đề cấp phép hoặc bảo mật. Có lẽ bạn có thể đủ khả năng phụ thuộc khác do các ràng buộc băng thông mạng hoặc 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:
Tuy nhiên, có những trường hợp ngoại lệ cho quy tắc đó. Một ví dụ đáng chú ý là hàm Ackermann, chỉ có thể được thể hiện dưới dạng đệ quy. Trước khi bạn đi xa hơn, hãy chắc chắn rằng bạn có một nắm bắt tốt về thuật toán tìm kiếm nhị phân. Bạn có thể tham khảo một phần trước của hướng dẫn này để được bồi dưỡng nhanh. Lặp đi lặp lạiĐệ quysearch elements by value and return their index: 9Tuy nhiên, có những trường hợp ngoại lệ cho quy tắc đó. Một ví dụ đáng chú ý là hàm Ackermann, chỉ có thể được thể hiện dưới dạng đệ quy. Trước khi bạn đi xa hơn, hãy chắc chắn rằng bạn có một nắm bắt tốt về thuật toán tìm kiếm nhị phân. Bạn có thể tham khảo một phần trước của hướng dẫn này để được bồi dưỡng nhanh. 0Phiên bản lặp của thuật toán liên quan đến một vòng lặp, sẽ lặp lại một số bước cho đến khi điều kiện dừng được đáp ứng. Hãy bắt đầu bằng cách thực hiện một chức năng sẽ tìm kiếm các yếu tố theo giá trị và trả về chỉ mục của chúng: 1Bạn sẽ sử dụng lại chức năng này sau này.integer division helps to handle both an odd and even number of elements in the bounded range by flooring the result. Depending on how you’re going to update the boundaries and define the stopping condition, you could also use a ceiling function. Giả sử rằng tất cả các yếu tố được sắp xếp, bạn có thể đặt các ranh giới dưới và trên ở hai đầu đối diện của chuỗi: 2Bâ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: Lưu ý cách phân chia số nguyên giúp xử lý cả số phần tử và số lượng các phần tử trong phạm vi giới hạn bằng cách đưa ra kết quả. Tùy thuộc vào cách bạn sẽ cập nhật các 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. 3Tiế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 trong một nửa kết quả: Nếu phần tử ở giữa là một trận đấu, thì bạn sẽ trả về chỉ mục của nó. Nếu không, nếu nó quá nhỏ, thì bạn cần di chuyển ranh giới dưới. Nếu nó quá lớn, thì bạn cần di chuyển ranh giới trên xuống. boils down to looking at an object’s attributes instead of its literal value. A key could be the number of characters in a fruit’s name, for example. You can adapt 83 to accept and use a 84 parameter: 4Để tiếp tục, bạn phải đặt hầu hết các bước trong một vòng lặp, điều này sẽ dừng lại khi ranh giới dưới đây vượt qua bước trên: Nói cách khác, bạn muốn lặp lại miễn là ranh giới dưới nằm dưới hoặc bằng với phần trên. Mặt khác, không có khớp và chức năng trả về 5Tìm kiếm bởi chính tập trung vào việc nhìn vào một thuộc tính đối tượng thay vì giá trị theo nghĩa đen của nó. Một chìa khóa có thể là số lượng ký tự trong một tên trái cây, chẳng hạn. Bạn có thể điều chỉnh 83 để chấp nhận và sử dụng tham số 84: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 84 mà bạn sẽ tìm kiếm với: 6>>> 7Trong ví dụ trên, 86 đã đượ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 được tạo thành từ ba chữ cái. 8Điều đó rất tuyệt, nhưng đồng thời, bạn đã 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 84 giá trị mặc định là 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 84. Theo mặc định, nó sẽ là một chức năng nhận dạng trả về chính phần tử:duplicates in your implementation. What if you had a collection of people, and
some of them shared a common name or surname? For example, there might be a 91 family or a few guys going by the name of 80 among the people: 9Ngoài ra, bạn có thể xác định chức năng nhận dạng nội tuyến với biểu thức Lambda ẩn danh: 0 83 chỉ trả lời một câu hỏi. Vẫn còn hai người khác, đó là người ở đó? và nó là gì?" Để trả lời hai điều này, bạn có thể xây dựng trên đầu nó: 1Với ba chức năng này, bạn có thể nói hầu hết mọi thứ về một yếu tố. Tuy nhiên, bạn vẫn chưa giải quyết các bản sao trong việc thực hiện của bạn. Điều gì sẽ xảy ra nếu bạn có một bộ sưu tập người, và một số trong số họ đã chia sẻ một tên hoặc họ chung? Ví dụ, có thể có một gia đình 91 hoặc một vài người đi theo tên của 80 trong số những người:Nói cách khác, bạn muốn lặp lại miễn là ranh giới dưới nằm dưới hoặc bằng với phần trên. Mặt khác, không có khớp và chức năng trả về 2Tìm kiếm bởi chính tập trung vào việc nhìn vào một thuộc tính đối tượng thay vì giá trị theo nghĩa đen của nó. Một chìa khóa có thể là số lượng ký tự trong một tên trái cây, chẳng hạn. Bạn có thể điều chỉnh 83 để chấp nhận và sử dụng tham số 84:>>> 3Để bắt chước các tính năng của mô -đun 8 được hiển thị trước đó, bạn có thể viết phiên bản 49 và 51 của riêng mình. Trước khi tìm thấy phiên bản ngoài cùng bên trái của một yếu tố trùng lặp, bạn muốn xác định xem có phải là một yếu tố như vậy không:leftmost instance of a duplicate element, you want to determine if
there’s such an element at all: 4Nế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 bắt gặp một yếu tố có khóa khác hoặc không có nhiều yếu tố nữa: 5Khi 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 trở lại một vị trí sang bên phải. Tìm trường hợp ngoài cùng bên phải là khá giống nhau, nhưng bạn cần phải lật các điều kiện:rightmost instance is quite similar, but you need to flip the conditions: 6Thay vì đi bên trái, bây giờ bạn sẽ đi bên phải cho đến khi kết thúc danh sách. Sử dụng cả hai chức năng cho phép bạn tìm thấy tất cả các mục xuất hiện của các mục trùng lặp:all occurrences of duplicate items: 7Hàm này luôn trả về một bộ. Nếu phần tử được tìm thấy, thì bộ sẽ trống. Nếu phần tử là duy nhất, thì tập hợp sẽ được tạo thành chỉ một chỉ mục. 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 chức năng 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: 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 yếu tố trong danh sách, mà còn để truy xuất các yếu tố đó. Bạn có thể hỏi những câu hỏi rất cụ thể:
Mã hoàn chỉnh của thư viện Python tìm kiếm nhị phân này có thể được tìm thấy tại liên kết bên dưới: Đệ quyĐể đơn giản, bạn sẽ chỉ xem xét phiên bản đệ quy của 06, cho bạn biết nếu một phần tử được tìm thấy.recursive version of 06, which tells you if an element was found.Cách tiếp cận đơn giản nhất là lấy 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 lát để cắt danh sách: 9Thay vì lặp lại, bạn kiểm tra điều kiện một lần và đôi khi gọi cùng một hàm trong danh sách nhỏ hơn. Điều gì có thể sai với điều đó? Chà, hóa ra việc cắt lát tạo ra các bản sao của các tài liệu tham khảo phần tử, có thể có bộ nhớ và chi phí tính toán đáng chú ý.copies of element references, which can have noticeable memory and computational overhead. Để 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 chức năng bất cứ khi nào cần thiết: 0Nhược điểm là mỗi khi bạn muốn gọi chức năng đó, 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: >>> 1Nếu bạn đã phạm sai lầm, thì nó có khả năng không tìm thấy yếu tố đó. Bạn có thể cải thiện điều này bằng cách sử dụng các đối số chức năng mặc định hoặc bằng cách giới thiệu chức năng trợ giúp ủy thác cho một hàm đệ quy: 2Đi xa hơn, bạn có thể thích tổ chức năng này một hàm khác để ẩn các chi tiết kỹ thuật và tận dụng việc tái sử dụng biến từ phạm vi bên ngoài: 3Hàm bên trong 16 có thể truy cập cả các tham số 17 và 18 mặc dù chúng đã được xác định trong phạm vi kèm theo. Vòng đời và khả năng hiển thị của các biến trong Python được quyết định bởi cái gọi là quy tắc LegB, cho biết người phiên dịch tìm kiếm các biểu tượng theo thứ tự sau:LEGB rule, which tells the interpreter to look for symbols in the following order:
Điều này cho phép các biến được xác định trong phạm vi bên ngoài được truy cập từ trong các khối mã lồng nhau. Sự lựa chọn giữa một lần lặp lại và thực hiện đệ quy thường là kết quả ròng của các cân nhắc về hiệu suất, sự tiện lợi, cũng như sở thích cá nhân. Tuy nhiên, cũng có những rủi ro nhất định liên quan đến đệ quy, đó là một trong những chủ đề của phần tiếp theo. Bao gồm các chi tiết khó khănTại đây, những gì tác giả của nghệ thuật lập trình máy tính nói về việc thực hiện thuật toán tìm kiếm nhị phân:
Nếu điều đó không ngăn cản bạn đủ từ ý tưởng tự viết thuật toán, thì có lẽ điều này sẽ xảy ra. Thư viện tiêu chuẩn trong Java đã có một lỗi tinh tế trong việc thực hiện tìm kiếm nhị phân, vẫn chưa được khám phá trong một thập kỷ! Nhưng bản thân lỗi theo dõi nguồn gốc của nó sớm hơn thế nhiều. Danh sách sau đây không đầy đủ, nhưng đồng thời, nó không nói về những sai lầm phổ biến như quên sắp xếp danh sách. Tràn số nguyênĐây là lỗi Java vừa được đề cập. Nếu bạn nhớ lại, thuật toán Python tìm kiếm nhị phân kiểm tra phần tử giữa của phạm vi giới hạn trong một bộ sưu tập được sắp xếp. Nhưng làm thế nào là phần tử trung gian đó được chọn chính xác? Thông thường, bạn lấy trung bình của ranh giới thấp hơn và trên để tìm chỉ số giữa: 4Phương pháp tính toán trung bình này hoạt động tốt trong phần lớn các trường hợp. Tuy nhiên, một khi việc thu thập các phần tử trở nên đủ lớn, tổng của cả hai ranh giới won won phù hợp với kiểu dữ liệu số nguyên. Nó sẽ lớn hơn giá trị tối đa được phép cho các số nguyên. Một số ngôn ngữ lập trình có thể gây ra lỗi trong các tình huống như vậy, điều này sẽ ngay lập tức dừng thực thi chương trình. Thật không may, điều đó không phải lúc nào cũng như vậy. Ví dụ, Java âm thầm bỏ qua vấn đề này, để giá trị lật xung quanh và trở thành một số dường như ngẫu nhiên. Bạn chỉ biết về vấn đề này miễn là số kết quả xảy ra là âm, ném một 19.Ở đây, một ví dụ thể hiện hành vi này trong JShell, giống như một thông dịch tương tác cho Java: 5Một cách an toàn hơn để tìm chỉ số giữa có thể tính toán phần bù trước và sau đó thêm nó vào ranh giới thấp hơn: 6Ngay cả khi cả hai giá trị được tối đa, tổng trong công thức trên sẽ không bao giờ được. Có một vài cách nữa, nhưng tin tốt là bạn không cần phải lo lắng về bất kỳ cách nào trong số này, bởi vì Python không có lỗi tràn số nguyên. Không có giới hạn trên về cách các số nguyên lớn có thể là ngoài bộ nhớ của bạn: >>> 7Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.Stack OverflowVề mặt lý thuyết, vấn đề tràn của ngăn xếp có thể liên quan đến việc thực hiện đệ quy của tìm kiếm nhị phân. Hầu hết các ngôn ngữ lập trình áp đặt giới hạn về số lượng các cuộc gọi chức năng 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 một ngăn xếp. Trong Python, giới hạn mặc định là một vài nghìn cấp của các cuộc gọi như vậy:stack overflow problem may, theoretically, concern the recursive implementation of binary search. Most programming languages impose a limit on the number of nested function calls. Each call is associated with a return address stored on a stack. In Python, the default limit is a few thousand levels of such calls: >>> 8Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.Stack Overflowinfinite recursion error to arise if the stopping condition is stated incorrectly due to a bug. In such a case, the infinite recursion will eventually cause a stack overflow. Về mặt lý thuyết, vấn đề tràn của ngăn xếp có thể liên quan đến việc thực hiện đệ quy của tìm kiếm nhị phân. Hầu hết các ngôn ngữ lập trình áp đặt giới hạn về số lượng các cuộc gọi chức năng 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 một ngăn xếp. Trong Python, giới hạn mặc định là một vài nghìn cấp của các cuộc gọi như vậy: >>> 9Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.Stack OverflowVề mặt lý thuyết, vấn đề tràn của ngăn xếp có thể liên quan đến việc thực hiện đệ quy của tìm kiếm nhị phân. Hầu hết các ngôn ngữ lập trình áp đặt giới hạn về số lượng các cuộc gọi chức năng 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 một ngăn xếp. Trong Python, giới hạn mặc định là một vài nghìn cấp của các cuộc gọi như vậy: >>> 0Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.Stack Overflowalgorithm stability, applies to sorting algorithms. Some are stable, meaning they don’t change the relative positions of equivalent elements. Others don’t make such guarantees. If you ever need to sort elements by multiple criteria, then you should always start from the least significant key to retain stability. Về mặt lý thuyết, vấn đề tràn của ngăn xếp có thể liên quan đến việc thực hiện đệ quy của tìm kiếm nhị phân. Hầu hết các ngôn ngữ lập trình áp đặt giới hạn về số lượng các cuộc gọi chức năng 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 một ngăn xếp. Trong Python, giới hạn mặc định là một vài nghìn cấp của các cuộc gọi như vậy:Điều này đã giành được đủ cho rất nhiều chức năng đệ quy. Tuy nhiên, nó rất khó có khả năng tìm kiếm nhị phân ở Python sẽ cần nhiều hơn do tính chất logarit của nó. Bạn cần một bộ sưu tập hai đến sức mạnh của ba ngàn yếu tố. Đó là một số với hơn chín trăm chữ số! >>> 1Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.>>> 2Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.>>> 3Tuy nhiên, có một cái bắt. Khi bạn gọi các chức năng từ thư viện, mã đó có thể phải tuân theo các ràng buộc ngôn ngữ C và vẫn gây ra tràn. Có rất nhiều thư viện dựa trên ngôn ngữ C trong Python. Bạn thậm chí có thể xây dựng mô-đun mở rộng C của riêng mình hoặc tải một thư viện được liên kết động vào Python bằng 20.floating-point rounding error.Nếu bạn cần phải làm việc với các số điểm nổi, thì bạn nên thay thế khớp chính xác bằng một so sánh gần đúng. Hãy cùng xem xét hai biến với các giá trị hơi khác nhau:approximate comparison. Let’s consider two variables with slightly different values: >>> 4So sánh thường xuyên cho kết quả âm, mặc dù cả hai giá trị gần như giống hệt 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ố khu phố nhỏ không: >>> 5So sánh thường xuyên cho kết quả âm, mặc dù cả hai giá trị gần như giống hệt 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ố khu phố nhỏ không: >>> 6So sánh thường xuyên cho kết quả âm, mặc dù cả hai giá trị gần như giống hệt 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ố khu phố nhỏ không: 7Khu phố đó, đó 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: 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:Mặt khác, việc triển khai tìm kiếm nhị phân trong Python chỉ dành riêng cho các số điểm nổi. Bạn không thể sử dụng nó để tìm kiếm bất cứ thứ gì khác mà không gặp lỗi. Phân tích độ phức tạp không gian thời gian của tìm kiếm nhị phân Phần sau đây sẽ không chứa mã và một số khái niệm toán học.space-time tradeoff and is useful in evaluating an algorithm’s complexity. Trong điện toán, bạn có thể tối ưu hóa hiệu suất của khá nhiều thuật toán với chi phí sử dụng bộ nhớ tăng. Chẳng hạn, bạn đã thấy rằng một tìm kiếm dựa trên băm của bộ dữ liệu IMDB yêu cầu thêm 0,5 GB bộ nhớ để đạt được tốc độ vô song.Ngược lại, để lưu băng thông, bạn đã nén một luồng video trước khi gửi nó qua mạng, tăng số lượng công việc phải làm. Hiện tượng này được gọi là sự đánh đổi không gian thời gian và rất hữu ích trong việc đánh giá độ phức tạp của thuật toán.computation time as well as the amount of memory it uses. Comparing the complexity of various algorithms allows you to make an informed decision about which is better in a given situation. Độ phức tạp không gian thời gian Độ phức tạp tính toán là một thước đo tương đối về số lượng tài nguyên mà một thuật toán cần phải thực hiện công việc của mình. Các tài nguyên bao gồm thời gian tính toán cũng như lượng bộ nhớ mà nó sử dụng. So sánh sự 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ề cái nào tốt hơn trong một tình huống nhất định. 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 so với một bộ dữ liệu lớn. Nó rõ ràng từ các phép đo rằng một tìm kiếm nhị phân nhanh hơn một tìm kiếm tuyến tính. Bạn thậm chí có thể nói bằng yếu tố nào.elementary operation that gets called a lot and consistently takes about the same time to run. For search algorithms, such an operation might be the comparison of two elements. 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 một chút hoặc có lẽ hoàn toàn khác nhau. Có những yếu tố vô hình khi chơi 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 aren luôn luôn 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?relationship between the number of elementary operations executed versus the size of the input. Formally, such a relationship is a mathematical function. However, you’re not interested in looking for its exact algebraic formula but rather estimating its overall shape. Bước đầu tiên là chia thuật toán thành các phần nhỏ hơn và tìm một phần đang làm nhiều công việc nhất. Nó có khả năng sẽ là một hoạt động cơ bản được gọi là rất nhiều và luôn mất khoảng thời gian để 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 của hai yếu tố. Đã thiết lập điều đó, bây giờ bạn có thể phân tích thuật toán. Để tìm sự phức tạp về thời gian, bạn muốn mô tả mối quan hệ giữa số lượng các hoạt động 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 loại chức năng nổi tiếng mà hầu hết các thuật toán đều phù hợp. Một 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ó theo thang điểm:
số mũ yếu tốasymptotic complexity, which describes the behavior under very large data sets. This simplifies the function formula by eliminating all terms and coefficients but the one that grows at the fastest rate (for example, n squared). Điều này có thể cung cấp cho bạn một ý tưởng về hiệu suất của thuật toán mà bạn đang xem xét. Một độ phức tạp không đổi, bất kể kích thước đầu vào, là thứ mong muốn nhất. Một độ phức tạp logarit vẫn còn khá tốt, cho thấy một kỹ thuật phân chia và chinh phục đang sử dụng. Càng ở phía bên phải trên thang đo này, sự phức tạp của thuật toán càng kém, bởi vì nó có nhiều việc phải làm hơn. Khi bạn nói về độ phức tạp về thời gian, ý nghĩa của bạn thường là sự phức tạp tiệm cận, mô tả hành vi trong các bộ dữ liệu rất lớn. Điều này đơn giản hóa công thức chức năng bằng cách loại bỏ tất cả các thuật ngữ và hệ số nhưng một điều khoản phát triển với tốc độ nhanh nhất (ví dụ: n bình phương). 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 O lớn.Big O notation. Ký hiệu O lớnKý hiệu O lớn đại diện cho trường hợp xấu nhất về sự 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, nó là một thước đo rất thô về tốc độ tăng trưởng ở đuôi của hàm mô tả sự phức tạp. Bạn phát âm nó là một thứ lớn của OH OH của một cái gì đó:Big O notation represents the worst-case scenario of asymptotic complexity. Although this might sound rather intimidating, you don’t need to know the formal definition. Intuitively, it’s a very rough measure of the rate of growth at the tail of the function that describes the complexity. You pronounce it as “big oh” of something: Đó là một thứ gì đó khác thường là một chức năng của kích thước dữ liệu hoặc chỉ là một chữ số, một trong số đó là không đổi. Ví dụ, thuật toán tìm kiếm tuyến tính có độ phức tạp về thời gian là 24, trong khi tìm kiếm dựa trên băm có độ phức tạp 25.Trong cuộc sống thực, ký hiệu O lớn được sử dụng ít chính thức hơn là cả 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 chức năng chính xác. Sự phức tạp của tìm kiếm nhị phânBạn sẽ ước tính độ phức tạp thời gian tiệm cận của tìm kiếm nhị phân bằng cách xác định số lượng so sánh trong kịch bản trường hợp xấu nhất khi một yếu tố bị thiếu là một hàm có 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:
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 các giá trị lấy mẫu nhãn cầu:tabular method is about collecting empirical data, putting it in a table, and trying to guess the formula by eyeballing sampled values:
Số lượng so sánh tăng lên khi bạn tăng số lượng các yếu tố trong bộ sưu tập, nhưng tốc độ tăng trưởng chậm hơn so với khi nó là hàm tuyến tính. Đó là một 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 bạn, bạn có thể thử phương thức đồ họa, giúp trực quan hóa dữ liệu được lấy mẫu bằng cách vẽ biểu đồ:graphical method, which visualizes the sampled data by drawing a graph: Các điểm dữ liệu dường như phủ lên với một đường cong, nhưng bạn không có đủ thông tin để cung cấp câu trả lời kết luận. Nó có thể là một đa thức, có biểu đồ bật lên và xuống cho các đầu vào lớn hơn. Thực hiện 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 các yếu tố thu hẹp trong mỗi bước của thuật toán:analytical approach, you can choose some relationship and look for patterns. For example, you might study how the number of elements shrinks in each step of the algorithm:
n/4 lần thứ 3 n/8 ⋮K-th n/2 k
Bây giờ bạn có thể:programming interview! Whether the binary search algorithm is an optimal solution to a particular problem, you have the tools to figure it out on your own. You don’t need a computer science degree to do so. Sử dụng mô -đun 8 để thực hiện tìm kiếm nhị phân trong PythonThực hiện tìm kiếm nhị phân trong Python đệ quy và lặp lại This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Creating a Binary Search in Python Làm thế nào để Python thực hiện thuật toán tìm kiếm nhị phân?Thực hiện tìm kiếm nhị phân trong Python.. # Phương pháp chức năng tìm kiếm nhị phân lặp đi lặp lại Triển khai Python .. # Nó trả về chỉ mục của n trong danh sách đã cho1 nếu có,. # khác trả về -1 .. def Binary_Search (list1, n):. thấp = 0 .. cao = len (list1) - 1 .. mid = 0 .. trong khi thấp Tìm kiếm nhị phân được thực hiện như thế nào?Tìm kiếm nhị phân hoạt động trên các mảng được sắp xếp.Tìm kiếm nhị phân bắt đầu bằng cách so sánh một phần tử ở giữa mảng với giá trị đích.Nếu giá trị đích khớp với phần tử, vị trí của nó trong mảng được trả về.Nếu giá trị đích nhỏ hơn phần tử, tìm kiếm tiếp tục ở nửa dưới của mảng.begins by comparing an element in the middle of the array with the target value. If the target value matches the element, its position in the array is returned. If the target value is less than the element, the search continues in the lower half of the array.
Python đã xây dựng trong tìm kiếm nhị phân?Khoa học dữ liệu thực tế sử dụng Python Bisect được sử dụng để tìm kiếm nhị phân.Kỹ thuật tìm kiếm nhị phân được sử dụng để tìm các yếu tố trong danh sách được sắp xếp.Bisect là một hàm thư viện.The bisect is used for binary search. The binary search technique is used to find elements in sorted list. The bisect is one library function.
Làm thế nào để tìm kiếm hoạt động trong Python?Trong Python, cách dễ nhất để tìm kiếm đối tượng là sử dụng các nhà khai thác thành viên - được đặt tên theo cách đó vì chúng cho phép chúng tôi xác định xem một đối tượng nhất định có phải là thành viên trong bộ sưu tập hay không.Các nhà khai thác này có thể được sử dụng với bất kỳ cấu trúc dữ liệu có thể lặp lại trong Python, bao gồm chuỗi, danh sách và bộ dữ liệu.use Membership Operators - named that way because they allow us to determine whether a given object is a member in a collection. These operators can be used with any iterable data structure in Python, including Strings, Lists, and Tuples. |