Đối với tất cả các đỉnh ∉

Một phần của tài liệu TỔNG QUAN VỀ THUẬT TOÁN VÀ PHƯƠNG PHÁP ĐẾM BM Công nghệ thông tin. Bài giảng Cơ sở toán học cho tin học. (Trang 32 - 40)

chúng như sau:

Nếu βj > m(𝑣∗,𝑣) thì đặt β = m(𝑣∗,𝑣) và nhãn của𝑣 là [𝑣∗, β ]. Ngược lại, ta giữ nguyên nhãn của𝑣. Sau đó quay lại Bước 3.

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 188 Thuật toán PRIM tìm CKNN của đồ thị cho bởi trọng số

• Trong phần này, giới thiệu về giải thuật tìm đường đi ngắn nhất giữa 2 đỉnh trên đồ thị có trọng số. • Nội dung gồm:

– Giới thiệu về bài toán – Thuật toán gán nhãn – Thuật toán Dijkstra

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 189 Tìm đường đi ngắn nhất

• Xét đồ thị G = (V, E) với |V| = n, |E| = m

• Với mỗi cạnh u, v∈E, có một giá trị trọng số A(u,v)

• Đặt A(u,v) = ∞ nếu u, v∉E

• Nếu dãy𝑣,𝑣,...,𝑣 là một đường đi trên G thì

–∑ 𝐴( 𝑣 ,𝑣) được gọi là độ dài của đường đi

• Bài toán: Tìm đường đi ngắn nhất từ đỉnh s đến đỉnh t của đồ thị G

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 190 Bài toán tìm đường đi ngắn nhất

• Thuật toán được mô tả như sau:

– Từ ma trận trọng số A(u,v), u,v∈V, tìm cận trên d[v] của khoảng cách từ s đến tất cả các đỉnh v∈V.

– Nếu thấy d[u] + A(u,v) < d[v] thì d[v] = d[u] + A(u,v) (làm tốt lên giá trị của d[v])

– Quá trình sẽ kết thúc khi không thể làm “tốt lên” được nữa – Khi đó d[v] sẽ cho ta giá trị ngắn nhất từ đỉnh s đến đỉnh v. – Giá trị d[v] được gọi là nhãn của đỉnh v

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 191 Thuật toán gán nhãn

• Tìm đường đi ngắn nhất từ A đến Z trong đồ thị G sau

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 192 Thuật toán gán nhãn – Ví dụ A B Z F C H 7 4 3 6 5 E D I

• Các bước thực hiện của giải thuật: – Bước 1: Gán cho nhãn đỉnh A là 0, d[A] = 0;

– Bước 2: Chọn cạnh có độ dài nhỏ nhất xuất phát từ A (cạnh AC), gán nhãn của đỉnh kề C với:

– d[C] = d[A] + A(A,C) = 0 + 5 = 5

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 193 Thuật toán gán nhãn – Ví dụ A B Z F C H 7 4 3 6 5 E D I

• Thuật toán này do E.Dijkstra, nhà toán học người Hà Lan, đề xuất năm 1959.

• Thuật toán tìm đường đi ngắn nhất từ đỉnh s đến các đỉnh còn lại được Dijkstra đề nghị áp dụng cho trường hợp đồ thị có hướng với trọng số không âm.

• Thuật toán được thực hiện trên cơ sở gán tạm thời cho các đỉnh. • Nhãn của mỗi đỉnh cho biết cận trên của độ dài đường đi ngắn

nhất tới đỉnh đó.

• Các nhãn này sẽ được biến đổi (tính lại) nhờ một thủ tục lặp, mà ở mỗi bước lặp một số đỉnh sẽ có nhãn không thay đổi, nhãn đó chính là độ dài đường đi ngắn nhất từ s đến đỉnh đó

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 194 Thuật toán Dijkstra

voidDijkstra(void) (adsbygoogle = window.adsbygoogle || []).push({});

//Đầu vào G =(V, E) với n đỉnh có ma trận trọng số A(u,v)>=0; s∈V //Đầu ra là khoảng cách nhỏ nhất từ s đến các đỉnh còn lại d[v]:v∈V //Truoc[v]: ghi lại đỉnh trước v trong đường đi ngắn nhất từ s đến v

