【问题标题】:Inserting element into left leaning black red tree c++将元素插入左倾黑红树c ++
【发布时间】:2016-09-26 08:12:05
【问题描述】:

我一整天都在盯着它看,稍微有点地方,但它仍然无法正常工作!只是试图将元素 k '放入'(真正插入或查找它是否存在)到 LL 红黑树中。这是我的方法:

Node * RPut(Node* p, const K& k, Node*& location)
{
  // if you are at the bottom of the tree,
  // add new node at bottom of the tree
  if (p == 0)
  {
    // new red note with new data
    location = NewNode(k, Data(), RED);
    return location;
  }

  if(greater_(k,p->key_))
  {
    // if it's greater than the root, move down to the left child
    p->left_ = Rput(p->left_, k, location);
  }
  // right subtree
  else if (greater_(p->key_,k))
  {
    // but if the key is less than root, move down to right child
    p->right_ = Rput(p->right_, k, location);
  }
  // if they are equal
  else
  {
    location = p;
  }   
  // code for rotating
  // this sort of worked.
  if(p->right_ && p->right_->IsRed())
  {
    p = RotateLeft(p);
    if (p->left_->IsBlack())
    {
      p->SetBlack();
      p->left_->SetRed();
    }
  }
  if (p->left_ && p->left_->IsRed())
  {       if (p->left_->left_ && p->left_->left_->IsRed())
    {
        p = RotateRight(p);
        p->left_->SetBlack();
        p->right_->SetBlack();
     }
   }
   return p;
}

我知道我的旋转方法非常有效。这会正确插入到第五个元素(我没有尝试过每种组合,但通常情况下。)例如,正确插入的 abcde 将是

   d
  b  e
 a c --

[以b为红色节点]

我的工作,但停在这里,给我:

    b
  a   d
- -  c   e

没有红色节点。

任何人看到我忽略的任何明显内容或为什么它无法正常工作?任何帮助都非常感谢。 谢谢!

