使用矢量的C ++二叉树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用矢量的C ++二叉树相关的知识,希望对你有一定的参考价值。
我的任务是在向量中存储二叉树。在每个节点内存储一个int ID,int Age和一个字符串名称。
节点通过ID在矢量内存储和组织。
当在向量中存储二叉树时,我使用算法2i和2i + 1分别指示节点的左和右子节点。
我设法创建一个插入方法,我相信满足这些条件并将一个节点插入一个向量,但是,在尝试将这些节点插入向量后
50蒂姆
75 22史蒂夫
我注意到它实际上并没有将这些节点插入到向量中。
我在插入后放置了一行打印索引,我意识到在第一次插入后,索引不再更新。
示例使用此示例运行insert方法
我的insert()方法有问题吗?
这是我的代码。
#include "BinaryTree.h"
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int index = 0;
struct Node
{
int ID;
int age;
string name;
Node()
{
}
Node(int id, int Age, string nm)
{
this->ID = id;
this->age = Age;
this->name = nm;
}
};
vector<Node> binaryTree(30);
BST::BST()
{
}
void BST::start()
{
int choice;
cout << "What would you like to do?" << endl;
cout << "1. Add a node to the tree" << endl;
cout << "2. Delete a node from the tree" << endl;
cout << "3. Find a node in the tree" << endl;
cout << "4. Report the contents of the tree" << endl;
cout << "5. Exit program" << endl;
cin >> choice;
if (choice == 1)
{
insert();
}
if (choice == 2)
{
Delete();
}
if (choice == 3)
{
find();
}
if (choice == 4)
{
report();
}
}
void BST::insert()
{
int ID;
int AGE;
string NAME;
int root = 1;
bool success = false;
cout << "Please enter the ID number, age and name:" << endl;
do
{
cin >> ID >> AGE >> NAME;
} while (ID < 0);
Node *tree = new Node(ID, AGE, NAME);
if (index == 0)
{
binaryTree[1] = *tree;
}
if (index > 0)
{
do
{
if (tree->ID > binaryTree.at(root).ID)
{
root = 2 * root + 1;
}
if (tree->ID < binaryTree.at(root).ID)
{
root = 2 * root;
}
if (binaryTree.at(root).ID == NULL)
{
binaryTree.at(root) = *tree;
cout << "Added!" << endl;
cout << "Vector size: " << binaryTree.size() << endl;
success = true;
}
} while (!success);
}
index++;
cout << index << endl;
delete tree;
start();
}
编辑:我意识到我没有检查索引,所以我将它从'='更改为'=='比较以启动循环。但是,现在我得到一个_Xout_of_range(“无效的向量下标”);向量类抛出的异常
这是错误。
do
{
cin >> ID >> AGE >> NAME;
} while (ID < 0);
不是实际的问题,但是你应该在这个操作之后检查std::cin
的状态 - 如果用户确实输入了无效输入("xyz"
),cin仍然处于失败状态,你将永远无法得到有效的输入...另外,如果你做的话id和age unsigned,您不必检查负输入。
我的个人变体:
for(;;)
{
std::cin >> id >> age >> name;
if(std::cin)
// input is valid!
break;
std::cout << "invalid input" << std::endl; // some better text?
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '
');
}
有关详细信息,请参阅this answer
if (index = 0)
// ^ this is an assignment! always sets index to 0 and then
// checks the value; for COMPARISON, you need to use ==
{
binaryTree[1] = *tree;
// ^ and when do you ever fill index 0???
}
赋值而不是比较是实际导致问题的原因!
如果index
代表向量中的元素数量,你可以完全删除它,使用binaryTree.size()
代替......
if (binaryTree.at(root).ID == NULL)
{
binaryTree.at(root) = *tree;
cout << "Vector size: " << binaryTree.size() << endl;
}
等等,你打算用默认值预先填充向量吗?如果是这样,binaryTree.size()将始终具有相同的大小......并且您可能需要一个巨大的预分配数组,并且可能会得到较差的填充等级。回来以后。请注意,NULL
是一个代表空指针的宏(如果你真的在处理,请改为使用nullptr
关键字!)。不要将它用于整数比较,直接使用值0
。
另外:如果向量不够大,at
将抛出异常。然后?首选使用索引运算符,但之前检查向量是否足够大。如果不是,请适当增加矢量的大小(例如,使其大小为之前的两倍)。
Node* tree = new Node(id, age, name);
binaryTree[x] = *tree;
delete tree;
那么,为什么然后在堆上呢?只需这样做:
Node tree(id, age, name);
// no pointer! creating object directly on the stack!
binaryTree[x] = tree; // assign directly
// no delete necessary, object will be destructed automatically when leaving scope
在当前不必要的情况下,移动和复制结果相同,但是对于更复杂的对象,移动而不是复制可能有值,因此您可以优化到:
binaryTree[x] = std::move(tree); // creates an rvalue reference...
回到size / fillgrade问题:二叉树只有保持平衡才有效。通常,在运行时,如果存储在像数组之类的结构中,也可以存储在内存中。所以你应该保持你的树平衡。变体可能不是从树的根开始,而是简单地在末尾附加元素(使用push_back
)然后向上移动它,只要它比父节点大,如果在左侧树中,或者小于父节点。 ,如果在正确的树上。如果提供移动构造函数,则可以使用std::swap
来交换元素。这种替代方法还避免了对sentinel值的需要(node.id == 0)......
编辑回复您的评论:
好的,现在首先让算法中包含索引0,不需要跳过位置0。
然后,您的问题可能已经是第一次插入:您是否确定向量确实包含两个虚拟元素?更好的是我们从一开始就考虑我们有一个空向量。然后我们可以做到:
unsigned int index = 0;
// renaming root to index, assuming we dropped
// the other index variable already
// benefit: you can clearly differentiate my and your code...
Node node(id, age, name);
for(;;)
{
if(index <= binaryTree.size()) // covers empty vector, too, as 0 <= 0...
{
binaryTree.resize(index + 1);
// vector with size of n can store n elements
// at indices [0 .. n - 1] - deduce the inverse yourself
// and you know why index + 1...
binaryTree[index] = node;
// if we needed to resize, the new elements are unoccupied
// anyway, so we simply can insert and are done...
break;
}
if(binaryTree[index].id == 0)
{
// sentinel found, can insert here:
binaryTree[index] = node;
break;
}
// now calculate the child index just as before
}
但是,计算下一个子索引也有错误:
if (tree->ID > binaryTree.at(root).ID)
root = 2 * root + 1;
if (tree->ID < binaryTree.at(root).ID)
root = 2 * root;
什么,如果ids是相同的???其中至少有一个必须包含相等,否则你将陷入无限循环。但是,一个条件与另一个条件完全相反,所以你可以简单地使用if / else:
if (node.id > binaryTree[index].id)
index = 2 * index + 1;
else
index = 2 * index;
现在一些很好的调整:在C ++中,比较总是得到布尔值,然后提升为(unsigned)int总是得到0或1,所以你可以,如果你愿意,可以将上面的内容缩短到下面的一行(好吧,我的重命名)适用于...):
index = 2 * index + (tree->ID > binaryTree[index].ID);
以上是关于使用矢量的C ++二叉树的主要内容,如果未能解决你的问题,请参考以下文章