操纵类内的指针

时间:2014-10-28 00:00:05

标签: c++ class pointers

我一直在寻找如何解决C ++中类中指针的问题。基本上,会发生的是操作您的实例,而不是操纵指向Class的指针。代码:

#include <iostream>

using namespace std;


const char BLACK = 'B';
const char RED = 'R';

template <class T>
class Node{

    public:
        Node *left;
        Node *right;
        Node *parent;
        char color;
        T key;

        Node(T x){
            this->left = NULL;
            this->right = NULL;
            this->parent = NULL;
            this->key = x;
            this->color = RED;
        };

        virtual ~Node(){};
};

template <class T>
class RBTree{

    private:

        int ammount;
        Node<T> *root;

        void destroy_node(Node<T> *&node);      
        void rotateLeft(Node<T> *&x);
        void rotateRight(Node<T> *&y);
        void insertFixUp(Node<T> *&x);
        void printInfo(Node<T> *&x);

    public:

        Node<T> *NIL;
        RBTree();
        virtual ~RBTree();
        void destroy();

        void insert(T x);

};


template <class T>
RBTree<T>::RBTree(){

    this->ammount = 0;

    this->NIL = new Node<T>(-1);
    this->NIL->color = BLACK;
    this->NIL->left = this->NIL->right = this->NIL->parent = this->NIL;


    this->root = this->NIL;
    this->root->color = BLACK;
    this->root->left = this->root->right = this->root->parent = this->NIL;
}


template <class T>
RBTree<T>::~RBTree(){
    this->destroy();
}


template <class T>
void RBTree<T>::destroy_node(Node<T> *&node){
    if(node != this->NIL){
        this->destroy_node(node->left);
        this->destroy_node(node->right);
        delete node;
    }
}

template <class T>
void RBTree<T>::destroy(){
    this->destroy_node(this->root);
}