{

//Bước 1: Khởi tạo nhãn tạm thời cho các đỉnh for( v∈V ){ d[v] = A(s,v); truoc[v]=s; } d[s]=0; T = V\{s}; //T là tập đỉnh có nhãn tạm thời //Bước lặp while(T !=Ø){ Tìm đỉnh u∈T sao cho d[u] = min { d[z] | z∈T}; T= T\{u}; //cố định nhãn đỉnh u*/ for( v∈T ){ //Gán lại nhãn cho các đỉnh trong T if(d[v] > d[u] + A(u,v)){ d[v] = d[u] + A(u,v); truoc[v] =u; } } } }

Giả mã của giải thuật Dijkstra

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 195

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 196

Ví dụ về giải thuật Dijkstra

V1 V2 V2 V6 V4 V3 V5 5 8 2 10 1

– Cho đồ thị G như hình vẽ, tìm đường từ V1->V6

–O(mlogn) Borůvka,Prim, Dijkstra, Kruskal,… –O(mlog logn) Yao (1975), Cheriton-Tarjan (1976) –O(m(m,n)) Fredman-Tarjan (1987)

–O(mlog(m,n))Gabow-Galil-Spencer-Tarjan (1986) –O(m(m,n)) Chazelle (JACM2000)

– Optimal Pettie-Ramachandran (JACM2002)

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 197 Độ phức tạp thuật toán

• Cây nhị phân • Cây đỏ đen

• B-Tree và cây nhiều nhánh

21/07/20 Bộ môn CNTT - Bài giảng Cơ sở toán học cho tin học 198 5.3. Một số loại cây đặc biệt và ứng dụng

• Một cây có gốc T được gọi là cây nhị-phân nếu mỗi đỉnh của T có nhiều nhất là 2 con. Với m=2, ta có một cây nhị phân.

• Trong một cây nhị phân, mỗi con được chỉ rõ là con bên trái hay con bên phải; con bên trái (t.ư. phải) được vẽ phía dưới và bên trái (t.ư. phải) của cha.

• Cây nhị phân có nhiều ứng dụng trong thực tế

• Tính GT của Biểu thức(a*b+c)*(d/e-f)

Cây nhị phân

199

Cài đặt Cây nhị phân

• Khai báo cấu trúc dữ liệu của cây nhị phân lưu biểu thức số học

Cấu trúc một nút trong cây:

typedef struct tagNode{ char *x;

struct tagNode *pLeft, *pRight; } Node;

Cấu trúc cây nhị phân:

typedef Node *TREE;

200 (adsbygoogle = window.adsbygoogle || []).push({});

Hàm tính giá trị của biểu thức từ cây nhị phân double Value(TREE Root){

if (Root!=NULL)

if (Root->x[0]=='+' || Root->x[0]=='-' || Root->x[0]=='*' || Root->x[0]=='/') switch (Root->x[0]){

case '+': return Value(Root->pLeft)+Value(Root->pRight);break; case '-' : return Value(Root->pLeft)-Value(Root->pRight);break; case '*': return Value(Root->pLeft)*Value(Root->pRight);break; case '/' : return Value(Root->pLeft)/Value(Root->pRight);break; }

else return atof(Root->x); //atof là hàm đổi 1 xâu gồm các kí tự số sang số thực

}

201

DUYỆT CÂY NHỊ PHÂN

• Trong nhiều trường hợp, ta cần phải “điểm danh” hay “thăm” một cách có hệ thống mọi đỉnh của một cây nhị phân, mỗi đỉnh chỉ một lần. Ta gọi đó là việc duyệt cây nhị phân hay đọc cây nhị phân.

• Có nhiều thuật toán duyệt cây nhị phân, các thuật toán đó khác nhau chủ yếu ở thứ tự thăm các đỉnh.

• Cây nhị phân T có gốc r được ký hiệu là T(r). Giả sử r có con bên trái là u, con bên phải là v. Cây có gốc u và các đỉnh khác là mọi dòng dõi của u trong T gọi là cây con bên trái của T, ký hiệu T(u). Tương tự, ta có cây con bên phải T(v) của T. Một cây T(r) có thể không có cây con bên trái hay bên phải.

202

DUYỆT CÂY NHỊ PHÂN

203

Các thuật toán duyệt cây nhị phân

• 1) Thuật toán tiền thứ tự: Node-Left-Right

• 2) Thuật toán trung thứ tự: Left-Node-

Right

• 3) Thuật toán hậu thứ tự: Left-Right-Node

Thuật toán tiền thứ tự: Node-Left-Right • 1.Thăm nút gốc.

• 2.Duyệt cây con bên trái của T(r) theo tiền thứ tự. • 3.Duyệt cây con bên phải của T(r) theo tiền thứ

tự.

205

Node-Left-Right

