JavaRush /Blog Java /Random-VI /Harvard CS50: Bài tập tuần 3 (Bài 7 và 8), Phần 1
Masha
Mức độ

Harvard CS50: Bài tập tuần 3 (Bài 7 và 8), Phần 1

Xuất bản trong nhóm
Các bài giảng của khóa học Harvard về nguyên tắc lập trình CS50 Tài liệu bổ sung: ký hiệu tiệm cận, thuật toán sắp xếp và tìm kiếm Phần hai. "Thẻ" trong C

Sự chuẩn bị

Trước khi làm bài, xem bài giảng 7-8 , đọc và nghiên cứu kỹ “ Tài liệu bổ sung của tuần thứ ba ”. Họ tập trung vào các thuật toán tìm kiếm (tuyến tính và nhị phân), sắp xếp (có rất nhiều thuật toán!), cũng như công việc của trình gỡ lỗi (khả năng làm việc với trình gỡ lỗi để gỡ lỗi chương trình là một kỹ năng cực kỳ quan trọng!). Nếu mọi thứ diễn ra như bình thường với các bài giảng và lý thuyết, bạn có thể dễ dàng trả lời các câu hỏi kiểm tra:
  • Tại sao tìm kiếm nhị phân yêu cầu một mảng được sắp xếp?
  • Tại sao sắp xếp bong bóng được ước tính là O(n2)?
  • Tại sao ước tính sắp xếp chèn là Ω(n)?
  • Sắp xếp lựa chọn hoạt động như thế nào? Mô tả trong ba câu (hoặc ít hơn).
  • Giới hạn trên (trường hợp xấu nhất) về thời gian có thể chạy loại hợp nhất là bao nhiêu?
  • Trình gỡ lỗi GDB cho phép bạn gỡ lỗi một chương trình. Và nếu bạn xây dựng công thức cụ thể hơn, chính xác thì nó cho phép bạn làm gì?

Bàn thắng

  • Tìm hiểu cách làm việc với các dự án chứa nhiều tệp
  • Học cách đọc mã nguồn của người khác
  • Hiểu các thuật toán và hàm đệ quy khác nhau
Hầu hết các mục tiêu này thực tế không thể đánh giá chính thức được. Do đó, từ quan điểm xác minh chính thức các vấn đề, có rất ít điều có vẻ khó khăn đối với bạn. Tuy nhiên, chúng tôi xin nhắc bạn: bạn chỉ có thể học lập trình thông qua thực hành liên tục! Do đó, chúng tôi khuyến khích bạn không chỉ giải quyết các nhiệm vụ mà còn dành thêm thời gian, công sức và thực hiện tất cả các thuật toán đã được thảo luận trong tuần này. Phía trước!

Bắt đầu

Hãy nhớ lại rằng đối với các bài tập thực hành ở tuần một và tuần hai, bạn đã viết chương trình từ đầu và tạo các thư mục pset1pset2 của riêng mình bằng lệnh mkdir . Đối với bài tập thực hành của tuần thứ ba, bạn cần tải xuống bản phân phối (hoặc "bản phân phối" như chúng tôi gọi) mà chúng tôi đã viết và thêm các dòng mã của riêng bạn vào đó. Đầu tiên, hãy đọc mã của chúng tôi và cố gắng hiểu nó. Kỹ năng quan trọng nhất tuần này là học cách đọc mã của người khác. Vì vậy, hãy đăng nhập vào cs50.io và chạy lệnh update50 trong cửa sổ terminal để đảm bảo phiên bản không gian làm việc được cập nhật. Nếu bạn vô tình đóng cửa sổ terminal và không thể tìm thấy nó, hãy chuyển đến menu View và đảm bảo rằng tùy chọn Console đã được chọn (kiểm tra nếu không). Bấm vào (+), bên trong vòng tròn xanh trên khung cửa sổ terminal, chọn New Terminal . Harvard CS50: Bài tập tuần 3 (Bài 7 và 8), Phần 1 - 1 Sau đó, chạy lệnh cd ~/workspace và đảm bảo bạn đang ở trong thư mục không gian làm việc (đây là thư mục của bạn). Sau đó, chạy lệnh: wget http://cdn.cs50.net/2015/fall/psets/3/pset3/pset3.zip để tải kho lưu trữ ZIP của sách bài tập về không gian làm việc của bạn (wget là lệnh tải xuống Linux). Nếu mọi thứ đều ổn, bạn sẽ thấy cụm từ sau trong dòng: 'pset3.zip' saved Đảm bảo rằng bạn thực sự đã tải xuống pset3.zip bằng cách chạy lệnh: ls rồi chạy unzip pset3.zip để giải nén tệp. Nếu bây giờ bạn chạy lại lệnh ls , bạn cũng sẽ thấy thư mục pset3 . Vào đó bằng cách chạy lệnh cd pset3 rồi yêu cầu xem lại nội dung của thư mục: ls bạn sẽ thấy trong thư mục này có hai thư mục con: fifteen find Đã hấp dẫn rồi!

