Duyệt theo chiều sâu

Một phần của tài liệu Bài giảng Cấu trúc dữ liệu và giải thuật (2013): Phần 1 (Trang 90)

a b c d a b c d b a d c b c NULL d NULL b NULL d NULL b a d c b c NULL a NULL a NULL b NULL c d b

Quá trình duyệt theo chiều sâu bắt đầu từ một đỉnh nào đó của đồ thị. Sau khi thăm đỉnh này, quá trình duyệt theo chiều sâu được lặp lại với tất cả các đỉnh kề của nó. Tuy nhiên, đồ thị có thể tồn tại các chu trình, do vậy, ta cần phải đánh dấu các đỉnh đã duyệt để tránh duyệt lại đỉnh này một lần nữa.

Với trình tự duyệt như trên, quá trình duyệt sẽ duyệt hết một “nhánh” của đồ thị rồi mới sang “nhánh” khác. Do vậy, phương pháp duyệt này được gọi là duyệt theo chiều sâu.

Hình 6.8 Duyệt đồ thị theo chiều sâu

Ví dụ, với đồ thịở trên, quá trình duyệt theo chiều sâu bắt đầu từ đỉnh a sẽ cho thứ tự duyệt

như sau:

- Sau khi thăm đỉnh a, tiến hành thăm đỉnh kề với a là b. Tiếp theo thăm đỉnh kề b là d. Đỉnh d không kề đỉnh nào, do vậy quay lại bước trước.

- Đỉnh b chỉ có 1 đỉnh kề là d đã thăm, do vậy quay trở lại bước trước. - Đỉnh a còn đỉnh kề là c chưa thăm, do vậy tiến hành thăm đỉnh này.

Như vậy, thứ tự các đỉnh trong qúa trình duyệt là: a, b, d, c

Quá trình duyệt sẽ chỉ duyệt theo các cạnh dẫn tới các đỉnh chưa thăm. Các cạnh dẫn tới các

đỉnh thăm rồi sẽ được bỏ qua. Chẳng hạn, trong quá trình duyệt đồ thị trên, khi duyệt đến đỉnh c, cạnh nối tới b sẽ được bỏ qua vì đỉnh b đã được thăm rồi.

Cài đặt phương pháp duyệt theo chiều sâu như sau:

Để kiểm tra việc duyệt mỗi đỉnh đúng một lần, chúng ta sử dụng một mảng daxet gồm n phần tử (tương ứng với n đỉnh). Nếu đỉnh thứ i đã được duyệt, daxet[i]=1, ngược lại, daxet[i]=0. Thuật toán tìm kiếm theo chiều sâu bắt đầu từ đỉnh v nào đó sẽ duyệt tất cả các đỉnh liên thông với v. Thuật toán có thể được mô tả bằng thủ tục đệ qui DeepFirstSearch.

void DeepFirstSearch(int v){

Thăm đỉnh v;

daxet[v] = 1;

for mỗi đỉnh u kề với v {

if (daxet[u]=0 ) DeepFirstSearch(v); } } b a d c

Thủ tục DeepFirstSearch sẽ thăm tất cả các đỉnh cùng thành phần liên thông với v mỗi đỉnh

đúng một lần. Để đảm bảo duyệt tất cả các đỉnh của đồ thị (có thể có nhiều thành phần liên thông), chúng ta chỉ cần thực hiện :

for( i=1; in; i++) daxet[i] = 0; for( i:=1;i n; i++) if (daxet[i]=0)

DeepFirstSearch(i);

6.3.2 Duyệt theo chiều rộng

Quá trình duyệt theo chiều rộng cũng bắt đầu từ một đỉnh nào đó của đồ thị. Tiếp đến, các đỉnh kề của nó sẽ được thăm, rồi tiếp tục đến các đỉnh kề của các đỉnh vừa thăm .v.v.

Như vậy, quá trình duyệt theo chiều rộng không duyệt theo từng “nhánh” của đồ thị mà duyệt

theo độ sâu của các đỉnh so với đỉnh ban đầu. Từ đỉnh bắt đầu, các đỉnh có khoảng cách với đỉnh ban

đầu là 1 được duyệt, tiếp đến là các đỉnh có khoảng cách 2, v.v.

Hình 6.9 Duyệt đồ thị theo chiều rộng

Ví dụ, vẫn với đồ thị như ở phần trước, quá trình duyệt theo chiều rộng với đỉnh bắt đầu là a sẽ

cho thứ tự duyệt như sau:

- Sau khi thăm đỉnh a, tiến hành thăm các đỉnh kề với a là b và c. - Tiếp theo, thăm các đỉnh kề với b là d.

- Đỉnh kề với c là b đã được thăm rồi nên bỏ qua.

Như vậy, thứ tự các đỉnh được thăm là: a, b, c, d.

Duyệt theo chiều rộng có thể được cài đặt không đệ qui bằng cách sử dụng hàng đợi để lưu các đỉnh cần được thăm. Các bước như sau:

Đầu tiên, đưa đỉnh bắt đầu v vào hàng đợi, sau đó lặp lại quá trình sau cho đến khi hàng đợi không còn phần tử nào:

- Lấy phần tử ra khỏi hàng đợi, đưa vào biến v. - Thămđỉnh v.

- Với mỗi đỉnh kề với v, nếu đỉnh này chưa được thăm thì đưa vào hàng đợi. Ví dụ, đối với đồ thịở hình … ở trên, các bước thực hiện như sau:

Đầu tiên, đưa đỉnh a vào hàng đợi.

b a

