Nơi tổng hợp và chia sẻ kiến thức liên quan đến thuật toán nói chung và lý thuyết tin học nói riêng.
Đang xem: Bfs là gì
Đồ thị — Giới thiệu về Lý thuyết đồ thị thuật toán
Tháng Chín 26, 2015 in Chưa được phân loại | Miễn bình luận
Trong loạt bài này và các bài tiếp theo chúng ta sẽ làm quen với đồ thị và các thuật toán với đồ thị. Graph là một đối tượng tổ hợp đã được nghiên cứu và ứng dụng rất nhiều trong thực tế (có lẽ viết cái này hơi thừa). Trong phần này chúng ta sẽ:
Làm quen với các khái niệm cơ bản liên quan đến đồ thị Cách biểu diễn đồ thị trong máy tính để chúng ta có thể thao tác với nó.
Độc giả có thể bỏ qua những phần đã quen thuộc. Ghi chú của Jeff Erickson vẫn là tài liệu tham khảo chính cho bài viết này.
Khái niệm
Một đồ thịký hiệu là $G(V,E)$, gồm 2 thành phần:
Tập hợp $V$, bao gồm các đối tượng, được gọi là tập hợp các đỉnh (đỉnh) của đồ thị Tập hợp $E subseteq V^2$, bao gồm một cặp đỉnh, được gọi là tập hợp các cạnh (đỉnh). ) của đồ thị
Chúng ta sẽ ký hiệu $n,m$ là số đỉnh và số cạnh của đồ thị, nghĩa là $|V| = n, |E|= m$. Số đỉnh trong một đồ thị đôi khi còn được gọi là . bậc của đồ thị (thứ tự của đồ thị).
Các đỉnh chúng ta sẽ biểu thị bằng các chữ thường như $u,v,x,y,z$. Cạnh giữa hai đỉnh $u,v$ có thể là không phương hướng hoặc có hướng. Trong trường hợp đầu tiên, chúng ta sẽ biểu thị cạnh là $uv$, và trong trường hợp sau, chúng ta sẽ biểu thị nó là $u
ightarrow v$ để chỉ định hướng của cạnh từ $u$ đến $v$. Thông thường khi chúng ta nói cạnh, chúng ta muốn nói đến cạnh vô hướng và đối với cạnh có hướng, chúng ta sẽ gọi nó là cạnh cây cung (cung). Hình $(1,2)$ của hình bên dưới biểu thị một đồ thị vô hướng (các cạnh là vô hướng) và hình $(3)$ của hình bên dưới biểu thị một đồ thị có hướng.
Một đồ thị vô hướng được gọi là liên thông nếu tồn tại đường đi giữa mọi cặp điểm. Một đồ thị có hướng được liên thông (yếu) nếu đồ thị vô hướng thu được từ đồ thị bằng cách bỏ qua hướng của cạnh được kết nối. Đồ thị có hướng được gọi là kết nối mạnh mẽ (liên thông mạnh) nếu tồn tại một đường đi có hướng giữa mọi cặp điểm. Rõ ràng, nếu một đồ thị có hướng liên thông mạnh thì nó cũng liên thông yếu. Tuy nhiên, điều ngược lại chưa chắc đã đúng (ví dụ?). Ví dụ: đồ thị $(1)$ bên dưới không liên thông, đồ thị $(2)$ liên thông, đồ thị $(3)$ liên thông yếu (nhưng không mạnh) và đồ thị $(4)$ liên thông . giao tiếp mạnh mẽ.
Bạn cũng có thể kết hợp biểu diễn danh sách kề với một số cấu trúc dữ liệu khác. Cụ thể, thay vì sử dụng danh sách liên kết để biểu diễn các đỉnh liền kề với đỉnh $u$, chúng ta cũng có thể sử dụng bảng băm hoặc cấu trúc cây để biểu diễn nó. Trong khuôn khổ các bài viết ở đây, chúng tôi ít sử dụng (hoặc không sử dụng) các cấu trúc như vậy.
Ngoài ra, chúng ta có thể biểu diễn đồ thị bằng cách liệt kê tất cả các cặp $(u,v)$ thỏa mãn $uv trong E$. Biểu diễn này có bộ nhớ $O(m)$. Tuy nhiên, việc thực hiện các thao tác cơ bản trong biểu diễn này sẽ rất tốn kém. Đôi khi có thể kết hợp biểu diễn này với biểu diễn danh sách kề để tận dụng lợi thế của cả hai biểu diễn trong khi bộ nhớ vẫn tuyến tính.
Duyệt đồ thị
Vấn đề 1: Cho một đồ thị $G(V,E)$ và một đỉnh $s trong V$, in các đỉnh $v$ sao cho tồn tại một đường đi từ $s$ đến $v$.
Chúng ta gọi bài toán trên là bài toán duyệt đồ thị từ một đỉnh $s$. Để đơn giản, chúng ta sẽ giả sử rằng đồ thị là liên thông. Trường hợp đồ thị không liên thông sẽ được mở rộng ở cuối phần này. Cách chung để duyệt đồ thị như sau: Chúng ta sẽ sử dụng hai loại nhãn để gán cho các đỉnh của đồ thị: chưa đến thăm (chưa ghé thăm) và đã đến thăm (đã viếng thăm). Ban đầu tất cả các đỉnh được đánh dấu là chưa được thăm. Chúng ta sẽ duy trì một set $C$ (cách triển khai set $C$ chúng ta sẽ tìm hiểu sau), ban đầu rỗng. Chúng ta sẽ lặp lại 2 bước sau:
Nhận một đỉnh $u$ trong $C$ (thủ tục Remove$(C)$ bên dưới). Đánh dấu $u$ là đã truy cập. Đặt các lân cận của $u$ với các nhãn chưa được thăm trong $C$. Thủ tục Add$(C,v)$ dưới đây sẽ đưa đỉnh $v$ vào tập hợp $C$.
Thuật toán dừng khi $C = emptyset$. Mã giả như sau:
GenericGraphTraverse($G(V,E),s$): đánh dấu tất cả các đỉnh không được viếng thăm Thêm$(C,s)$ trong khi $C
ot= tập rỗng$ $u leftarrow$ Xóa$(C)$ $ll gg$ nếu $u$ là không được viếng thăm đánh dấu $u$ đã truy cập cho tất cả $uv trong E$ và $v$ không được truy cập $ll(**)gg$
Thêm$(C,v)$ Nhận xét: Một đỉnh có thể được bao gồm nhiều lần trong tập hợp $C$ (vì vậy $C$ không nhất thiết phải là một tập hợp vì nó có nhiều phần tử giống nhau). Ví dụ, xét ba đỉnh kề nhau $u,v,w$. Đỉnh $u$ được lấy ra từ đỉnh $C$ đầu tiên; đánh dấu $u$ là đã truy cập. Chẳng bao lâu nữa, $v$ và $w$ sẽ được đưa vào $C$. Tiếp theo, lấy $v$ ra khỏi $C$ và đánh dấu $v$ là đã truy cập. Bây giờ chúng ta tiếp tục đặt $w$ vào $C$ một lần nữa vì theo mã giả trên, $w$ là hàng xóm của $v$ và có nhãn không được thăm. Ở đây, tôi sẽ không
kiểm tra xem một đỉnh đã có trong $C$ chưa trước khi đưa nó vào $C$.
Từ mã giả trên, chúng ta thấy rằng tập hợp $C$ lưu trữ các đỉnh liền kề với ít nhất một đỉnh được thăm.
Xem thêm: “tất cả các cách” Về Phong Thủy Phòng Khách, 14 Lưu Ý Phong Thủy Phòng Khách Ít Người Biết Phân tích thuật toán:
Giả sử rằng chúng ta sử dụng một cấu trúc để triển khai $C$ sao cho việc thêm hoặc lấy bất kỳ đỉnh nào (dòng $
$ và dòng cuối cùng) được thực hiện trong thời gian $O(1)$ (ví dụ: nếu $C$ được triển khai với danh sách liên kết, việc thêm hoặc xóa đỉnh ở đầu danh sách có thể được thực hiện trong thời gian ngắn. thời gian $O(1)$). Chúng tôi có một vài quan sát:
Các đỉnh đã bị xóa khỏi $C$ và được đánh dấu là đã truy cập sẽ không bao giờ được trả về tập hợp $C$. Mỗi khi đỉnh $v$ được chèn vào $C$, một đỉnh lân cận của nó sẽ được đánh dấu là đã thăm. Do đó, đỉnh $v$ sẽ được chèn vào $C$ không quá $d(v)$ lần. Mỗi khi chúng ta lấy một đỉnh $u$ ra khỏi $C$, chúng ta sẽ đi qua tất cả các lân cận của $u $. Thao tác này mất $O(d(u))$ thời gian. Theo nhận xét 1, việc truyền tải này chỉ có thể được thực hiện nhiều nhất một lần.
Từ nhận xét trên, ta suy ra tổng thời gian tính toán của thuật toán là $O(sum_{u in V}d(u)) = O(m)$. Trong trường hợp đồ thị không liên thông, ta phải duyệt lần lượt các thành phần liên thông. Vì đồ thị có tối đa $n$ thành phần liên thông nên ta có: Nếu chúng ta triển khai $C$ với danh sách liên kết thì chắc chẳng có gì thú vị. Tuy nhiên, nếu chúng ta triển khai $C$ với hàng đợi hoặc ngăn xếp, chúng ta sẽ nhận được một số thuộc tính thú vị từ biểu đồ. Trong trường hợp chúng tôi thực thi $C$ bằng hàng đợi, chúng tôi gọi thuật toán duyệt theo chiều rộng (Tìm kiếm hơi thở đầu tiên – BFS). Trong trường hợp chúng tôi thực thi $C$ trên ngăn xếp, chúng tôi gọi thuật toán
duyệt theo chiều sâu
(Tìm kiếm theo chiều sâu – DFS). Sau đây chúng ta sẽ thảo luận về cả hai thuật toán.
$. Giá trị của $d $, như chúng tôi sẽ chỉ ra bên dưới, là khoảng cách ngắn nhất từ $s$ đến $v$. Mã giả như sau: BFS($G(V,E),s$): cho mỗi $d
mũi tên trái 0$ trong khi $C ot= tập rỗng$ $u leftarrow$ Dequeue$(C)$ nếu $u$ là không được viếng thăm đánh dấu $u$ đã truy cập cho
mũi tên trái d
+1$
Mã giả mã trong C:
= DỄ DÀNG
“);}////////////////////////////////////////////// ///////////////////////////////////////////////// / /////////////////////////////////////////////// HÀNG ĐỢI GIAO DIỆN//////////////////////////////////////////////// ///////////////////////////////////////////////// ///////////////////////////////Queue *init_queue(int size){Queue *Q = malloc(sizeof(Queue)); Q ->storage = (int *)malloc(size*sizeof(int));Q->front = 0;Q->back = -1;return Q;}void enqueue(Queue *Q, int elem){Q -> quay lại ++;Q->lưu trữ
duhoc-o-canada.com có thể thay đổi & cải thiện nội dung tốt hơn cho các bạn nhé! Cám ơn bạn đã ghé thăm Website: duhoc-o-canada.com của duhoc-o-canada.com
Nhớ để nguồn bài viết này: Thuật Toán Bfs Là Gì của website duhoc-o-canada.com
Chuyên mục: Là gì?