Tải bản đầy đủ (.doc) (31 trang)

Chương 6 cấu trúc dữ liệu kiểu đồ thị

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (130.67 KB, 31 trang )

254

Chương 6
Cấu trúc dữ liệu kiểu Đồ thị ( Graph )
Trong chương 5 chúng ta đã nghiên cứu
một loại cấu trúc phi tuyến là cây. Cây là một
trường hợp đặc biệt của một loại cấu trúc dữ
liệu tổng quát hơn ,đó là đồ thị( Graph). Trong
chương này, chúng ta sẽ nghiên cứu hai loại đồ
thị là đồ thị có hướng và đồ thị vô hướng.
6.1 Đồ thị có hướng
6.1.1 Khái niệm
Đồ thị có hướng ( Directed graph ) gồm một
tập hợp hữu hạn các phần tử gọi là nút hay
đỉnh, cùng với một tập hợp hữu hạn các
cạnh có hướng nối các cặp đỉnh với nhau .
Chẳng hạn cho đồ thị sau đây:

254


255

1

5

2

4


3

Đồ thị này gồm 5 nút được đánh số
1,2,3,4,5 và 7 cạnh nối các nút từ 1 đến 2, 1
đến 4, 1 đến 5, 2 đến 4, 3 đến chính nó,4 đến
2, và 4 đến 3.
Cây có thể coi là trường hợp đặc biệt của
đồ thị có hướng và được đặc trưng bởi tính
chất là một trong các nút, nút gốc,không có
cạnh nào hướng đến nó, và tất cả các nút còn
lại có thể đạt đến từ nút gốc bằng một đường
255


256

duy nhất . Nghĩa là ,chỉ đi theo một và chỉ một
dãy các cạnh liên tiếp.
Đồ thị trên đây có một nút "gần giống
như nút gốc"
( Không có cạnh nào hướng đến nó) là nút 1,
nhưng có nhiều đường khác nhau từ nút 1 đến
nút 3.
Ví dụ:
1→ 2 →3
1→ 4 →3
1→ 4 →2 →3
..........
Sau đây là một ví dụ khác về đồ thị:


1

2
6

5

4

3

256


257

Trong trường hợp này ta có các đường đi như
sau:
1→ 5 → 4 → 3
1→ 2 → 6
1→ 4 → 3 → 3
.......
Đồ thị có rất nhiều ứng dụng trong thực
tiễn. Đồ thị có hướng được dùng để thiết
kế,phân tích các sơ đồ mạng điện, biểu diễn
đường găng trình tự thực hiện các hạng mục
trong một công trình xây dựng.
Ví dụ :
Đồ thị có hướng biểu diễn quá trình lập kế
hoạch sản xuất trong một doanh nghiệp.


257


258

3.1
1

2

3

3.2

4

5

3.3
1 Đặ
t mục tiêu kếhoạch
2 Nghiên cứu thịtr ờng
3 Đ ánh giá các tiềmnăng của danh nghiệp
3.1 Lao đ
ộng
3.2 Khả năng tài chính
3.3 Năng lực sản xuất
4 Xâ
y dựng các chỉtiêu kếhoạch

5 Thực hiện kếhoạch

Trong s ny mi hỡnh ch nht
biu din mt cụng on trong qui trỡnh lp k
hoch ,bt u t cụng on tin k hoch l
nghiờn cu th trng n cụng on cui cựng
l thc hin k hoch.
6.1.2 Phng phỏp ci t th cú hng
Mt phng phỏp rt thụng dng ci
t th l s dng ma trn k ( Adjacency
258


259

matrix). Để xây dựng ma trận kề ,trước hết
chúng ta đánh số các nút của đồ thị có hướng
1,2,2 ... n. Ma trận kề là ma trận Adj bậc n x n
trong đó thành phần ở hàng i, cột j có giá trị 1
nếu có một cạnh từ i đến j ,và có giá trị o nếu
khác.
Ví dụ : Cho đồ thị có hướng sau đây:
1

2
B

5

A


E
3

C

D

4

Ta có ma trận kề :

259


260

Adj =

0

1

1

0

1

0


0

1

0

0

0

0

0

1

0

0

0

0

1

0