void NLR(Node Root) { if (Root != NULL) { //Thăm nút gốc NLR(Root->Left); NLR(Root->Right); } } 206

Thuật toán trung thứ tự: Left-Node-Right

• 1.Duyệt cây con bên trái của T(r) theo trung thứ tự.

• 2.Thăm nút gốc

• 3.Duyệt cây con bên phải của T(r) theo trung thứ tự.

207 (adsbygoogle = window.adsbygoogle || []).push({});

Left-Node-Right

void LNR(Node Root) { if (Root != NULL) { LNR(Root->Left); //Thăm nút gốc LNR(Root->Right); } } 208

Thuật toán hậu thứ tự: Left-Right-Node

• 1.Duyệt cây con bên trái của T(r) theo hậu thứ tự. • 2.Duyệt cây con bên phải của T(r) theo hậu thứ

tự.

• 3.Thăm nút gốc.

209

Left-Right-Node

void LRN(Node Root) { if (Root != NULL) { LRN(Root->Left); LRN(Root->Right); //Thăm nút gốc } } 210

• Cây nhị phân

• Bảo đảm nguyên tắc bố trí khoá tại mỗi nút:

– Các nút trong cây trái nhỏ hơn nút hiện hành – Các nút trong cây phải lớn hơn nút hiện hành

18

13 37

15 23 40

Ví dụ:

Khái niệm CNP TK

Ưu điểm của cây nhị phân tìm kiếm

• Nhờ trật tự bố trí khóa trên cây : – Định hướng được khi tìm kiếm • Cây gồm N phần tử :

– Trường hợp tốt nhất h = log2N – Trường hợp xấu nhất h = N

– Tình huống xảy ra trường hợp xấu nhất?

Cài đặt cây nhị phân tìm kiếm • Cấu trúc dữ liệu của 1 nút

typedefstruct tagTNode {

intKey; //trường dữ liệu là 1 số nguyên

structtagTNode *pLeft;

structtagTNode *pRight; }TNode;

• Cấu trúc dữ liệu của cây typedefTNode *TREE;

Các thao tác trên cây nhị phân tìm kiếm • Tạo 1 cây rỗng

• Tạo 1 nút có trường Key bằng x • Thêm 1 nút vào cây nhị phân tìm kiếm • Duyệt cây nhị phân tìm kiếm • Xoá 1 nút có Key bằng x trên cây • Tìm 1 nút có khoá bằng x trên cây

Tạo cây rỗng (adsbygoogle = window.adsbygoogle || []).push({});

• Cây rỗng -> địa chỉ nút gốc bằng NULL

voidCreateTree(TREE&T) {

T=NULL; }

Tạo 1 nút có Key bằng x

TNode*CreateTNode(intx) { TNode*p; p =newTNode; //cấp phát vùng nhớ động if(p==NULL) exit(1); // thoát else {

p->key = x; //gán trường dữ liệu của nút = x p->pLeft = NULL;

p->pRight = NULL; }

returnp; }

• Rằng buộc: Sau khi thêm cây đảm bảo là cây nhị phân tìm kiếm.

intinsertNode(TREE &T, Data X)

{ if(T)

{if(T->Key == X) return0;

if(T->Key > X)returninsertNode(T->pLeft, X);

else returninsertNode(T->pRight, X); }

T= new TNode;

if(T == NULL) return -1; T->Key = X;

T->pLeft =T->pRight = NULL;

return1; } Thêm một nút x 44 18 88 13 37 59 108 15 23 40 55 71 Thêm X=50 44 < X 88 > X 59 > X 50 55 > X

Minh họa thêm 1 phần tử vào cây

95 14 5 14 8 4 6 3 12 13 Minh hoạ thành lập 1 cây từ dãy số 9, 5, 4, 8, 6, 3, 14,12,13

Tìm nút có khoá bằng x (không dùng đệ quy)

TNode *searchNode(TREE Root, int x) { TNode *p = Root; while(p != NULL) { if(x == p->Key)returnp; else if(x < p->Key) p = p->pLeft; else p = p->pRight; } returnp; } Tìm nút có khoá bằng x (dùng đệ quy) TNode*SearchTNode(TREE T, int x)

{ if(T!=NULL) if(T!=NULL) { if(T->key==x) returnT; else if(x>T->key) returnSearchTNode(T->pRight,x); else returnSearchTNode(T->pLeft,x); } returnNULL; } 44 18 88 13 37 59 108 15 23 40 55 71 Tìm X=55 Tìm thấy X=55 55 55 Minh hoạ tìm một nút

Duyệt cây nhị phân tìm kiếm

• Có 6 phép duyệt cây như sau

– NLR (gốc, trái, phải) – NRL (gốc, phải, trái) – LNR (trái,gốc, phải) – RNL (Phải,gốc,trái) – LRN (trái, phải,gốc) – RLN (phải, trái,gốc)

Thuật toán duyệt cây nhị phân tìm kiếm

voidNLR(TREEt) { if(t!=NULL) { printf(“%d”,t->key);//Thăm nút gốc NLR(t->pLeft); NLR(t->pRight); } }

Bài tập cho phần duyệt cây

Viết chương trình thực hiện các yêu cầu sau: 1. Đếm số nút trên cây (adsbygoogle = window.adsbygoogle || []).push({});

2. Tình tổng tất cả các khóa trên cây 3. Đếm số nút lá trên cây

4. Đếm số nút có duy nhất 1 cây con 5. Đếm số nút có 2 cây con

6. Cho biết khoá lớn nhất trong cây là bao nhiêu 7. Cho biết khóa nhỏ nhất trong cây là bao nhiêu

Viết hàm đếm số nút trong cây voidDem(TREEt,int&s)

{ if(t!=NULL) if(t!=NULL) { if (t->pLeft==NULL&&t->pRight==NULL) //Đếm lá if (t->pLeft==NULL||t->pRight==NULL) //Đếm nút có 1 con if (t->pLeft!=NULL&&t->pRight!=NULL) //Đếm nút có 2 con s++; Dem(t->pLeft,s); Dem(t->pRight,s); } } Lời gọi hàm voidmain() { TREEt; ints=0; Dem(t,s);

printf(“so nut trong cay :=%d”,s); } Duyệt cây • NLR: 9, 2, 6, 1, 10, 8, 5, 3, 7, 12, 4. • LNR: 6, 2, 10, 1, 9, 3, 5, 8, 12, 7, 4. 9 8 2 1 6 10 5 3 7 4 12

Hủy 1 nút có khoá bằng X trên cây

• Hủy 1 phần tử trên cây phải đảm bảo điều kiện ràng buộc của Cây nhị phân tìm kiếm

• Có 3 trường hợp khi hủy 1 nút trên cây TH1: X là nút lá

TH2: X chỉ có 1 cây con (cây con trái hoặc cây con phải) TH3: X có đầy đủ 2 cây con

• TH1: Ta xoá nút lá mà không ành hưởng đến các nút khác trên cây • TH2: Trước khi xoá x ta móc nối cha của X với con duy nhất của X. • TH3: Ta dùng cách xoá gián tiếp

44

18 88

13 37 59 108

15 23 55 71

Hủy X=37

Minh hoạ hủy phần tử x có 1 cây con

Hủy 1 nút có 2 cây con

• Ta dùng cách hủy gián tiếp, do X có 2 cây con

• Thay vì hủy X ta tìm phần tử thế mạng Y. Nút Y có tối đa 1 cây con. • Thông tin lưu tại nút Y sẽ được chuyển lên lưu tại X.

• Ta tiến hành xoá hủy nút Y (xoá Y giống 2 trường hợp đầu) • Cách tìm nút thế mạng Y cho X: Có 2 cách

 C1: Nút Y là nút có khoá nhỏ nhất (trái nhất) bên cây con phải X

C2: Nút Y là nút có khoá lớn nhất (phải nhất) bên cây con trái của X

4418 88 18 88 13 37 59 108 15 23 40 55 71 30 23 Xoá nút có trường Key = 18, lúc đó nút có khoá 23 là nút thế mạng

Minh họa hủy phần tử X có 2 cây con

Cài đặt thao tác xoá nút có trường Key = x voidDeleteNodeX1(TREE &T,int x)

{

if(T!=NULL)

{ if(T->Key<x)DeleteNodeX1(T->Right,x); else {

if(T->Key>x)DeleteNodeX1(T->Left,x); else //timthấy Node có trường dữ liệu= x { TNode *p; (adsbygoogle = window.adsbygoogle || []).push({});

p=T;

if (T->Left==NULL) T = T->Right; else { if(T->Right==NULL) T=T->Left;

else ThayThe1(p, T->Right);//tìm bên cây con phải }

delete p; } } }

else printf("Khong tim thay phan can xoa tu");}

Hàm tìm phần tử thế mạng void ThayThe1(TREE &p, TREE &T) { if(T->Left!=NULL) ThayThe1(p,T->Left); else { p->Key = T->Key; p=T; T=T->Right; }

Ví dụ

• Cho dãy số nguyên: 30, 15, 20, 18, 10, 12, 11, 40, 35, 33, 37, 36, 34

• Hãy vẽ hình dạng cây nhị phân tìm kiếm ( cây sau cùng) khi thêm lần lượt từng giá trị trên vào cây. • Hãy cho biết kết quả của phép duyệt cây theo thứ

tự LNR( trái, gốc, phải), LRN( trái, phải, gốc). • Hãy vẽ hình dạng của cây nhị phân khi tiến hành

xóa liên tiếp nút mang giá trị 12 và 30

235

Bài tập về Cây nhị phân tìm kiếm

Một phần của tài liệu TỔNG QUAN VỀ THUẬT TOÁN VÀ PHƯƠNG PHÁP ĐẾM BM Công nghệ thông tin. Bài giảng Cơ sở toán học cho tin học. (Trang 32 - 40)