AVL树
来源:互联网 发布:香港中文大学人工智能 编辑:程序博客网 时间:2024/06/05 02:31
大概学习了一下AVL树,基本思路还是比较清楚,但是发现还是很难自己写一个AVL树来。
下面记录下自己学习的过程(网上资料很多,就不解释AVL了):
1.参考的代码: http://rosettacode.org/wiki/AVL_tree#C.2B.2B
2.图形化参考工具: https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
3.各种递归、指针,各种云里雾里;
4.相对于BST(二叉搜索树),多了“父结点指针”,需要调整“父结点指针”的指向;
5.AVL最重要的是为了保证左右子树平衡度绝对差值为1,必须进行旋转,旋转可以总结为下面4种:
根->左1->左0 -->> (根)右旋
根->左1->右0 -->> (左1)左旋,(根)右旋
根->右1->右0 -->> (根)左旋
根->右1->左0 -->> (右1)右旋,(根)左旋
我最开始担心:数据很多的情况下,插入一个数据,引起“多米诺骨牌”效应,引起多次旋转;实际上插入一个数据最多旋转2次,即使是头结点被旋转;数据越多,只是会加大对树高度(平衡)的判断。
6.还是要多画图、多调试代码、多思考才能理清楚,还需要反复来学习。
下面代码是在上述“1”的基础上修改的代码与注释。
#include <algorithm>#include <iostream>#include <deque>using namespace std; // AVL 结点 class AVLnode {public: int key; int balance; AVLnode *left, *right, *parent; AVLnode(int k, AVLnode *p) : key(k), balance(0), parent(p), left(NULL), right(NULL) {} ~AVLnode() { delete left; delete right; }}; // AVL 树 class AVLtree {public:AVLtree(void) : root(NULL) {} ~AVLtree(void) {delete root;} //插入bool insert(int key) {if (root == NULL) {root = new AVLnode(key, NULL);}else { //n为遍历结点 //parent是n的父结点,后面n结点的状态会变(n会指向下一个结点)AVLnode *n = root, *parent; while (true) {if (n->key == key)return false; parent = n; bool goLeft = n->key > key;n = goLeft ? n->left : n->right; //上面两句循环判断key值加在左子树还是右子树,然后指针下移 //下面这句,找到位置为NULL后才进入插入 if (n == NULL) {if (goLeft) {parent->left = new AVLnode(key, parent);}else {parent->right = new AVLnode(key, parent);} rebalance(parent);break;}}} return true;}//删除 //1.如果删除结点没有子结点,直接删除 //2.如果删除结点有1个子结点,将其父结点指向其子结点,然后删除 //3.如果删除结点有2个子结点,将其用左子树最大结点值取代(或用右子树最小结点值取代),然后删除 //4.重置平衡void deleteKey(const int delKey) {if (root == NULL)return; AVLnode //删除结点的右侧最小值结点//n为删除结点的替补值,parent为n的父结点,child为n的子树,delNode为删除结点,tmp为临时结点*n = root,*parent = root,*delNode = NULL,*child = root,*tmp = NULL; //即使找到删除结点后,依旧继续遍历,然后找到删除结点右侧的最小值/左侧最大值while (child != NULL) {parent = n;n = child;//取右侧最小值child = delKey >= n->key ? n->right : n->left;//取左侧最大值//child = delKey <= n->key ? n->left : n->right;if (delKey == n->key) delNode = tmp = n; } if (delNode != NULL) { //直接修改(删除结点的值)为替补值,其左右指针不变delNode->key = n->key; child = n->left != NULL ? n->left : n->right; if (root->key == delKey) {root = child;}else { //parent为删除结点n的父结点if (parent->left == n) {parent->left = child;}else {parent->right = child;} //delete tmp;rebalance(parent);}}}//deleteElem 使用递归的方法,参考自之前总结的BSTvoid deleteElem(int elem){deleteElem(root,elem);cout<<endl;} void printBalance() {printBalance(root);cout << endl;}void LDR_order(){ LDR_order(root); cout << endl;} //层序遍历二叉树,即广度优先。 //从根结点开始遍历,存入队列;出队列,遍历此结点左子树,有值,存入队列,再遍历此结点右子树,有值,存入队列; //递归:出队列,遍历此结点左子树,有值,存入队列,再遍历此结点右子树,有值,存入队列;void level_traverse() { if(root == NULL) { return; } deque<AVLnode *> dequesTree; dequesTree.push_back(root); while(dequesTree.size()) { AVLnode *p = dequesTree.front(); dequesTree.pop_front(); cout << (p->key)<<" "; if(p->left) { dequesTree.push_back(p->left); } if(p->right) { dequesTree.push_back(p->right); } } cout<<endl;} private: AVLnode *root; //自平衡void rebalance(AVLnode *n) {setBalance(n); if (n->balance == -2) {if (height(n->left->left) >= height(n->left->right)) //根左左,直接右旋根n = rotateRight(n);else //根左右n = rotateLeftThenRight(n);}else if (n->balance == 2) {if (height(n->right->right) >= height(n->right->left))//判断左旋还是*旋? //根右右,直接左旋根n = rotateLeft(n);else //根右左n = rotateRightThenLeft(n);} if (n->parent != NULL) {rebalance(n->parent);//从下向上(子结点到父结点)依次来检查平衡}else {root = n;}} //左旋 AVLnode* rotateLeft(AVLnode *a) { //原来a为b父结点(b为a的右子树),在这里做了交换(a变为b的左子树)AVLnode *b = a->right;b->parent = a->parent;//a的右子树将指向原b的左子树a->right = b->left; // if (a->right != NULL) //将原b左子树(现a右子树)父结点指向aa->right->parent = a; b->left = a;a->parent = b; //改变原a(现b)父结点的指向if (b->parent != NULL) {if (b->parent->right == a) {b->parent->right = b;}else {b->parent->left = b;}} setBalance(a);setBalance(b);return b;} //右旋 AVLnode* rotateRight(AVLnode *a) {AVLnode *b = a->left;b->parent = a->parent;a->left = b->right; if (a->left != NULL)a->left->parent = a; b->right = a;a->parent = b; if (b->parent != NULL) {if (b->parent->right == a) {b->parent->right = b;}else {b->parent->left = b;}} setBalance(a);setBalance(b);return b;} //左旋后右旋,适用于左右 root->left->right情况 AVLnode* rotateLeftThenRight(AVLnode *n) {n->left = rotateLeft(n->left);return rotateRight(n);} //右旋后左旋,适用于右左 root->right->left情况 AVLnode* rotateRightThenLeft(AVLnode *n) {n->right = rotateRight(n->right);return rotateLeft(n);} //求高度 int height(AVLnode *n) {if (n == NULL)return -1;//递归遍历所有结点求得高度(一个顶点的左、右子树都会被递归到,然后取最大值)return 1 + max(height(n->left), height(n->right));} //设置平衡因子balance void setBalance(AVLnode *n) {n->balance = height(n->right) - height(n->left);} //打印平衡因子 void printBalance(AVLnode *n) {if (n != NULL) {printBalance(n->left);cout << n->balance << " ";printBalance(n->right);}}//LDR遍历void LDR_order(AVLnode *n){if (n!=NULL){LDR_order(n->left);cout<<n->key<<" ";LDR_order(n->right);}}//递归的方式来删除,没有求平衡struct AVLnode * deleteElem(AVLnode *root, int elem){if(root == NULL)return root;//定位删除结点elem的位置else if(elem < root->key)root->left = deleteElem(root->left, elem);else if(elem > root->key)root->right = deleteElem(root->right, elem);else { //如果删除结点elem没有子树,直接删除if(root->left == NULL && root->right == NULL){delete root;root = NULL;}//如果删除结点elem左子树为NULL(只有右子树),则原elem指针指向下一(右子树)结点,删除原elem元素else if(root->left == NULL){struct AVLnode *tmp = root;//删除结点elem被它的右子树取代root = root->right;//rebalancerebalance(root->parent);delete tmp;}//如果删除结点elem右子树为NULL(只有左子树),则原elem指针指向下一(左子树)结点,删除原elem元素else if(root->right == NULL){struct AVLnode *tmp = root;root = root->left;rebalance(root->parent);delete tmp;}//删除结点elem有左、右子树else { //查找右子树的最小值struct AVLnode *tmp = findMin(root->right);//struct bstNode *tmp = findMax(root->left);root->key = tmp->key;//这里“很巧妙”,递归查找该删除的元素tmp->data,此时的tmp->data是没有子树的结点,将会被直接删除root->right = deleteElem(root->right, tmp->key);}}return root;} //找最小值,最小值一定在左子树,且它的左子树为空AVLnode* findMin(AVLnode* root) {static AVLnode* pre_node;if(root == NULL) {return pre_node;}else {pre_node = root;return findMin(root->left);}} }; int main(void){ AVLtree tree; int array[] = {16,3,7,11,9,26,18,14,15,17}; for (int i = 0; i <10; ++i) tree.insert(array[i]); tree.printBalance(); tree.LDR_order(); tree.level_traverse(); tree.deleteKey(11); tree.LDR_order(); tree.level_traverse(); tree.deleteElem(9); tree.LDR_order(); tree.level_traverse();}
0 0
- AVL树
- AVL树
- AVL树
- avl树
- AVL树
- avl树
- AVL树
- AVL树
- AVL树
- AVL树
- avl树
- avl树
- AVL树
- AVL树
- AVL树
- AVL树
- AVL 树
- AVL树
- 【HDU】 2818 Building Block
- SGU 326 Perspective (网络流)
- 监控进程(二进制程序)运行状态的C语言实现与脚本实现
- UIGraphicsBeginImageContext系列知识
- Android intent返回数据给上一个活动
- AVL树
- JAVA多线程
- LeetCode-3.Longest Substring Without Repeating Characters
- 欢迎使用CSDN-markdown编辑器
- 日本 西暦と和暦の変換
- mysqladmin命令修改Mysql密码
- OS及Mac开源项目和学习资料【超级全面】
- JavaScript高级程序设计学习笔记——变量、作用域和内存问题(重要)
- 使用ARToolkit时发生的DsRenderer.ax丢失错误