Tìm kiếm

Bây giờ chúng ta hãy đi sâu vào một trong những thư mục con này. Để thực hiện việc này, chúng ta sẽ chạy lệnh: cd ~/workspace/pset3/find Nếu bạn hiển thị nội dung của thư mục này trên màn hình (có thể bạn đã nhớ cách thực hiện việc này), đây là những gì bạn sẽ thấy: helpers.c helpers.h Makefile find.c generate.c Ồ, có rất nhiều tệp. Nhưng đừng lo lắng, chúng ta sẽ giải quyết chúng ngay bây giờ. Tệp generate.c chứa mã cho một chương trình sử dụng "trình tạo số giả ngẫu nhiên" (được tạo bởi hàm drand48 ) để tạo ra một số lượng lớn các số ngẫu nhiên (thực ra là giả ngẫu nhiên, máy tính không thể xử lý số ngẫu nhiên thuần túy!) , và đặt từng cái một trong một dòng. Biên dịch chương trình: make generate Bây giờ hãy chạy nó bằng cách chạy lệnh: ./generate Chương trình sẽ đưa ra thông báo sau: Usage: generate n [s] Điều này có nghĩa là chương trình mong đợi một hoặc hai đối số dòng lệnh. Sử dụng đối số đầu tiên, n, là bắt buộc; con số này có nghĩa là bạn muốn tạo bao nhiêu số giả ngẫu nhiên. Tham số s là tùy chọn, được biểu thị bằng dấu ngoặc vuông. Số s có thể được gọi là "hạt giống" cho trình tạo số giả ngẫu nhiên. Bởi "hạt giống" ý chúng tôi là dữ liệu đầu vào của trình tạo số giả ngẫu nhiên ảnh hưởng đến đầu ra của nó. Ví dụ: nếu bạn đang sử dụng drand48, trước tiên Bằng cách gọi srand48 (một hàm khác có mục đích là "gieo mầm" drand48) với đối số là 1 và sau đó gọi drand48 ba lần, drand48 có thể trả về 2728, rồi 29785, rồi 54710. Nếu bạn thay vì gọi drand48 trước đó, hãy gọi srand48 với đối số là 2, sau đó sử dụng lại drand48 ba lần, drand48 có thể trả về 59797, rồi 10425, rồi 37569. Nhưng nếu bạn nhìn thấy lại drand48 bằng cách gọi lại srand48 với đối số là 1, kết quả của ba lần gọi tiếp theo tới drand48, bạn sẽ nhận lại 2728, rồi 29785, rồi 54710! Bạn thấy đấy, mọi thứ xảy ra đều có lý do. Chạy lại chương trình, lần này giả sử n=10, như minh họa bên dưới; bạn sẽ thấy danh sách 10 số giả ngẫu nhiên. ./generate 10 Hãy chạy chương trình lần thứ ba với cùng giá trị n; bạn sẽ thấy một danh sách khác gồm 10 số. Bây giờ hãy thử chạy chương trình với hai tham số. Hãy lấy s=0 như hình dưới đây. ./generate 10 0 Bây giờ hãy chạy lại lệnh tương tự: ./generate 10 0 Bạn thậm chí không thể tranh luận: bạn lại thấy cùng một chuỗi mười chữ số “ngẫu nhiên”. Đây là điều sẽ xảy ra nếu bạn không thay đổi hạt giống của trình tạo số giả ngẫu nhiên. Bây giờ chúng ta hãy xem chính chương trình generate.c(nhớ làm thế nào?). Các nhận xét ở đầu tệp này giải thích chức năng chung của chương trình. Nhưng có vẻ như chúng ta đã quên bình luận về chính đoạn mã đó. Đọc kỹ mã và đọc nó cho đến khi bạn hiểu ý nghĩa của từng dòng. Sau đó, hãy nhận xét mã này cho chúng tôi, thay thế mỗi TODO bằng một cụm từ mô tả mục đích hoặc chức năng của dòng hoặc các dòng mã tương ứng. (lưu ý: unsigned int là int “unsigned”, nghĩa là nó không thể âm). Để biết thêm thông tin về rand hoặc srand, hãy chạy: man drand48 hoặc man srand48 Sau khi bạn đã nhận xét nhiều nhất có thể trong generate.c, hãy biên dịch lại chương trình để đảm bảo bạn không vi phạm bất cứ điều gì: make generate Nếu generate không còn biên dịch nữa, hãy sửa những gì bạn phá sản: )! Xin nhắc lại, lệnh make sẽ tự động biên dịch mã, do đó bạn không cần phải chạy lệnh clang bằng cách chèn một loạt công tắc theo cách thủ công. Nhưng trên thực tế, make chỉ đơn giản là đơn giản hóa việc nhập liệu của chúng ta, nhưng trên thực tế, đằng sau nó ẩn chứa tiếng kêu tương tự với các tham số chúng ta cần. Tuy nhiên, khi chương trình của bạn ngày càng lớn hơn, make không còn có thể tìm ra cách biên dịch mã từ ngữ cảnh nữa. Trong trường hợp này, bạn sẽ phải cho biết cách biên dịch chương trình, đặc biệt nếu chúng liên quan đến việc sử dụng các tệp nguồn khác nhau (chẳng hạn như .c). Để giải quyết vấn đề này, chúng tôi sẽ sử dụng các tệp cấu hình (Makefiles) để cho biết chính xác những gì cần làm. Làm thế nào lệnh make biết chúng ta nên biên dịch tạo như thế nào? Trên thực tế, nhóm đã sử dụng tệp cấu hình mà chúng tôi đã viết sẵn. Tệp này được gọi là Makefile và nó nằm trong cùng thư mục với generate.c . Makefile là danh sách các quy tắc chỉ định cách tạo tệp được tạo từ generate.c. Cụ thể, trong tệp bạn sẽ tìm thấy các dòng có liên quan: generate: generate.c clang -ggdb3 -O0 -std=c11 -Wall -Werror -o generate generate.c Dòng đầu tiên cho biết rằng "mục tiêu" có tên là tạo phải được tạo bằng cách gọi lệnh từ dòng thứ hai. Hơn nữa, dòng đầu tiên cho biết việc tạo đó phụ thuộc vào generate.c, có nghĩa là việc tạo sẽ chỉ xây dựng lại tạo trong các lần chạy tiếp theo nếu tệp đó đã bị thay đổi. Một thủ thuật tiết kiệm thời gian không tồi phải không? Trên thực tế, hãy chạy lại lệnh bên dưới nếu bạn không thay đổi generate.c . make generate Bạn sẽ được thông báo rằng việc tạo đã được cập nhật lên phiên bản hiện tại. Lưu ý : Dấu thụt lề ở đầu dòng thứ hai không phải là một chuỗi khoảng trắng mà là ký tự tab. Thật không may, make yêu cầu các lệnh phải được đặt trước các tab, vì vậy hãy cẩn thận đừng thay đổi chúng thành dấu cách, nếu không bạn sẽ gặp phải các lỗi lạ! Cờ -Werror báo lệnh kêu vangcoi các cảnh báo (xấu) là lỗi (thậm chí còn tệ hơn), vì vậy bạn sẽ buộc phải sửa chúng (theo cách tốt, mang tính giáo dục!) Bây giờ chúng ta hãy nhìn vào file find.c. Lưu ý rằng chương trình này yêu cầu một đối số dòng lệnh: "igloo", đối số này phải được tìm thấy trong một "đống cỏ khô" gồm các giá trị. Sau đó, xem lại mã và biên dịch chương trình bằng cách chạy lệnh bên dưới. make find make về cơ bản đã cho chúng tôi những điều sau: clang -ggdb3 -O0 -std=c11 -Wall -Werror -o find find.c helpers.c -lcs50 -lm Hãy chú ý! Bạn vừa biên soạn một ứng dụng bao gồm một nhưng hai tệp: helpers.cfind.c . Làm sao biết được điều này? Để hiểu điều này, hãy mở lại Makefile để xem điều gì đang thực sự diễn ra ở đó. Các dòng có liên quan dưới đây. find: find.c helpers.c helpers.h clang -ggdb3 -O0 -std=c11 -Wall -Werror -o find find.c helpers.c -lcs50 -lm Ý của chúng tôi về sự phụ thuộc (sau dấu hai chấm) là bất kỳ thay đổi nào đối với find.c , helpers.c hoặc helpers.h sẽ buộc make phải xây dựng lại find vào lần tiếp theo nó được gọi cho những mục đích đó. Bây giờ, hãy chạy chương trình này bằng cách thực hiện các thao tác sau: Ví dụ: ./find 13 Sau đó, bạn sẽ được yêu cầu cung cấp một ngăn xếp nhất định (nghĩa là các số nguyên) và cho chúng ăn từng ống hút một. Khi đã chán việc gõ số, hãy nhấn tổ hợp phím Ctrl-D . Sự kết hợp này sẽ gửi cho chương trình một ký tự cuối tệp (EOF). Biểu tượng sẽ buộc hàm GetInt từ thư viện CS50 trả về hằng số INT_MAX và điều này, đến lượt nó, trong find.c sẽ buộc find dừng gõ "stack". Bây giờ chương trình sẽ tìm kiếm cái kim trong đống cỏ khô mà bạn đã cung cấp và cuối cùng nó sẽ cho bạn biết liệu nó có được tìm thấy hay không. Nói tóm lại, chương trình tìm kiếm một số giá trị trong một mảng. Ít nhất thì cô ấy nên làm vậy, nhưng điều đáng chú ý là cô ấy vẫn chưa tìm thấy gì! Nhưng ở đây bạn đến để giải cứu! Chúng ta sẽ nói về tầm quan trọng của vai trò của bạn sau. Trên thực tế, quá trình cung cấp đống cỏ khô có thể được tự động hóa, ít nhất bằng cách "hợp nhất" đầu ra của generate thành find làm đầu vào. Ví dụ: lệnh bên dưới chuyển 1000 số giả ngẫu nhiên để tìm, sau đó tìm kiếm 42 trong số các giá trị đó. ./generate 1000 | ./find 42 Lưu ý rằng khi tạo chuyển dữ liệu thô cần tìm, bạn sẽ không thấy số được tạo mà sẽ thấy tìm đang chạy . Ngoài ra, bạn có thể "chuyển hướng" đầu ra của generate sang một tệp bằng lệnh như sau: ./generate 1000 > numbers.txt Nội dung của tệp này có thể được chuyển hướng đến đầu vào của find bằng lệnh: ./find 42 < numbers.txt Chúng ta hãy xem lại mã trong Makefile và chú ý dòng sau: all: find generate Điều này có nghĩa là bạn có thể xây dựng tạo và tìm bằng cách chạy lệnh sau: make all Hơn nữa, lệnh bên dưới dòng này tương đương với lệnh phía trên nó, vì make xây dựng mục nhập đầu tiên trong Makefile theo mặc định. make Giá như bạn có thể tổng hợp tất cả các nhiệm vụ thực hành này thành một lệnh! Nhưng - than ôi! Cuối cùng, hãy chú ý đến những dòng cuối cùng này trong Makefile: clean: rm -f *.o a.out core find generate Mục này cho phép bạn xóa tất cả các tệp kết thúc bằng .o hoặc được gọi là lõi (chúng tôi sẽ giải thích điều này ngay lập tức!), đồng thời chạy các chương trình tìm hoặc tạo một cách đơn giản bằng cách thực thi dòng: Nếu bạn muốn make clean thử nghiệm thì đây là điều cần cẩn thận: không thêm, chẳng hạn *.c vào dòng cuối cùng của Makefile! (tại sao?) Tất cả các dòng bắt đầu bằng dấu # chỉ là nhận xét.

