From a2cbb2ad7df15535289183d71257de271d8385a1 Mon Sep 17 00:00:00 2001 From: e2hang <2099307493@qq.com> Date: Sun, 10 Aug 2025 18:13:25 +0800 Subject: [PATCH] HBLT --- .../priorityQueue/maxHBLT/CMakeLists.txt | 6 + .../maxHBLT/Height-biased Leftist Tree | 0 BinaryTree/priorityQueue/maxHBLT/README.MD | 191 ++++++++++++++++++ .../priorityQueue/maxHBLT/binaryTreeNode.h | 22 ++ BinaryTree/priorityQueue/maxHBLT/main.cpp | 34 ++++ BinaryTree/priorityQueue/maxHBLT/maxHblt.h | 133 ++++++++++++ 6 files changed, 386 insertions(+) create mode 100644 BinaryTree/priorityQueue/maxHBLT/CMakeLists.txt create mode 100644 BinaryTree/priorityQueue/maxHBLT/Height-biased Leftist Tree create mode 100644 BinaryTree/priorityQueue/maxHBLT/README.MD create mode 100644 BinaryTree/priorityQueue/maxHBLT/binaryTreeNode.h create mode 100644 BinaryTree/priorityQueue/maxHBLT/main.cpp create mode 100644 BinaryTree/priorityQueue/maxHBLT/maxHblt.h diff --git a/BinaryTree/priorityQueue/maxHBLT/CMakeLists.txt b/BinaryTree/priorityQueue/maxHBLT/CMakeLists.txt new file mode 100644 index 0000000..d88ff51 --- /dev/null +++ b/BinaryTree/priorityQueue/maxHBLT/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.31) +project(maxHblt) + +set(CMAKE_CXX_STANDARD 20) + +add_executable(maxHblt main.cpp) diff --git a/BinaryTree/priorityQueue/maxHBLT/Height-biased Leftist Tree b/BinaryTree/priorityQueue/maxHBLT/Height-biased Leftist Tree new file mode 100644 index 0000000..e69de29 diff --git a/BinaryTree/priorityQueue/maxHBLT/README.MD b/BinaryTree/priorityQueue/maxHBLT/README.MD new file mode 100644 index 0000000..8d89e8b --- /dev/null +++ b/BinaryTree/priorityQueue/maxHBLT/README.MD @@ -0,0 +1,191 @@ +# 左高树合并 — 逐步图解(示例:根 50 与 根 45) + +下面是你给出的两个左高树(Max-Leftist)的逐步合并图解。我把每一步的递归调用、比较、左右交换和 s 值(null path length,定义为:s(nullptr)=0,s(leaf)=1,节点 s = right.s + 1)都写清楚了。 + +--- + +## 初始两棵树与 s 值计算 + +**Tree A(根 50)** + +``` + 50(s=2) + / \ + 40(s=2) 30(s=1) + / \ +20(s=1) 10(s=1) +``` + +计算过程: + +* s(20)=1, s(10)=1 → s(40)=right.s + 1 = 1 + 1 = 2 +* s(30)=1(叶子) +* s(50)=right.s + 1 = 1 + 1 = 2 + +**Tree B(根 45)** + +``` + 45(s=2) + / \ + 35(s=2) 25(s=1) + / \ +15(s=1) 5(s=1) +``` + +计算过程: + +* s(15)=1, s(5)=1 → s(35)=1 + 1 = 2 +* s(25)=1(叶子) +* s(45)=right.s + 1 = 1 + 1 = 2 + +--- + +## 合并入口:`merge(50, 45)` + +* 比较根:50 >= 45 → 保留 50 为新根。 +* 按算法把 **第二棵树(45)合并到 50 的右子树**: + +递归调用: `merge(50,45)` → 需要计算 `50->right = merge(30, 45)`。 + +--- + +## 递归 1:`merge(30, 45)` + +* 比较根:30 < 45 → 交换(让数值大的作为子树根),所以在实现上会把参数交换,使 `h1` 指向 45,`h2` 指向 30。 +* 结果:以 45 为当前子树根,继续将 `h2(30)` 合并到 `45->right`: + +递归调用:`merge(45,30)` → `45->right = merge(25, 30)`(因为 45 的右子树原为 25)。 + +当前(在这一层)状态: + +``` + (暂时) 45 + / \ + 35 25 + (将与 30 合并) +``` + +--- + +## 递归 2:`merge(25, 30)` + +* 比较根:25 < 30 → 交换 → 以 30 为根,25 为待合并树。 +* 执行 `30->right = merge(30->right, 25)`。但原来 30 没有孩子,所以 `30->right` 是 `nullptr`。 +* 所以调用变成 `merge(nullptr, 25)` → 直接返回 25。 + +所以在这一步,临时构造出: + +``` + 30 + \ + 25 +``` + +接下来要维护左高性质(保证 s(left) >= s(right)): + +* 计算 s 值:原来 30 的左子为空(left\_s = 0),右子为 25(right\_s = 1)。 +* 因为 left\_s < right\_s,所以**交换左右子树**,得到: + +``` + 30 + / +25 +``` + +* 更新 s(30) = (right ? right.s : 0) + 1 = (nullptr ? 0 : ) + 1 = 0 + 1 = 1 + +所以 `merge(25,30)` 返回的子树为: + +``` + 30(s=1) + / +25(s=1) +``` + +--- + +## 回到上层(恢复到 45 的层) + +* 把返回的子树作为 `45->right`:现在 45 的左右子树为 + +``` + 45 + / \ +35(s=2) 30(s=1) + / + 25(s=1) +``` + +* 检查并维持左高性质: + + * left\_s = s(35) = 2 + * right\_s = s(30) = 1 + * left\_s >= right\_s,**不必交换**。 +* 更新 s(45) = right.s + 1 = 1 + 1 = 2(保持不变)。 + +`merge(30,45)` 到此结束,返回的子树根为 45(其 s=2)。 + +--- + +## 回到最顶层(恢复到 50 的层) + +* 将上一步得到的子树赋为 `50->right`,现在 50 的结构为: + +``` + 50 + / \ + 40(s=2) 45(s=2) + / \ / \ +20 10 35 30 + /\ / + 15 5 25 +``` + +(为清楚起见:35 下保留 15、5;30 下保留 25) + +* 检查并维持左高性质: + + * left\_s = s(40) = 2 + * right\_s = s(45) = 2 + * left\_s >= right\_s(等于也符合),所以**不交换**。 + +* 更新 s(50) = right.s + 1 = 2 + 1 = 3。 + +--- + +## 最终合并结果(图与 s 值) + +``` + 50(s=3) + / \ + 40(s=2) 45(s=2) + / \ / \ +20(1)10(1)35(2) 30(1) + /\ / + 15(1)5(1)25(1) +``` + +说明: + +* 合并过程中确实发生了你关心的“原来右子树的位置(30)被另一棵树的节点(45/35)取代”的情况,这很正常:合并算法**优先保证堆序(根值最大)**,于是较大的根会在递归中“上移”到合适位置。 +* 同时,算法通过「递归合并到右子树」+「必要时交换左右子树」来保持左高性质。最终时间复杂度按树的右路径长度上界(均摊 O(log n))来保证。 + +--- + +## 伪代码回顾(便于对应每一步) + +```cpp +Node* merge(Node* h1, Node* h2) { + if (!h1) return h2; + if (!h2) return h1; + if (h1->key < h2->key) swap(h1, h2); // 确保 h1 的根更大(Max-heap) + h1->right = merge(h1->right, h2); + // 保持左高:如果左子 s < 右子 s,则交换 + if (npl(h1->left) < npl(h1->right)) swap(h1->left, h1->right); + h1->s = npl(h1->right) + 1; + return h1; +} +``` + +--- + diff --git a/BinaryTree/priorityQueue/maxHBLT/binaryTreeNode.h b/BinaryTree/priorityQueue/maxHBLT/binaryTreeNode.h new file mode 100644 index 0000000..05791a9 --- /dev/null +++ b/BinaryTree/priorityQueue/maxHBLT/binaryTreeNode.h @@ -0,0 +1,22 @@ +// +// Created by PC on 25-8-6. +// + +#ifndef BINARYTREENODE_H +#define BINARYTREENODE_H + +template +class binaryTreeNode { +public: + T element; + binaryTreeNode* left; + binaryTreeNode* right; +public: + binaryTreeNode() {left = right = nullptr;} + explicit binaryTreeNode(const T& e) : element(e), left(nullptr), right(nullptr) {} + binaryTreeNode(const T& e, binaryTreeNode* l, binaryTreeNode* r) : element(e), left(l), right(r) {} + ~binaryTreeNode() = default; + +}; + +#endif //BINARYTREENODE_H diff --git a/BinaryTree/priorityQueue/maxHBLT/main.cpp b/BinaryTree/priorityQueue/maxHBLT/main.cpp new file mode 100644 index 0000000..ee579f8 --- /dev/null +++ b/BinaryTree/priorityQueue/maxHBLT/main.cpp @@ -0,0 +1,34 @@ +#include "maxHblt.h" + +int main() { + /* +Tree1 + 50 + / \ + 40 30 + / \ +20 10 +Tree2 + 45 + / \ + 35 25 + / \ +15 5 +*/ + maxHblt t1,t2; + t1.push(50);t1.push(30);t1.push(40);t1.push(20);t1.push(10); + t2.push(45);t2.push(25);t2.push(35);t2.push(15);t2.push(5); + t1.display(); + t2.display(); + //正确的树 + t1.meld(t2); + t1.display(); + return 0; +} +/* +最后输出了 +{2, 50}, {2, 40}, {1, 30}, {1, 20}, {1, 10}, +{2, 45}, {2, 35}, {1, 25}, {1, 15}, {1, 5}, +{3, 50}, {2, 40}, {2, 45}, {1, 20}, {1, 10}, {2, 35}, {1, 30}, {1, 15}, {1, 5}, {1, 25}, +与预测一致,详情见README.MD +*/ \ No newline at end of file diff --git a/BinaryTree/priorityQueue/maxHBLT/maxHblt.h b/BinaryTree/priorityQueue/maxHBLT/maxHblt.h new file mode 100644 index 0000000..63a7205 --- /dev/null +++ b/BinaryTree/priorityQueue/maxHBLT/maxHblt.h @@ -0,0 +1,133 @@ +// +// Created by PC on 25-8-9. +// + +#ifndef MAXHBLT_H +#define MAXHBLT_H +#include +#include +#include +#include "binaryTreeNode.h" +template +class maxHblt { +private: + binaryTreeNode>* root; + int bsize; + std::vector>*> data; + static void meld(binaryTreeNode>* &x, binaryTreeNode>* &y); +public: + maxHblt() : root(nullptr), bsize(0) {} + maxHblt(binaryTreeNode>* r, int b) : root(r), bsize(b) {} + ~maxHblt(); + + void push(const T& x); + void pop(); + void meld(maxHblt &y); + void initialize() {} + void display(); + + T& top() {return root->element.second;} + bool empty() {return bsize == 0;} + int size() {return bsize;} + void dispose(binaryTreeNode>* r) { + if (r == nullptr) return; + if (r->left != nullptr) dispose(r->left); + if (r->right != nullptr) dispose(r->right); + delete r; + } +}; + +template +maxHblt::~maxHblt() { + dispose(root); + root = nullptr; + bsize = 0; +} + +template +void maxHblt::push(const T& x) { + if (root == nullptr) { + root = new binaryTreeNode>(std::make_pair(1, x)); + return; + } + auto tmp = new binaryTreeNode>(std::make_pair(1, x)); + meld(root, tmp); + bsize++; +} + +template +void maxHblt::pop() { + if (root == nullptr) { + std::cerr << "Empty Error!" << std::endl; + } + auto left = root->left; + auto right = root->right; + delete root; + root = nullptr; + meld(left, right); + bsize--; +} + +template +void maxHblt::meld(maxHblt &y) { + meld(root, y.root); + bsize += y.bsize; + y.dispose(y.root); + y.root = nullptr; + y.bsize = 0; +} + +template +void maxHblt::display() { + if (root == nullptr) { + std::cerr << "Empty Error!" << std::endl; + return; + } + data.clear(); + data.push_back(root); + int cnt = 0; + while (cnt < bsize) { + if (data.at(cnt)->left != nullptr) data.push_back(data.at(cnt)->left); + if (data.at(cnt)->right != nullptr) data.push_back(data.at(cnt)->right); + cnt++; + } + for (auto x : data) { + std::cout << "{" << x->element.first << ", " << x->element.second << "}" << ", "; + } + std::cout << std::endl; +} + +//重要 -> 合并两个子树,把y合并进入x +//* &x,指针的引用,表示指针可以修改(传入函数) +template +void maxHblt::meld(binaryTreeNode>*& x, + binaryTreeNode>*& y) { + if (y == nullptr) return; + if (x == nullptr) { + x = y; + //一定要y = nullptr + y = nullptr; + return; + } + + if (x->element.second < y->element.second) { + std::swap(x, y); + } + + meld(x->right, y); + + if (x->left == nullptr) { + x->left = x->right; + x->right = nullptr; + x->element.first = 1; + } + else { + if (x->left->element.first < x->right->element.first) { + std::swap(x->left, x->right); + } + int rightNpl = (x->right ? x->right->element.first : 0); + x->element.first = rightNpl + 1; + } +} + +#endif //MAXHBLT_H