背景

今天遇到一个题,需要将扁平数组转树结构,题目大致如下
将扁平数组转为树结构输出 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++还是可以写的,平时还是需要多练习
水平有限可能有更优的解法欢迎指出

扁平数组转树结构C++实现方式相关推荐

  1. (C++)字符数组的四种输入输出方式

    scanf/printf+%s getchar()/putchar() 前者不带参数后者带 gets()/puts() 二者都带参数,为一维字符数组或二维字符数组的一维 运用指针+scanf/prin ...

  2. JS数组遍历的几种方式

    JS数组遍历的几种方式 JS数组遍历,基本就是for,forin,foreach,forof,map等等一些方法,以下介绍几种本文分析用到的数组遍历方式以及进行性能分析对比 第一种:普通for循环 代 ...

  3. java中打印输出数组内容的三种方式

    今天输出数组遇到问题,学习一下打印输出数组内容的几种方式 错误示范:System.out.println(array); //这样输出的是数组的首地址,而不能打印出数组数据.(唉,我开始就是这么写的. ...

  4. php如何判断二维数组为空,PHP判断数组为空的具体方式

    在学习PHP语言的时候,初学者往往会对数组感到一些棘手.不过在通过深入的学习之后,我们会发现,这些其实并没有想象中的困难.我们今天就要向大家介绍PHP判断数组为空的具体方式,希望能让新手们了解一些新知 ...

  5. java定义数组_java中数组的三种定义方式_java中数组的定义及使用方法(推荐)...

    java中数组的三种定义方式 java中,数组是一种很常用的工具,今天我们来说说数组怎么定义 [java] view plain copy /** * 数组的三种定义方法 * 1.数组类型[] 数组名 ...

  6. 初始化一个java空数组_Java 数组的两种初始化方式

    一.数组 1.数组中存储元素的类型是统一的,每一个元素在内存中所占用的空间大小是相同的,知道数组的首元素的内存地址,要查找的元素只要知道下标,就可以快速的计算出偏移量,通过首元素内存地址加上偏移量,就 ...

  7. 数组转化为集合的方式asList()

    asList()的使用 String[] arr = {"abc","ccc","ddd"};/*把数组变成list集合的好处?* 可以使用 ...

  8. js中数组的几种循环方式

    js中数组的几种循环方式 for循环最基本的循环方式,不多说.这种最基本的循环才是速度最快的,效率最高的. for(var i = 0;i<5;i++){console.log(i) } for ...

  9. C语言的二维数组初始化的几种方式介绍(私藏大数组初始化方式)

    C语言的二维数组初始化的几种方式介绍 1.直接赋值 2.循环对每个元素赋值 3.借用memset/memset_s初始化为0或-1 4.`数组所有元素初始化为相同值(用于大数组初始化贼方便)` 1.直 ...

最新文章

  1. idea集成spring+spring MVC+mybatis问题
  2. PTA 09-排序3 Insertion or Heap Sort (25分)
  3. raid1 热备盘 linux,Centos 6.5 RAID1加热备盘
  4. mysql myisampack_每天进步一点达——MySQL——myisampack
  5. dcs服务器性能指标,第6章DCS的性能指标.PDF
  6. 深度学习2.0-10.tensorflow的高阶操作之张量的限幅
  7. c语言字符是源码,C语言基础字符串函数源代码
  8. 图灵的遗产和后继者们的责任
  9. 简单C语言程序的编写,c语言编写简单程序.doc
  10. 二项分布期望和方差公式推导
  11. Incorrect string value: ‘\xE4\xBB\x8E\xE5\x85\xA5...‘ for column ‘detail‘ at row 1
  12. 条形码生成EAN-13码(用JavaScript生成)
  13. 【科普】关于装机CPU参数介绍及选取原则
  14. linux 将当前时间往后调整2分钟_linux调整系统时间 永久 z | 学步园
  15. Learning to Localize Sound Sources in Visual Scenes: Analysis and Applications
  16. Android 进阶——Framework 核心ANR( Applicatipon No Response)机制设计思想详解
  17. 导入EXCEL报错:外部表不是预期的格式错误、文件格式和扩展名不匹配,文件可能已损坏或不安全的解决方法
  18. P1456 Monkey King
  19. configure: error: C preprocessor “/lib/cpp“ fails sanity check错误解决办法
  20. OpenGL渲染管线之简单示例(五)

热门文章

  1. css -- js动态改变before和after
  2. CTFHUB-WEB--cooki注入wp
  3. ubuntu18.04如何新建文件
  4. 华为OD机试题,用 Java 解【比赛评分】问题 | OD统一考试(B卷)
  5. 扩展欧几里得算法、ax+by=c求解、ax≡c(mod m)、逆元求解、(b/a)%m计算c++代码
  6. 奇瑞版Model 3与Model Y登场:正式进军高端纯电
  7. python中删除某一行_python 删除大文件中的某一行(最有效率的方法)
  8. 详解SVM支持向量机算法(一:感知器和SVM的优点)
  9. 26岁的我离婚了!80后婚姻注定死在房子上!
  10. ubuntu安装向日葵远程简明教程