【问题讨论】:

    标签: c++ data-structures binary-search-tree red-black-tree


    【解决方案1】:

    这并不能直接回答问题,但是您是否阅读过 Sedgewick 的 paper 左倾红黑树?里面的代码非常清晰,有漂亮的图表来解释事情是如何工作的,而且,我想,将所有东西重新实现到 C++ 中会很简单。

    编辑

    为了好玩,我尝试实现 Sedgewick 的代码。事实证明,这篇论文遗漏了一些方法/子例程,这些方法/子例程包含在内会非常有帮助。无论如何,我的 C++11 实现以及一些测试如下。

    由于 Java 执行自动内存管理,Sedgewick 没有明确指出应该在其代码中释放内存的位置。我没有尝试为快速项目解决这个问题并可能留下内存泄漏,而是选择使用std::shared_ptr,它提供了类似的无忧行为。

    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <memory>
    
    template<class keyt, class valuet>
    class LLRB {
     private:
      static const bool COLOR_RED   = true;
      static const bool COLOR_BLACK = false;
    
      class Node {
       public:
        keyt   key;
        valuet val;
        std::shared_ptr<Node> right;
        std::shared_ptr<Node> left;
        bool   color;
        Node(keyt key, valuet val){
          this->key   = key;
          this->val   = val;
          this->color = COLOR_RED;
          this->right = nullptr;
          this->left  = nullptr;
        }
      };
    
      typedef std::shared_ptr<Node> nptr;
    
      nptr root;
    
      nptr rotateLeft(nptr h){
        nptr x  = h->right;
        h->right = x->left;
        x->left  = h;
        x->color = h->color;
        h->color = COLOR_RED;
        return x;
      }
    
      nptr rotateRight(nptr h){
        nptr x  = h->left;
        h->left  = x->right;
        x->right = h;
        x->color = h->color;
        h->color = COLOR_RED;
        return x;
      }
    
      nptr moveRedLeft(nptr h){
        flipColors(h);
        if(isRed(h->right->left)){
          h->right = rotateRight(h->right);
          h        = rotateLeft(h);
          flipColors(h);
        }
        return h;
      }
    
      nptr moveRedRight(nptr h){
        flipColors(h);
        if(isRed(h->left->left)){
          h = rotateRight(h);
          flipColors(h);
        }
        return h;
      }
    
      void flipColors(nptr h){
        h->color        = !h->color;
        h->left->color  = !h->left->color;
        h->right->color = !h->right->color;
      }
    
      bool isRed(const nptr h) const {
        if(h==nullptr) return false;
        return h->color == COLOR_RED;
      }
    
      nptr fixUp(nptr h){
        if(isRed(h->right) && !isRed(h->left))       h = rotateLeft (h);
        if(isRed(h->left)  &&  isRed(h->left->left)) h = rotateRight(h);
        if(isRed(h->left)  &&  isRed(h->right))          flipColors (h);
    
        return h;
      }
    
      nptr insert(nptr h, keyt key, valuet val){
        if(h==nullptr)
          return std::make_shared<Node>(key,val);
    
        if     (key == h->key) h->val   = val;
        else if(key  < h->key) h->left  = insert(h->left, key,val);
        else                   h->right = insert(h->right,key,val);
    
        h = fixUp(h);
    
        return h;
      }
    
      //This routine probably likes memory
      nptr deleteMin(nptr h){
        if(h->left==nullptr) return nullptr;
        if(!isRed(h->left) && !isRed(h->left->left))
          h = moveRedLeft(h);
        h->left = deleteMin(h->left);
        return fixUp(h);
      }
    
      nptr minNode(nptr h){
        return (h->left == nullptr) ? h : minNode(h->left);
      }
    
      //This routine leaks memory like no other!! I've added a few cleanups
      nptr remove(nptr h, keyt key){
        if(key<h->key){
          if(!isRed(h->left) && !isRed(h->left->left))
            h = moveRedLeft(h);
          h->left = remove(h->left, key);
        } else {
          if(isRed(h->left))
            h = rotateRight(h);
          if(key==h->key && h->right==nullptr)
            return nullptr;
          if(!isRed(h->right) && !isRed(h->right->left))
            h = moveRedRight(h);
          if(key==h->key){
            std::shared_ptr<Node> mn = minNode(h->right);
            h->val = mn->val;
            h->key = mn->key;
            h->right = deleteMin(h->right);
          } else {
            h->right = remove(h->right, key);
          }
        }
    
        return fixUp(h);
      }
    
      void traverse(const nptr h) const {
        if(h==nullptr)
          return;
        traverse(h->left);
        std::cout<< h->key << "=" << h->val <<std::endl;
        traverse(h->right);
      }
    
     public:
      LLRB(){
        root = nullptr;
      }
    
      void traverse() const {
        traverse(root);
      }
    
      valuet search(keyt key){
        nptr x = root;
        while(x!=nullptr){
          if      (key == x->key) return x->val;
          else if (key  < x->key) x=x->left;
          else                    x=x->right;
        }
    
        return keyt();
      }
    
      void insert(keyt key, valuet val){
        root        = insert(root,key,val);
        root->color = COLOR_BLACK;
      }
    
      void remove(keyt key){
        root        = remove(root,key);
        root->color = COLOR_BLACK;
      }
    };
    
    int main(){
      for(int test=0;test<500;test++){
        LLRB<int,int> llrb;
        std::vector<int> keys;
        std::vector<int> vals;
    
        for(int i=0;i<1000;i++){
          //Ensure each key is unique
          int newkey = rand();
          while(llrb.search(newkey)!=int())
            newkey = rand();
    
          keys.push_back(newkey);
          vals.push_back(rand()+1);
          llrb.insert(keys.back(),vals.back());
        }
    
        //llrb.traverse();
    
        for(int i=0;i<1000;i++){
          if(llrb.search(keys[i])!=vals[i]){
            return -1;
          }
        }
    
        for(int i=0;i<500;i++)
          llrb.remove(keys[i]);
    
        for(int i=500;i<1000;i++){
          if(llrb.search(keys[i])!=vals[i]){
            return -1;
          }
        }
      }
    
      std::cout<<"Good"<<std::endl;
    }
    

    【讨论】:

    • 我没有!我尝试了与此类似的变体,但遇到了段错误问题。打算按照他的逻辑再试一次。
    • 我想知道你是否能找到方法在你的代码中加入一些健全的断言? assert() 函数会在出现问题时将其炸毁,稍后可以将其排除在编译之外以提高速度,并在发生故障时告诉您失败的原因。
    • @Tracy 我尝试了与此类似的变体,但遇到了段错误问题 - IMO 的问题是 C++ 不是一种好的(应该说是理想的)语言如果您想根据您在教科书中阅读的内容实现数据结构,请使用。像 Java 这样的语言更适合这种情况。原因是对于 C++,您必须担心如何正确管理动态分配的内存,这与其他语言不同。所以你有两座山要爬——语言本身和你正在实现的数据结构。
    • @Tracy:我有一点空闲时间,所以我按照 Sedgewick 的论文实现了 LLRB。也许你会发现它很有帮助。和你一样,我在大约 5 个对象上遇到了问题。这些是由于没有在插入例程中将h 设置为fixUp() 的返回值。还存在问题,因为需要初始化 leftright 指针以及 root
    • 是的,您可以对空指针运行 fixUp,因为 isRed 可以防止滥用。
    猜你喜欢
    • 2012-11-01
    • 2021-05-22
    • 1970-01-01
    • 2019-06-04
    • 2020-09-19
    • 2013-06-12
    • 2018-11-06
    • 2013-11-17
    相关资源
    最近更新 更多