Cong ty Cong Nghe Tin hoc Nha truong http://www.vnschool.net
Bài toán tìm theo khoảng với phương pháp tìm tuần tự, phương pháp lưới
13/05/2008

Cho một tập điểm trong mặt phẳng, một câu hỏi hiển nhiên là tìm các điểm rơi trong một vùng đã cho nào đó. “Liệt kê tên tất cả các quốc gia trong khu vực Đông Nam Á” là một câu hỏi thuộc loại này với tập điểm là các quốc gia trên bản đồ khu vực Đông Nam Á. Cũng có thể thấy một ví dụ điển hình trong thực tế “ Lịêt kê những người từ 20 đến 23 tuổi với mức thu nhập nào đó”.


Ta đưa bài toán về dạng tổng quát như sau: giả sử có một tập bản ghi với một thuộc tính nhất định có giá trị sắp xếp được. Tìm kiếm vùng là tìm tất cả những bản ghi thoả mãn các hạn chế phạm vi cho trước trên một tập các thuộc tính. Đây là một bài toán khó và quan trọng trong các ứng dụng thực tế

Chúng ta sẽ xét một phương pháp được tổng quát hoá trực tiếp từ các phương pháp đã biết về việc tìm kiếm theo những khoá đơn (một chiều). Ta coi các câu hỏi là đựơc đặt trên cùng một tập điểm, như vậy bài toán có thể chia làm hai phần: ta cần một thuật toán tiền xử lý để đưa các điểm đã cho vào một cấu trúc hỗ trợ có hiệu quả cho việc tìm kiếm vùng và một thuật toán tìm kiếm vùng, dùng cấu trúc trên để trả về các điểm rơi trong vùng đã cho. Sự phân biệt này là để so sánh các phương pháp khác nhau vì tổng chi phí không chỉ phụ thuộc vào sự phân bố các điểm mà còn vào số lượng và bản chất các câu hỏi.

Đến đây, chúng ta có thể hiểu “Bài toán tìm theo khoảng” nghĩa là tìm tất cả các điểm rơi trong khoảng cho trước. Điều này có thể làm được bằng cách sắp xếp các điểm và dùng phép tìm nhị phân để dò các điểm cuối cùng của khoảng đã cho, rồi trả lại tất cả các điểm rơi trên khoảng trên. Một biện pháp khác là xây dựng cây tìm kiếm nhị phân và thực hiện một phép duyệt đệ quy trên cây, trả về các điểm trong khoảng tìm và bỏ qua các điểm của cây nằm ở ngoài khoảng tìm. Nếu điểm cuối trên bên trái của khoảng tìm rơi vào bên trái của nút gốc, với mỗi nút ta gặp, kiểm tra xem giá trị của nút có rơi trong khoảng tìm hay không.

Chương trình có thể cải tiến hiệu quả hơn một chút bằng cách dùng một biên toàn cục a để lưu khoảng tìm hơn là truyền biến cho các lời đệ quy mà không thay đổi giá trị của nó. Như vậy ta có thấy:

Tìm kiếm theo khoảng có thể được thực hiện với O(NlogN) bước xử lý trước và O(R+logR) để tìm kiếm vùng, ở đây R là các điểm thực sự rơi trong khoảng tìm

Mục đích của chúng ta là sẽ đạt tới cùng thời gian thực hiện như trên khi tìm kiếm trên vùng nhiều chiều. Tham số R rất quan trọng: tạo thuận lợi để sinh các câu hỏi vùng, người dùng có thể dễ dàng phát biểu những câu hỏi yêu cầu tất cả hoặc hầu hết các điểm. Kiểu câu hỏi này được dùng trong nhiều ứng dụng người ta sẽ không cần đến các thuật giải phức tạp nếu mọi câu hỏi thuộc vào kiểu trên. Ta sẽ xét các thuật toán được thiết kế có hiệu quả cho các câu hỏi về một số lớn các điểm.

Phương pháp cơ bản (tuần tự)

Trong trường hợp 2 chiều,”vùng “ là một miền phẳng. Để đơn giản ta sẽ xét bài toán tìm tất cả các điểm có toạ độ x, y rơi trong các khoảng cho trước; nghĩa là ta sẽ tìm các điểm rơi trong một hình chữ nhật cho trước. Như vậy, ta sẽ giả thiết rằng kiểu HCN là một bản ghi có bốn số nguyên cho các điểm cuối theo chiều dọc và chiều ngang. Thao tác cơ bản của chúng ta là kiểm tra xem một điểm có rơi vào HCN đã cho không, như vậy ta sẽ dùng hàm Kiemtra(p: point ; r: HCN) để kiểm tra điều này, trả về tru nếu điểm p rơi trong r. Mục tiêu của chúng ta là tìm tất cả các điểm rơi trong hình chữ nhật đã cho, dùng càng ít lời gọi hàm Kiemtra càng tốt.

