已知边的连通关系建树

例:
节点数:
12

边的连通关系 :
5 6
11 0
8 6
0 3
9 6
6 0
10 7
4 0
2 6
4 7
3 1

ps:

  1. 没有约定序号小的节点一定是父亲
  2. 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
对本文进行修改后的文章务必同样开源
禁止利用本文进行盈利(包括但不限于付费文章等)

posted @ 2024-07-10 13:32  石木古月  阅读(23)  评论(0)    收藏  举报