Để xác định các giá trị A,B,C ... của các nút

chúng ta sử dụng thêm một ma trận Data chỉ
gồm một cột chứa các giá trị này , trong đó dữ
liệu của nút thứ i được lưu trữ tại Data[i]. Như
vậy chúng ta có hai mảng :

Adj =

0

1

1

0

1

0

0

1

0

0

0

0


0

1

0

0

0

0

1

0

260


261

Data =

A
B
C
D
E


Thông thưòng trong ma trận kề có chứa
rất nhiều phần tử bằng không, do đó sẽ tốn rất
nhiều không gian nhớ để lưu trữ các phần tử
này. Chúng ta có thể sử dụng phương pháp lưu
trữ ma trận kề bằng danh sách liên kết theo
hàng( Linked Row List) chúng ta sẽ có cách
biểu diễn danh sách kề cho một đồ thị có
hướng.
Cho đồ thị có hướng sau đây:

261


262
1

2
B

A

5

E
3

C

D


4

Danh sách kề của đồ thị này như sau:

V[1]
V[2]

Nót ®
Çu
A

2

B

3

V[3]

C

2

V[4]

D

4

V[5]


Nót dØ
nh
3

5

4

E

262


263

Một đồ thị có hướng được biểu diễn
bởi một mảng các con trỏ V[1],V[2],
...V[n] ,mỗi con trỏ cho mỗi nút trong đồ thị có
hướng. Mỗi phần tử mảng V[i] chỉ đến một nút
đầu lưu trữ dữ liệu cho nút ấy và chứa một con
trỏ chỉ đến một danh sách liên kết của các nút
kề ( Nút được nối với i theo hướng từ i đi ra).
Mỗi nút kề có hai trường : trường số nguyên
,lưu trữ dữ liệu của nút và một trường liên kết
chỉ đến nút tiếp thẻo trong danh sách kề này.
Cách biểu diễn đồ thị có hướng bằng
danh sách kề có thể được cài đặt với các khai
báo như sau:
Const

MaxVertices=.....( Số các nút của đồ thị có
hướng)
Type
DataType=.........( Kiểu dữ liệu trong các nút)
VertexNumber= 1.. MaxVertices;
AdjPointer =^. VertexNode;
VertexNode= Record
Vertex: VertexNumber;
263


264

Next: AdjPointer
end;
HeadNode=Record
Data: DataType;
Next: AdjPointer
end;
HeadPointer=^. HeadNode;
ArrayOfPointers= Array[VertexNumber]
HeadPointer;
Var
V: ArrayOfPointer;

of

6.1.3 Các giải thuật xử lý danh sách kề
Để xây dựng các danh sách kề cho một đồ thị
có hướng chúng ta phải thực hiện các giải

thuật cơ bản xử lý danh sách kề.
Giải thuật thiết lập danh sách kề
Gải thuật thiết lập danh sách kề được biểu diễn
như sau:
264


265

For i:= 1 to MaxVertices thực hiện các bước
sau đây:
1 - Lấy một nút đầu được chỉ bởi V[i] và khởi
động trường Next của nó tại giá trị Nil
2 - Đọc dữ liệu trong nút này vào trường dữ
liệu V[i]^.Data của nút đầu
3 - Với mỗi nút kề với nút i ( Có hướng từ i đi
ra) thực hiện các bước sau đây:
a. Đọc số của nút ấy
b. Chèn số này vào danh sách liên kết
của các nút kề được chỉ bởi V[i]^.Next bằng
cách dùng một trong các giải thuật chèn trong
danh sách đã xét trong chương 5.
Giải thuật tìm theo chiều sâu
Để hiểu rõ bản chất của giải thuật tìm
theo chiều sâu ( Depth- First Search) chúng ta
xét đồ thị có hướng sau đây:

265



266

A
B
E

C
F

D
G

H

Trước hết chúng ta thăm gốc rồi chọ
một trong các nút con của nó chẳng hạn nút B
và thăm nút này. Tuy nhiên ,trước khi thăm các
nút con khác ,chúng ta thăm các nút con của B
theo chiều sâu. Chúng ta chọn một trong các
con của B chẳng hạn nút E và thăn nó: Ta có
trình tự sau đây:
A,B,E
Ta tiếp tục thăm các nút con của E
nhưng vì E không có các nút con nên ta trở lại
thăm các nút con của nút B . Ta thăm nút F và
nút con của nó là H.
Ta có:
266



