将元素插入左倾黑红色树c ++中

时间:2016-05-27 21:52:01

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

我一整天都在盯着这个,并且稍微有些地方,但它仍然无法正常工作!只是试图'把'(真的​​插入,或发现它是否存在)元素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

没有红色节点。

任何人都会看到任何明显的我忽视或为什么它不能正常工作?任何帮助都非常感谢。 谢谢!

1 个答案:

答案 0 :(得分:4)

这并没有直接回答这个问题,但是你在左倾的​​红黑树上读过塞奇威克的paper吗?其中的代码格外清晰,有漂亮的图表解释了工作原理,我想,将所有内容重新实现到C ++中会很简单。

Sedgewick's Insert Function

Sedgewick's rotate function

修改

我试过,为了实现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;
}