C++ 是否可能组合对称代码段?
我正在为我的学校项目实现avl树,发现自己为对称情况编写了两次几乎相同的代码。例如,此函数执行两个节点的旋转以平衡树。If子句处理较低节点是较高节点的左子节点的情况,而else子句处理相反的情况:C++ 是否可能组合对称代码段?,c++,oop,tree,encapsulation,avl-tree,C++,Oop,Tree,Encapsulation,Avl Tree,我正在为我的学校项目实现avl树,发现自己为对称情况编写了两次几乎相同的代码。例如,此函数执行两个节点的旋转以平衡树。If子句处理较低节点是较高节点的左子节点的情况,而else子句处理相反的情况: void avl<T>::rotate(node<T> *x, node<T> *y) { if (x == y->l) { x->p = y->p; if (y->p != nullptr) if(y-&
void avl<T>::rotate(node<T> *x, node<T> *y)
{
if (x == y->l)
{
x->p = y->p;
if (y->p != nullptr)
if(y->p->l == y)
y->p->l = x;
else
y->p->r = x;
else
this->setHead(x);
y->p = x;
y->l = x->r;
if(x->r != nullptr)
x->r->p = y;
x->r = y;
y->dl = y->calcd('l');
x->dr = x->calcd('r');
if(x->p != nullptr)
if(x->p->l == x)
x->p->dl = x->p->calcd('l');
else
x->p->dr = x->p->calcd('r');
}
else
{
x->p = y->p;
if (y->p != nullptr)
if(y->p->r == y)
y->p->r = x;
else
y->p->l = x;
else
this->setHead(x);
y->p = x;
y->r = x->l;
if(x->l != nullptr)
x->l->p = y;
x->l = y;
y->dl = y->calcd('l');
x->dr = x->calcd('r');
if(x->p != nullptr)
if(x->p->r == x)
x->p->dr = x->p->calcd('r');
else
x->p->dl = x->p->calcd('l');
}
}
void avl::旋转(节点*x,节点*y)
{
如果(x==y->l)
{
x->p=y->p;
如果(y->p!=nullptr)
如果(y->p->l==y)
y->p->l=x;
其他的
y->p->r=x;
其他的
这->设定值(x);
y->p=x;
y->l=x->r;
如果(x->r!=nullptr)
x->r->p=y;
x->r=y;
y->dl=y->calcd('l');
x->dr=x->calcd('r');
如果(x->p!=nullptr)
如果(x->p->l==x)
x->p->dl=x->p->calcd('l');
其他的
x->p->dr=x->p->calcd('r');
}
其他的
{
x->p=y->p;
如果(y->p!=nullptr)
如果(y->p->r==y)
y->p->r=x;
其他的
y->p->l=x;
其他的
这->设定值(x);
y->p=x;
y->r=x->l;
如果(x->l!=nullptr)
x->l->p=y;
x->l=y;
y->dl=y->calcd('l');
x->dr=x->calcd('r');
如果(x->p!=nullptr)
如果(x->p->r==x)
x->p->dr=x->p->calcd('r');
其他的
x->p->dl=x->p->calcd('l');
}
}
正如您所看到的,else子句与if子句非常相似,替换了'l'和'r'。有没有办法把它们结合起来。我能做些什么来改进它?我的代码中有设计错误吗
计算机科学中的所有问题都可以通过另一个层次的技术来解决
间接的,当然除了太多的问题
间接的。(大卫·惠勒) 您可以这样做(完全未经测试):
节点**y\u同级\u 1=x==y->l&y->p->l:&y->p->r;
节点**y\U同级\U 2=x==y->l&y->p->r:&y->p->l;
节点**x_子节点=x==y->l&x->r:&x->l;
节点**y\U子节点=x==y->l&y->l:&y->r;
x->p=y->p;
如果(y->p!=nullptr)
如果(*y_同级兄弟姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹姐妹
*y_同胞_1=x;
其他的
*y_同胞_2=x;
其他的
这->设定值(x);
y->p=x;
*y_child=*x_child;
如果(*x_child!=nullptr)
(*x_child)->p=y;
*x_child=y;
y->dl=y->calcd('l');
x->dr=x->calcd('r');
如果(x->p!=nullptr)
如果(x->p->l==x)
x->p->dl=x->p->calcd('l');
其他的
x->p->dr=x->p->calcd('r');
(请注意,在这两种情况下,您的最终条件是等效的。)
这是否有太多的间接性是个人意见的问题。您可能需要这里的模板,因此您需要
calcd()
和calcd()
有了这些变化,你就可以写作了
template<bool xChildy>
void avl<T>::rotateImpl(node<T> *x, node<T> *y);
void avl<T>::rotate(node<T> *x, node<T> *y)
{
if (x == y->l) {
rotateImpl<true>(x,y);
}
else {
rotateImpl<false>(x,y);
}
}
模板
void avl::rotateImpl(节点*x,节点*y);
void avl::旋转(节点*x,节点*y)
{
如果(x==y->l){
rotateImpl(x,y);
}
否则{
rotateImpl(x,y);
}
}
使用指向成员的指针。这两个分支之间的唯一区别在于您访问的是哪个成员,因此这是一种简单的方法来提取:
using Child = node<T> node<T>::*;
void rotate_impl(node<T>* x, node<T>* y, Child* left, Child* right)
{
x->p = y->p;
if (y->p != nullptr) {
if(y->p->*left == y) {
y->p->*left = x;
}
else {
y->p->*right = x;
}
}
else {
this->setHead(x);
}
y->p = x;
y->*left = x->*right;
if(x->*right != nullptr) {
(x->*right)->p = y;
}
x->*right = y;
y->dl = y->calcd('l');
x->dr = x->calcd('r');
if(x->p != nullptr) {
if(x->p->*left == x) {
x->p->dl = x->p->calcd('l');
}
else {
x->p->dr = x->p->calcd('r');
}
}
}
void avl<T>::rotate(node<T> *x, node<T> *y)
{
if (x == y->l) {
rotate_impl(x, y, &node<T>::l, &node<T>::r);
}
else {
rotate_impl(x, y, &node<T>::r, &node<T>::l);
}
}
使用Child=node::*;
void rotate_impl(节点*x,节点*y,子节点*左,子节点*右)
{
x->p=y->p;
如果(y->p!=nullptr){
如果(y->p->*左==y){
y->p->*左=x;
}
否则{
y->p->*右=x;
}
}
否则{
这->设定值(x);
}
y->p=x;
y->*左=x->*右;
如果(x->*右!=nullptr){
(x->*右)->p=y;
}
x->*右=y;
y->dl=y->calcd('l');
x->dr=x->calcd('r');
如果(x->p!=nullptr){
如果(x->p->*左==x){
x->p->dl=x->p->calcd('l');
}
否则{
x->p->dr=x->p->calcd('r');
}
}
}
void avl::旋转(节点*x,节点*y)
{
如果(x==y->l){
旋转(x、y和节点::l和节点::r);
}
否则{
旋转(x、y和节点::r和节点::l);
}
}
我还冒昧地在代码中添加了大括号。以后你可以谢谢我。我喜欢迈克的模板方法。但为了记录在案,我在此提出另一种选择 首先,考虑每个节点有两个子节点。称他们为“左”和“右”只是一种思想观点。您还可以将它们放在一个数组中:
template <class T>
class node {
public:
...
enum side{ left,right,last}; // just to make clear my intent here
node *p, *c[last], *d[last]; // no more l and r !!
node* calcd(enum side x) {} // lets use our index here instead of char
...
};
模板
类节点{
公众:
...
枚举侧{left,right,last};//只是为了说明我在这里的意图
节点*p,*c[last],*d[last];//不再有l和r!!
node*calcd(enum side x){}//让我们在这里使用索引而不是char
...
};
然后,您可以计算出与侧相关的代码。我喜欢lambdas,所以这里有一个第一个建议:
template <class T>
void avl<T>::rotate(node<T> *x, node<T> *y)
{
// this lambda works directly with locals of rotate() thanks to [&]
// so put in the side dependent code, and put the side as parameter
// for easy switch. For simplicity I used l and r to facilitate
// transposition, but reafctoring it in a neutral side1 and sinde2
// could help readbility
auto rt = [&](enum node<T>::side l, enum node<T>::side r)->void {
x->p = y->p;
if (y->p != nullptr)
if(y->p->c[l] == y) // l is a parameter here instead of member name
y->p->c[l] = x;
else
y->p->c[r] = x;
else
this->setHead(x);
y->p = x;
y->c[l] = x->c[r];
if (x == y->c[l])
{
if(x->c[r] != nullptr)
x->c[r]->p = y;
x->c[r] = y;
y->d[l] = y->calcd(sd[l]);
x->d[r] = x->calcd(sd[r]);
if(x->p != nullptr)
if(x->p->c[l] == x)
x->p->d[l] = x->p->calcd(sd[l]);
else
x->p->d[r] = x->p->calcd(sd[r]);
}
}; // end of the definition of the lambda
// the code of the function is then reduced to this:
if (x == y->c[node<T>::left])
rt(node<T>::left,node<T>::right);
else
rt(node<T>::right, node<T>::left);
}
模板
void avl::旋转(节点*x,节点*y)
{
//由于[&],此lambda直接与rotate()的局部变量一起工作
//因此,输入side-dependent代码,并将side作为参数
//为了方便切换。为了简单起见,我使用了l和r来方便切换
//换位,但在中性侧重新换位1和sinde2
//有助于提高可读性
自动rt=[&](枚举节点::侧l,枚举节点::侧r)->void{
x->p=y->p;
如果(y->p!=nullptr)
如果(y->p->c[l]==y)//l是这里的参数,而不是成员名
y->p->c[l]=x;
其他的
y->p->c[r]=x;
其他的
这->设定值(x);
y->p=x;
y->c[l]=x->c[r];
如果(x==y->c[l])
{
如果(x->c[r]!=nullptr)
x->c[r]->p=y;
x->c[r]=y;
y->d[l]=y->calcd(sd[l]);
x->d[r]=x->calcd(sd[r]);
如果(x->p!=nullptr)
如果(x->p->c[l]==x)
x->p->d[l]=x->p->calcd(sd[l]);
其他的
x->p->d[r]=x->p->calcd(sd[r]);
}
};//lambda定义的结尾
//然后,该函数的代码缩减为:
如果(x==y->c[节点::左])
rt(节点::左,节点::右);
其他的
rt(节点::右,节点::左);
}
y->calcd('l')
-让我猜一下,有一个if(arg==''l'))
template <class T>
void avl<T>::rotate(node<T> *x, node<T> *y)
{
// this lambda works directly with locals of rotate() thanks to [&]
// so put in the side dependent code, and put the side as parameter
// for easy switch. For simplicity I used l and r to facilitate
// transposition, but reafctoring it in a neutral side1 and sinde2
// could help readbility
auto rt = [&](enum node<T>::side l, enum node<T>::side r)->void {
x->p = y->p;
if (y->p != nullptr)
if(y->p->c[l] == y) // l is a parameter here instead of member name
y->p->c[l] = x;
else
y->p->c[r] = x;
else
this->setHead(x);
y->p = x;
y->c[l] = x->c[r];
if (x == y->c[l])
{
if(x->c[r] != nullptr)
x->c[r]->p = y;
x->c[r] = y;
y->d[l] = y->calcd(sd[l]);
x->d[r] = x->calcd(sd[r]);
if(x->p != nullptr)
if(x->p->c[l] == x)
x->p->d[l] = x->p->calcd(sd[l]);
else
x->p->d[r] = x->p->calcd(sd[r]);
}
}; // end of the definition of the lambda
// the code of the function is then reduced to this:
if (x == y->c[node<T>::left])
rt(node<T>::left,node<T>::right);
else
rt(node<T>::right, node<T>::left);
}