AVL树_插入与删除

来源:互联网 发布:java super重载 编辑:程序博客网 时间:2024/05/17 23:55
以前AVL树学习的很不扎实,昨天复习了一下。代码参考了 http://www.cppblog.com/cxiaojia/archive/2012/08/20/187776.html

哦,其实我基本上代码就是照搬人家的>_<,只不过偷个懒,树的节点里面的数据没用泛型而是直接用char, 然后就是改了几个原文中的小错误。

AVL树节点的定义:

class AVLNode{public:char ch;int height;int freq;AVLNode *left;AVLNode *right;AVLNode(char c = 'a'):ch(c), height(0), freq(0), left(NULL), right(NULL){}void insertNode(AVLNode * &root, AVLNode *node);void deleteNode(AVLNode * &root, AVLNode *node);void search(AVLNode * root, AVLNode *node);int getHeight(AVLNode * root);void singleRotateLeft(AVLNode * &root);void singleRotateRight(AVLNode * &root);void doubleRotateLR(AVLNode * &root);void doubleRotateRL(AVLNode * &root);void traversing_inorder_recursive(AVLNode * root);void printNode(AVLNode * root);};

节点设计,我各种偷懒。access section只有一个public,然后成员函数里面居然还有一个 AVLNode * &类型,而没有直接用this。

主要想集中精力研究AVL树的操作,这里各种违反OOP的设计敬请无视之。


因为每次对树进行修改,都要获取节点的高度,先上getHeight:

int AVLNode::getHeight(AVLNode *root){if(root != NULL)return root->height;elsereturn -1;}

接下来,每次调整树的结构都要用到4种旋转。其中zig-zig型的有左单旋、右单旋;zig-zag型的有双左右旋、双右左旋。

左单旋singleRotateLeft:


void AVLNode::singleRotateLeft(AVLNode * &root)//root相当于图中k2{AVLNode * k1;k1 = root->left;root->left = k1->right;k1->right = root;root->height = max(getHeight(root->left), getHeight(root->right)) + 1;k1->height = max(getHeight(k1->left), root->height) + 1;root = k1;}

对称地,有右单旋singleRotateRight,图略:

void AVLNode::singleRotateRight(AVLNode * &root){AVLNode * k1;k1 = root->right;root->right = k1->left;k1->left = root;root->height = max(getHeight(root->left), getHeight(root->right)) + 1;k1->height = max(root->height, getHeight(k1->right)) + 1;root = k1;}


双左右旋doubleRotateLR:




void AVLNode::doubleRotateLR(AVLNode * &root)//此处root相当于k3{singleRotateRight(root->left);singleRotateLeft(root);}


对称地,有双右左旋doubleRotateRL,图略:

void AVLNode::doubleRotateRL(AVLNode * &root){singleRotateLeft(root->right);singleRotateRight(root);}


至此旋转终于说完了,可以进入正题——插入节点了= =。

void AVLNode::insertNode(AVLNode * &root, AVLNode *node){if(root == NULL){root = node;return;}if(node->ch < root->ch)    //要插入节点的值小于当前root,递归地向root的左子树插入{insertNode(root->left, node);if(getHeight(root->left) - getHeight(root->right) == 2){if(node->ch < root->left->ch)singleRotateLeft(root);elsedoubleRotateLR(root);}}else if(node->ch > root->ch)//要插入节点的值大于当前root,递归地向root的右子树插入{insertNode(root->right, node);if(getHeight(root->right) - getHeight(root->left) == 2){if(node->ch < root->right->ch)doubleRotateRL(root);elsesingleRotateRight(root);}}else//如果相等,当前root节点的频率加一{root->freq++;}root->height = max(getHeight(root->left), getHeight(root->right)) + 1;}

正题二——删除节点是AVL树最繁琐的操作,直接代码中分析之:

void AVLNode::deleteNode(AVLNode * &root, AVLNode *node){if(root == NULL)return;if(node->ch < root->ch)//递归地从左子树删除此节点{deleteNode(root->left, node);if(getHeight(root->right) - getHeight(root->left) == 2){if(root->right->left != NULL &&    getHeight(root->right->left) > getHeight(root->right->right) ){doubleRotateRL(root);}else{singleRotateRight(root);}}}else if(node->ch > root->ch)//递归地从右子树删除此节点{deleteNode(root->right, node);if(getHeight(root->left) - getHeight(root->right) == 2){if(root->left->right != NULL &&   getHeight(root->left->right) > getHeight(root->left->left)){doubleRotateLR(root);}else{singleRotateLeft(root);}}}else//当前节点就是要删除的节点{if(root->left && root->right)//有左右两个儿子{/*找右子树的最左节点,即大于根节点的最小节点*/AVLNode *tmp = root->right;while(tmp->left != NULL)tmp = tmp->left;/*把右子树的最左节点的值赋给根节点*/root->ch = tmp->ch;root->freq = tmp->freq;/*递归地删除右子树的最左节点*/deleteNode(root->right, tmp);if(getHeight(root->left) - getHeight(root->right) == 2){if(root->left->right != NULL &&   getHeight(root->left->right) > getHeight(root->left->left)){doubleRotateLR(root);}else{singleRotateLeft(root);}}}else{AVLNode * tmp = root;if(!root->left && root->right)//只有右儿子{root = root->right;}else if(root->left && !root->right)//只有左儿子{root = root->left;}else//没有儿子{root = NULL;}/*如果构成树的节点都是堆变量,那需要delete指针并将指针置为NULL。我的测试用例中,树的节点均用栈变量,故不需要。*///delete(tmp);//tmp = NULL;}}if(root == NULL)return;root->height = max(getHeight(root->left), getHeight(root->right)) + 1;return;}


打完收工。