Thuật toán Bellman-Ford

Một phần của tài liệu Các giao thức định tuyến cổng nội trong mạng IP (Trang 76 - 79)

Khác với thuật toán Dijkstra, tìm và quét đỉnh có nhãn nhỏ nhất, và mỗi đỉnh chỉ phải quét một lần, thuật toán Bellman quét các đỉnh theo thứ tự gán nhãn của đỉnh, vì vậy sẽ không phải tìm đỉnh nhỏ nhất, tuy nhiên lại dẫn tới việc một đỉnh có thể phải quét nhiều lần.

Thuật toán Bellman cơ bản hoạt động bằng cách quét lần lợt tất cả các đỉnh, nhằm gán lại nhãn cho các đỉnh khác. Và cứ thực hiện lặp lại nh vậy cho đến khi sau một vòng lặp mà không có đỉnh nào đợc gán nhãn lại nữa. Tuy nhiên, làm nh vậy phải thực hiện một lợng tính toán rất lớn. Thông thờng, khi quét một đỉnh, chỉ cần kiểm tra xem có phải gán lại nhãn cho các đỉnh lân cận hay không. Và chỉ cần quét những đỉnh đợc gán nhãn lại trong vòng lặp trớc.

Để thực hiện theo cách vừa nói, có thể sử dụng một hàng đợi để lu giữ thứ tự quét các đỉnh cần quét. Mỗi khi một đỉnh đợc gán nhãn, nó lại đợc đa vào hàng đợi. Vì hàng đợi là kho dữ liệu quản lý theo kiểu vào trớc - ra trớc (FIFO) nên các đỉnh sẽ đợc quét theo thứ tự gán nhãn. Nếu một đỉnh đợc gán nhãn lại sau khi đã quét, nó lại đợc đa vào trong hàng đợi.

Để hiểu thuật toán Bellman-Ford, ta xem ví dụ sau: Xét mạng nh trong Hình 2.10, giả sử A là đỉnh nguồn. A đợc gán nhãn 0 và đợc đa vào hàng đợi. Quét A, đỉnh B và C đợc gán nhãn tơng ứng là 5 và 1, và cùng đợc đa vào hàng đợi. Tiếp theo, ta quét đỉnh B, gán nhãn cho D và E các giá trị 6 và 11. D và E cũng đợc đặt vào hàng đợi. Tiếp theo ta quét đỉnh C, B đợc gán nhãn mới là 4 và đợc đa trở lại hàng đợi. Quét D, gán nhãn 10 cho F và đa F vào hàng đợi. Quét E. B đợc quét lần thứ 2, nó gán cho D và E các nhãn tơng ứng là 5 và 10, và cả hai tiếp tục lại quay trở lại hàng đợi. Quét F, không gán nhãn mới cho đỉnh nào. Quét D, gán nhãn 9 cho F và đa F trở lại hàng đợi. Quét E, quét F.

Hình 2..10 Mạng ví dụ

Thuật toán Bellman đợc cài đặt nh sau:

Phạm Văn Hiến - Đ01VT E A B C D F 5 1 3 5 1 6 4 2 0 1 4 5 9 10 70

array[n]  Bellman (n , root , dist [n,n])

var pre_node[n] , cur_dist[n] , in_queue[n] , scan_queue[n] void  Scan( i )

in_queue[ i ] = FALSE for j = 1 to n

if (cur_dist [j] > cur_dist [i] + dist [i,j] ) cur_dist [j] = cur_dist [i] + dist [i,j] pre_node [j] = i if ( ! in_queue [j] ) push (scan_queue , j) in_queue [j] = FALSE cur_dist  INFINITY pre_node  -1 in_queue  FALSE initialize_queue (scan_queue) cur_dist [root] = 0

push (scan_queue , root) in_queue[root] = TRUE

while ( ! empty (scan_queue)) i  pop(scan_queue) scan (i)

return (pre_node).

Ta thấy rằng, các đỉnh đợc quét theo thứ tự gán nhãn, dẫn đến là các đỉnh đợc quét theo khoảng cách bớc (hop) tới đỉnh nguồn. Đầu tiên, đỉnh nguồn đợc quét (hop = 0), tiếp theo là các đỉnh lân cận đỉnh nguồn (hop = 1). Và cứ thế tiếp tục. Do đó, ta thấy, một đỉnh có thể cần phải quét tối đa n-1 lần.

Trong hầu hết các trờng hợp thực tế, số lần quét trung bình của các đỉnh không lớn, thờng chỉ là 3 đến 4 lần, dù là mạng có tới hàng ngàn đỉnh. Trong khi đó, với những mạng có số lợng đỉnh lớn, chơng trình sử dụng thuật toán Dijkstra phải mất khá nhiều thời gian vào việc tìm đỉnh có giá trị nhãn nhỏ nhất. Do đó, thuật toán Bellman nói chung thực hiện nhanh hơn so với thuật toán Dijkstra.

Nh trong ví dụ trớc, khi quét đỉnh C, ta đã gán nhãn lại cho đỉnh B, mà trớc đó, đỉnh B đã gán nhãn cho hai đỉnh D, E. Sau khi quét C xong, ta quét D và E rồi mới đến

đỉnh B lần thứ hai. Khi quét B lần thứ hai, ta gán nhãn lại cho D và E, dẫn tới là lại phải quét lại hai đỉnh này. Dờng nh, khi ta quét lại B thì cũng phải quét lại D và E. Từ vấn đề đó, ta thấy rằng có thể giảm đợc số lần quét D và E bằng cách đặt B vào đầu hàng đợi ngay sau khi nó đợc gán nhãn lại. Công việc này thực tế làm tăng đáng kể hiệu quả của chơng trình, mà ta chỉ phải sửa đổi thuật toán một chút, đó là sử dụng một hàng đợi có hai đầu vào, và ngoài việc lu thông tin về việc có mặt của một đỉnh trong hàng đợi hay cha, ta còn cần thông tin về việc đỉnh đó đã từng ở trong hàng đợi hay cha.

Tuy nhiên, với thuật toán Bellman-Ford sửa đổi này, ta có thể gặp phải trờng hợp vô cùng xấu, nh trong ví dụ sau (Hình 2.11):

Hình 2.11 Mạng ví dụ

Nếu khi gán nhãn các đỉnh lân cận theo thứ tự ABC, quá trình quét các đỉnh sẽ xảy ra nh sau: đầu tiên, R gán cho A nhãn 11, B nhãn 9 v.v Sau đó quét A không gán…

nhãn cho đỉnh nào cả. Tiếp theo, quét B, gán nhãn cho A, đặt A vào đầu hàng đợi, rồi sau đó lại quét A. Quét C, gán nhãn lại cho A và B Cứ tiếp tục nh… thế, cuối cùng, đỉnh A đợc gán nhãn và quét 2N-1 lần.

Trờng hợp trên xảy ra là các giá trị không tự nhiên của trọng số các đoạn đờng và cách ta gán nhãn các đỉnh lân cận của các đỉnh đang quét. Tuy nhiên, trờng hợp tơng tự rất hiếm khi xảy ra trong thực tế. Và nếu ta thấy nó xảy ra thờng xuyên, thì tốt nhất nên sử dụng thuật toán Dijkstra.

So sánh với thuật toán Dijkstra:

Cả hai thuật toán này đều là những thuật toán đơn giản, hiệu quả, dễ cài đặt, tuy nhiên có khác nhau ở một số điểm sau:

♦ Thuật toán Dijkstra chỉ có thể hoạt động đợc ở những mạng có độ dài các kênh đều dơng. Trong khi đó, thuật toán Bellman có thể sử dụng đợc ở trong những mạng có kênh có độ dài âm, miễn là không tồn tại các vòng có tổng độ dài các cung trong vòng âm.

♦ Thuật toán Dijkstra cần thông tin về tất cả các đỉnh, tất cả các cung. Trong khi đó, thuật toán Bellman, có thể tìm đờng ngắn nhất cho một đỉnh dựa vào thông tin tìm

đờng ngắn nhất của các đỉnh lân cận, và độ dài các cung nối với các đỉnh lân cận đó.

Một phần của tài liệu Các giao thức định tuyến cổng nội trong mạng IP (Trang 76 - 79)

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

(113 trang)
w