Phương pháp đơn giản nhất để giải bài toán này là tìm kiếm tuần tự: quét tất cả các điểm, kiểm tra xem mỗi điểm có rơi trong khoảng đã cho hay không (bằng cách gọi Kiemtra cho từng điểm). Trong thực tế, phương pháp này được dùng cho nhiều cơ sở dữ liệu vì nó dễ dàng được cải tiến bằng cách “làm thành đợt” các câu hỏi vùng, kiểm tra nhiều câu hỏi khác nhau trong cùng một lần quét qua các điểm. Trong cơ sở dữ liệu rất lớn, nơi mà các dữ liệu được lưu trong các thiết bị ngoài mà thời gian đọc dữ liệu là vượt xa chi phí cho các câu hỏi, các câu hỏi được gom lại trong bộ nhớ trong và tìm các điểm thoả các câu hỏi trong một lần duyệt tập tin dữ liệu ngoài. Tuy nhiên, nếu cách làm thành đợt không thuận tiện hay cơ sở dữ liệu nhỏ hơn, thì có các phương pháp tốt hơn nhiều

Một cải tiến đơn giản đầu tiên của phương pháp tìm kiếm tuần tự là áp dụng trực tiếp phương pháp cho vùng một chiều trênc các chiều được tìm kiếm. Hình sau sẽ cho một ví dụ tìm các điểm trong một hình chữ nhật

Một cách làm là tìm các điểm có hoành độ x rơi trong khoảng tìm x của hình chữ nhật , rồi kiểm tra tung độ y của các điểm này để xét các điểm có thuộc hình chữ nhật đã cho hay không. Như vậy các điểm không thuộc hình chữ nhật , do hoành độ x của chúng ở ngoài khoảng tìm, sẽ không bao giờ đựơc xét đến. Kỹ thuật này đựơc gọi là phép chiếu; rõ ràng ta cũng có dùng cách trên cho tung độ y. Trong ví dụ, ta kiểm tra các điểm E C H F và I khi chiếu theo x và ta cũng có thể kiểm tra O E F K P N và L khi chiếu theo y

Nếu các điểm phân bố đều trong một miền HCN, dễ tính được số trung bình các điểm được kiểm tra. Phần các điểm ta muốn tìm trong HCN đã cho là tỉ số của vùng chữ nhật với toàn miền; phần các điểm ta tìm theo chiều x là tỉ số giữa bề rộng của hình chữ nhật với chiều rộng của toàn miền; và tương tự theo chiều y. Trong ví dụ, ta dùng hình chữ nhật 4x6 trong miền 16x16 nghĩa là ta trống 3/32điểm trong hình chữ nhật, ¼ chúng trong phép chiéu x và 3/8 chúng theo phép chiếu y. Rõ ràng, dưới những tình huống như vậy, tốt nhất là chiếu lên trục ứng với chiều ngắn hơn của hình chữ nhật.

Nhìn lướt qua lần đầu, cóvể là kỹ thuật chiếu được cải tiến để cho các điểm rơi trong khoảng tìm x và các điểm rơi trong khoảng tìm y là “cắt nhau”. Hãy cố gắng làm điều này mà không xét tới các trường hợp xấu nhất là tất cả các điểm trong khoảng tìm x hoặc tất cả các điểm rơi trong khoảng tìm y, sẽ giúp chúng ta hiểu rõ hơn phương pháp phức tạp mà ta xét sau đây

Phương pháp lưới

Một kỹ thuật đơn giản là duy trì quan hệ gần nhau giữa các điểm trong mặt phẳng để cấu trúc thành một lưới, chia vùng được tìm thành nhiều ô. Kế tiếp, khi các điểm nằm trong hình chữ nhật tìm kiếm được xét, ta chỉ xét các ô có giao với hình chữ nhật. Trong ví dụ dưới, chỉ các điểm E, C, J và K là được xét

