目錄
一、簡介
寬度優先搜索算法(又稱廣度優先搜索)是最簡便的圖的搜索算法之一,這一算法也是很多重要的圖的算法的原型。Dijkstra單源最短路徑算法和Prim最小生成樹算法都採用了和寬度優先搜索類似的思想。其別名又叫BFS,屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的所有節點,以找尋結果。換句話說,它並不考慮結果的可能位置,徹底地搜索整張圖,直到找到結果爲止。下面我使用寬度優先搜索算法實現克隆圖。
二、圖的表示
1、鄰接矩陣
對於N個點的圖,需要N×N的矩陣表示點與點之間是否有邊的存在。這種表示法的缺點是浪費空間,尤其是對於N×N的矩陣是稀疏矩陣,即邊的數目遠遠小於N×N的時候,浪費了巨大的存儲空間。
圖 1
2、邊的數組
使用一個Edge類,它含有兩個int實例變量。這種表示方法很簡潔但獲取頂點v所有鄰接頂點要檢查圖中所有的邊。這種表示方法使用較少。
3、鄰接鏈表
對於任何一個node A,外掛一個鄰接鏈表,如果存在 A->X這樣的邊,就將X鏈入鏈表。 這種表示方法的優點是節省空間,缺點是所有鏈表都存在的缺點,地址空間的不連續造成緩存命中降低,性能有不如臨界矩陣這樣的數組。我們使用鄰接鏈表來表示此次算法的實現。
圖 2
三、實戰
1、題目概述
題目:給你無向連通圖中一個節點,實現該圖的 深拷貝(克隆)。
我們使用鄰接鏈表來表示此次算法的實現。
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
2、實現方法1
我們可以利用寬度優先搜索遍歷圖,先把圖的節點都生成一遍,把生成的節點和原始節點存到hash表中(clone nodes)。然後再遍歷一遍hash表,生成邊(clone edges )。
Node* cloneGraph(Node* node) {
if (node == NULL)
{
return NULL;
}
unordered_map<Node*, Node*> mapNode;
std::queue<Node*> queueNode;
queueNode.push(node);
Node*pnode = node;
//clone nodes
while (!queueNode.empty())
{
node = queueNode.front();
queueNode.pop();
if (mapNode.find(node) != mapNode.end())
{
continue;
}
mapNode[node] = new Node(node->val);
int s = node->neighbors.size();
for (int i = 0; i < s; i++)
{
queueNode.push(node->neighbors[i]);
}
}
//clone edge
unordered_map<Node*, Node*>::iterator it = mapNode.begin();
while (it != mapNode.end())
{
int s = it->first->neighbors.size();
for (int i = 0; i < s; ++i)
{
it->second->neighbors.push_back(mapNode[it->first->neighbors[i]]);
}
++it;
}
return mapNode[pnode];
}
3、實現方法2
我們可以利用寬度優先搜索遍歷圖,把圖的節點和節點的neighbour節點都生成一遍,把生成的節點和原始節點存到hash表中(clone nodes)。在遍歷的同時生成邊(clone edges)。
Node* cloneGraph2(Node* node) {
if (node == NULL)
{
return NULL;
}
unordered_map<Node*, Node*> mapNode;
std::queue<Node*> queueNode;
queueNode.push(node);
Node*pnode = node;
//clone node and edges
mapNode[node] = new Node(node->val);
while (!queueNode.empty())
{
node = queueNode.front();
queueNode.pop();
int s = node->neighbors.size();
for (int i = 0; i < s; i++)
{
if (mapNode.find(node->neighbors[i]) == mapNode.end())
{
mapNode[node->neighbors[i]] = new Node(node->neighbors[i]->val);
queueNode.push(node->neighbors[i]);
}
mapNode[node]->neighbors.push_back(mapNode[node->neighbors[i]]);
}
}
return mapNode[pnode];
}
四、總結
深度優先搜索比較簡單,但是可以解決很多問題,克隆圖就可以通過深度優先搜索輕鬆的解決。方法1邏輯上比較清晰,方法2只進行一次遍歷,效率高。