- Lấy đỉnh a ra khỏi hàng đợi, thăm đỉnh a.

- Đưa 2 đỉnh kề với a là b và c vào hàng đợi.

- Lấy đỉnh b ra khỏi hàng đợi, thăm đỉnh b

- Đưa đỉnh kề với b là d vào hàng đợi

- Lấy đỉnh c ra khỏi hàng đợi, thăm đỉnh c

- Đỉnh kề với c là b đã thăm, vì vậy không đưa vào hàng đợi. Lấy đỉnh d ra khỏi hàng đơi, thăm đỉnh d.

- Hàng đợi hết phần tử, quá trình duyệt kết thúc. Thứ tự thăm các đỉnh là: a, b, c, d Cài đặt cho thuận toán duyệt theo chiều rộng như sau:

void BreadthFirstSearch(int v){ queue = ;

Đưa v vào hàng đợi; daxet[v] = 1;

while (queue   ){

Lấy phần tử ra khỏi hàng đợi, đưa vào biến u;

Thăm đỉnh u;

for mỗi đỉnh w kề với u { if (daxet[w]=0 ) {

Đưa w vào hàng đợi;

daxet[w] = 1; } } } a b c c c d d

Tương tự như duyệt theo chiều sâu, thủ tục BreadthFirstSearch sẽthăm tất cả các đỉnh cùng thành phần liên thông với v. Để thăm tất cả các đỉnh của đồ thị, chúng ta chỉ cần thực hiện:

for( v=1; vn; v++) daxet[v] = 0; for(v=1; vn; v++) if (daxet[v]=0)

BreadthFirstSearch(u);

6.3.3 Ứng dụng duyệt đồ thị để kiểm tra tính liên thông

Như đã nói ở trên, duyệt đồ thị (theo chiều rộng hay theo chiều sâu) sẽ thăm tất cả các đỉnh cũng thành phần liên thông với đỉnh bắt đầu duyệt. Vì vậy, ta có thể sử dụng thủ tục duyệt đồ thịđể

kiểm tra tính liên thông của đồ thị, hoặc thậm chí có thểđếm được số thành phần liên thông của đồ

thị.

Để làm được điều này, ta thực hiện duyệt từ đầu đến cuối danh sách các đỉnh của đồ thị. Tại mỗi bước, ta kiểm tra nếu đỉnh chưa được thăm thì ta tiến hành gọi thủ tục duyệt đồ thị cho đỉnh này. Như vậy, nếu đồ thị liên thông hoàn toàn thì chỉ mất một lần gọi thủ tục duyệt cho đỉnh đầu tiên. Ngược lại, số lần gọi thủ tục duyệt chính là số thành phần liên thông của đồ thị.

int lt=0; for( v=1; vn; v++) daxet[v] = 0; for(v=1; vn; v++) if (daxet[v]=0){ BreadthFirstSearch(u); lt++; }

if (lt ==1) printf(“Do thi lien thong!”);

else printf(“Do thi khong lien thong, so thanh phan lien thong la %d”, lt);

6.4TÓM TẮT CHƯƠNG 6

- Khái niệm đồ thị có hướng:

Đồ thị có hướng G = <V, E> bao gồm: (1) V là một tập hữu hạn các đỉnh.

(2) E là một tập hữu hạn, có thứ tự các cặp đỉnh của V, gọi là các cạnh. - Khái niệm đồ thị vô hướng:

Đồ thị vô hướng G = <V, E> bao gồm: (1) V là một tập hữu hạn các đỉnh.

(2) E là một tập hữu hạn các cặp đỉnh phân biệt của V, gọi là các cạnh. - Đồ thị có thểđược biểu diễn bằng ma trận kề hoặc danh sách kề.

- Đồ thị biểu diễn bằng ma trận kề A có tính chất: Phần tửở hàng i, cột j của ma trận A có giá trị 1 khi có một cạnh nối từ vi đến vj. Ngược lại, phần tử đó có giá trị 0.

- Biểu diễn đồ thị bằng danh sách kề: Sử dụng một danh sách liên kết cho mỗi đỉnh của đồ

thị. Danh sách liên kết của một đỉnh sẽ chứa các đỉnh khác kề với nó

- Duyệt theo chiều sâu bắt đầu từ một đỉnh nào đó của đồ thị. Sau khi thăm đỉnh này, quá trình duyệt theo chiều sâu được lặp lại với tất cả các đỉnh kề của nó.

- Duyệt theo chiều rộng cũng bắt đầu từ một đỉnh nào đó của đồ thị. Tiếp đến, các đỉnh kề

của nó sẽ được thăm, rồi tiếp tục đến các đỉnh kề của các đỉnh vừa thăm .v.v.

6.5CÂU HỎI VÀ BÀI TẬP

1. Cho biết biểu diễn bằng ma trận kề và danh sách kề của đồ thị bên dưới:

2. Cho biết ma trận kề của đồ thị trọng số sau:

3. Với đồ thị câu 1, cho biết trình tự thăm các đỉnh khi thực hiện duyệt theo chiều sâu bắt đầu từđỉnh a.

4. Với đồ thị câu 2, cho biết trình tự thăm các đỉnh khi thực hiện duyệt theo chiều rộng bắt

đầu từđỉnh a.

5. Cho biết số thành phần liên thông của đồ thị bên dưới. 2 9 4 7 a b c d e 5 b a d c a b c d e

Một phần của tài liệu Bài giảng Cấu trúc dữ liệu và giải thuật (2013): Phần 1 (Trang 90)

Tải bản đầy đủ (PDF)

(95 trang)