4.2.1. Khái niệm
Cây nhị phân là cấu trúc cây quan trọng, đặc điểm là mọi node trên cây có tối đa 2 node con. Đối với cây nhị phân bao giờ cũng phân biệt cây con bên trái và cây con bên phải. Như vậy cây nhị phân là cây có thứ tự.
Hình 4.2. Cây nhị phân Một số dạng đặc biệt của cây nhị phân:
Cây nhị phân lệch trái: là cây nhị phân chỉ có các nút bên trái Cây nhị phân lệch phải: là cây nhị phân chỉ có các nút bên phải
Cây nhị phân hoàn chỉnh: nếu nút gốc và nút trung gian đều có hai con.
Cây nhị phân đầy đủ: một cây nhị phân đầy đủ với chiều sâu d nếu nó là cây nhị phân hoàn chỉnh và tất cả các nút lá đều có chiều sâu là d
Hình 4.3. a Cây nhị phân đầy đủ
Hình 4.3. b Cây nhị phân hoàn chỉnh
Cây nhị phân tìm kiếm là cây nhị phân hoặc là rỗng hoặc là tất cả các nút trên cây thỏa mãn các điều kiện sau:
Nội dung của tất cả các nhánh bên trái đều nhỏ hơn nội dung của nút gốc Nội dung của tất cả các nhánh bên phải đều lớn hơn nội dung nút gốc
Các cây con bên trái và bên phải cũng tự nhiên hình thành cây nhị phân tìm kiếm
Hình 4.4. Cây nhị phân tìm kiếm 4.2.2 Biểu diễn cây nhị phân
Trong trường hợp cây nhị phân đầy đủ, ta dễ dàng biểu diễn bằng mảng lưu trữ kế tiếp. Node gốc là phần tử đầu tiên của mảng, node con thứ i>=1 của cây nhị phân là phần tử thứ 2i và 2i+1 hay cha của node thứ j là [j/2].
Hình 4.5. Biểu diễn cây nhị phân bằng mảng
Với cây nhị phân không đầy đủ, phương pháp biểu diễn cây nhị phân bằng mảng không hiệu quả vì để trống quá nhiều phần tử gây lãng phí bộ nhớ.
Biểu diễn cây nhị phân bằng danh sách móc nối
Trong phương pháp này, mỗi node được mô tả bằng 3 thông tin như sau: Left là con trỏ trỏ tới nút bên trái của nút
Infor là thông tin về nút
Right là con trỏ trỏ tới nút bên phải phải của nút
Ví dụ biểu diễn bằng danh sách móc nối với cây nhị phân sau:
Hình 4.6. Biểu diễn cây nhị phân bằng danh sách móc nối 4.2.3. Các phép duyệt cây nhị phân
Phép duyệt cây là phương pháp thăm cây một cách hệ thống sao cho mỗi node được thăm đúng một lần.
Có 3 phép duyệt cây phổ biến:
Duyệt theo thứ tự trước Duyệt theo thứ tự giữa Duyệt theo thứ tự sau
Hình 4.7. Duyệt cây
Duyệt theo thứ tự trước
Thăm nút gốc n
Thăm cây con T1 theo thứ tự trước. Thăm cây con T2 theo thứ tự trước. Thăm cây con Tk theo thứ tự trước.
Hình 4.8. Thứ tự duyệt cây
Với cây trên, trình tự thăm các nút là:
Duyệt cây con trái theo thứ tự giữa (adsbygoogle = window.adsbygoogle || []).push({});
Thăm gốc
Thăm cây con T2 theo thứ tự giữa Thăm cây con Tk theo thứ tự giữa
Với cây con hình 4.8. như trên, thứ tự thăm các như sau: 4->3->5->2->1->6->8->7->9
Duyệt theo thứ tự sau
Thăm cây con T1 theo thứ tự sau Thăm cây con T2 theo thứ tự sau Thăm cây con Tk theo thứ tự sau Thăm gốc n
Với cây hình 4.8. như trên, thứ tự thăm như sau: 4->5->3->2->6->8->9->7->1
4.2.4. Thao tác với cây nhị phân
Cài đặt cây nhị phân tìm kiếm bằng danh sách móc nối: #include<stdlib.h>
#include<stdio.h>
typedef int item; //kieu item la kieu nguyen struct Node
{
item key; //truong key cua du lieu
Node *Left, *Right; //con trai va con phai };
typedef Node *Tree; //cay
int insertNode(Tree &T, item x) // chen 1 Node vao cay {
if (T != NULL) {
if (T->key == x) return -1; // Node nay da co
if (T->key > x) return insertNode(T->Left, x); // chen vao Node trai
else if (T->key < x) return insertNode(T->Right, x); // chen vao Node phai }
if (T == NULL) return 0; // khong du bo nho T->key = x;
T->Left = T->Right = NULL; return 1; // ok
}
void CreateTree(Tree &T) // nhap cay {
int x; while (1) {
printf("Nhap vao Node: "); scanf("%d", &x);
if (x == 0) break; // x = 0 thi thoat int check = insertNode(T, x);
if (check == -1) printf("Node da ton tai!"); else if (check == 0) printf("Khong du bo nho"); } } // Duyet theo LNR void LNR(Tree T) { if(T!=NULL) { LNR(T->Left); printf("%d ",T->key); LNR(T->Right); } }
Node* searchKey(Tree T, item x) // tim nut co key x {
if (T!=NULL) {
if (T->key == x) { Node *P = T; return P;} if (T->key > x) return searchKey(T->Left, x); if (T->key < x) return searchKey(T->Right, x); } (adsbygoogle = window.adsbygoogle || []).push({});
return NULL; }
int delKey(Tree &T, item x) // xoa nut co key x {
if (T==NULL) return 0;
else if (T->key > x) return delKey(T->Left, x); else if (T->key < x) return delKey(T->Right, x); else // T->key == x
{
Node *P = T;
if (T->Left == NULL) T = T->Right; // Node chi co cay con phai else if (T->Right == NULL) T = T->Left; // Node chi co cay con trai else // Node co ca 2 con
{
Node *S = T, *Q = S->Left;
// S la cha cua Q, Q la Node phai nhat cua cay con trai cua P while (Q->Right != NULL)
{ S = Q; Q = Q->Right; } P->key = Q->key; S->Right = Q->Left; delete Q; } } return 1; } int main() { Tree T;
T=NULL; //Tao cay rong
CreateTree(T); //Nhap cay //duyet cay
printf("Duyet cay theo LNR: n"); LNR(T);
printf("n");
Node *P; item x;
printf("Nhap vao key can tim: "); scanf("%d", &x);
if (P != NULL) printf("Tim thay key %dn", P->key); else printf("Key %d khong co trong cayn", x);
if (delKey(T, x)) printf("Xoa thanh congn"); else printf("Khong tim thay key %d can xoan", x); printf("Duyet cay theo LNR: n");
LNR(T); printf("n"); return 0; }