扁平数组转树结构C++实现方式

背景

今天遇到一个题,需要将扁平数组转树结构,题目大致如下
将扁平数组转为树结构输出 pid0为根节点,id顺序可能不递增,pid可能不存在于数组内
给定输入

[
  {id: 1, name: '111', pid: 0},
  {id: 2, name: '222', pid: 1},
  {id: 3, name: '333', pid: 1},
  {id: 4, name: '444', pid: 3},
  {id: 5, name: '555', pid: 4},
]

给定输出:

{
  "id": 1,
  "name": "111",
  "pid": 0,
  "children": [
      {
          "id": 2,
          "name": "222",
          "pid": 1,
          "children": []
      },
      {
          "id": 3,
          "name": "333",
          "pid": 1,
          "children": [
              // ...
          ]
      }
  ]
}

思考

这个题当时用c++没有做出来,一看这个输出就是json格式,应该就是个前端的题,后来一搜果然。

不过用c++肯定也能写就是构造个树,递归去查找比较插入唄。额外支持一下要求的特例。后来还是用c++写了一下最后输出格式没弄。算法可能不是最优,先实现了吧。

写完也没明白用这个前端题来考什么,估计是应变能力吧,还是得加强算法练习,才能遇题不慌不乱。

上代码

由于题目要求,这里可能会存在多棵树(pid不在树内的情况)。
考虑到插入树时,若id不是顺序的,则会产生临时的N棵树,后续还要合并这些树,比较麻烦,就先排一下序,这样除非不在当前树内的,否则都能找到对应节点插入。
这里我们使用了preorder先序遍历的算法,在遍历时,判断pid 和id有无和待插入的元素有关系的,找到了就挂在树上。
有个特殊的情况是待插入元素会成为当前树的根,这里需要处理一下

#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

// 节点定义
class onenode
{
public:
    int id;
    int pid;
    std::vector<onenode*> childs;

    onenode(int idt, int pidt)
    {
        id = idt,
        pid = pidt;
    }
    ~onenode(){};
};
// 遍历找位置插入树
onenode* preorder(onenode* node, onenode*tmpnode)
{
    if (node == nullptr)
        return nullptr;
    if (node->id == tmpnode->pid)
    {
        node->childs.push_back(tmpnode);
        return node;
    }
    if (node->pid == tmpnode->id)
    {
        tmpnode->childs.push_back(node);
        return tmpnode;
    }
    for (auto it = node->childs.begin(); it != node->childs.end(); it++)
    {
        onenode* tmpnode1 = preorder(*it, tmpnode);
        if (tmpnode1 != nullptr)
            return tmpnode1;
    }
    return nullptr;
}

int tryaddtotree(onenode* tmproot, onenode* cur, std::map<int, onenode*>& nodetree)
{
    onenode* tmpptr = preorder(tmproot, cur);
    if (tmpptr != nullptr)
    {
        if (tmpptr == cur)
        {
            for (auto it = tmpptr->childs.begin(); it != tmpptr->childs.end(); it++)
            {
                if ((*it)== tmproot)
                {
                    return 1;// 新节点是root了 需要换root                    
                }
            }
        }
        return 2;// 树里的一个子节点
    }
    else
    {   //没加进去需要新增树了
        return 3;
    }
}

int preprint(onenode* root)
{
    if (root == nullptr)
        return 0;
    printf("id: %d, pid %d\n", root->id, root->pid);
    for (auto it = root->childs.begin(); it != root->childs.end(); it++)
    {
        preprint(*it);
    }
    return 0;
}

int main()
{
    std::map<int, onenode*> nodetree;
    //std::vector<onenode> srcdata = {{1,0},{2,1},{3,1},{4,3},{5,4},{6, 99}};
    std::vector<onenode> srcdata = {{1,0},{4,3},{5,4},{2,1},{3,1},{6, 99}};
    for (auto it = srcdata.begin(); it != srcdata.end(); it++)
    {
        printf("%d %d\n", (*it).id, (*it).pid);
    }
    //for (auto it : srcdata) 
    //{ printf("%d %d\n", it.id, it.pid);}

    sort(srcdata.begin(), srcdata.end(),[](onenode a, onenode b){
        return a.id < b.id;
    });
    
    for (auto it = srcdata.begin(); it != srcdata.end(); it++)
    {
        onenode* willaddnode = &(*it);
        if (nodetree.empty())
        {
            nodetree.emplace(std::make_pair(willaddnode->id, willaddnode));
            continue;
        }
        bool added = false;
        for (auto itm = nodetree.begin(); itm != nodetree.end(); itm++)
        {
            onenode* tmproot = itm->second;
            int addret = tryaddtotree(tmproot, willaddnode, nodetree);
            if (addret == 1)
            {
                nodetree.emplace(std::make_pair(willaddnode->id, willaddnode));
                nodetree.erase(tmproot->id);
                added = true;
            }
            else if (addret == 2)
            {
                added = true;
            }
            if (added)
                break;
        }
        if (!added)
        {
            nodetree.emplace(std::make_pair(willaddnode->id, willaddnode));
        }
    }

    for (auto itm = nodetree.begin(); itm != nodetree.end(); itm++)
    {
        printf("*****\n");
        preprint(itm->second);
    }
    return 0;
}

总结

虽然是个前端题不过是涉及到树的遍历,用c++还是可以写的,平时还是需要多练习
水平有限可能有更优的解法欢迎指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nwao7890

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值