如何实现每个ID节点指向子AVL树的AVL树结构?
解决两层AVL树的实现问题
看起来你已经搭好了AVL树的基础框架,现在要实现的是以ID为上层AVL节点,每个ID节点关联一棵存储对应element的AVL树,核心是调整结构体定义和插入逻辑,让两层树能正确关联起来。我来一步步帮你梳理清楚:
1. 重构结构体定义
你原来的avl_node_id结构设计有点绕,我们直接给它加一个指向element层AVL树根节点的指针,逻辑会更清晰:
class AVLTree { public: AVLTree(); void readFile(); void printToScreen(); // 存储element的AVL节点结构 struct avl_node { int data; struct avl_node *left; struct avl_node *right; }; // 存储ID的AVL节点,每个节点绑定一棵element的AVL树 struct avl_node_id { int id; // 存储ID数据 avl_node* elem_root; // 指向对应element树的根节点 struct avl_node_id *left; struct avl_node_id *right; }*id_root; // 针对element树的AVL工具方法 int height(avl_node *); int diff(avl_node *); avl_node *rr_rotation(avl_node *); avl_node *ll_rotation(avl_node *); avl_node *lr_rotation(avl_node *); avl_node *rl_rotation(avl_node *); avl_node* balance(avl_node *); avl_node* insert_element(avl_node *, int); // 插入element的方法 // 针对ID树的AVL工具方法(结构不同,需单独实现) int height_id(avl_node_id *); int diff_id(avl_node_id *); avl_node_id *rr_rotation_id(avl_node_id *); avl_node_id *ll_rotation_id(avl_node_id *); avl_node_id *lr_rotation_id(avl_node_id *); avl_node_id *rl_rotation_id(avl_node_id *); avl_node_id* balance_id(avl_node_id *); avl_node_id* insert_id(avl_node_id *, int, int); // 插入ID+对应element // 遍历与打印方法 void display_element(avl_node *, int); void display_id(avl_node_id *, int); void inorder_element(avl_node *); void inorder_id(avl_node_id *); private: int n,m; };
这里的关键改动:
- 拆分了
avl_node(element层)和avl_node_id(ID层)的独立结构 - 给
avl_node_id新增elem_root指针,专门关联该ID对应的element树 - 因为两层树的节点结构不同,需要分别实现平衡、旋转、插入方法(比用模板更直观)
2. 实现ID树的插入逻辑
原来的插入方法只能处理单一数据,现在要改成:插入ID时先检查是否已存在——存在则把element插入对应树,不存在则新建ID节点并初始化element树。
insert_id方法实现:
AVLTree::avl_node_id* AVLTree::insert_id(avl_node_id *root, int id_val, int elem_val) { if (root == NULL) { // 新建ID节点,同时初始化它的element树 root = new avl_node_id; root->id = id_val; root->elem_root = insert_element(NULL, elem_val); root->left = NULL; root->right = NULL; return root; } else if (id_val < root->id) { root->left = insert_id(root->left, id_val, elem_val); root = balance_id(root); } else if (id_val > root->id) { root->right = insert_id(root->right, id_val, elem_val); root = balance_id(root); } else { // ID已存在,直接插入到对应的element树 root->elem_root = insert_element(root->elem_root, elem_val); } return root; }
3. 修正readFile读取逻辑
现在读取文件时,每次读取ID和element,直接调用insert_id即可完成两层树的插入:
void AVLTree::readFile() { ifstream read("input2.txt"); while(read >> n >> m){ id_root = insert_id(id_root, n, m); } }
4. 补充ID树的平衡方法
ID树的平衡、旋转逻辑和element树完全一致,只是参数换成avl_node_id类型,比如:
int AVLTree::height_id(avl_node_id *node) { int h = 0; if (node != NULL) { int l_height = height_id(node->left); int r_height = height_id(node->right); int max_height = max(l_height, r_height); h = max_height + 1; } return h; } int AVLTree::diff_id(avl_node_id *node) { int l_height = height_id(node->left); int r_height = height_id(node->right); int balance_factor = l_height - r_height; return balance_factor; } AVLTree::avl_node_id* AVLTree::rr_rotation_id(avl_node_id *parent) { avl_node_id *temp; temp = parent->right; parent->right = temp->left; temp->left = parent; return temp; } // 同理实现ll_rotation_id、lr_rotation_id、rl_rotation_id、balance_id方法
5. 实现整体打印逻辑
要展示整个两层树结构,可以先遍历ID树,每个ID节点打印后,再遍历它关联的element树:
void AVLTree::printToScreen() { cout << "ID AVL Tree with Associated Element Trees:\n"; display_id(id_root, 0); } void AVLTree::display_id(avl_node_id *node, int space) { if (node == NULL) return; space += 5; display_id(node->right, space); cout << endl; for (int i = 5; i < space; i++) cout << " "; cout << node->id << endl; // 打印当前ID对应的element树 cout << " Element Tree for ID " << node->id << ":" << endl; display_element(node->elem_root, space + 5); display_id(node->left, space); } // display_element方法和你原来的display逻辑一致,参数为avl_node*
核心逻辑总结
- 两层树的关联核心是
avl_node_id中的elem_root指针,每个ID节点独立维护自己的element AVL树 - 插入时区分ID是否存在:不存在则新建ID节点并初始化element树;存在则直接往对应element树插入数据
- ID树和element树的平衡逻辑完全独立,各自维护AVL树的平衡属性
内容的提问来源于stack exchange,提问作者thelaw
相关产品推荐
相关产品推荐

