gitbook-way-to-algorithm
  • Introduction
  • Preface 前言
  • Content 目录
  • MathSymbolTable 数学符号表
  • Chapter-1 BasicKnowledge 第1章 基础知识
    • TimeComplexity 时间复杂度
    • Recursion 递归式
  • Chapter-2 Sort 第2章 排序
    • InsertSort 插入排序
    • BubbleSort 冒泡排序
    • QuickSort 快速排序
    • MergeSort 归并排序
  • Chapter-3 Search 第3章 搜索
    • BinarySearch 二分查找法(折半查找法)
    • AdditionMultiplicationPrinciple 加法乘法原理
    • BruteForce 暴力枚举
    • Recursion 递归
    • BreadthFirstSearch 广度优先搜索
    • BidirectionalBreadthSearch 双向广度搜索
    • AStarSearch A*搜索
    • DancingLink 舞蹈链
  • Chapter-4 DataStructure 第4章 数据结构
    • DisjointSet 并查集
    • PrefixTree(TrieTree) 前缀树
    • LeftistTree(LeftistHeap) 左偏树(左偏堆)
    • SegmentTree 线段树
    • FenwickTree(BinaryIndexedTree) 树状数组
    • BinarySearchTree 二叉查找树
    • AVLTree AVL平衡树
    • RedBlackTree 红黑树
    • SkipList 跳跃表
    • BPlusTree B+树
    • BMinusTree B-树
  • Chapter-5 DynamicProgramming 第5章 动态规划
    • Section-1 LinearDP 第1节 线性动规
      • LongestCommonSubsequence 最长公共子序列
      • LongestIncreasingSubsequence 最长递增子序列
      • BidirectionalSubsequence 双向子序列
      • MaximumContinuousSubsequenceSum 最大连续子序列和
      • LongestPalindromicSubsequence 最长回文子序列
    • Section-2 BagDP 第2节 背包问题
      • 01-Bag 01背包
      • CompleteBag 完全背包
      • TwoDimensionBag 二维背包
    • Section-3 RegionalDP 第3节 区域动规
      • MinimumMergeCost - 最小合并代价
      • UniquePath 唯一路径
      • TrianglePath 三角形路径
    • Section-4 TreeDP 第4节 树形动规
      • MaximumBinaryTree 最大二叉树
      • MaxMultipleTree 最大多叉树
      • MaximumBinaryTreeRadiusSum 最大二叉树和
  • Chapter-6 GraphTheory 第6章 图论
    • Section-1 Traverse 第1节 遍历
      • DepthFirstSearch 深度优先搜索
      • BreadthFirstSearch 广度优先搜索
      • TopologicalSort 拓扑排序
      • EulerCycle 欧拉回路
    • Section-2 MinSpanningTree 第2节 最小生成树
      • Kruskal Kruskal算法
      • Prim Prim算法
    • Section-3 ShortestPath 第3节 最短路径
      • BellmanFord BellmanFord算法
      • Dijkstra Dijkstra算法
      • FloydWarshall FloydWarshall算法
      • DifferentConstraints 差分约束
    • Section-4 StronglyConnectedComponents 第4节 强连通分支
      • Kosaraju Kosaraju算法
      • Tarjan Tarjan算法
      • 2-SAT 2-SAT问题
    • Section-5 NetworkFlow 第5节 网络流
      • EdmondsKarp EdmondsKarp算法(最短路径增广算法)
      • PushRelabel 压入与重标记算法
      • Dinic - Dinic算法
      • MinimumCostFlow - 最小费用流
      • MultipleSourceMultipleSinkMaxflow - 多源点多汇点最大流
    • Section-6 BinaryMatch 第6节 二分匹配
      • Hungarian 匈牙利算法
      • HopcroftKarp Hopcroft-Karp算法
      • MatchToMaxflow 二分匹配转化为最大流
      • KuhnMunkres Kuhn-Munkres算法
      • Introduction-Domination,Independent,Covering,Clique 介绍支配集、独立集、覆盖集和团
      • WeightedCoveringAndIndependentSet 最小点权覆盖和最大点权独立集
      • MinimumDisjointPathCovering 最小不相交路径覆盖
      • MinimumJointPathCovering 最小可相交路径覆盖
      • Coloring 染色问题
  • Chapter-7 CombinatorialMathematics 第7章 组合数学
    • FullPermutation 全排列
    • Combination 组合
    • Permutation 排列
    • PermutationGroup 置换群
  • Chapter-8 NumberTheory 第8章 数论
    • PrimeSieve 素数筛法
    • GreatestCommonDivisor 最大公约数
    • Euclid 欧几里得算法
    • ExtendedEuclid 扩展欧几里得算法
    • ChineseRemainerTheorem 中国剩余定理
    • ModularExponentiation 模幂运算
  • Chapter-9 LinearAlgebra 第9章 线性代数
    • Section-1 Matrix 第1节 矩阵
      • Strassen Strassen算法
      • GaussElimination 高斯消元法
      • LUP LUP分解
      • InverseMatrix 矩阵求逆
    • Section-2 LinearProgramming 第2节 线性规划
      • Simplex 单纯形算法
      • Dinkelback Dinkelback算法
  • Chapter-10 AnalyticGeometry 第10章 解析几何
    • Section-1 Polygon 第1节 多边形
      • Cross 向量叉积
      • SegmentIntersection 线段相交
      • Sweeping 扫除算法
      • ConvexPolygonArea 凸多边形面积
      • ConvexPolygonGravityCenter 凸多边形重心
      • NearestNeighbor 最近点对
    • Section-2 ConvexHull 第2节 凸包
      • GrahamScan Graham扫描算法
      • QuickHull 快速凸包算法
      • RotatingCalipers 旋转卡壳
  • Chapter-11 PatternMatch 第11章 文本匹配
    • SimpleMatch 简单匹配
    • AhoCorasickAutomata AC自动机
    • KnuthMorrisPratt KMP匹配算法
    • RabinKarp RabinKarp算法
    • BoyerMoore BoyerMoore算法
  • Chapter-12 GameTheory 第12章 博弈论
    • BashGame 巴什博弈
    • WythoffGame 威佐夫博弈
    • NimGame 尼姆博弈
