1. Khái niệm cây nhị phân tìm kiếm (Binary Search Tree).

Cây tìm kiếm ứng với n khóa k1,k2,…kn là cây nhị phân mà mỗi nút đều được gán một khóa sao cho với mỗi mỗi nút k:
• •

Mọi khóa trên cây con trái đều nhỏ hơn khóa trên nút k Mọi khóa trên cây con phải đều lớn hơn khóa trên nút k

Cây tìm kiếm nhị phân là một cấu trúc dữ liệu cơ bản được sử dụng để xây dựng các cấu trúc dữ liệu trừu tượng hơn như các tập hợp, đa tập hợp, các dãy kết hợp. Nếu một BST có chứa các giá trị giống nhau thì nó biểu diễn một đa tập hợp. Cây loại này sử dụng các bất đẳng thức không nghiêm ngặt. Mọi nút trong cây con trái có khóa nhỏ hơn khóa của nút cha, mọi nút trên cây con phải có nút lớn hơn hoặc bằng khóa của nút cha. Nếu một BST không chứa các giá trị giống nhau thì nó biểu diễn một tập hợp đơn trị như trong lý thuyết tập hợp. Cây loại này sử dụng các bất đẳng thức nghiêm ngặt. Mọi nút trong cây con trái có khóa nhỏ hơn khóa của nút cha, mọi nút trên cây con phải có nút lớn hơn khóa của nút cha. Việc chọn đưa các giá trị bằng nhau vào cây con phải (hay trái) là tùy theo mỗi người. Một số người cũng đưa các giá trị bằng nhau vào cả hai phía, nhưng khi đó việc tiìm kiếm trở nên phức tạp hơn. 2. Các phép toán trên cây nhị phân tìm kiếm BST Tìm kiếm (Searching) Việc tìm một khóa trên BST có thể thực hiện nhờ đệ quy. Chúng ta bắt đầu từ gốc. Nếu khóa cần tìm bằng khóa của gốc thì khóa đó trên cây, nếu khóa cần tìm nhỏ hơn khoa ở gốc, ta phải tìm nó trên cây con trái, nếu khóa cần tìm lớn hơn khóa ở gốc, ta phải tìm nó trên cây con phải. Nếu cây con (trái hoặc phải) là rỗng thì khóa cần tìm không có trên cây.

int Search2(node *&root, int k) {

tmp->key = k.k). if (root->key == k) return 1. return Search2(root->right.k). if (root->key > k) Insert2(root->left. root = tmp. . else Insert2(root->right. } } Chèn (Insertion) Phép chèn bắt đầu giống như phép tìm kiếm. tmp->key = k.k).k). root = tmp. else if (root->key > k) return Search2(root->left. int k) { return Search2(t. tmp->right = NULL. int k) { if (root) { if (root->key==k) return.} int Search(BSTree &t.k). if (root->key > k) Insert2(root->left. } void Insert2(node *&root. int k) { if (root) { if (root->key==k) return. Nếu cây con trái hoặc phải tương ứng là rỗng (không tìm thấy) thì thêm một nút và gán cho nút ấy khóa cần chèn.k). Nếu khóa của gốc khác khóa cần chèn ta tìm nó trong cây con trái hoặc phải. } else { node *tmp = new node. void Insert2(node *&root. else Insert2(root->right.root. tmp->left = NULL. tmp->right = NULL.k). } else { node *tmp = new node. tmp->left = NULL.

} } void Insert(BSTree &t. Vì các nút kiểu này có ít hơn hai con nên việc xóa nó được quy về hai trường hợp trước. . int k) { Insert2(t.k). } Xét các trường hợp sau • Xóa một lá: Vì lá không có con nên chỉ cần giải phóng nó khỏi cây. • Xóa nút có một con: Xóa và thay thế nó bằng con duy nhất của nó. • Xóa một nút có hai con: Xóa nút đó và thay thế nó bằng nút có khóa lớn nhất trong các khóa nhỏ hơn khóa của nó (được gọi là “nút tiền nhiệm” -nút cực phải của cây con trái) hoặc nút có nhỏ nhất trong các khóa lớn hơn nó (được gọi là “nút kế vị” – nút cực trái của cây con phải) Cũng có thể tìm nút tiền nhiệm hoặc nút kế vị đổi chỗ nó với nút cần xóa và sau đó xóa nó.root.

root=root->left. else if (root->left == NULL) { node *tmp = root.k). tmp->key). } else { node *tmp = root->left. delete tmp.k). else if (root->key > k) Remove2(root->left. delete tmp. . root->key = tmp->key. } } } } void Remove(BSTree &t. else { if (root->left ==NULL && root->right == NULL) delete root. while (tmp->right) tmp = tmp->right.root. root=root->right. Remove2(root->left. else { if (root->key < k) Remove2(root->right.void Remove2(node *&root. } else if (root->right == NULL) { node *tmp = root. int k) { Remove2(t.k). int k) { if (root == NULL) return.

root=NULL. struct BSTree { node *root. else if (root->key > k) return Search2(root->left. }. *right. if (root->key > k) Insert2(root->left.root). } int Search(BSTree &t.h> struct node { int key. return Search2(root->right.k). void Init(BSTree &t) { t. node *left. } else { node *tmp = new node. tmp->left = NULL. else Insert2(root->right. int k) { return Search2(t. tmp->key = k. Destroy2(root->right).k).k). tmp->right = NULL.k). } int Search2(node *&root.k). . delete root. int k) { if (root->key == k) return 1. } void Insert2(node *&root. } void Destroy(BSTree &t) { Destroy2(t. } void Destroy2(node *&root) { Destroy2(root->left).} #include <iostream. }. int k) { if (root) { if (root->key==k) return.root.

delete tmp. } void Insert(BSTree &t. int k) { if (root == NULL) return. } void TraverseLNR2(node *&root) { if (root) { TraverseLNR2(root->left). else { if (root->key < k) Remove2(root->right. else { if (root->left ==NULL && root->right == NULL) delete root. . else if (root->key > k) Remove2(root->left. else if (root->left == NULL) { node *tmp = root. while (tmp->right) tmp = tmp->right. delete tmp. cout<<root->key<<" ". } void Remove2(node *&root. root=root->right. root=root->left. } } } } void Remove(BSTree &t. int k) { Insert2(t.k).k).root. int k) { Remove2(t. Remove2(root->left.root. } else { node *tmp = root->left.k). tmp->key).} root = tmp. root->key = tmp->key. } else if (root->right == NULL) { node *tmp = root.k). TraverseLNR2(root->right).

cout<<endl. } void main() { BSTree t. cout<<endl. Remove(t. cout<<"Sau khi them vao cay: ". Insert(t.root). int n. cout<<"Nhap phan tu muon them vao cay:". TraverseLNR(t). cout<<"Nhap phan tu muon xoa khoi cay: ". TraverseLNR(t). Insert(t. for (int i=0. int x. } . Init(t). cout<<"Nhap so luong phan tu cua cay: ".} } void TraverseLNR(BSTree &t) { TraverseLNR2(t.x).i++) { cin>>x. cout<<endl. } cout<<"Duyet cay theo LNR: ". cin>>n. cout<<"Sau khi xoa khoi cay: ".x).x). cin>>x.i<n. cin>>x. TraverseLNR(t).

Sign up to vote on this title
UsefulNot useful