267

A,B,E,F,H
Như vậy, chúng ta đã xem xét xong nút
B và các con cháu của nó. Chúng ta trở lại nút
A và tiếp tục thăm các nút con ( C và D ) của
nó. Ta có các trình tự sau đây:
A,B,E,F, H,C
A,B,E,F,H,C,D,G
Giải thuật sau đây thực hiện việc tìm
theo chiều sâu trong một đồ thị có hướng ,được
biểu diễn bắng các danh sách kề , bắt đầu từ
nút Start . Tập hợp Unvisited chứa các số của
các nút chưa được thăm :
Procedure
DepthFirstSearch(
V:
ArrayOfPointers;
Var
Unvisited:
SetOfVertices);
Start : VertexNumber);
Var
CurrPtr: AdjPointer;
NewStart: VertexNumber;
Begin
(* Chèn các lệnh để xư lý V[Start]^.Data*)
Unvisited:= Unvisited- V[Start];
267



268

(* Quét danh sách kề tìm theo chiều sâu*)
CurrPtr:= V[Start]^.Next;
While CurrPtr <> Nil do
Begin
NewStart := CurrPtr^.Vertex;
if ( NewStart in Unvisited) then
DepthFirstSeach (V ,Unvisited, NewStart);
CurrPtr:= CurrPtr^.Next
end;
end;
Trong giải thuật này Unvisited là một tập hợp
có kiểu SetOfVertices= Set of VertexNumber .
Nó có thể được khởi động bằng lệnh:
Unvisited:= [1.. NumVertices] trước khi gọi
thủ
tục
DepthFirstSearch,
trong
đó
NumVertices là số các nút trong đồ thị có
hướng.
Giải thuật tìm theo chiều rộng
Xét đồ thị có hướng:

268



269

A
B
E

C
F

D
G

H

Chúng ta xem xét việc quét đồ thị này theo
chiều rộng . Trước hết chúng ta bắt đầu từ gốc,
thăm gốc và các con của nó , chẳng hạn từ phải
sang trái:
A,B,C,D
Sau đó tiến hành thăm các con của các nút
trong mức đầu tiên này:
A,B,C,D,E,F,G
và cuối cùng chúng ta thăm các nút con của
các nút trong mức thứ hai:
A,B,C,D,E,F,G,H
Giải thuật sau đây thực hiện việc tìm theo
chièu rộng trong một đồ thị có hướng :
269



270

Bước 1 Thăm nút xuất phát
Bước 2 Khởi động một Queue chỉ chứa nút
xuất phát
Bước 3 While( Queue không rỗng) thực hiện
các bước sau đây:
* Lấy một nút V từ hàng đợi
* Với tất cả các nút W kề với V thực hiện
các bước sau đây:
if ( W chưa được thăm) then
a. Thăm W
b. Thêm W vào hàng đợi
Giải thuật quét đồ thị có hướng
Giải thuật sau đây thực hiện việc quét
một đồ thị có hướng ,thăm mõi nút đúng một
lần dựa trên cơ sở tìm kiếm theo chiều sâu:
1. Khởi động một tập hợp Unvisited chứa các
số của các nút trong đồ thị
2. While ( Unvisited khác rỗng) làm các bước
sau đây:
a. Chọn một nút xuất phát từ tập Unvisited
270


271

b. Dùng giải thuật tìm theo chiều sâu để thăm
tất cả các nút có thể đạt được từ nút xuất phát
này

6.2 Đồ thị vô hướng
6.2.1 Khái niệm
Đồ thị vô hướng gồm một tập hợp hữu hạn
các phần tử gọi là nút hay đỉnh cùng với
một tập hợp hữu hạn các cạnh nối các cặp
đỉnh với nhau.
Như vậy , đồ thị vô hướng khác với đồ
thị có hướng ở chỗ các cạnh của nó không
được định hướng và không có một nút nào
được nối với chính nó.

271


272

1

5
E

2

A