Powered by GitBook
On this page
  • 左偏树
  • 源码
  • 测试
  1. Chapter-4 DataStructure 第4章 数据结构

LeftistTree(LeftistHeap) 左偏树(左偏堆)

PreviousPrefixTree(TrieTree) 前缀树NextSegmentTree 线段树

Last updated 6 years ago

左偏树

左偏树是一种类似小根堆的二叉树,它的根节点总是树中的最小值。左偏树的每次取出/加入操作的时间复杂度为O(log2n)O(log_2 n)O(log2​n),与小根堆相同。与堆不同的是,合并两个数量为nnn的堆的时间复杂度为O(n×log2n)O(n \times log_2 n)O(n×log2​n)(因为合并两个堆需要从其中一个取出元素加入另一个,重复nnn次),而合并两个数量为nnn的左偏树的时间复杂度为O(log2n)O(log_2 n)O(log2​n)。

左偏树的主要操作有:(1)(1)(1) 合并两个左偏树;(2)(2)(2) 插入新节点;(3)(3)(3) 查找最值;(4)(4)(4) 删除最值。其中(2)−(4)(2) - (4)(2)−(4)的实现依赖于(1)(1)(1),合并操作是左偏树的核心。

左偏树中的节点的距离ddd是该节点到最右下叶子节点的距离。左偏树具有以下性质:

(1)(1)(1) 父节点的值小于等于其左右孩子节点的值,即valuefather≤valueleft,valuefather≤valuerightvalue_{father} \leq value_{left}, value_{father} \leq value_{right}valuefather​≤valueleft​,valuefather​≤valueright​。最小的值在根节点类似小根堆的头节点;

(2)(2)(2) 父节点的左孩子节点的距离大于等于右孩子节点的距离,即dleft≥drightd_{left} \geq d_{right}dleft​≥dright​;

(3)(3)(3) 父节点的距离等于其右孩子节点的距离加111,即dfather=dright+1d_{father} = d_{right} + 1dfather​=dright​+1;

(4)(4)(4) 具有nnn个节点的左偏树的根节点的距离小于等于log2⁡(n+1)−1log_2⁡(n+1) - 1log2​⁡(n+1)−1,即droot≤log2⁡(n+1)−1d_{root} \leq log_2⁡(n+1) - 1droot​≤log2​⁡(n+1)−1;

下图中每个节点上,上面的数字代表节点的值,下面的数字代表距离。合并两个左偏树的操作,分为两步:

(1)(1)(1) 从根节点开始递归向下合并两个左偏树。每次合并时比较两个子树根节点的值valueavalue_{a}valuea​和valuebvalue_{b}valueb​,总是用根节点较大的子树valuebvalue_{b}valueb​(设valueb>valueavalue_{b} \gt value_{a}valueb​>valuea​)替换根节点较小的子树valueavalue_{a}valuea​的右孩子节点valuea−leftvalue_{a-left}valuea−left​,替换后valuea−leftvalue_{a-left}valuea−left​成为新的子树。然后递归的,继续考虑valuea−leftvalue_{a-left}valuea−left​作为根节点的子树与valuebvalue_{b}valueb​作为根节点的子树;

(2)(2)(2) 从叶子节点开始递归向上更新所有节点的距离。对于每个节点,首先若不满足dleft≥drightd_{left} \geq d_{right}dleft​≥dright​则将左右孩子子树交换,其次若不满足dfather=dright+1d_{father} = d_{right} + 1dfather​=dright​+1则更新父结点的距离dfatherd_{father}dfather​;

下图是合并两个左偏树的过程:

左偏树的插入操作,可以看作左偏树与一个只有根节点的左偏树的合并操作;删除最值的操作,可以看作删除根节点后,合并左右子树的操作。

