You are on page 1of 7

20.

1 Biểu diễn đồ thị

Bạn có thể chọn giữa hai cách tiêu chuẩn để biểu diễn đồ thị G = (V,

E): như một tập hợp các danh sách liền kề hoặc như một ma trận liền kề. Hoặc

Cách áp dụng cho cả đồ thị có hướng và không định hướng. Bởi vì các

Biểu diễn danh sách liền kề cung cấp một cách nhỏ gọn để thể hiện

đồ thị thưa thớt—những biểu đồ |E | ít hơn nhiều so với |V|

2 — thường là

phương pháp lựa chọn. Hầu hết các thuật toán đồ thị được trình bày trong này

Sách giả sử rằng một đồ thị đầu vào được biểu diễn dưới dạng danh sách liền kề.

Tuy nhiên, bạn có thể thích biểu diễn ma trận liền kề hơn khi

Biểu đồ dày đặc—|E | gần |V|

2—hoặc khi bạn cần có khả năng

cho biết nhanh liệu có một cạnh nối hai đỉnh nhất định hay không. Cho

Ví dụ, hai trong số các thuật toán đường dẫn ngắn nhất tất cả các cặp được trình bày trong

Chương 23 giả định rằng đồ thị đầu vào của chúng được biểu diễn bằng tính liền kề

Ma trận.

Hình 20.1 Hai biểu diễn của một đồ thị không định hướng. (a) Đồ thị G không định hướng với 5

đỉnh và 7 cạnh. (b) Biểu diễn danh sách liền kề của G. (c) Ma trận liền kề

đại diện của G.

Hình 20.2 Hai biểu diễn của đồ thị có hướng. (a) Đồ thị có hướng G với 6 đỉnh và 8

Cạnh. (b) Biểu diễn danh sách liền kề của G. (c) Biểu diễn ma trận liền kề của G.

Biểu diễn danh sách liền kề của đồ thị G = (V, E) bao gồm một

mảng Adj của |V| danh sách, một cho mỗi đỉnh trong V. Với mỗi u ∈ V, các

Danh sách liền kề Adj[u] chứa tất cả các đỉnh v sao cho có một cạnh
(u, v) ∈ E. Nghĩa là, Adj[u] bao gồm tất cả các đỉnh liền kề u trong G.

(Ngoài ra, nó có thể chứa các con trỏ đến các đỉnh này.) Kể từ khi

Danh sách liền kề đại diện cho các cạnh của biểu đồ, mã giả của chúng tôi xử lý

mảng Adj như một thuộc tính của đồ thị, giống như tập hợp cạnh E. Trong

mã giả, do đó, bạn sẽ thấy ký hiệu như G.Adj [u]. Hình

20.1(b) là biểu diễn danh sách liền kề của đồ thị không định hướng trong

Hình 20.1(a). Tương tự, Hình 20.2(b) là một danh sách liền kề

biểu diễn đồ thị có hướng trong Hình 20.2(a).

Nếu G là đồ thị có hướng, tổng độ dài của tất cả các phần liền kề

Danh sách là |E|, vì một cạnh của dạng (u, v) được biểu diễn bằng cách có v

xuất hiện trong Adj[u]. Nếu G là đồ thị không định hướng, tổng độ dài của

Tất cả các danh sách liền kề là 2 |E|, vì nếu (u, v) là một cạnh không định hướng, thì u

xuất hiện trong danh sách liền kề của V và ngược lại. Đối với cả đạo diễn và

đồ thị không định hướng, biểu diễn danh sách liền kề có mong muốn

tài sản mà dung lượng bộ nhớ mà nó yêu cầu là Θ (V + E). Tìm

mỗi cạnh trong đồ thị cũng mất thời gian Θ (V + E), thay vì chỉ Θ (E),

kể từ mỗi |V| Danh sách phụ cận phải được kiểm tra. Tất nhiên, nếu |E | =

Ω(V)—chẳng hạn như trong đồ thị được kết nối, không định hướng hoặc đồ thị mạnh

Đồ thị được kết nối, có định hướng—chúng ta có thể nói rằng việc tìm kiếm mỗi cạnh cần

Thời gian Θ(E).

Danh sách liền kề cũng có thể đại diện cho các biểu đồ có trọng số, nghĩa là đồ thị cho

mà mỗi cạnh có trọng số liên quan được cho bởi một hàm trọng lượng w :

E → R. Ví dụ, cho G = (V, E) là đồ thị có trọng số với trọng số

Hàm W. Sau đó, bạn có thể chỉ cần lưu trữ trọng lượng w (u, v) của cạnh (u,

v) ∈ E với đỉnh v trong danh sách liền kề của u. Danh sách liền kề

