基于C++中的list实现的N叉树
- 问题的引入:某家公司要做一个决策类软件,针对每一种方案都有n种需要执行的任务,每一种任务下面都有m种可以完成该方案的技术,且每一项任务都必须要完成,现在要根据每一项技术的特点求出完成该方案最优的技术组合。
- 思考:假设要完成第一项任务,假设可以完成该项任务的技术总共有n1种,那么可供我们选择的技术组合就有(2^n1-1)种(至少要有一种技术)对于m个任务,我们完成该方案的技术组合可以用数据结构中的树来表示:(如下图)
这里以两个任务为例,任务一下面有技术1,2,任务二下面有技术3,4,5,6,那么完成这个目标的方案组合就有(1,3)(1,4)(1,5)(1,6)(2,3)(2,4)(2,5)(2,6),那么,我们得到这些技术组合的方式就很简单了,只需要对树做一次从左到右的遍历就可以了。在每次遍历结束后,我们根据特定的算法计算每种方案对目标的贡献度的大小,就可以得到最优的方案组合。
下面是怎么生成一个N叉树(在实际情况中,每种任务下方的技术个数是不定的)的代码
先来错误的代码:
#include<iostream>
#include<list>
using namespace std;
struct TreeNode {
int data;
list<TreeNode*> childList;
TreeNode(int data)
{
this->data = data;
}
};
list<TreeNode*> lis;
void CreatTree(list<TreeNode*>&lis, list<TreeNode*>&nodes)
{
if (lis.empty())
{
for (const auto&item : nodes)
{
lis.push_back(item->data);
}
return;
}
else
{
for (const auto&item : lis)
{
CreatTree(item->childList, nodes);
}
}
return;
}
void Print_Tree(list<TreeNode*>&lis)
{
if (lis.empty())
{
}
}
int main()
{
list<TreeNode*> node1;
node1.push_back(new TreeNode(12));
node1.push_back(new TreeNode(13));
list<TreeNode*> node2;
node2.push_back(new TreeNode(114));
node2.push_back(new TreeNode(132));
node2.push_back(new TreeNode(1321));
list<TreeNode*> node3;
node3.push_back(new TreeNode(15));
node3.push_back(new TreeNode(16));
CreatTree(lis, node1);
CreatTree(lis, node2);
CreatTree(lis, node3);
system("pause");
return 0;
}
接下来放正确的代码
#include<iostream>
#include<list>
using namespace std;
struct TreeNode {
int data;
list<TreeNode*> childList;
TreeNode(int data)
{
this->data = data;
}
};
list<TreeNode*> lis;
void CreatTree(list<TreeNode*>&lis, list<TreeNode*>&nodes)
{
if (lis.empty())
{
for (const auto&item : nodes)
{
lis.push_back(new TreeNode(item->data));
}
return;
}
else
{
for (const auto&item : lis)
{
CreatTree(item->childList, nodes);
}
}
return;
}
void Print_Tree(list<TreeNode*>&lis)
{
if (lis.empty())
{
}
}
int main()
{
list<TreeNode*> node1;
node1.push_back(new TreeNode(12));
node1.push_back(new TreeNode(13));
list<TreeNode*> node2;
node2.push_back(new TreeNode(114));
node2.push_back(new TreeNode(132));
node2.push_back(new TreeNode(1321));
list<TreeNode*> node3;
node3.push_back(new TreeNode(15));
node3.push_back(new TreeNode(16));
CreatTree(lis, node1);
CreatTree(lis, node2);
CreatTree(lis, node3);
system("pause");
return 0;
}
相比较于上方正确的代码,做出更改的只有这一部分
在原来的代码中
if (lis.empty())
{
for (const auto&item : nodes)
{
lis.push_back(item->data);
}
return;
}
lis.push_back(itm->data)会将一个地址存放在父亲的ChildList中,那么当左边的树添加完子节点的时候,此时再给右边的树添加子节点,会让上一层中对称位置的指针指向同一个地址,此时,如果我们要在下一层添加子节点,当我们遍历左边的树的时候可以添加子节点,但是当我们遍历右边的树的时候,因为左边的树的对称位置下方已经添加了数据,那么此时判定右边的树不为空,就会进入递归调用中,给这一层下方添加子节点,添加完成之后,返回初始调用的位置,执行for循环,此时下一个节点和上一个节点同样的问题。此时看似是在遍历右边的树,其实是在遍历左边的树,因此,程序就会卡死,不停的给15的下面添加15,16,导致栈溢出。
当我们把代码修改为
lis.push_back(new TreeNode(item->data));
后,此时指针指向的地址不是同一个地址,程序顺利运行。