B
4

3
D


C

Đồ thị trên đây bao gồm 5 nút A,B,C,D,E và
các cạnh nối các nút
1 với 2
1 với 4
1 với 5
3 với 4
4 với 5
6.2.2 Phương pháp cài đặt đồ thị vô hướng
Có 3 phương pháp cài đặt đồ thị vô hướng:
- Dùng ma trận kề
- Dùng danh sách kề
- Dùng danh sách các cạnh
272


273

Dùng ma trận kề
Cũng như đồ thị có hướng , chúng ta có thể
biểu diễn đồ thị vô hướng bằng ma trận kề .
Chẳng hạn , ma trận kề của đồ thị ở trên biểu
diễn như sau:

Adj =

0


1

0

1

1

1

0

0

1

0

0

0

0

1

0

1


1

1

0

1

1

0

0

1

0

trong đó số 1 trong hàng i cột J chỉ ra sự tồn tại
của một cạnh nối các nút i và J. Vì những cạnh
này không có hướng ,số 1 này cũng có mặt
trong hàng J cột i. Như vậy , ma trận kề của đồ
thị vô hướng là một ma trận đối xứng .
Dùng danh sách kề

273


274


Bây giờ chúng ta dùng danh sách kề để biểu
diễn đồ thị vô hướng trên đây:
V[1]
V[2]

Nót ®
Çu
A

C¸c nót kÒ
4
5

2

B

1

V[3]

C

4

V[4]

D

1


2

E

1

4

V[5]

4

3

5

Cách biểu diễn bằng danh sách kề đối với một
dồ thị vô hướng cũng khong hiệu quả cho lắm
vì phải lưu trữ các thông tin thừa. Nếu một
cạnh nối các nút i và J thì nút chứa i xuất hiện
trong danh sách kề của nút i và nút chứa J xuấ
hiện trong danh sách kề của nút I.

274


275

Dùng danh sách các cạnh

Một cách cài đặt hiệu quả hơn đồ thị vô hướng
là dúng danh sách các cạnh. Mỗi nút
cạnh( Edge node) trong danh sách biểu diễn
một cạnh trong đồ thị và nó có dạng sau đây:
V ertex[1]

Link[1]

Vertex[2]

L ink[2]

trong đó Vertex[1], Vertex[2] là các nút được
nối bởi một cạnh , Link[1] chỉ đến một cạnh
khác có Vertex[1] như là một điểm cuối , và
Link[2] chỉ đến một cạnh khác có Vertex[2]
như là một điểm cuối. Người ta dùng một
mảng V chứa các con trỏ chỉ đến các nút đầu
lưu trữ các mục dữ liệu của các nút, nút đầu
được chỉ bởi V[i] cũng chứa một trường liên
275


276

kết chỉ đến một nút cạnh có nút thứ i là một
trong các điểm cuối của nó.
Biểu diễn danh sách cạnh của đồ thị trên đây
như sau:
1


5

e3

E

e2

A

B

e2
4
e4

2

e6
D

3
e5

C

trong đó chúng ta đã đánh dấu các cạnh trên
hình vẽ có thể biểu diễn trong hình vẽ sau đây.
Các giải thuật tìm theo chiều sâu, chiều rộng,

giải thuật quét đồ thị, giải thuật tìm đường
ngắn nhất trong đồ thị cũng tương tự như đối
với đồ thị có hướng đã xét trong mục trước
đây.
Đồ thị vô hướng có nhiều ứng dụng trong việc
mô phỏng các sơ đồ mạng điện , các hệ thống
giao thông liên lạc vv.
276


277

C¸c nót ®
Çu
V[1]
V[2]

A

C

V[4]

D

e1
1 2

1


4

e3 1

5

e4

5

B

V[3]

V[5]

C¸c nót c¹nh

4

e2

E
e5

e6

3

2


4

4

277


278

Câu hỏi và bài tập chương

6
Bài 1

Tìm đồ thị có hướng biểu diễn bởi ma trận kề
Adj và ma trận dữ liệu Data cho dưới đây:

Adj =

0

1

1

0

1


0

0

1

0

0

0

1

0

1

0

0

1

0

1

0


0

1

0

0

0

278


×