Bài toán Upper Bound và Lower Bound trên cây nhị phân tìm kiếm
Cây nhị phân tìm kiếm là một cấu trúc dữ liệu phổ biến được dùng để lưu trữ thông tin một cách có tổ chức, mọi thông tin trên cây đều tuân thủ quy luật nhất định, từ đó, việc quản lý và tìm kiếm dữ liệu được tối ưu hơn. Các thao tác trên cây thường rất đa dạng và đơn giản, nhưng không phải thao tác nào cũng đơn giản, ví dụ như thuật toán tìm Upper bound và Lower bound, nó đòi hỏi bạn phải biết cách dùng đệ quy khéo léo(à quên giới thiệu về Upper và lower bound, cứ hiểu đơn giản như sau, Cho một dãy số, tìm trong dãy các số lower bound của x (số lớn nhất mà nhỏ hơn x) và upper bound của x (số nhỏ nhất mà lớn hơn x)), để làm được bài này thì có rất nhiều cách, chẳng hạn sử dụng mảng để lưu trữ có sắp xếp, sau đó duyệt tuyến tính hoặc dùng BinarySearch để tìm kiếm, hoặc dùng danh sách liên kết đơn, kép, vòng,..tùy các bạn. Nhưng có lẽ tốt hơn hết là dùng cây nhị phân tìm kiếm, việc thêm vào và tìm kiếm sẽ nhanh hơn nhiều. Giả sử bài toán được "biến tấu" như sau:
Cho một dãy số, tìm trong dãy các số lower bound của x (số lớn nhất mà nhỏ hơn x) và upper bound của x (số nhỏ nhất mà lớn hơn x)
Sau đây là code mẫu của mình, ngôn ngữ được dùng là C++.
template code:
INPUT
Mỗi dòng của input chứa hai con số a và b. Số a có giá trị là 1 hoặc 2 hoặc 3. Số b giá trị b không quá 1 tỷ.
Dòng: 1 565481 có nghĩa là thêm 565481 vào dãy số
Dòng: 2 87126 nghĩa là tìm lowerbound của 87126
Dòng: 3 48769 nghĩa là tìm upperbound của số 48769
Input sẽ kết thúc bằng dòng chỉ chứa một số 0.
OUTPUT
Ứng với mỗi yêu cầu tìm kiếm xuất ra trên một dòng lowerbound hoặc upperbound tìm được, nếu không tồn tại upperbound hoặc lowerbound xuất ra chuỗi “NULL”
Sau đây là code mẫu của mình, ngôn ngữ được dùng là C++.
template code:
#include<iostream>
using namespace std;
- struct Node
- {
- int x;
- Node*Left;
- Node*Right;
- Node(){ this->Left = this->Right = NULL; }
- };
- struct Tree
- {
- Node*Root;
- Tree(){ this->Root = NULL; }
- };
- void add(Node*&R, int&x)
- {
- if (!R)
- {
- Node*P = new Node;
- P->x = x;
- R = P;
- return;
- }
- else
- {
- if (R->x == x) return;
- if (R->x > x) add(R->Left, x);
- else add(R->Right, x);
- }
- }
- int min(int a, int b)
- {
- if (a > b) return b;
- return a;
- }
- int searchBeNhatLonHonX(Node*&R, int&x, int&t)//truyen vao t mot so rat lon
- {
- if (!R) return 1999999999;
- int a = R->x - x;
- if (a > 0)
- {
- t = min(a, t);
- return min(t, searchBeNhatLonHonX(R->Left, x, t));
- }
- return min(t, searchBeNhatLonHonX(R->Right, x, t));
- }
- int max(int a, int b)
- {
- if (a < b) return b;
- return a;
- }
- int searchLonNhatBeHonX(Node*&R, int&x, int&t)//truyen vao t mot so rat be
- {
- if (!R) return -1999999999;
- int a = R->x - x;
- if (a < 0)
- {
- t = max(a, t);
- return max(t, searchLonNhatBeHonX(R->Right, x, t));
- }
- return max(t, searchLonNhatBeHonX(R->Left, x, t));
- }
- int main()
- {
- std::ios::sync_with_stdio(false);
- cout.tie(NULL);
- cin.tie(NULL);
- Tree A;
- int a = 3;
- int b;
- int d;
- int t;
- while (a)
- {
- cin >> a;
- if (a == 1)
- {
- cin >> b;
- add(A.Root, b);
- }
- else
- {
- if (a == 2)
- {
- cin >> b;
- t = -1999999999;
- d = searchLonNhatBeHonX(A.Root, b,t);
- if (d != -1999999999)
- cout << d + b << "\n";
- else
- {
- cout << "NULL\n";
- }
- }
- else
- {
- if (a == 3)
- {
- cin >> b;
- t = 1999999999;
- d = searchBeNhatLonHonX(A.Root, b,t);
- if (d != 1999999999)
- cout << d + b << "\n";
- else
- {
- cout << "NULL\n";
- }
- }
- else break;
- }
- }
- }
- return 0;
- }
Comments