Đại diện khá mạnh mẽ ở chỗ bạn có thể sửa đổi nó để hỗ trợ nhiều

các biến thể đồ thị khác.

Một nhược điểm tiềm ẩn của đại diện danh sách liền kề là
Nó không cung cấp cách nào nhanh hơn để xác định xem một cạnh nhất định (U, V) có phải là

trình bày trong biểu đồ hơn là tìm kiếm v trong danh sách liền kề Adj [u]. Một

Biểu diễn ma trận liền kề của đồ thị khắc phục điều này

bất lợi, nhưng với chi phí sử dụng bộ nhớ không tiệm cận. (Xem

Bài tập 20.1-8 để đề xuất các biến thể trên danh sách liền kề

cho phép tra cứu cạnh nhanh hơn.)

Biểu diễn ma trận liền kề của đồ thị G = (V, E) giả định

rằng các đỉnh được đánh số 1, 2, ... , |V| theo một cách tùy tiện nào đó.

Sau đó, biểu diễn ma trận liền kề của đồ thị G bao gồm một |V|

× |V| ma trận A = (aij

) sao cho

Hình 20.1(c) và 20.2(c) là các ma trận liền kề của các ma trận không định hướng

và các đồ thị có hướng trong Hình 20.1(a) và 20.2(a), tương ứng. Các

ma trận liền kề của đồ thị yêu cầu bộ nhớ Θ(V2), độc lập với

số cạnh trong biểu đồ. Bởi vì việc tìm kiếm từng cạnh trong biểu đồ

yêu cầu kiểm tra toàn bộ ma trận liền kề, làm như vậy sẽ mất Θ (V2)

Thời gian.

Quan sát sự đối xứng dọc theo đường chéo chính của phần liền kề

ma trận trong Hình 20.1(c). Vì trong một đồ thị không định hướng, (u, v) và (v, u)

đại diện cho cùng một cạnh, ma trận liền kề A của đồ thị không định hướng

là chuyển vị riêng của nó: A = AT. Trong một số ứng dụng, nó chỉ trả tiền để lưu trữ

các mục trên và phía trên đường chéo của ma trận liền kề, do đó

Cắt bộ nhớ cần thiết để lưu trữ biểu đồ gần một nửa.

Giống như biểu diễn danh sách liền kề của đồ thị, liền kề

Ma trận có thể đại diện cho một đồ thị có trọng số. Ví dụ, nếu G = (V, E) là một

Biểu đồ trọng số với hàm trọng số cạnh-trọng lượng w, bạn có thể lưu trữ trọng lượng
w(u, v) của cạnh (u, v) ∈ E là mục nhập trong hàng u và cột v của

ma trận liền kề. Nếu cạnh không tồn tại, bạn có thể lưu trữ giá trị NIL

như mục nhập ma trận tương ứng của nó, mặc dù đối với nhiều vấn đề, nó là

thuận tiện để sử dụng một giá trị như 0 hoặc ∞.

Mặc dù đại diện danh sách liền kề ít nhất là không có triệu chứng

tiết kiệm không gian như biểu diễn ma trận liền kề, liền kề

Ma trận đơn giản hơn, và vì vậy bạn có thể thích chúng hơn khi đồ thị

khá nhỏ. Hơn nữa, ma trận liền kề mang một hơn nữa

Lợi thế cho các biểu đồ không trọng số: chúng chỉ yêu cầu một bit cho mỗi mục nhập.

Đại diện cho các thuộc tính

Hầu hết các thuật toán hoạt động trên đồ thị cần duy trì các thuộc tính cho

đỉnh và/hoặc cạnh. Chúng tôi chỉ ra các thuộc tính này bằng cách sử dụng thông thường của chúng
tôi

ký hiệu, chẳng hạn như v.d cho một thuộc tính d của đỉnh v. Khi chúng tôi chỉ ra

Các cạnh như các cặp đỉnh, chúng tôi sử dụng cùng một kiểu ký hiệu. Cho

Ví dụ: nếu các cạnh có thuộc tính f, thì chúng tôi biểu thị thuộc tính này cho

cạnh (u, v) bởi (u, v).f. Với mục đích trình bày và hiểu biết

thuật toán, ký hiệu thuộc tính của chúng tôi là đủ.

Thực hiện các thuộc tính đỉnh và cạnh trong các chương trình thực có thể là

Một câu chuyện hoàn toàn khác. Không có cách nào tốt nhất để lưu trữ và truy cập

Thuộc tính đỉnh và cạnh. Đối với một tình huống nhất định, quyết định của bạn có thể sẽ

Phụ thuộc vào ngôn ngữ lập trình bạn đang sử dụng, thuật toán bạn đang sử dụng

đang triển khai và cách phần còn lại của chương trình của bạn sử dụng biểu đồ. Nếu

Bạn đại diện cho một biểu đồ bằng cách sử dụng danh sách liền kề, một lựa chọn thiết kế là

biểu diễn các thuộc tính đỉnh trong các mảng bổ sung, chẳng hạn như mảng d[1: |V|]

song song với mảng Adj. Nếu các đỉnh liền kề u thuộc Adj[u],

Sau đó, thuộc tính U.D thực sự có thể được lưu trữ trong mục nhập mảng d [u].

Nhiều cách khác để thực hiện các thuộc tính là có thể. Chẳng hạn
Trong ngôn ngữ lập trình hướng đối tượng, các thuộc tính đỉnh có thể là

được biểu diễn dưới dạng các biến thể hiện trong một lớp con của lớp Vertex.

Bài tập

20.1-1

Cho một biểu diễn danh sách liền kề của một đồ thị có hướng, bao lâu

Có cần tính toán mức độ ngoài của mỗi đỉnh không? Nó bao lâu

Lấy để tính toán bằng cấp?

20.1-2

Đưa ra một biểu diễn danh sách liền kề cho một cây nhị phân hoàn chỉnh trên 7

Đỉnh. Đưa ra một biểu diễn ma trận liền kề tương đương. Cho rằng

rằng các cạnh không được định hướng và các đỉnh được đánh số từ 1

đến 7 như trong một đống nhị phân.

20.1-3

Hoán vị của đồ thị có hướng G = (V, E) là đồ thị GT = (V, E

T),

trong đó E

T = {(v, u) ∈ V × V : (u, v) ∈ E}. Đó là, GT là G với tất cả

các cạnh đảo ngược. Mô tả các thuật toán hiệu quả để tính GT từ G,

cho cả biểu diễn danh sách liền kề và ma trận liền kề của G.

Phân tích thời gian chạy các thuật toán của bạn.

20.1-4

Cho một biểu diễn danh sách liền kề của một đa đồ thị G = (V, E),

mô tả thuật toán thời gian O(V + E) để tính toán danh sách liền kề

biểu diễn đồ thị không định hướng "tương đương" G′ = (V, E′), trong đó

E′ bao gồm các cạnh trong E với tất cả nhiều cạnh giữa hai đỉnh

được thay thế bằng một cạnh duy nhất và với tất cả các vòng lặp tự loại bỏ.
20.1-5

Bình phương của đồ thị có hướng G = (V, E) là đồ thị G2 = (V, E

2)

sao cho (u, v) ∈ E

2 khi và chỉ khi G chứa một đường dẫn với nhiều nhất hai

cạnh giữa u và v. Mô tả các thuật toán hiệu quả để tính toán G2

từ G cho cả biểu diễn danh sách liền kề và biểu diễn ma trận liền kề

của G. Phân tích thời gian chạy của các thuật toán của bạn.

20.1-6

Hầu hết các thuật toán đồ thị lấy biểu diễn ma trận liền kề làm

đầu vào yêu cầu thời gian Ω (V2), nhưng có một số trường hợp ngoại lệ. Hướng dẫn cách thực hiện

xác định xem đồ thị có hướng G có chứa bồn rửa phổ quát hay không—a

đỉnh có bằng cấp |V| - 1 và ngoài bậc 0 — trong thời gian O(V), cho một

ma trận liền kề cho G.

20.1-7

Ma trận tới của đồ thị có hướng G = (V, E) không có tự lặp là

a |V| × |E | ma trận B = (bij

) sao cho

Mô tả những gì các mục của sản phẩm ma trận BB

T đại diện, trong đó

T là hoán vị của B.

20.1-8
Giả sử rằng thay vì một danh sách được liên kết, mỗi mục nhập mảng Adj [u] là một hàm băm

Bảng chứa các đỉnh v mà (u, v) ∈ E, có va chạm

được giải quyết bằng cách xâu chuỗi. Theo giả định độc lập thống nhất

băm, nếu tất cả các tra cứu cạnh đều có khả năng như nhau, thời gian dự kiến là bao nhiêu

Để xác định xem một cạnh có trong biểu đồ hay không? Nhược điểm là gì

Đề án này có? Đề xuất cấu trúc dữ liệu thay thế cho mỗi danh sách cạnh

Điều đó giải quyết những vấn đề này. Thay thế của bạn có nhược điểm không

So với bảng băm?

You might also like