Nhiệm vụ 1: Tìm kiếm

Đã đến lúc có điều gì đó thú vị! Lưu ý rằng find.c gọi search , một hàm được khai báo trong helpers.h . Thật không may, chúng ta đã quên triển khai đầy đủ chức năng này trong helpers.c ! (Cần lưu ý rằng chúng ta có thể đặt nội dung của helpers.hhelpers.c vào một find.c. Nhưng đôi khi tốt hơn nên tách các chương trình thành nhiều tệp. Đặc biệt nếu một số chức năng, hay đúng hơn là các chức năng tiện ích, có thể hữu ích cho các chương trình khác. Ví dụ như các hàm thư viện CS50. Hãy xem helpers.c và bạn sẽ thấy rằng tìm kiếm luôn trả về false, bất kể giá trị đã cho có nằm trong các giá trị hay không. Viết lại tìm kiếm để nó sử dụng tìm kiếm tuyến tính, trả về true , nếu giá trị nằm trong giá trị và sai nếu giá trị không nằm trong giá trị. Hãy cẩn thận trả về sai ngay lập tức nếu n không dương. Khi bạn đã sẵn sàng kiểm tra tính hợp lệ, hãy thử gọi lệnh sau: Vì một trong các số được ./generate 1000 50 | ./find 127 in với generate khi 50 được gieo hạt là 127, mã của bạn nên tìm kim! Ngược lại, hãy thử lệnh này: Vì ./generate 1000 50 | ./find 128 128 không nằm trong tập hợp các số được tạo bởi generate khi 50 được gieo hạt, mã của bạn không cần phải tìm "kim" . Chạy các thử nghiệm khác bằng cách chạy tạo với một số hạt giống, phân tích đầu ra và tìm kiếm cái kim trong đống cỏ khô. Lưu ý rằng main trong find.c được viết theo cách find trả về 0 nếu tìm thấy "kim", nếu không thì trả về 1. Bạn có thể kiểm tra cái gọi là "mã đầu ra" mà main trả về khi được thực thi sau khi chạy một số mã khác lệnh echo $? . Ví dụ: nếu việc triển khai tìm kiếm của bạn là chính xác, nếu bạn chạy, ./generate 1000 50 | ./find 127 echo $? bạn sẽ thấy 0, trong khi 127 nằm trong số 1000 số được tạo ra bằng cách tạo với hạt giống là 50, do đó tìm kiếm bạn viết sẽ trả về đúng. Trong trường hợp này, main (do chúng tôi viết) sẽ trả về 0 (nghĩa là thoát). Nếu bạn cung cấp thông tin đầu vào sau ./generate 1000 50 | ./find 128 echo $? , bạn sẽ thấy 1 vì 128 không nằm trong số 1000 số được tạo ra bằng cách tạo với hạt giống 50. Trong trường hợp này, tìm kiếm (do bạn viết) sẽ trả về sai và chính (do chúng tôi viết ) sẽ trả về 1 (và sau đó hoàn thành công việc). Bạn có hiểu logic không? Khi mọi thứ đã sẵn sàng để kiểm tra bằng check50, hãy chạy lệnh sau: check50 2015.fall.pset3.find helpers.c Nhân tiện, bạn không nên làm quen với việc kiểm tra mã của mình bằng check50 trước khi tự kiểm tra mã đó. Xét cho cùng, check50 không thực sự tồn tại, vì vậy việc chạy mã với các mẫu đầu vào của riêng bạn, so sánh kết quả thực tế với kết quả mong đợi, là thói quen tốt nhất bạn có thể áp dụng vào thời điểm này. Đúng đấy, đừng nghiện nhé! Nếu bạn muốn thử nghiệm việc triển khai tìm kiếm của trợ lý cs50, hãy chạy lệnh này: ~cs50/pset3/find

Sắp xếp

Tìm kiếm tuyến tính không phải là thứ thực sự ấn tượng, nhưng từ bài giảng đầu tiên (và trong bài giảng thứ bảy, chúng tôi đã lặp lại thủ thuật này một lần nữa!) Bạn hãy nhớ rằng bạn có thể tìm kim đáy bể nhanh hơn nhiều. Nhưng trước tiên chúng ta cần sắp xếp đống cỏ khô của mình. Lưu ý rằng find.c gọi Sort , một hàm được khai báo trong helpers.h . Thật không may, chúng tôi “quên” triển khai đầy đủ tính năng này trong helpers.c ! Nhìn vào helpers.c và bạn sẽ thấy kiểu sắp xếp đó trả về ngay lập tức, mặc dù chức năng chính của find thực sự chuyển mảng thực tế cho nó. Bây giờ hãy nhớ cú pháp khai báo mảng. Bạn không chỉ chỉ định loại phần tử của mảng này mà còn chỉ định kích thước của nó trong dấu ngoặc vuông. Đây là những gì chúng tôi làm cho haystack trong find.c : int haystack [MAX]; Nhưng khi duyệt một mảng, bạn chỉ xác định tên của nó. Và chúng ta làm điều đó theo cách tương tự khi chúng ta duyệt qua đống cỏ khô để sắp xếp trong find.c : sort (haystack, size); (Đoán xem tại sao chúng ta chuyển kích thước của mảng đó một cách riêng biệt?) Khi chúng ta khai báo một hàm lấy mảng một chiều làm đối số, chúng ta không cần chỉ định kích thước của mảng. Tương tự như vậy, chúng ta đã không làm điều này khi khai báo sắp xếp trong helpers.h (và helpers.c): void sort (int values [] int n); Thực hiện sắp xếp để hàm thực sự sắp xếp mảng số từ nhỏ đến lớn. Nó cần thời gian chạy bằng O(n 2 ), trong đó n là kích thước của mảng. Bạn có thể muốn triển khai sắp xếp bong bóng, sắp xếp lựa chọn hoặc sắp xếp chèn như chúng ta đã tìm hiểu về những điều đó trong tuần thứ ba. Tuy nhiên, điều quan trọng cần lưu ý là: không có cách nào “chính xác” để triển khai các thuật toán này. Có một số lượng lớn các biến thể. Trên thực tế, bạn luôn có thể cải thiện chúng nếu thấy phù hợp, miễn là việc triển khai của bạn hội tụ đến O(n2 ) . Tuy nhiên, hãy để việc thử nghiệm cho phần thân hàm và để đơn giản hóa việc kiểm tra, đừng thay đổi khai báo sắp xếp của chúng ta. Nó sẽ trông như thế này: void sort (int values [] int n); Vì hàm trả về một giá trị void nên nó không trả về một mảng đã được sắp xếp. Thay vào đó, nó phải sắp xếp "phá hủy" mảng thực tế mà nó đang "chạy" qua, di chuyển các phần tử của nó. Trong tuần thứ tư, chúng ta sẽ thảo luận về việc mảng được truyền theo tham chiếu chứ không phải theo giá trị. Nghĩa là, sắp xếp sẽ không nhận được bản sao của mảng mà là chính mảng ban đầu. Mặc dù bạn không thể thay đổi khai báo sắp xếp của chúng tôi, nhưng bạn luôn có thể xác định hàm của riêng mình trong helpers.c, sau đó có thể được gọi từ sắp xếp. Hãy tự quyết định cách tốt nhất để kiểm tra việc thực hiện sắp xếp của bạn. Đừng quên rằng printf và GDB sẽ giúp bạn! Và đừng quên rằng bạn có thể tạo đi tạo lại cùng một chuỗi số giả ngẫu nhiên bằng cách chỉ định rõ ràng các giá trị hạt giống để tạo.

Tìm kiếm nhị phân, mẹo

Điều đầu tiên bạn cần hiểu về hàm find là chúng ta đã có sẵn code viết sẵn (phân phối). Chúng tôi chỉ đơn giản là điền vào một số khoảng trống trong mã hiện có. Chương trình find.c yêu cầu nhập các số (nghĩa là điền vào một "ngăn xếp"), sau đó tìm kiếm một "kim" trong đó theo yêu cầu của người dùng, sử dụng các hàm sắp xếp và tìm kiếm được xác định trong helpers.c . Vì vậy, find đã được viết sẵn, chúng ta cần viết helpers . Vì vậy, đây là những gì chúng ta cần làm:
  1. Thực hiện tìm kiếm. Hàm này sẽ trả về true nếu tìm thấy giá trị trong ngăn xếp và trả về false nếu không có giá trị đó.
  2. Triển khai sắp xếp, một hàm sắp xếp một mảng các giá trị.
Ban đầu, việc tìm kiếm được thực hiện tuyến tính. Nhưng bạn có thể làm tốt hơn. Thuật toán tìm kiếm tuyến tính chạy trong thời gian O(n) . Nhiệm vụ của bạn là viết thuật toán tìm kiếm nhị phân. Thời gian thực hiện của nó là O(log n) . Tuy nhiên, vấn đề của nó là nó cần dữ liệu được sắp xếp làm đầu vào, nếu không nó sẽ không hoạt động. Bạn còn nhớ ví dụ về cuốn sách bị rách và có thể bạn biết tại sao lại như vậy. Nếu bạn đã thực hiện tìm kiếm nhị phân thông qua các phần tử và không còn phần tử nào trong số chúng nữa (nghĩa là đơn giản là không có “kim” trong “ngăn xếp” này), bạn cần hàm trả về false. Tìm kiếm nhị phân có thể được thực hiện lặp đi lặp lại hoặc đệ quy (David Malan đã nói về đệ quy trong bài giảng thứ tám).
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION