Итеративная вставка BST в C++
Я пытаюсь понять BSTs и как вставлять в него элементы итеративно. Моя реализация структуры узла выглядит так:
struct Node{
Node *left;
Node *right;
T data; //template class
};
и моя реализация вставки выглядит так:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
if(root == NULL) {root = newNode;} //If the BST is empty
else
{//The BST is not empty
Node *ptr = root; //points to the current Node
Node *ptr_parent; //points to the parent Node
while(ptr != NULL)
{
if((ptr -> data) > value)
{
ptr_parent = ptr;
ptr = ptr -> left;
}
if((ptr -> data) < value)
{
ptr_parent = ptr;
ptr = ptr -> right;
}
}
}
ptr = newNode; //insert the newNode at the spot
if((ptr_parent -> data) < value)
ptr_parent -> right = newNode;
else
ptr_parent -> left = newNode;
return true;
}
вставка работает при добавлении первого узла в пустое дерево, но я получаю ошибку сегментации, когда я пытаюсь добавить дополнительные узлы. Я понимаю, что есть сообщения, которые показывают, как реализовать вставки в BSTs, но большинство из них показывают рекурсивный метод, и те, у кого есть итеративные примеры, являются неполными или слишком конкретными. Спасибо.
7 ответов
вчера вечером я смог заставить свой исходный код работать, я делюсь ответом здесь:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *ptr;
Node *ptr_parent;
if(root == NULL)
{//The BST is Empty...
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
root = newNode;
ptr = root;
} else { //traversing the tree to find the insertion point
ptr = root;
while(ptr != NULL)
{
if((ptr -> data) == value) {return false;} //to check for duplicates
if(value < (ptr -> data))
{
ptr_parent = ptr;
ptr = ptr -> left;
} else {
ptr_parent = ptr;
ptr = ptr -> right;
}
}
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
//checking for parent value to determine if
//the Node is a left or right child
if(value < (ptr_parent -> data))
ptr_parent -> left = newNode;
else
ptr_parent -> right = newNode;
}
++count;//to keep track of the Node count
return true;
}
ради себя я хотел решить это без использования двойных указателей.
Я думаю, что сделал бы все немного по-другому. Во-первых, я бы немного упростил другой код, добавив ctor в класс Node:
struct Node{
Node *left;
Node *right;
T data;
Node(T const &data) : left(nullptr), right(nullptr), data(data) {}
};
затем вы можете использовать указатель на указатель, чтобы пересечь дерево и вставить элемент:
bool insert(const T value) {
Node **pos;
for (pos = &root; *pos != nullptr;) {
if (value < (*pos)->value)
pos = &(*pos)->left;
else if ((*pos)->value < value )
pos = &(*pos)->right;
else
return false;
}
*pos = new Node(value);
return true;
}
обратите внимание, что я отложил создание нового узла до тех пор, пока мы не выпали из цикла. Таким образом, если у нас есть дубликат элемента, мы можем просто вернуться (без утечки узла, так как мы не выделили новый узел еще.)
для чего это стоит, если бы вы собирались сделать это рекурсивно, вероятно, было бы проще использовать ссылку на указатель вместо указателя на указатель.
вы не справились с делом, когда ptr->data == value
таким образом, цикл будет бесконечным, когда будет найден дубликат, и ptr = newNode
ничего не делает, он просто делает ptr
выберите пункт newNode
. Попробуйте это
//ptr holds the address of pointers to nodes.
Node **ptr = &root;
while(*ptr != NULL){
if((*ptr)->data > T)
ptr = &(*ptr)->right;
else
ptr = &(*ptr)->left;
//Not handling duplicates
}
//Change the value of the pointer to newNode
*ptr = newNode;
используйте жесткие указатели
Node **ptr = &root; //points to the current Node
Node **ptr_parent; //points to the parent Node
когда вы пытаетесь сделать это
ptr = newNode; //insert the newNode at the spot
он не делает ничего, потому что вам нужно изменить указатель, который указывает на левый или правый подузел
что-то вроде этого:
template<typename T>
bool BST<T>::Insert(const T value)
{
Node *newNode = new Node;
newNode -> data = value;
newNode -> left = NULL;
newNode -> right = NULL;
if(root == NULL) {root = newNode;} //If the BST is empty
else
{//The BST is not empty
Node **ptr = &root; //points to the current Node
Node **ptr_parent; //points to the parent Node
while((*ptr) != NULL)
{
if(((*ptr) -> data) > value)
{
ptr_parent = ptr;
ptr = &ptr -> left;
}
if(((*ptr) -> data) < value)
{
ptr_parent = ptr;
ptr = &ptr -> right;
}
}
}
(*ptr) = newNode; //insert the newNode at the spot
if(((*ptr_parent) -> data) < value)
(*ptr_parent) -> right = newNode;
else
(*ptr_parent) -> left = newNode;
return true;
}
Как я понимаю, это не из-за следующей строки:
ptr = newNode; //insert the newNode at the spot
после цикла while ваш ptr равен нулю, иначе вы не сможете выйти из цикла while. Вы назначаете структуру NULL, что неправильно.
надеюсь, это поможет. Все остальное выглядит нормально.
void insert(node* root, int value)
{
if (root == NULL)
{
root = new node;
root->data = value;
return;
}
while(!((root->data < value && root->right == NULL) || (root->data >= value && root->left == NULL)))
{
if (root->data < value)
root = root->right;
else
root = root->left;
}
if (root->data < value)
{
root->right = new node;
root->right->data = value;
} else
{
root->left = new node;
root->left->data = value;
}
}
template <class T>
class TreeNode{
private:
T data;
TreeNode<T>* right,*left;
public:
void setData(T d){
this->data =d;
}
T getData(){
return this->data;
}
void setRight(TreeNode<T>* r){
this->right =r;
}
TreeNode<T>* getRight(){
return this->right;
}
void setLeft(TreeNode<T>* r){
this->left =r;
}
TreeNode<T>* getLeft(){
return this->left;
}
static TreeNode<T>* newNode(T data){
TreeNode<T>* n = new TreeNode<T>();
n->setData(data);
n->setRight(NULL);
n->setLeft(NULL);
return n;
}
};
template <class T>
class BinaryTree{
private:
TreeNode<T>* root;
public:
void insert(T data){
TreeNode<T>* n = TreeNode<T>::newNode(data);
if(root==NULL)
root = n;
else{
TreeNode<T>* t = root;
while(t!=NULL){
if(n->getData() >= t->getData()){
if(t->getRight()==NULL){
t->setRight(n); //newnode attached as right child in tree
t = NULL;
}
else
t = t->getRight();
}
else{
if(t->getLeft()==NULL){
t->setLeft(n); //newnode attached as left child in tree
t=NULL;
}
else
t = t->getLeft();
}
}
}
}
void preorder(){
TreeNode<T>* t = root;
preorderUtil(t);
}
void preorderUtil(TreeNode<T>* node){
if(node==NULL)
return;
preorderUtil(node->getLeft());
cout<<node->getData()<<" ";
preorderUtil(node->getRight());
}
};
Я ответил на случай здесь вставка дерева двоичного поиска не работает посмотреть, если это помогает