我一直在寻找如何解决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
答案 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;
}
}
除非你错过了一些代码,否则我不知道如何进一步改变你。