C++的引用不过是对于某块内存区域的永久引用而已,真要说有什么好处的话,大概就只能把* const ptr打包一下,以增加可读性和安全性了。因此,C++的reference只是一个别名,与java的引用变量没法比,实现java的功能还是要靠指针。但是,今天在学习AVL树时,倒是遇到了一个有趣的用法。
template <class E, class K>
void AVLTree<E,K>::RotateL(AVLNode<E,K> *&ptr){
AVLNode<E,K> *subL = ptr;
ptr = subL->right;
subL->right = ptr->left;
ptr->left = subL;
ptr->bf = subL->bf = 0;//bf是平衡因子
}
这段代码实现的是AVL树的单左旋转,功能简单,代码也不长。但这里的入口参数很有趣,是(AVLNode<E, K> *&ptr),按引用传递是很常见的方法,但此处用的是“引用的指针”,或者说是“一个
AVLNode<E, K>型指针变量的别名”。
乍一看,这段代码似乎忽视了一个大问题——旋转的子树根结点还是被他的父节点指向着。因此,新的根节点不但做不成根节点,实际上还会在树中被删除。当然,事实并非如此。在这里,ptr大概就是子树根节点的父节点指向他的引用了。随着ptr指向的结点变为新的根节点,完整的旋转也就实现。
此处&的意义,在于确保传入的变量是left的别名而非复制,*则是指针声明的规范,所以参数应为(AVLNode<E,K>* &ptr)。虽然有点让人困惑,但却是高效又优雅的方案。不然,要不然用二维指针,要不然把AVLNode<E,K>的指针传过来,复杂度上升不说,总是有些难看了。