Trong việc cài đặt phương pháp này, điều quyết định chủ yếu là xác định kích thước của lưới: nếu quá to, mỗi ô lưới sẽ chứa quá nhiều điểm, và nếu quá nhỏ, phải tìm kiếm trên quá nhiều ô lưới (phần lớn các ô là rỗng). Một cách nhằm vào sự cân đối là chọn kích thước ô sao cho các ô là một phân số trên tổng số các điểm. Như vậy các điểm trên một ô được hy vọng là xấp xỉ một hằng số nào đó. Trong ví dụ, ta dùng lưới 4x4 cho tập 16 điểm nghĩa là mỗi o có thể chứa một điểm

Sau đây là một cách cài đặt đơn giản của chương trình xây dựng lưới chứa các điểm trong mảng p[0…N] các điểm theo type được định nghĩa như sau:

……….

type point = record x, y : integer end;

………..

biến size dùng để xác định kích cỡ của ô lưới. Để đơn giản, ta giả thiết các toạ độ của điểm trong khoảng 0 và một giá trị max nào đó. Vì biến size được lấy làm cỡ của ô lưới nên ta có (max/size)*(max/size) ô lưới. Để tìm ô lưới chứa một điểm nào đó, ta chia các toạ độ một điểm cho size, như trong cài đặt sau:

Chương trình này dùng cách biểu diễn danh sách liên kết chuẩn, với nút rỗng z ở cuối. Biến max được cho làm biến toàn cục, có giá trị ban đầu là giá trị toạ độ lớn nhất trong sô các điểm được nhập vào.

Như đã mô tả ở trên, giá trị biến size phụ thuộc vào số các điểm, lượng bộ nhớ sử dụng và vùng các giá trị toạ độ. Một cách ước chừng, để có M điểm trong mỗi ô, ta nên chọn size là số nguyên lớn nhất gần với max/sqrt(N/M). Có nghĩa là ta có khoảng N/M ô. Sự ước lượng này không chính xác cho các giá trị nhỏ của các biến, nhưng nó dùng được trong hầu hết các trường hợp, và ước lượng tương tự có thể dễ dàng công thức hoá trong các ứng dụng đặc biệt. Giá trị ước lượng trên có thể không cần chính xác và trong cài đặt này, ta dùng size là luỹ thừa của 2 bằng cách nhân và chia với size, sẽ hiệu quả hơn rất nhiều trong hầu hết các môi trường lập trình

Một cách chọn thông thường là lấy M=1 và ta dùng giá trị M này trong cài đặt. Nếu khoảng trống quá nhiều, có thể lấy giá trị M lớn hơn, nhưng giá trị M nhỏ hơn thì ít được dùng ngoại trừ trong những tình huống đặc biệt

Như vậy, ta đã nắm được hầu hết công việc để tìm kiếm vùng theo chỉ mục trên mảng grid:

Thời gian thực hiên của chương trình này tỉ lệ với số ô được xét. Vid ta đã thận trọng sắp xếp sao cho mỗi ô chứa (về trung bình) một hằng số các điểm và số các ô được xét cũng tỉ lệ (về trung bình) với số các điểm được xét

Có thể thấy rằng: Tính trung bình, phương pháp lưới có thời gian tuyến tính đối với số các điểm trong vùng tìm, và tuyến tính đối với tổng số điểm trong trường hợp xấu nhất.

Nếu số điểm trong hình chữ nhật tìm kiếm là R, thì số ô được xét sẽ tỉ lệ với R; như vậy tổng số thời gian thực hiện (trung bình) là tuyến tính với R. Với R lớn, số các điểm không rơi trong vùng tìm, mà vẫn được xét, thì khá nhỏ: tất cả những điểm như vậy rơi trong các ô có phần giao với hình chữ nhật tìm kiếm và số những ô như thế tỉ lệ với căn bặc hai của R khi R lớn. Lập luận này có phần sai nếu các ô quá nhỏ (có quá nhiều ô rỗng trong HCN tìm kiếm) hoặc quá lớn (có quá nhiều điểm trong các ô nằm trên chu vi của HCN tìm kiếm) hoặc nếu HCN tìm kiếm mảnh hơn các ô (nó có thể giao với nhiều ô nhưng chỉ có ít điểm rơi trong đó)

Phương pháp lưới làm việc tốt nếu các điểm nằm rải đều trong vùng tìm, nhưng sẽ là không tốt thậm chí rất xấu nếu các điểm cụm lại thành đám (ví dụ, tất cả các điểm nằm trong một ô, như vậy tất cả các ô khác sẽ không chứa gì cả).
URL của bài viết này::http://www.vnschool.net/modules.php?name=News&file=article&sid=2114
© Cong ty Cong Nghe Tin hoc Nha truong contact: sales@schoolnet.vn