已知边的连通关系建树
例:
节点数:
12
边的连通关系 :
5 6
11 0
8 6
0 3
9 6
6 0
10 7
4 0
2 6
4 7
3 1
ps:
- 没有约定序号小的节点一定是父亲
- 0号节点一般为根节点
附树的示意图:(兄弟节点之间不分顺序)
![]()
-
- 数组建树
点击查看代码
//树中每个节点的信息
struct Node
{
int No = -1;
int parent = -1;
std::vector<int> children;
};
//建树函数,接受边的数组,返回建好的树的数组
std::vector<Node> createTree(std::vector<std::pair<int, int>> EDGEs)
{
std::vector<Node> tree(EDGEs.size() + 1); //节点数 == 边数 + 1
std::vector<int> ergodiced(tree.size()); //记录各个节点是否已经被加入到树中
std::queue<int> node;
node.push(0);
ergodiced[0] = 1;
tree[0].No = 0;
tree[0].parent = 0;
//从根节点开始按层次建树
while (!node.empty())
{
//遍历各个边找到与当前节点相邻的边
for (std::pair<int, int> ii : EDGEs)
{
if (ii.first == node.front())
{
//如果相连的节点没有被加入到树中(不是当前节点的父亲节点)
if (!ergodiced[ii.second])
{
tree[ii.second].No = ii.second;
//建立两条边的父子关系
tree[node.front()].children.push_back(ii.second);
tree[ii.second].parent = node.front();
//将新加入节点的加入情况设为‘是’
ergodiced[ii.second] = 1;
}
}//同上
else if (ii.second == node.front())
{
if (!ergodiced[ii.first])
{
tree[ii.first].No = ii.first;
tree[node.front()].children.push_back(ii.first);
tree[ii.first].parent = node.front();
ergodiced[ii.first] = 1;
}
}
}
//每个节点处理完成之后将其所有孩子节点加入队列依次处理,当前节点出队
for (int i : tree[node.front()].children)
{
node.push(i);
}
node.pop();
}
//函数返回建好的树的数组
return tree;
}
附BFS遍历代码及运行结果:
`
std::queue<Node> T;
T.push(tree[0]);
while(!T.empty())
{
std::cout << T.front().No << " ";
for (int i : T.front().children)
{
T.push(tree[i]);
}
T.pop();
}
/*0 11 3 6 4 1 5 8 9 2 7 10*/
`
-
- 指针建树
点击查看代码
//树中每个节点的信息
struct Node
{
int No = -1;
Node* parent = nullptr;
std::vector<Node*> children;
};
//建树函数,接受边的数组,返回建好的树的跟节点的指针
Node* createTree(std::vector<std::pair<int, int>> EDGEs)
{
Node* root(new Node);
root->No = 0; //根节点序号为0
root->parent = root; //令根节点的父亲节点为其本身
std::vector<int> ergodiced(EDGEs.size() + 1); //记录各个节点是否已经被加入到树中
std::queue<Node*> node;
node.push(root);
ergodiced[0] = 1;
//从根节点开始按层次建树
while (!node.empty())
{
//遍历各个边找到与当前节点相邻的边
for (std::pair<int, int> ii : EDGEs)
{
if (ii.first == node.front()->No)
{
//如果相连的节点没有被加入到树中(不是当前节点的父亲节点)
if (!ergodiced[ii.second])
{
Node* child(new Node);
child->No = ii.second;
//建立两条边的父子关系
node.front()->children.push_back(child);
child->parent = node.front();
//将新加入节点的加入情况设为‘是’
ergodiced[ii.second] = 1;
}
}//同上
else if (ii.second == node.front()->No)
{
if (!ergodiced[ii.first])
{
Node* child(new Node);
child->No = ii.first;
node.front()->children.push_back(child);
child->parent = node.front();
ergodiced[ii.first] = 1;
}
}
}
//每个节点处理完成之后将其所有孩子节点加入队列依次处理,当前节点出队
for (Node* N : node.front()->children)
{
node.push(N);
}
node.pop();
}
//函数返回建好的树的指向根节点的指针
return root;
}
附DFS遍历代码及运行结果
`
Node* root(createTree(edges));
std::stack<Node*> node;
node.push(root);
while (!node.empty())
{
std::cout << node.top()->No << " ";
Node* top(node.top());
node.pop();
for (Node* N : top->children)
{
node.push(N);
}
}
/*0 4 7 10 6 2 9 8 5 3 1 11*/
`
-
- 时间复杂度问题
假设边的个数为N,节点数为N+1,
用数组存储边,处理每个节点时都要把所有的边全部遍历一遍,
时间复杂度为O(N^2)。
如果边数特别多时很影响效率
极端情况:
0,1
0,2
0,3
……
0,10000(或者更多)
解决方案:
用一个循环队列存储边,
每加入一个边就令其出队
本文内容开源,转载请附上本文链接
https://www.cnblogs.com/ShimuGuyue513/articles/18293869
对本文进行修改后的文章务必同样开源
禁止利用本文进行盈利(包括但不限于付费文章等)


浙公网安备 33010602011771号