Итеративная вставка 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());
    }
};

Я ответил на случай здесь вставка дерева двоичного поиска не работает посмотреть, если это помогает