Tài liệu rất hay và dễ hiểu về Danh sách Cây nhị phân
Trang 1Bai 3
DANH SÁCH
Trang 2Ôn kiểu dữ liệu struct
đối t−ợng có nhiều thành phần Các thành phần có thể thuộc các kiểu dữ liệu khác nhau.
• Đ Định ịnh ịnh ngh ngh nghĩĩĩĩaaaa ki ki kiểểểểuuuu hocvien hocvien hocvien ::::
Trang 3Kiểu dữ liệu struct (tt)
• Khai báo kết hợp với định nghĩa kiểu :
Trang 4Ví dụ về kiểu dữ liệu struct
10 } ;
11 struct hocvien hv;
Trang 5Truy xuất thành biến kiểu struct
• Truy xuÊt thµnh phÇn cña biÕn struct
BiÕn.thµnhphÇn[.thanhphan]*
Truy xuÊt tíi hä cña häc viªn hv : hv.ho
Truy xuÊt tíi th¸ng sinh cña häc viªn hv:
hv.ngsinh.thang
hv.ngsinh.thang
Trang 7Con trỏ và biến struct
Khai báo con trỏ và mảng struct
• struct hocvien hv, *p, ds[100];
p trỏ dến địa chỉ biến hv : p = &hv;
Truy nhập đến thành phần của biến struct bằng con trỏ Cách 1 : p->thanhphan
ví dụ : p->ho
Cách 2 : (*p).thanhphan
ví dụ : (*p).ho
Trang 8Ví dụ về mảng và con trỏ struct
1 #define MAX_SOSV 100 // số sinh viên tối đa trong danh sách
2 typedef struct sinhvien // định nghĩa kiểu sinhvien
Trang 9VÝ dô vÒ m¶ng vµ con trá struct
Trang 10VÝ dô vÒ m¶ng vµ con trá struct
1 int Timkiem(struct danhsach_sv *psv, char maso[])
Trang 11VÝ dô vÒ m¶ng vµ con trá struct
11 printf("Ho ten cua sinh vien la %s",ds.sv[vitri].hoten);
12 else printf(" Khong co sinh vien voi ma ban nhap vao");
13 getch();
14.}
Trang 12Danh sỏch tuyến tớnh
• Định nghĩa
Danh sách tuyến tính là 1 dãy các phần tử có cùng
kiểu dữ liệu được sắp xếp liên tiếp nhau trong bộ nhớ.
- Kích thước của danh sách sẽ được cấp phát theo khai báo.
- Các phần tử của danh sách nằm liên tục nhau trong bộ nhớ, giữa các phần tử này không có khoảng trống.
- Tiêu biểu cho danh sách đặc là dãy (array) Để cài đặt danh sách tuyến tính, ta dùng mảng 1 chiều.
Trang 13Định nghĩa và khai báo danh sách
1 #define MAXLIST 100
2 typedef struct list
5 };
6 struct list ds; // biÕn ds thuéc kiÓu struct list
Trang 14Phộp toỏn trờn danh sỏch
Phép
Phép to to toáááánnnn Empty Empty Empty: kiểm tra xem danh sách có rỗng hay không?
1 int Empty(struct list plist)
2 {
3 return (plist.n==0 ? TRUE : FALSE);
4 }
Phép
Phép to to toáááánnnn Full Full Full: kiểm tra xem danh sách đã đầy ch−a?
1 int Full(struct list plist)
2 {
3 return (plist.n==MAXLIST ? TRUE : FALSE);
4 }
Trang 16Phộp toỏn trờn danh sỏch
Phép
Phép th th thêêêêm m m vvvvààààoooo : Thêm một phần tử có nội dung
là info vào vị trí thứ i của danh sách
• Nếu i ==0 : thêm phần tử vào đầu danh sách
• Nếu i ==ds.n+1 : thêm phần tử vào cuối danh
sách.
L
L−−−−u ý u ý u ý: : : :
• Khi thêm một phần tử vào danh sách, ta phải
kiểm tra xem danh sách đã đầy hay ch−a?
Trang 17Thêm phần tử vào danh sách
1 void Insert_item(struct list &plist, int i, int info)
Trang 18Loại bỏ phần tử i khỏi danh sách
1 void Delete_item (struct list &plist, int i)
Trang 20Tìm kiếm phần tử trong danh sách
s¸ch plist NÕu kh«ng cã x trong plist th× hµm
Trang 21Khái niệm danh sách liên kết
• Cấu trúc danh sách liên kết là cấu trúc động, việc cấp phát và giải phóng nút động trên danh sách xảy ra khi chương trình đang chạy
Trang 22Khái niệm về DSLK (tt)
• First là con trỏ chỉ đến phần tử đầu của danh sách liên kết
• Phần tử cuối của danh sách liên kết với vùng liên kết có giá trị NULL
• Mỗi nút của danh sách có trường info chứa nội dung của nút và trường next là con trỏ chỉ đến nút kế tiếp trong danh sách
Nil
Trang 23Ưu nhược điểm của DSLK
Ư
Ưu u u đđđđiiiiểểểểm : m :
Danh sách liên kết rất thích hợp khi thực hiện các phép toán trên danh sách thường bị biến động
Trong trường hợp xóa hay thêm phần tử trong danh sách liên kết thì ta
không dời các phần tử đi như trong mảng mà chỉ việc hiệu chỉnh lại trường next tại các nút đang thao tác
Thời gian thực hiện các phép toán thêm vào và loại bỏ không phụ thuộc vào
số phần tử của danh sách liên kết
Trang 24§ Þnh nghÜa vµ khai b¸o danh s¸ch
§Þnh nghÜa nót cña danh s¸ch
Khai b¸o biÕn First qu¶n lý d¸nh s¸ch
NODEPTR First;
Khëi t¹o danh s¸ch liªn kÕt :
First = NULL;
Trang 25§ Þnh nghÜa vµ khai b¸o danh s¸ch (2)
kiÓu d÷ liÖu kh¸c nhau.
6 typedef struct node *NODEPTR
s¸ch ®a liªn kÕt hoÆc danh s¸ch liªn kÕt kÐp.
1 struct node
2 { int info;
3 struct node *next ;
4 struct node *previous;
5 };
6 typedef struct node *NODEPTR
Trang 26Định nghĩa struct con trỏ
kÕt, nã cã thÓ lµ kiÓu con trá (nh− khai b¸o trªn), vµ còng cã thÓ lµ mét struct cã hai thµnh phÇn:
Trang 27Các phép toán trên danh sách
1 Tạo danh sách
2 Cập nhật danh sách
3 Duyệt danh sách
4 Sắp xếp danh sách
Trang 28Tạo danh sách
1 void Initialize(NODEPTR &First)
Trang 29Tạo danh sách : thêm nút
dung x vµo ®Çu danh s¸ch liªn kÕt.
1 void Insert_First (NODEPTR &First, int x)
Trang 30Tạo danh sỏch : thờm nỳt
• Thêm nút mới vào sau nút có địa chỉ p (Insert_After): thêm một nút có nộidung x vào sau nút có địa chỉ p trong danh sách liên kết First
1 void Insert_After(NODEPTR p, int x)
Trang 31Cập nhật dỏnh sỏch
Gi
Giảảảảiiii phóngphóngphóng vvvvùùùùngngng nhnhnhớớớớ(Free_Node(Free_Node(Free_Node): Hàm này dùng để hủy nút đã cấp
phát, và trả vùng nhớ về lại cho memory heap
Trang 32Cập nhật dánh sách : xóa nút
Xãa phXãa phphÇÇÇÇnnnn ttttöööö ®®®®ÇÇÇÇuuuu ccccññññaaaa danhdanhdanh ssss¸¸¸¸chchch ((((Delete_FirstDelete_FirstDelete_First):):): muèn xãa 1 phÇn tö khái danhs¸ch liªn kÕt th× ta ph¶i kiÓm tra xem danh s¸ch cã rçng hay kh«ng NÕudanh s¸ch cã phÇn tö th× míi xãa ®−îc
1 int Delete_First (NODEPTR &First)
Trang 33Cập nhật dỏnh sỏch : xúa nỳt
Xóa phần tử đứng sau nút có địa chỉ p (Delete_After):
1 int Delete_After(NODEPTR First, NODEPTR &Last, NODEPTR p)
2 { NODEPTR q;
3 // nếu p là NULL hoặc sau p không có nút
4 if((p == NULL) || (p->next == NULL))
Trang 34Cập nhật danh sách : xóa danh sách
1 void Delete_All (NODEPTR &First)
Trang 36Tìm kiếm phần tử chứa nội dung x
Trang 37Sắp xếp danh sỏch
• Nội dung: Ta so sánh tất cả các phần tử của
danh sách để chọn ra một phần tử nhỏ nhất đ−a
về đầu danh sách; sau đó, tiếp tục chọn phần tử nhỏ nhất trong các phần tử còn lại để đ−a về
phần tử thứ hai trong danh sách Quá trình này lặp lại cho đến khi chọn ra đ−ợc phần tử nhỏ
thứ (n-1).
Trang 38Sắp xếp danh sách : selection sort
1 void Selection_Sort(NODEPTR First)
Trang 39Stack (Ngăn xếp) và ứng dụng
• Stack lµ mét danh s¸ch mµ viÖc thªm vµo vµ lo¹i bá chØ diÔn
ra cïng mét ®Çu cña danh s¸ch, tøc lµ theo c¬ chÕ LIFO
(Last In First Out) Stack gåm nhiÒu phÇn tö cã cïng kiÓu
d÷ liÖu, phÇn tö trªn cïng Stack lu«n lu«n cã mét con trá
chØ tíi ta gäi lµ Stack Pointer (ký hiÖu: sp)
10 5 Stack Sp
Trang 40Phép toán trên stack
• Stack cã 2 phÐp to¸n chÝnh :
* Push : thªm mét phÇn tö vµo ®Çu Stack
* Pop : xãa mét phÇn tö khái Stack, tr¶ cho ch−¬ng tr×nh gäi gi¸ trÞ cña phÇn tö võa xãa.
2 0
1 5
1 0 5
0 1 2
0 1 2 3
s p
2 0 4
1 5
1 0 5
1 2 3
s p
2 0 4
1 5
1 0 5
1 2 3
2 0 4
0 1 2
0 1 2 3
s p
2 0 4
1 5
1 0 5
1 2 3
s p
2 0 4
1 5
1 0 5
1 2 3
2 0 4
1
s p
5
Trang 410 1 1
0 0 1 1
1 0 0 1 1
Trang 42Ví dụ về stack
• TÝnh trÞ mét biÓu thøc d¹ng hËu tè (PostFix), biÕt r»ng mçi sè h¹ng lµ 1 ký sè vµ c¸c to¸n tö trong biÓu thøc
gåm cã: céng(+), trõ (-), nh©n (*), chia (/), lòy thõa (^).
• D¹ng hËu tè cña biÓu thøc cã d¹ng nh− sau:
Trang 43Stack bằng danh sách tuyến tính
Trang 44Phép toán trên stack (dstt)
PhÐp
PhÐp to to to¸¸¸¸nnnn push push push : thªm mét phÇn tö cã gi¸ trÞ x vµo ®Çu stack
1 void push (struct stack &st, int x)
Trang 45Phép toán trên stack (dstt)
• PhÐp PhÐp to to to¸¸¸¸nnnn pop pop pop : lo¹i bá phÇn tö khái Stack vµ tr¶ vÒ gi¸ trÞ cña
phÇn tö võa xãa; tr−íc khi xãa, ta ph¶i kiÓm tra Stack cã kh¸c rçng hay kh«ng.
1 int pop(struct stack &st)
Trang 46Chương trình đổi số thập phân không âm
5 long int so;
6 st.sp =- 1; // khoi dong stack
7 printf("\n\nNhap vao mot so thap phan: ");
Trang 48Hàng đợi và ứng dụng
• Queue lµ mét danh s¸ch h¹n chÕ mµ viÖc thªm vµo
®−îc thùc hiÖn ë ®Çu danh s¸ch, vµ viÖc lo¹i bá ®−îc thùc hiÖn ë ®Çu cßn l¹i (FIFO - First In First Out) Queue chøa c¸c phÇn tö cã cïng kiÓu d÷ liÖu Queue còng cã thÓ ®−îc tæ chøc theo danh s¸ch tuyÕn tÝnh hoÆc danh s¸ch liªn kÕt
Trang 49• Vị trí để loại bỏ phần tử được gọi là Front
• Vị trí để thêm vào được gọi là Rear
• Queue có hai phép toán chính:
- Insert_queue : thêm một phần tử vào hàng đợi; khi
thêm ta phải lưu ý xem hàng đợi bị tràn hay bị đầy để
xử lý cho thích hợp.
trị của phần tử vừa xóa; trước khi xóa, ta phải kiểm tra Queue có khác rỗng hay không.
Trang 50+ Hàng đợi bị tràn : là trường hợp khi Rear =
(trường hợp này Front luôn nhỏ hơn Rear)
- Di chuyển vòng : cho Rear = 0, Front giữ nguyên
(trường hợp này Front có lúc nhỏ hơn, có lúc lớn hơn
Rear )
Trang 51Vớ dụ về hàng đợi bị tràn
C B A
RearFront
C B
Rear
Front
Di chuyển vòng
0 1 2 3
n
C B A
RearFront
C B
Rear
Front
Di chuyển vòng
0 1 2 3
n
Hàng đợi bị tràn Rear ≥ Front Rear >< Front
Trang 52VÍ dụ về hàng đợi bị đầy
• Hàng đợi bị đầy: hàng đợi không có phần tử nào
trống: Front = 0 và Rear = n hoặc Rear đứng ngay
trước Front; do đó nếu tiếp tục thêm vào sẽ bị mất dữ liệu.
Rear = QUEUESIZE-1
Front = -1 } Rear - Front + 1 = QUEUESIZE
hoặc hoặc
Rear đứng ngay trước Front: Rear - Front + 1 = 0
Rear
Front
0
Rear Front Rear
Front
0
Rear Front
Trang 53Khởi tạo và phộp toỏn trờn hàng đợi
- Khởi tạo hàng đợi:
Trang 54Định nghĩa hàng đợi
Ta khai báo biến q có kiểu cấu trúc Queue gồm 3 thành phần:
- front, rear : số nguyên chỉ đầu và cuối hàng đợi
- nodes: mảng 1 chiều, mỗi phần tử của mảng là 1 phần tử trong
Trang 55Hàm thờm vào hàng đợi
• Phép thêêêêm v Phép th m v m vààààoooo : thêm một phần tử x vào hàng đợi; khi thêm ta phải lưu ý xem hàng
đợi bị tràn hay bị đầy để xử lý cho thích hợp.
Trang 56Thờm vào hàng đợi
2 3 4
<- Front & Rear 0 01
1 02 2
3 4
Danh sách rỗng
Hàng đợi chỉ
có 1 phần tử
Trang 59Trường hợp hàng đợi tràn, đầy
Hàng đợi đầy
Trang 60Stack bằng danh sỏch liờn kết
Khai báo: Ta khai báo biến sp (Stack Pointer) là con trỏ
chỉ đến một danh sách là Stack, mỗi phần tử trong
Stack là 1 số nguyên nh− sau:
Trang 61Thêm vào Stack DSLK
• a a PhÐp PhÐp PhÐp th th thªªªªm m m vvvvµµµµoooo (push) (push) (push) : Thªm mét phÇn tö cã gi¸
trÞ x vµo ®Çu Stack.
1 void push(Stack &sp, int x)
Trang 63Hàng đợi danh sỏch liờn kết
• Khai báo: Ta khai báo biến q có kiểu cấu trúc Queue gồm 2 thành phần front, rear
là con trỏ chỉ đầu và cuối hàng đợi Mỗi phần tử của hàng đợi là một nút chứa một
Trang 64Thờm vào hàng đợi DSLK
• PhépPhép thththêêêêmmm vvvvààààoooo : Thêm vào cuối danh sách liên kết nên sẽ thay đổi giá trịcủa Rear
1 void Insert_queue(Queue &q, int x)
Trang 66Kiểm tra giữa kỳ Đ08VTA2
1 Viết hàm đệ qui F(x,n)
• F= 1 khi n=0
• F= x * F(x, n-1) khi n>0
2 Viết hàm tính điểm trung binh của học viên i trong
bảng điểm có n học viên sau :
Hệ số môn 2 có hệ số 2 còn các môn còn lại có hệ số 1.
Trang 67Fn = 1 Fn-1 + Fn-2 ; n =0,1 ; n>1
Cho hàm Fibonacci như sau
1 Viết một hàm đệ qui tính hàm Fibonacci
2 Dùng một mảng để lưu trữ các phần tử của dãy Fibonnaci Viết một hàm tính các phần tử của dãy Fibonacci
Trang 69Cõy nhị phõn tỡm kiếm
• (Binary Search Tree): Một cây nhị phân gọi là cây nhị phân tìm kiếm nếu và chỉ nếu đối với mọi nút của cây thì khóa của một nút bất kỳ phải lớn hơn khóa của tất cả các nút trong cây con bên trái của nó và phải nhỏ hơn khóa của tất cả các nút trong cây con bên phải
của nó.
Trang 70Ví dụ về cây nhị phân tìm kiếm
1
5
k 1 <k 1 <k 1
Trang 71Preorder cho cây con bên phải.
• Ví dụ: Theo cây nhị phân 5.4, ta có:
• ROOT 1 2 3 4 6 7 5 8 9
• Inorder - Trung tự (LNR) : qua cây con bên trái duyệt trước (theo thứ tự LNR), sau
đó thăm nút gốc Cuối cùng qua cây con bên phải (theo thứ tự LNR)
• Ví dụ: Theo cây nhị phân 5.4, ta có:
Trang 72Định nghĩa cấu trúc cây nhị phân
1 struct nodetype
2 {
7 };
8 typedef struct nodetype *NODEPTR;
9 NODEPTR tree;
Trang 73Phép toán trên cây nhị phân
Khëi t¹o c©y(Initialize):
1 void Initialize(NODEPTR &root)
Trang 74Thờm nỳt vào cõy
1 void Insert(NODEPTR root, int x, int a)
9 // điều kiện dừng giải thuật đệ qui
10 if(x < root->key && root->left == NULL) {
19 //điều kiện dừng giải thuật đệ qui
20 if(x > root->key && root->right == NULL)
Trang 75Tạo cây nhị phân tìm kiếm
1 void Create_Tree(NODEPTR &root)
2 { int khoa, noidung;
Trang 76• Lêi gäi hµm: Free_Node (p);
• KiÓm tra c©y nhÞ ph©n rçng hay kh«ng (Empty): hµm Empty tr¶ vÒ TRUE nÕu c©y nhÞ ph©n rçng, vµ ng−îc l¹i
1 int Empty(NODEPTR root)
2 return(root == NULL ? TRUE : FALSE);
3 }
• Lêi gäi hµm: Empty(tree)
Trang 77Xóa nút
Trang 78Trường hợp 1 : nút p cần xóa là nút lá Việc xóa nút p chỉ đơn giản là hủy nút p
Trang 79Trường hợp 2 : Nút p cần xóa có 1 cây con, thì ta cho rp chỉ tới nút p Sau đó, ta tạo liên kết từ nút cha của p tới nút con của rp, cuối cùng hủy nút p.
2
10 5
20
Trang 80Trường hợp 3 : Nút p cần xóa có 2 cây con Ta cho rp chỉ tới nút p
Do tính chất nút cực trái của cây con bên phải của p có khóa vừa lớn hơn khóa của p, nên để loại p thì ta sẽ cho r chỉ tới nút cực trái đó Sau đó, ta sao chép nội dung và khóa của nút r vào nút mà rp đang chỉ tới Ta tạo liên kết thích hợp để bứt nút rp
ra khỏi cây nhị phân và cuối cùng xóa nút rp.
Trang 8111 if (rp->right == NULL) p = rp->left;
// p lµ nót l¸ hoac la nut chi co cay con ben trai
12 else if (rp->left == NULL)
13 p = rp->right; // p lµ nut co cay con ben phai
14 else remove_case_3 (rp->right);
Trang 829 rp->key = r->key; //Chep noi dung cua r sang rp ";
10 rp->info =r->info; // de lat nua free(rp)
11 rp = r;
12 r = r->right;
13 }
14 }
Trang 84Duyệt cây
• C C¸¸¸¸cccc phÐp phÐp phÐp duy duy duyÖÖÖÖtttt cccc©©©©yyyy : : : : Cã 3 c¸ch duyÖt c¬ b¶n lµ NLR, LNR, LRN
a DuyÖt c©y theo thø tù NLR (Preorder):
void Preorder (NODEPTR root)
b DuyÖt c©y theo thø tù LNR (Inorder):
void Inorder(NODEPTR root) { if(root != NULL)
{ Inorder(root->left);
printf("%d ", root->info);
Inorder(root->right);
} }
c DuyÖt c©y theo thø tù LRN (Posorder):
void Posorder(NODEPTR root)
{ if(root != NULL)
{ Posorder(root->left);
Posorder(root->right);
printf("%d ", root->info);
Trang 85C©©©©yyyy nhÞ nhÞ nhÞ ph ph ph©©©©nnnn tttt××××m m m kiÕm kiÕm kiÕm cccc©©©©nnnn bbbb»»»»ng ng
(AVL)
• AVL lµ c©y nhÞ ph©n t×m kiÕm mµ t¹i tÊt c¶ c¸c nót cña nã
chiÒu cao cña c©y con bªn tr¸i cña nã vµ chiÒu cao cña c©y con bªn ph¶i chªnh lÖch nhau kh«ng qu¸ mét.
10
20
6 8
Trang 86AVL: balance factor
• Ch Ch ChØØØØ ssssèèèè cccc©©©©nnnn bbbb»»»»ng ng ng (balance factor) cña mét nót p trªn c©y AVL= = lh(p
lh(p) ) ) rh(p rh(p rh(p))))
lh (p) lµ chiÒu cao cña c©y con bªn tr¸i cña p
rh(p) lµ chiÒu cao cña c©y con bªn ph¶i cña p
-1 1
0
B
0 B
0
0 0
A
Trang 88PhÐp to to to¸¸¸¸nnnn tr tr trªªªªnnnn cccc©©©©yyyy AVL: AVL: AVL: Th Th Thªªªªm m
- Néi dung: : : : Thªm 1 nót cã khãa x, néi dung a vµo c©y nhÞ ph©n t×m kiÕm c©nb»ng sao cho sau khi thªm th× c©y nhÞ ph©n vÉn lµ c©y nhÞ ph©n t×m kiÕmc©n b»ng
-Chó ý: Cã 2 tr−êng hîp khi thªm nót x vµo c©y AVL lµm c©y mÊt c©n b»ng,
- thªm c¸c nót vµo sau bªn tr¸i cña nót cã bf = 1,
- vµ thªm c¸c nót vµo sau bªn ph¶i cña nót cã bf = -1
Trang 89• TrTrTr−−−−êng hêng hêng hỵỵỵỵp 1ap 1ap 1a: NÕu thªm nĩt míi x vµo vÞ trÝ nĩt sau bªn tr¸i cđa s (thuéc nh¸nh T1) ta xoay ph¶i quanh nĩt ya
• - Nĩt s sÏ lµ nĩt gèc míi cđa nh¸nh c©y nµy víi bfs = 0
• - Nĩt ya lµ nĩt con bªn ph¶i cđa s víi bf ya = 0
0
T1 chiều sâu n
0
T2 chiều sâu n
T3 chiều sâu n
T1 chiều sâu n
T2 chiều sâu n
S
ya
xoay phải quanh nút ya
0
T1 chiều sâu n
0
T2 chiều sâu n
T3 chiều sâu n
0
T2 chiều sâu n
T3 chiều sâu n
T1 chiều sâu n
T2 chiều sâu n
S
ya
xoay phải quanh nút ya xoay phải quanh nút ya