1. Trang chủ
  2. » Công Nghệ Thông Tin

Bài giảng Cấu trúc dữ liệu và giải thuật (2016): Phần 2

101 94 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 101
Dung lượng 2,2 MB

Nội dung

Nối tiếp phần 1, phần 2 tiếp tục trình bày về các cấu trúc dữ liệu rời rạc (cây, đồ thị). Đối với với mỗi cấu trúc dữ liệu, tài liệu tập trung trình bày bốn nội dung cơ bản: Định nghĩa, biểu diễn, thao tác và ứng dụng của cấu trúc dữ liệu. Ứng với mỗi thuật toán, tài liệu trình bày bốn nội dung cơ bản: Biểu diễn, đánh giá, thử nghiệm và cài đặt thuật toán. Mời các bạn cùng tham khảo để nắm nội dung chi tiết.

HỌC VIỆN CƠNG NGHỆ BƯU CHÍNH VIỄN THƠNG KHOA CƠNG NGHỆ THÔNG TIN -   BÀI GIẢNG CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Biên soạn : TS NGUYỄN DUY PHƯƠNG Hà Nội, tháng 12/2016 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT CHƯƠNG CÂY NHỊ PHÂN (BINARY TREE) Như đề cập trên, hạn chế lớn mảng ln địi hỏi khơng gian nhớ liên tục Điều gặp phải khó khăn xử lý đối tượng liệu lớn Hàng đợi khơng địi hỏi khơng gian nhớ liên tục gặp phải vấn đề tìm kiếm Trong chương ta xem xét cấu trúc liệu rời rạc nhị phân Các node tổ chức truy cập không theo thứ tự Cây nhị phân cho phép ta tổ chức xử lý ứng dụng có liệu lớn Tìm kiếm nhị phân khơng nhanh tìm kiếm mảng tốt nhiều so với danh sách liên kết Nội dung đề cập chương bao gồm:  Định nghĩa khái niệm  Biểu diễn nhị phân  Các thao tác nhị phân  Ứng dụng nhị phân  Cây nhị phân tìm kiếm  Cây nhị phân tìm kiếm cân  Cây nhiều nhánh 5.1 Định nghĩa khái niệm Đối với cấu trúc liệu ta có hai phương pháp tiếp cận: tiếp cận nhị phân tiếp cận lý thuyết đồ thị Cây nhị phân xem đơn giản cấu trúc Tuy nhiên, kết quan trọng nghiên cứu nhị phân tổng quát dịch chuyển nhị phân tương đương Điều có nghĩa kết phát biểu nhị phân cho tổng quát Dưới số khái niệm nhị phân 4.1.1 Định nghĩa Tập hợp hữu hạn node có kiểu liệu (có thể tập ) phân thành tập: • Tập thứ  có node gọi node gốc (root) • Hai tập cịn lại tự hình thành hai bên trái (left subtree) bên phải (right subtree) node gốc (hai tập tập ) Một số khái niệm cây: • Node gốc (Root) node định hình • Node cha (Father): node A node cha node B B node bên trái node A (left son) B node bên phải node B (right son) • Node (Leaf): node khơng có node trái, khơng có node phải NGUYỄN DUY PHƯƠNG 126 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT • • • • • • • • Node trung gian (Internal Node): node có node trái, có node phải, hai hai Node trước (Ancestor): node A gọi node trước node B node gốc A chứa node B Node sau trái (left descendent): node B node sau bên trái node A bên trái node A chứa node B Node sau phải (right descendent): node B node sau bên phải node A bên phải node A chứa node B Node anh em (brother): A B anh em A B node trái node phải node cha Bậc node (degree of node): Số tối đa node Mức node (level of node): mức node gốc có bậc 1, mức node khác mức node cha cộng thêm Chiều sâu (depth of tree): mức lớn node Như vậy, độ sâu độ dài đường dài từ node gốc đến node Hình 4.1 Cây nhị phân 5.1.2 Một số tính chất nhị phân Cây nhị phân có số tính chất đây:  Số lượng lớn node mức h 2h-1 Ví dụ, số lượng mức node gốc 21-1 = 1, mức 22-1 = 2…  Số lượng node lớn nhị phân có chiểu cao h 2h-1 Điều suy luận trực tiếp từ tính chất N≤ 20 + 21 + …+2h-1 = 2h-1 NGUYỄN DUY PHƯƠNG 127 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT  Đối với nhị phân có N node chiều cao tối thiểu hay mức tối thiểu ⌈𝑙𝑜𝑔2 (𝑁 + 1)⌉  Một nhị phân có L node có chiều cao tối đa ⌈𝑙𝑜𝑔2 (𝐿)⌉ +  Trong nhị phân số lượng node nhiều node có hai node đơn vị 5.1.3 Các loại nhị phân Dưới số loại nhị phân đặc biệt: • Cây lệch trái: nhị phân có node bên trái • Cây lệch phải: có node bên phải • Cây nhị phân (strickly binary tree): node gốc tất node trung gian có hai node (Hình 4.2) • Cây nhị phân đầy đủ(complete binary tree): nhị phân tất node có mức d (Hình 4.3) • Cây nhị phân gần đầy (almost complete binary tree):Cây nhị phân gần đầy có chiều sâu d nhị phân thỏa mãn (Hình 4.4): • Tất node có mức khơng nhỏ d-1 có hai node (cây nhị phân đầy đủ mức d-1) • Các node mức d đầy từ trái qua phải • Cây nhị phân hồn tồn cân bằng.Cây nhị phân có số node thuộc nhánh trái số node thuộc nhánh phải chênh lệch không (Hình 4.5) • Cây nhị phân tìm kiếm Cây nhị phân thỏa mãn điều kiện (Hình 4.6): • Hoặc rỗng có node gốc • Mỗi node gốc có tối đa hai Nội dung node gốc lớn nội dung node bên trái nhỏ nội dung node bên phải • Hai bên trái bên phải hình thành nên hai tìm kiếm • Cây nhị phân tìm kiếm hồn tồn cân Cây nhị phân tìm kiếm có chiều sâu bên trái chiều sâu bên phải chênh lệch không (Hình 4.7) NGUYỄN DUY PHƯƠNG 128 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT Hình 4.2 Cây nhị phân Hình 4.3 Cây nhị phân đầy đủ Hình 4.4 Cây hịn phân gần đầy NGUYỄN DUY PHƯƠNG 129 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT Hình 4.5 Cây nhị phân hồn tồn cân Hình 4.6 Cây nhị phân tìm kiếm Hình 4.7 Cây nhị phân tìm kiếm hồn tồn cân NGUYỄN DUY PHƯƠNG 130 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT 5.2 Biểu diễn nhị phân Có hai phương pháp biểu diễn nhị phân: biểu diễn liên tục biểu diễn rời rạc Trong trường hợp biểu diễn liên tục ta sử dụng mảng Trong trường hợp biểu diễn rời rạc ta sử dụng danh sách liên kết Phương pháp biểu diễn thực 5.2.1 Biểu diễn nhị phân mảng Tổ chức lưu trữ node mảng node[MAX] Trong đó:  Node gốc lưu trữ vị trí node[0]  Node trái node phải node[p] vị trí tương ứng node[2p+1] node[2p+2] Hình 4.8 mơ tả chi tiết phương pháp biểu diễn nhị phân dựa vào mảng Hình 4.8 Biểu diễn nhị phân mảng 5.2.2 Biểu diễn nhị phân danh sách liên kết Định nghĩa node node danh sách liên kết kép Mỗi node gồm có ba thành phần:  Thành phần liệu (data): dùng để lưu trữ thông tin node  Thành phần trỏ left: dùng để liên kết với node bên trái node  Thành phần trỏ right: dùng để liên kết với node bên phải node struct node { //định nghĩa node int data; //thành phần liệu node struct node *left; //liên kết với node bên trái struct node *right; // liên kết với node bên phải }*Tree; //đây Ví dụ với Hình 4.8 biểu diễn Hình 4.9 danh sách liên kết NGUYỄN DUY PHƯƠNG 131 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT Hình 4.9 Biểu diễn danh sách liên kết 5.3 Các thao tác nhị phân Các thao tác nhị phân bao gồm:  Tạo node cho  Tạo node gốc cho  Thêm vào node bên trái node p  Thêm vào node bên phải node p  Loại bỏ node bên trái node p  Loại bỏ node bên phải node p  Loại bỏ  Duyệt theo thứ tự trước  Duyệt theo thứ tự  Duyệt theo thứ tự sau 5.3.1 Định nghĩa khai báo nhị phân Sử dụng phương pháp biểu diễn danh sách liên kết, ta định nghĩa lớp thao tác sau: struct node { //định nghĩa cấu trúc node int data; //thành phần liệu node node *left;//thành phần liên kết với node trái node *right; //thành phần liên kết với node phải }*T; //cây nhị phân T NGUYỄN DUY PHƯƠNG 132 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT class Tree { //định nghĩa lớp thao tác T public: Tree(void){ //constructor lớp T=NULL; //cây ban đầu khởi tạo NULL } node *Make_Node(void);//tạo node rời rạc cóa giá trị value void Make_Root(void); //tạo node gốc cho void Insert_Left(node *root, int value); //tạo node trái cho node void Insert_Right(node *root, int value);//tạo node phải cho node void Remove_Left(node *root, int value); //loại node trái node void Remove_Right(node *root, int value); //loại node phải node void Clear_Tree(node *root); //loại bỏ void NLR(node *root); //duyệt theo thứ tự trước void LNR(node *root); //duyệt theo thứ tự void LRN(node *root); //duyệt theo thứ tự sau void Function(void); //hàm kiểm tra thao tác }; 5.3.2 Các thao tác thêm node vào nhị phân Đối với nhị phân tổng qt, node đóng vai trị quan trọng node gốc (root) (Make-Root()) Sau có node gốc, tồn định hình xung quanh node gốc Quá trình định hình thực phép thêm node bên trái (Insert-Left())cho node thêm node bên phải cho node (Insert_Right()) Các thao tác thêm node cụ thể tiến hành sau: Thao tác tạo node rời rạc có giá trị value: node *Tree::Make_Node(void){ //tạo node rời rạc có giá trị value node *tmp; //sử dụng trỏ node tmp int value;//giá trị node cần tạo tmp = new node; //cấp phát miền nhớ cho node coutvalue; tmp->data = value; //thiết lập thành phần liệu node tmp->left = NULL; //thiết lập liên kết trái cho node tmp->right = NULL; //thiết lập liên kết phải cho node return tmp; // node rời rạc tạo } Thao tác tạo node gốc cho cây: void Tree::Make_Root(void){ //tạo node gốc cho if (T!=NULL) {//nếu không rỗng NGUYỄN DUY PHƯƠNG 133 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT coutcuoi>>w; //đọc cạnh (dau, cuoi, trongso) graph[dau][cuoi]=graph[cuoi][dau]=w; } fp.close(); primMST(graph,n); } 6.6 Bài tốn tìm đường ngắn Xét đồ thị G=; | V| = n, | E | = m Với cạnh (u, v)E, ta đặt tương ứng với số thực A[u][v] gọi trọng số cạnh Ta đặt A[u,v]= p (u, v)E Nếu dãy v0, v1, , vk đường G i 1 A[vi 1 , vi ] gọi độ dài đường Bài tốn tìm đường ngắn đồ thị dạng tổng quát phát biểu dạng sau: tìm đường ngắn từ đỉnh xuất phát sV (đỉnh nguồn) đến đỉnh cuối tV (đỉnh đích) Đường gọi đường ngắn từ s đến t, độ dài đường d(s,t) gọi khoảng cách ngắn từ s đến t (trong trường hợp tổng quát d(s,t) âm) Nếu khơng tồn đường từ s đến t độ dài đường d(s,t)= Dưới số thể cụ thể toán Trường hợp Nếu s cố định t thay đổi, tốn phát biểu dạng tìm đường ngắn từ s đến tất đỉnh lại đồ thị Đối với đồ thị có trọng số khơng âm, tốn ln có lời giải thuật tốn Dijkstra Đối với đồ thị có trọng số âm khơng tồn chu trình âm, tốn có lời giải thuật tốn Bellman-Ford Trong trường hợp đồ thị có chu trình âm, tốn khơng có lời giải NGUYỄN DUY PHƯƠNG 213 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT Trường hợp Nếu s thay đổi t thay đổi, tốn phát biểu dạng tìm đường ngắn tất cặp đỉnh đồ thị Bài tốn ln có lời giải đồ thị khơng có chu trình âm Đối với đồ thị có trọng số khơng âm, toán giải cách thực lặp lại n lần thuật tốn Dijkstra Đối với đồ thị khơng có chu trình âm, tốn giải thuật toán Floyd-Warshall 6.6.1 Thuật toán Dijkstra Thuật toán tìm đường ngắn từ đỉnh s đến đỉnh lại 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 thực sở gán tạm thời cho đỉnh Nhãn đỉnh cho biết cận độ dài đường ngắn tới đỉnh Các nhãn biến đổi (tính lại) nhờ thủ tục lặp, mà bước lặp số đỉnh có nhãn khơng thay đổi, nhãn độ dài đường ngắn từ s đến đỉnh Thuật tốn Dijkstra tìm đường ngắn từ s đến tất đỉnh cịn lại đồ thị mơ tả chi tiết Hình 5.17 a) Biểu diễn thuật tốn Thuật toán Dijkstra (s): //s V đỉnh G = Begin Bước (Khởi tạo): d[s]=0; //Gán nhãn đỉnh s T = V\{s}; // T tập đỉnh có nhãn tạm thời for each v V { //Sử dụng s gán nhãn cho đỉnh lại d[v] = A[s,v]; truoc[v]=s; endfor; Bước (Lặp): while (T  ) { Tìm đỉnh uT cho d[u] = { d[z] | zT}; T= T\{u}; //cố định nhãn đỉnh u for each v T { //Sử dụng u, gán nhãn laị cho đỉnh if ( d[v] > d[u] + A[u, v] ) then { d[v] = d[u] + A[u, v]; //Gán lại nhãn cho đỉnh v; truoc[v] = u; endif; endfor; endwhlie; Bước (Trả lại kết quả): Return (d[s], truoc[s]); End Hình 5.17 Thuật tốn Dijkstra NGUYỄN DUY PHƯƠNG 214 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT b) Độ phức tạp thuật toán Độ phức tạp thuật tốn O(V2), V số đỉnh đồ thị Bạn đọc tự tìm hiểu chứng minh độ phức tạp thuật toán Dijkstra tài liệu liên quan c) Thử nghiệm thuật toán Bạn đọc tự tìm hiểu phương pháp thử nghiệm thuật tốn Dijkstra tài liệu liên quan d) Cài đặt thuật toán #include #include #define MAX 100 using namespace std; //hàm tìm đỉnh có nhãn nhỏ int minDistance(int dist[], bool sptSet[], int n){ // thiết lập nhãn nhỏ ban đầu int = INT_MAX, min_index; for (int v = 1; v >cuoi>>trongso; graph[dau][cuoi]= trongso; graph[cuoi][dau]= trongso;//bỏ đồ thị có hướng } fp.close(); dijkstra(graph, 1, 9); } 6.6.2 Thuật tốn Bellman-Ford Thuật tốn Bellman-Ford dùng để tìm đường ngắn đồ thị khơng có chu trình âm Do vậy, thực thuật toán Bellman-Ford ta cần kiểm tra đồ thị có chu trình âm hay khơng Trong trường hợp đồ thị có chu trình âm, tốn khơng có lời giải Thuật tốn thực theo k = n - vòng lặp tập đỉnh tập cạnh tùy thuộc vào dạng biểu diễn đồ thị Nếu đồ thị biểu diễn dạng ma trận kề, độ phức tạp thuật toán O(V3), với V số đỉnh đồ thị Trong trường hợp đồ thị biểu diễn dạng danh sách cạnh, độ phức tạp thuật toán O(V.E), với V số đỉnh đồ thị, E số cạnh đồ thị Thuật tốn mơ tả chi tiết Hình 5.18 cho đồ thị biểu diễn dạng ma trận kề NGUYỄN DUY PHƯƠNG 216 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT a) Biểu diễn thuật toán Thuật toán Bellman-Ford (s): //s V đỉnh đồ thị Begin: Bước (Khởi tạo): for vV { //Sử dụng s gán nhãn cho đỉnh vV D[v] = A[s][v]; Truoc[v] = s; } Bước (Lặp) : D[s] = 0; K=1; while (K D[u] + A[u][v] ) { D[v]= D[u] + A[u][v]; Truoc[v] = u; endif; endfor; endfor; endwlie; Bước (Trả lại kết quả): Return( D[v], Truoc[v]: vU); End Hình 5.18 Thuật tốn Bellman-Ford b) Độ phức tạp thuật toán Độ phức tạp thuật toán O(VE), V, E số đỉnh số cạnh đồ thị Bạn đọc tự tìm hiểu chứng minh độ phức tạp thuật toán Bellman-Ford tài liệu liên quan c) Thử nghiệm thuật toán Bạn đọc tự tìm hiểu phương pháp thử nghiệm thuật toán Bellman-Ford tài liệu liên quan d) Cài đặt thuật toán #include #include #include #include #define MAX 100 #define MAXC 10000 NGUYỄN DUY PHƯƠNG 217 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT int C[MAX][MAX]; //Ma tran so bieu dien thi int D[MAX]; //Do dai duong di int Trace[MAX]; //Luu lai vet duong di int n, m, S, F; // n:So dinh; S: Dinh bat dau; F: Dinh ket thuc FILE *fp; void Read_Data(void){ int i, u, v;fp = fopen("dothi.in","r"); fscanf(fp,"%d%d%d%d",&n,&m,&S,&F); for(u=1; uedge[j].dest; int weight = graph->edge[j].weight; if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) dist[v] = dist[u] + weight; } } // Bước 3: kiểm tra chu trình âm for (int i = 1; i < E; i++) { int u = graph->edge[i].src; int v = graph->edge[i].dest; int weight = graph->edge[i].weight; if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) { printf("Đồ thị có chu trình âm"); return; } } printArr(dist, V); } int main() { int V, E; // số đỉnh số cạnh đồ thị int dau, cuoi, trongso; ifstream fp("dothich.in"); //mở file đồ thị dạng danh sách cạnh fp>>V>>E;V=V; E=E; //đọc số đỉnh số cạnh Graph* graph = createGraph(V+1, E+1); //tạo đồ thị G= for(int i=1; i>dau>>cuoi>>trongso; graph->edge[i].src = dau; graph->edge[i].dest = cuoi; graph->edge[i].weight = trongso; } NGUYỄN DUY PHƯƠNG 220 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT fp.close(); BellmanFord(graph, 2); } 6.6.3 Thuật tốn Floyd-Warshall Để tìm đường ngắn tất cặp đỉnh đồ thị, sử dụng V lần thuật tốn Ford_Bellman Dijkstra (trong trường hợp trọng số không âm) Tuy nhiên, hai thuật toán sử dụng có độ phức tạp tính tốn lớn (chí O(V3)) Trong trường hợp tổng quát, người ta thường dùng thuật tốn FloydWarshall Thuật tốn Floy mơ tả chi tiết Hình 5.19 a) Biểu diễn thuật tốn Thuật toán Floyd-Warshall: Begin: Bước (Khởi tạo): for (i=1; i n; i++) { for (j =1; j n; j++) { d[i,j] = a[i, j]; p[i,j] = i; } } Bước (lặp) : for (k=1; k n; k++) { for (i=1; i n; i++){ for (j =1; j n; j++) { if (d[i,j] > d[i, k] + d[k, j]) { d[i, j] = d[i, k] + d[k, j]; p[i,j] = p[k, j]; } } } } Bước (Trả lại kết quả): Return (p([i,j], d[i,j]: i, jV); Hình 5.19 Thuật toán Floyd-Warshall b) Độ phức tạp thuật toán NGUYỄN DUY PHƯƠNG 221 CHƯƠNG NGĂN XẾP, HÀNG ĐỢI, DANH SÁCH LIÊN KẾT Độ phức tạp thuật toán O(V3), V số đỉnh đồ thị Bạn đọc tự tìm hiểu chứng minh độ phức tạp thuật toán Floyd-Warshall tài liệu liên quan c) Kiểm nghiệm thuật tốn Bạn đọc tự tìm hiểu phương pháp kiểm nghiệm thuật toán Floyd-Warshall tài liệu liên quan d) Cài đặt thuật toán #include #include #include #define MAX 10000 #define TRUE #define FALSE int A[50][50], D[50][50], S[50][50]; int n, u, v, k;FILE *fp; void Init(void){ int i, j, k; fp=fopen(“FLOY.IN”,”r”); if(fp==NULL){ printf(“\n Khong co file input”); getch(); return; } for(i=1; i

Ngày đăng: 01/03/2022, 09:35

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN