[英]C++ | Print tree (not necessarily binary) in a pretty way to stdout
[英]How to do a DFS on a tree? (not necessarily binary)
我有一棵n
節點的樹(標記為0 to n
)。 我使用兩個向量來保存邊緣信息。
typedef std::vector<std::vector<int>> graph;
輸入形式為n-1
邊:
0 1
1 2
2 3
and so on
有人告訴我節點0
始終是根節點。 我使用以下方法掃描邊緣:
for (int i = 0; i < n-1; i++) {
scanf("%d %d", &a, &b);
g[a].push_back(b);
g[b].push_back(a); // the second approach doesn't use this line
}
這是我簡單的dfs:
void dfs(graph &g, int v) {
std::vector<int> visited; // I don't use a visited array for the second approach
for (int i = 0; i < g.size(); i++) {
visited.push_back(0);
}
std::stack<int> s;
std::set<int> t;
s.push(v);
while (!s.empty()) {
int i = s.top(); s.pop();
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (!visited[i]) {
visited[i] = true;
s.push(g[v][i]);
}
}
}
}
例如,說我們有4個節點和以下邊:
0 1
0 2
3 2
2 4
假設我對從2
開始的子樹感興趣。 上面的方法行不通,因為我要插入無方向的邊0 2
和2 0
。 因此,當我從2
開始dfs
,將節點0
添加到堆棧中是錯誤的。
我嘗試了另一種方法,即僅插入給定的邊,但是也沒有用,因為在示例中,我將插入3 2
,這是從3
到節點2
的邊,因此當我在節點2
啟動dfs
,我贏了無法到達節點3
。
我覺得問題很簡單,而且我缺少一些大創意!
由於您的圖是一棵有根的樹,因此可以進行以下預處理。
parent
,根據上述定義, parent[u] = v
,並且parent[0] = -1
。 parent
數組,如果您執行s.push(g[v][i])
,則v
是i
的父級(否則您將首先訪問i
); parent[v]
是距全局根(vertex 0)最短路徑的先前頂點,因此它也是距其子樹中包含v的任何頂點x的最短路徑的先前頂點。 現在,當您想在頂點u的子樹上進行DFS時,您可以像現在那樣執行DFS,但不要訪問任何頂點的父級 。 說,如果要執行s.push(v)
,而parent[u] = v
,則不要這樣做。 這樣,您將永遠不會離開u的子樹。
實際上,了解parent
,您可以擺脫visited
數組。 當您對頂點v進行 “處理”時,已經訪問過的v的唯一鄰居是parent[v]
。 此屬性不依賴於您要遍歷其子樹的初始頂點。 DFS代碼如下所示(假設您已經完成了獲取parent
預處理:
void dfs(graph &g, vector<int> &parent, int v) {
std::stack<int> s;
s.push(v);
while (!s.empty()) {
int v = s.top(); s.pop(); // By the way, you have mistake here: int i = s.top().
// do stuff
for (int i = 0; i < g[v].size(); i++) {
if (parent[v] != g[v][i]) {
s.push(g[v][i]);
}
}
}
}
PS這種方法在某種程度上類似於您的第二種方法:它僅處理從根到子樹的邊緣。 但這沒有缺陷,例如在您的示例中“ 3 2”是錯誤的方向,因為您是通過從根目錄執行DFS從算法上推斷方向的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.