template <class T>
void RBTree<T>::rotateLeft(Node<T> *&x){

    Node<T> *y = x->right;
    x->right = y->left;

    if(y->left != this->NIL)
        y->left->parent = x;

    y->parent = x->parent;

    if(x->parent == this->NIL)
        this->root = y;
    else if(x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;

    y->left = x;
    x->parent = y;

}


template <class T>
void RBTree<T>::rotateRight(Node<T> *&y){

    Node<T> *x = y->left;
    y->left = x->right;

    if(x->right != this->NIL)
        x->right->parent = y;

    cout << "x:"; this->printInfo(x);
    cout << "y:"; this->printInfo(y);
    cout << endl;

    x->parent = y->parent;

    cout << "x:"; this->printInfo(x);
    cout << "y:"; this->printInfo(y);
    cout << endl;

    if(y->parent == this->NIL)
        this->root = x;
    else if(y == y->parent->left)
        y->parent->left = x;
    else
        y->parent->right = x;


    x->right = y;
    y->parent = x;

}


template <class T>
void RBTree<T>::insertFixUp(Node<T> *&z){


    Node<T> *y;

    while(z != this->root and z->parent->color == RED){
        if(z->parent == z->parent->parent->left){
            y = z->parent->parent->right;
            if(y->color == RED){
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            }
            else{

                if(z == z->parent->right){
                    z = z->parent;
                    this->rotateLeft(z);
                }


                z->parent->color = RED;
                z->parent->parent->color = BLACK;
                this->rotateRight(z->parent->parent);
            }
        }
        else{
            y = z->parent->parent->left;
            if(y->color == RED){
                z->parent->color = BLACK;
                y->color = BLACK;
                z->parent->parent->color = RED;
                z = z->parent->parent;
            }
            else{
                if(z == z->parent->left){
                    z = z->parent;
                    this->rotateRight(z);
                }

                z->parent->color = BLACK;
                z->parent->parent->color = RED;
                this->rotateLeft(z->parent->parent);
            }
        }
    }


    this->root->color = BLACK;

}



template <class T>
void RBTree<T>::insert(T val){

    Node<T> *z = new Node<T>(val);
    Node<T> *x = this->root;
    Node<T> *y = this->NIL;

    while(x != this->NIL){
        y = x;
        if(z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }


    z->parent = y;

    if(y == this->NIL)
        this->root = z;
    else if(z->key < y->key)
        y->left = z;
    else
        y->right = z;


    z->left = this->NIL;
    z->right = this->NIL;
    z->color = RED;

    this->insertFixUp(z);
    this->ammount++;
}


template <class T>
void RBTree<T>::printInfo(Node<T> *&x){
    cout << "  key=";
    cout << x->key;

    cout << "  l->key=";
    if(x->left == this->NIL) 
        cout << "N";
    else 
        cout << x->left->key;

    cout << "  r->key=";
    if(x->right == this->NIL) 
        cout << "N";
    else 
        cout << x->right->key;

    cout << "  p->key=";
    if(x->parent == this->NIL) 
        cout << "N";
    else 
        cout << x->parent->key;

    cout << "  color=" << x->color << endl;
}



int main(){

    srand(time(NULL));
    RBTree<int> *bt = new RBTree<int>();

    int x = 0;
    int vet[9] = {11, 2, 14, 1, 7, 15, 5, 8, 4};

    for(int i=0; i<9; i++){
        x = vet[i];
        bt->insert(x);
    }

    delete bt;

    return 0;
}

好的,当调用 rotateRight 方法时,printInfos之间的行正在改变y的值,而不是只改变父x指针。

程序给出的结果:

x:  key=7  l->key=2  r->key=8  p->key=11  color=R
y:  key=11  l->key=8  r->key=14  p->key=N  color=B

x:  key=7  l->key=2  r->key=8  p->key=N  color=R
y:  key=-1  l->key=N  r->key=N  p->key=N  color=B

正确应该是:

x:  key=7  l->key=2  r->key=8  p->key=11  color=R
y:  key=11  l->key=8  r->key=14  p->key=N  color=B

x:  key=7  l->key=2  r->key=8  p->key=N  color=R
y:  key=11  l->key=8  r->key=14  p->key=N  color=B

那么,是什么导致了这个? 说真的,这很奇怪O.o

1 个答案:

答案 0 :(得分:0)

基于新增代码: 您应该更改方法签名以使用Node<T> *y而不是Node<T> *&y

例如:void rotateRight(Node<T> *y);

当您使用*&y时,您指的是指向传递给该方法的Node的指针。由于您有它的引用,您可以修改指针指向的位置。 执行此行时:

x->parent = y->parent;

x-&gt; parent是y(因为x被初始化为y-> left),y-&gt; parent是NIL。所以这一行实际上将y设置为NIL。 执行此行后,您有: x-&gt; parent = y = NIL

如果您不使用*&y,但*y,则会获得y指针引用的副本。所以当你打电话     x-&gt; parent = y-&gt; parent; 你没有修改y,而是复制了引用,因此你得到了想要的结果。


了解您的代码:

首先,似乎可以将方法签名更改为仅使用指针,因为您不会在方法内修改它:

void MyClass::myMethod(Node *y){

在此行上,y-&gt; parent设置为NULL。所以y的父指针改变了:

y->parent = NULL;

如果y为NULL,则此行上可能有问题,因为您将取消引用Null指针。所以最好检查一下。

在此行中,您声明一个Node指针x,并为其指定y节点的左指针。

Node *x = y->left;

最后,将y父节点(在第一行上设置为NULL,因为它设置为第一行)分配给x父节点。

x->parent = y->parent;

如果在上面的行中y-&gt; left为NULL,则可能会出现问题,因为您将取消引用Null指针。所以最好检查一下。如果x不为NULL,则此行具有与以下相同的效果:     x-&gt; parent = NULL;

但是,由于您不再使用x,因此在方法返回时会丢失。话虽这么说,你的方法具有与此相同的效果:

void MyClass::myMethod(Node *y){
    y->parent = NULL;
}

但我建议先检查一下:

void MyClass::myMethod(Node *y){
    if (y != NULL){
        y->parent = NULL;
    }
}

除非你错过了一些代码,否则我不知道如何进一步改变你。