!!版權聲明:本文為博主原創文章,版權歸原文作者和博客園共有,謝絕任何形式的 轉載!!
作者:mohist
更新那時間: 22:13 03-02-2020 邏輯存在問題:插入節點后,調整數的結構不正確。 待修復
------ 歡迎指正-------
1、參考資料:
書籍:《算法導論》
博文:http://www.cnblogs.com/fivestudy/fivestudy/p/10340647.html 原理講的很棒。有動畫,方便理解。
這個網站可以清晰看清楚平衡二叉樹的插入刪除等詳細過程: https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
源碼:

#include <iostream> using namespace std; struct node { int data; int height; node *lc; node *rc; node() : data(0) , height(0) , lc(0) , rc(0) { } }; // 平衡二叉樹 class avltree2 { public: // 構造函數 avltree2() : root(NULL) { } virtual ~avltree2(){} //--------------------------------------------------------- // 返回結點的高度 int height(node *pnode) { return pnode == NULL ? 0 : pnode->height; } // 計算兩個的最大值 int max(int a, int b) { return a > b ? a : b; } //------------------------------------------------------------ /* 旋轉代碼: LL型 RR型 LR型 RL型 */ // 左旋轉, 函數命名方式是以二叉樹插入結點的形狀命名的,這里的左旋, // 對應的形狀是 RR型,即在結點右孩子插入結點。 node *rotate_rr(node *pnode) { node *ret_node = NULL; if (NULL != pnode) { // 保存失衡結點的右孩子 node *loss_balance_node_rc = pnode->rc; // 將失衡結點的右孩子的左孩子賦值給失衡結點的右孩子 pnode->rc = loss_balance_node_rc->lc; // 將失衡結點作為失衡結點的左孩子 loss_balance_node_rc->lc = pnode; // 更新失衡結點與新根結點的高度 pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1; loss_balance_node_rc->height = max( height( loss_balance_node_rc->lc), height(loss_balance_node_rc->rc)) + 1; ret_node = loss_balance_node_rc; } return ret_node; } // 右旋, 函數名是以插入結點后的形式命名的,這里是 // 將新結點插入后,形成LL形狀, node *rotate_ll(node *pnode) { node *ret_node = NULL; if (NULL != pnode) { node *loss_balance_node_lc = pnode->lc; if (NULL != loss_balance_node_lc) { // 將失衡結點的左孩子的右孩子為失衡結點的左孩子 pnode->lc = loss_balance_node_lc->rc; // 將失衡結點作為失衡結點左孩子的右孩子 loss_balance_node_lc->rc = pnode; // 更新高度 pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1; loss_balance_node_lc->height = max( height(loss_balance_node_lc->lc), height(loss_balance_node_lc->rc)) + 1; } ret_node = loss_balance_node_lc; } return ret_node; } // LR 型 // 函數命名方式同上, 需要先左旋在右旋 node* rotate_lr(node *pnode) { if (NULL != pnode) { pnode->lc = rotate_rr(pnode->lc); pnode = rotate_ll(pnode); } return pnode; } // RL型 // 同上,需要先右旋,再左旋 node *rotate_rl(node *pnode) { if (NULL != pnode) { // 先右旋再左旋 pnode->rc = rotate_ll(pnode->rc); pnode = rotate_rr(pnode); } return pnode; } //------------------------------------------------------------ // 計算pnode結點的平衡因子 int get_balance_factor(node *pnode) { // 平衡因子= 左孩子 - 右孩子 return (NULL == pnode) ? 0 : height(pnode->lc) - height(pnode->rc); } // 找到以pnode為根結點的最小結點 node *get_min(node *pnode) { if (NULL == pnode) return pnode; while (pnode->lc) pnode = pnode->lc; return pnode; } // 找到以pnode為根結點的最大結點 node *get_max(node *pnode) { if (NULL == pnode) { return pnode; } while (pnode->rc) pnode = pnode->rc; return pnode; } // 插入結點 void insert(int key) { root = insert(root, key); } // 刪除結點值為key的結點 void remove_node(int key) { if (NULL == root) return; // del_node(root, key); root = del_node2(root, key); } // 中序遍歷 void in_order_traverse() { if (NULL == root) return; in_order(root); } // 刪除整棵樹 void remove() { if (NULL == root) return; remove(root); } // 前序遍歷 void pre_order_traverse() { if (NULL == root) return; pre_order(root); } private: // 刪除所有結點 void remove(node *pnode) { if (pnode) { remove(pnode->lc); remove(pnode->rc); delete pnode; } pnode = NULL; } // 前序遍歷 void pre_order(node *pnode) { if (NULL != pnode) { cout << pnode->data << ", height = " << pnode->height << " "; pre_order(pnode->lc); pre_order(pnode->rc); } } // 中序遍歷 void in_order(node *pnode) { if (NULL != pnode) { in_order(pnode->lc); cout << pnode->data << ", height = " << pnode->height << " "; in_order(pnode->rc); } } // 插入 node* insert(node *pnode, int key) { // 為空,則創建結點 if (NULL == pnode) { pnode = new(std::nothrow) node; if (NULL != pnode) { pnode->data = key; pnode->height = 1; return pnode; } } // 1、插入值比當前結點的值還要小,應該繼續找左子樹 if (key < pnode->data) { pnode->lc = insert(pnode->lc, key); } // 2、比當前值大。應該繼續找當前結點的右子樹 else if (key > pnode->data) { pnode->rc = insert(pnode->rc, key); } else { // 3、相等,樹中已經存在插入的結點了,無法繼續插入相同結點 return pnode; } // 4、更新結點的高度 pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1; // 5、獲取插入后的平衡情況的平衡因子 int pnode_bf = get_balance_factor(pnode); // 6、下面開始判斷新插入節點的平衡因子,當前插入結果是否需要旋轉結點 // 6.1 若為LL型,右旋 if ( (1 < pnode_bf) && (key < pnode->data) ) return rotate_ll(pnode); // 6.2 若為RR型,左旋 if ( (-1 > pnode_bf) && (key > pnode->data) ) return rotate_rr(pnode); // 6.3 若為LR型 if ( (1 < pnode_bf) && (key > pnode->data) ) return rotate_lr(pnode); // 6.4 若為RL型 if ( (-1 > pnode_bf) && (key < pnode->data) ) return rotate_rl(pnode); return pnode; } // 找到參數結點的父節點 node *get_parent_node(node *pnode) { if (NULL == pnode) { return pnode; } node *parent_node = NULL; int key = pnode->data; node *cur_node = root; while (cur_node) { if (key == cur_node->data) break; else if (key < cur_node->data) { parent_node = cur_node; cur_node = cur_node->lc; } else if (key > cur_node->data) { parent_node = cur_node; cur_node = cur_node->rc; } } return parent_node; } // 刪除 node *del_node2(node *pnode, int key) { if (NULL == pnode) { return pnode; } // 找 刪除結點的位置 if (key < pnode->data) { pnode->lc = del_node2(pnode->lc, key); } else if (key > pnode->data) { pnode->rc = del_node2(pnode->rc, key); } else { // 找到刪除結點, // 3.1 若刪除結點同時存在左右孩子 if ( (NULL != pnode->lc) && (NULL != pnode->rc) ) { // 需要從左右子樹中最高的那棵樹開始刪除 // 從左子樹中開始刪除 if (height(pnode->lc) > height(pnode->rc)) { // 找到左子樹中最大的結點,替換當前結點 node *pre_node = get_max(pnode->lc); // 將當前結點的值替換為前驅結點的值 pnode->data = pre_node->data; // 刪除左子樹中最大的結點 pnode->lc = del_node2(pnode->lc, pnode->data); } // 刪除的結點從右子樹中開始找 else { // 找到后繼結點 node *successor_node = get_min(pnode->rc); // 將刪除結點的值賦值給當前結點 pnode->data = successor_node->data; // 刪除后繼結點中指定結點的值 pnode->rc = del_node2(pnode->rc, pnode->data); } } // 3.2 若只有左孩子 else if ((NULL != pnode->lc) && (NULL == pnode->rc) ) { // 指向需要刪除的結點 node *del_node_tmp = pnode->lc; // 將孩子的值賦值給刪除結點 pnode->data = del_node_tmp->data; // 將父節點指向孩子結點的分支設置為NULL pnode->lc = NULL; delete del_node_tmp; del_node_tmp = NULL; } // 3.3 若只有右孩子 else if ( (NULL == pnode->lc) && (NULL != pnode->rc)) { // 指向需要刪除的結點 node *del_node_tmp = pnode->rc; pnode->data = del_node_tmp->data; // 將分支設置為NULL del_node_tmp->rc = NULL; delete del_node_tmp; del_node_tmp = NULL; } // 3.4 刪除的是葉子結點 else { node *pnode_pa = get_parent_node(pnode); if (NULL != pnode_pa) { if (pnode == pnode_pa->lc) pnode_pa->lc = NULL; else if (pnode == pnode_pa->rc) pnode_pa->rc = NULL; } // 說明只有根結點 else root = NULL; delete pnode; pnode = NULL; } } // 為了保證樹的平衡 if (NULL == pnode) return pnode; // ------- 刪除節點后,需要做平衡 pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1; // 當前結點的平衡因子 int pnode_bf = get_balance_factor(pnode); // LL型 if ( (1 < pnode_bf) && (0 <= get_balance_factor(pnode->lc)) ) { return rotate_ll(pnode); } // LR型 if ( (1 < pnode_bf) && (0 > get_balance_factor(pnode->lc)) ) { return rotate_lr(pnode); } // RR型 if ( (-1 > pnode_bf) && (0 >= get_balance_factor(pnode->rc)) ) { return rotate_rr(pnode); } // RL型 if ( (-1 > pnode_bf) && (0 < get_balance_factor(pnode->rc)) ) { return rotate_rl(pnode); } return pnode; } private: node *root; }; int main() { avltree2 tree; int insert_key = 0; cout << "插入開始,結束插入 輸入-1" << endl << endl << endl; while (1) { cout << "請輸入插入值:"; cin >> insert_key; if (-1 == insert_key) break; tree.insert(insert_key); cout << endl << "插入后,中序遍歷結果:"; tree.in_order_traverse(); cout << endl << endl; } cout << "前序遍歷:"; tree.pre_order_traverse(); cout << endl; cout << "========================================" << endl; cout << "開始刪除, 請輸入刪除元素的值, 結束輸入-1" << endl << endl; int del_key = 0; while (1) { cout << "請輸入刪除結點值: "; cin >> del_key; if (-1 == del_key) break; tree.remove_node(del_key); cout << "刪除后,中序遍歷:"; tree.in_order_traverse(); cout << endl << "刪除后,前序遍歷:"; tree.pre_order_traverse(); cout << endl << endl; } cout << endl << endl << endl << "----------------------------" << endl << endl; cout << "刪除樹" << endl; tree.remove(); return 0; }
2、結果:
3、GitHub 地址:https://github.com/mohistH/base_data_structure