源码

测试

(1)(1)(1) 比较两树的根节点6<76 \lt 76<7,节点777沿着节点666向右下寻找第111个满足7<x7 \lt x7<x的节点xxx,替换xxx作为节点666的新右孩子节点。该节点为节点888(7<87 \lt 87<8),节点666的原右孩子节点888暂时脱离;

(2)(2)(2) 节点888沿着节点777向右下寻找第111个满足8<x8 \lt x8<x的节点xxx,替换xxx作为节点777的新右孩子节点。该节点为节点121212(8<128 \lt 128<12),节点777的原右孩子节点121212暂时脱离;

(3)(3)(3) 节点121212沿着节点888向右下寻找第111个满足12<x12 \lt x12<x的节点xxx,替换xxx作为节点888的新右孩子节点。该节点为节点131313(12<1312 \lt 1312<13),节点888的原右孩子节点131313暂时脱离;

(4)(4)(4) 节点131313沿着节点121212向右下寻找第111个满足13<x13 \lt x13<x的节点xxx,替换xxx作为节点121212的新右孩子节点。该节点为节点262626(13<2613 \lt 2613<26),节点121212的原右孩子节点262626暂时脱离;

(5)(5)(5) 节点262626沿着节点131313向右下寻找第111个满足26<x26 \lt x26<x的节点xxx,节点131313没有右孩子节点,因此节点262626直接成为节点131313的右孩子节点,不再需要替换,合并操作结束;

向右下插入节点的操作会影响到左偏树的平衡性,右子树变得越来越庞大。而且所有节点的距离也是错的(没有更新)。实际上每一步合并操作后还需要检查左右子树的距离属性:(1)(1)(1)对于dleft<drightd_{left} \lt d_{right}dleft​<dright​的情况,交换左右子树;(2)(2)(2)对于droot≠dright+1d_{root} \neq d_{right} + 1droot​=dright​+1的情况,更新drootd_{root}droot​。

节点距离的更新必须从叶子节点开始向上进行,对于之前步骤中修改过的节点,重新遍历计算其距离(其中dnil=−1d_{nil} = -1dnil​=−1):

(6)(6)(6) 对于节点262626,d27=0≥dnil=−1d_{27} = 0 \ge d_{nil} = - 1d27​=0≥dnil​=−1,不需要交换左右子树,更新d26=dnil+1=−1+1=0d_{26} = d_{nil} + 1 = - 1 + 1 = 0d26​=dnil​+1=−1+1=0;

(7)(7)(7) 对于节点131313,d28=0≥d26=0d_{28} = 0 \ge d_{26} = 0d28​=0≥d26​=0,不需要交换左右子树,更新d13=d26+1=0+1=1d_{13} = d_{26} + 1 = 0 + 1 = 1d13​=d26​+1=0+1=1;

(8)(8)(8) 对于节点121212,d31=1≥d26=1d_{31} = 1 \ge d_{26} = 1d31​=1≥d26​=1,不需要交换左右子树,更新d12=d13+1=1+1=2d_{12} = d_{13} + 1 = 1 + 1 = 2d12​=d13​+1=1+1=2;

(9)(9)(9) 对于节点888,d10=1<d12=2d_{10} = 1 \lt d_{12} = 2d10​=1<d12​=2,需要交换子树101010和子树121212,更新d8=d10+1=1+1=2d_{8} = d_{10} + 1 = 1 + 1 = 2d8​=d10​+1=1+1=2;

(10)(10)(10) 对于节点777,d9=1<d8=2d_{9} = 1 \lt d_{8} = 2d9​=1<d8​=2,需要交换子树999和子树888,更新d7=d9+1=1+1=2d_{7} = d_{9} + 1 = 1 + 1 = 2d7​=d9​+1=1+1=2;

(11)(11)(11)对于节点666,d11=2≥d7=2d_{11} = 2 \ge d_{7} = 2d11​=2≥d7​=2,不需要交换左右子树,更新d6=d7+1=2+1=3d_{6} = d_{7} + 1 = 2 + 1 = 3d6​=d7​+1=2+1=3;

编码时通过递归的方式将合并和更新距离两个操作放在同一个递归函数中,合并函数Merge返回合并后左偏树的根节点的距离ddd,在Merge中调用左右孩子的合并操作,获取左右孩子的距离,然后再决定是否交换左右子树,并更新父节点的距离。本文的将两个步骤分开是为了方便理解算法。

左偏树的合并操作、插入节点操作、删除根节点操作的时间复杂度都为O(log2⁡n)O(log_2⁡n)O(log2​⁡n)。

LeftistTree.h
LeftistTree.cpp
LeftistTreeTest.cpp
LeftistTree2.png
LeftistTree3.png
LeftistTree4.png
LeftistTree5.png
LeftistTree6.png
LeftistTree7.png
LeftistTree8.png
LeftistTree9.png
LeftistTree10.png
LeftistTree11.png
LeftistTree12.png