Chủ đề tuần này Làm thế nào để sử dụng công cụ gỡ lỗi gdb Cấu trúc dữ liệu cây - Cây nhị fân - Cây nhị fân tìm kiếm Đệ quy tiến trình trên cây... Không giống với cây tự nhiên, nhữ
Trang 1Chủ đề tuần này
Làm thế nào để sử dụng công cụ gỡ lỗi (gdb)
Cấu trúc dữ liệu cây
- Cây nhị fân
- Cây nhị fân tìm kiếm
Đệ quy tiến trình trên cây
Trang 2Gdb để gỡ lỗi (1)
misc/gdb.html
Sử dụng khi lõi chương trình hỏng
Hoặc khi ta muốn đi xuyên suốt sự thi hành của chương trình theo từng dòng 1
Trang 5Gdb – Các câu lệnh cơ bản (1)
Dò ngược ngăn xếp (“where”)
- Chương trình bị lỗi
- Đâu là dòng lệnh cuối cùng trong chương trình được
thực thi trước khi gặp lỗi?
- Đó là điều lệnh where sẽ chỉ ra cho bạn
Trang 7- Free vùng nhớ mà bạn không cấp phát trước đó.
- Truy nhập mảng sau phần tử cuối cùng của nó
- Con trỏ quy chiếu ngược không trỏ tới phần của khối đã được malloc()
Trang 8Gdb – Các câu lệnh cơ bản (4)
Các câu lệnh break,continue,next, step
- break: dừng sự thi hành ở dòng được chỉ ra.
gdb> break foo.c: 100(đặt điểm break).
- continue: tiếp tục lại sự thi hành từ điểm đó.
- next: thực thi dòng lệnh tiếp theo, sau đó dừng lại.
- step: thực thi câu lệnh tiếp theo.
• Đi vào trong hàm nếu cần thiết (next thì
không).
Trang 11Gdb – in mảng (2)
gdb xảy ra vấn đề với các mảng được cấp phát động
int*arr;
arr= (int*)malloc(3 * sizeof(int));
arr[0] = 1; arr[1] = 2; arr[2] = 3;
gdb> print arr
$1 = (int*) 0x8094610
Nó không thực sự hữu dụng
Trang 12Gdb – in mảng (3)
Có thể in mảng này sử dụng @ (cú pháp gdb
đặc biệt).
int*arr;
arr = (int*)malloc(3 * sizeof(int));
arr[0] = 1; arr[1] = 2; arr[2] = 3;
gdb> print *arr@3
$2 = {1, 2, 3}
Trang 14Cây,cây nhị fân,cây tìm kiếm nhị fân
Danh sách liên kết là 1 cấu trúc tuyến tính, và rất khó sử dụng nó để tổ chức biểu diễn các đối
(cạnh,cung) Không giống với cây tự nhiên,
những cây này được vẽ từ trên xuống với root ở trên cùng và các lá (leaf) ở dưới cùng
Trang 15Cây gia đình (family tree)
Xem hình minh hoạ trong slide tiếng anh tr17
Trang 16Định nghĩa của tree
1 cây là 1 tập hợp xác định của 1 hay nhiều node mà:
- Có 1 node đắc biệt gọi là root
- Các node còn lại chúng lại phân hoạch thành n>=0 tập T1,T2,…Tn, mà mỗi tập này lại là 1 cây
- Ta gọi T1,T2,…Tn là các subtree(cây con) của root
Trang 17Định nghĩa đệ quy (recursive definition)
Xem hình minh hoạ slide tiếng anh tr19
Trang 18Binary tree(cây nhị fân)
Cây nhị fân là 1 cây mà không node nào của nó có quá
2 con
Mỗi node có 0,1 hoặc 2 con
Trang 19Biểu diễn liên kết
Mỗi node của cây được biểu diễn như là 1 đối tượng
có cùng kiểu dữ liệu
Không gian yêu cầu bởi n node cây nhị fân = n *
(không gian yêu cầu của 1 node)
Trang 201 cây nhị fân liên kết
Xem hình minh hoạ slide tiếng anh tr22
Trang 21Binary Tree ADT (kiểu dữ liệu trừu
tượng cây nhị fân)
makenullTree(treetype *t)
creatnewNode()
isEmpty()
Trang 22Khởi tạo và đặc tả cây
Trang 23Truy nhập con trái và con fải
treetype LeftChild(treetype n)
{
if (n!=NULL) return n->left;
else return NULL;
}
treetype RightChild(treetype n)
{
if (n!=NULL) return n->right;
else return NULL;
}
Trang 24Tạo 1 node mới
node_type *create_node(elmtype NewData)
Trang 26Xử lí đệ quy: tính số lượng node
Vì cây là 1 cấu trúc dữ liệu đệ quy, nên thuật toán đệ
quy rất hữu dụng khi ta áp dụng trên cây
Trang 27Tạo 1 cây từ 2 cây con
Treetype createfrom2(elmtype v, treetype l,
Trang 28Thêm 1 node mới vào vị trí trái nhất
treetype Add_Left(treetype *Tree, elmtype NewData){
node_type *NewNode = Create_Node(NewData);
if (NewNode == NULL) return (NewNode);
if (*Tree == NULL)
*Tree = NewNode;
else{
node_type *Lnode = *Tree;
while (Lnode->left != NULL)
Trang 29Thêm 1 node mới vào vị trí phải nhất
treetype Add_Left(treetype *Tree, elmtype NewData){
node_type *NewNode = Create_Node(NewData);
if (NewNode == NULL) return (NewNode);
if (*Tree == NULL)
*Tree = NewNode;
else{
node_type *Rnode = *Tree;
while (Rnode->right != NULL)
Trang 30Minh hoạ
Xem hình silde tiếng anh tr32
Trang 31Exercise
Phát triển hàm trợ giúp sau cho cây:
- Trả lại chiều cao cây nhị fân
- Trả lại số lượng lá
- Trả lại số lượng các node trong
- Đếm số lượng con phải
Trang 32 1 cây nhị fân có thể biểu diễn 1 biểu thức số
học: các lá là các toán hạng và các node khác là các phép toán.
Con trái và con phải của 1 node toán tử biểu
diễn các biểu thức con mà phải tính giá trị trước khi thực hiện toán tử ở root của cây con.
Ví dụ: !a + (b-c)/d (xem hình minh hoạ ở slide
tiếng anh tr 34).
Viết 1 chương trình tạo 1 cây biểu diễn biểu
thức này.
Trang 33Binary search tree (cây tìm kiếm nhị fân)
Mỗi phần tử chỉ có 1 key duy nhất
Các key trong các node không rỗng ở cây con trái (cây con phải) nhỏ hơn (lớn hơn) key ở root của subtree
Các cây con trái và phải cũng là cây nhị fân tìm kiếm
Xem hình minh hoạ slide tiếng anh tr35
Trang 34Triển khai BST
#include <stdio.h>
#include <stdlib.h>
typedef KeyType; // đặc tả 1 kiểu dữ liệu
typedef struct Node{
Trang 35Tìm kiếm trên BST
TreeType Search(KeyType x,TreeType Root){
if (Root == NULL) return NULL; // không tìm thấy
else if (Root->key == x) /* tìm thấy x */
Trang 36Chèn 1 node vào BST
Trong 1 cây nhị phân, không có 2 node có cùng key
void InsertNode(KeyType x,TreeType *Root ){
Trang 37Xoá 1 node khỏi BST
Loại bỏ 1 node lá thì không có gì đáng bàn, chỉ cần thiết lập con trỏ con của node cha thích hợp về NULL
Loại bỏ 1 node trong mà chỉ có 1 cây con cũng rất đơn giản, chỉ cần thiết lập con trỏ con của con trỏ cha tương ứng trỏ đến root của cây con
Trang 38Xoá 1 node khỏi BST
Loại bỏ 1 node trong có 2 cây con thì phức tạp hơn
- Tìm node trái nhất của cây con phải, và đổi dữ liệu của nó với dữ liệu của node cần xoá
- Xoá dữ liệu đã được đổi khỏ cây con phải
Trang 39Tìm node trái nhất của cây con phải
Hàm này tìm ra node trái nhất rồi xoá nó, trả về key của node bị xoá
KeyType DeleteMin (TreeType *Root ){
Trang 40Xoá 1 node khỏi BST
void DeleteNode(key X,TreeType *Root){
if (*Root!=NULL)
if (x < (*Root)->Key) DeleteNode(x, &(*Root)->left)
else if (x > (*Root)->Key)
DeleteNode(x, &(*Root)->right) else if
((*Root)->left==NULL)&&((*Root)->right==NULL)
*Root=NULL;
else if ((*Root)->left == NULL)
*Root = (*Root)->right else if ((*Root)->right==NULL)
*Root = (*Root)->left
Trang 41printf("\302");strcat(prefix,"\263 ");
} prettyprint(tree->left,prefix);
Trang 42 Viết 1 hàm xoá tất cả các node của cây Hàm này phải được gọi trước khi kết thúc chương trình
Trang 44 Tạo 1 BST với 10 nodes, mỗi node chứa 1 số nguyên ngẫu nhiên
Yêu cầu người dùng nhập vào 1 số và tìm kiếm nó
In ra nội dung của cây
Trang 45if (p!=NULL) printf("Key %d found on the tree",n);
else insert(n, tree);
}while (n!=-1);
return 0;
}
Trang 46 Ta giả sử rằng tạo 1 danh bạ điện thoại
Định nghĩa 1 cấu trúc chứa ít nhất name, sđt, địa chỉ
Định nghĩa cấu trúc cây nhị fân có thể chứa cấu trúc
danh bạ ở trong Đọc 10 dữ liệu từ file đầu vào vào cây nhị fân theo luật sau:
- Địa chỉ nhỏ hơn theo thứ tự từ điển (xét theo địa chỉ
email) thì được chứa ở bên trái của node
- Địa chỉ lớn hơn theo thứ tự từ điển (xét theo địa chỉ
email) thì được chứa ở bên phải của node
Xác thực rằng dữ liệu được tổ chức theo cấu trúc cây nhị fân qua 1 vài phương thức(in, debug…)
Tìm 1 địa chỉ mail được mô tả trong cây nhị phân và in chúng ra file nếu tìm thấy
Trang 48Hàm tìm kiếm
TreeType Search(char* email,TreeType Root){
if (Root == NULL) return NULL; // not found
else if (strcmp((Root->Key).email, email) == 0)
return Root;
else if (strcmp((Root->Key).email, email) < 0)
//Tiếp tục tìm trong cây con phải
Trang 50int i,n, irc; // return code
int reval = SUCCESS;