文章目录

  • 前言
  • 左高树
    • 什么是左高树?
    • 为什么要使用左高树?
  • 最大左高树实现及复杂度分析
    • 节点类和最大左高树类
    • 合并方法
    • 插入(push)、删除(pop)
    • 初始化
  • 左高树合并图解

前言

看到左高树的时候,对左高树的印象大概只有左高树这三个字了。看的时候费劲了一点,因为不知道这个数据结构是干嘛的。网上的资料也比较少。所以这篇文章理解能力有限,请见谅。

左高树

什么是左高树?

左高树大致分为高度优先左高树和重量优先左高树两类。
本文以高度优先左高树为例。

左高树中定义了几个新的概念,比如外部节点内部节点扩充二叉树

  • 外部节点:一类特殊的节点,假设原本的树中节点x的任意孩子节点为空,可以将该指针指向外部节点。
  • 内部节点:至少有一个孩子节点不为空的节点叫做内部节点。
  • 扩充二叉树:增加了外部节点的二叉树。

我原以为这是很重要的概念,但是后面函数实现中却不曾用过。所以我暂且认为这几个概念是为了更形象的定义s(x)

s(x)是一个函数,代表了内部节点x到其子树外部节点的最短路径。

如果x是外部节点,那么s(x)= 0。

如果x是内部节点 ,那么s(x) >= 1.

如果x的一个孩子s(x1) = 1,另一个孩子s(x2) = 2,那么s(x) = 2

一颗二叉树称为高度优先二叉树(height-biased leftist tree,HBLT)。当且仅当其任何一个内部节点的左孩子的s(x) 值都大于或等于右孩子的s值。

++++++++++++++++++++分割线+++++++++++++++++++++++++++++++++++++++++++

在之后的二叉树实现中,所有结点都为内部节点,即叶节点也为内部节点,且叶节点的s(x) = 1。也就是说外部节点隐式存在。

为什么要使用左高树?

书上的解释为堆(Heap)并不适合所有优先级队列的应用,尤其是当两个优先级队列或多个长度不同的队列需要合并时,需要使用左高树,左高树可在对数时间内实现两个优先级队列的合并。

假设有两个优先级队列,节点数为n、m。且n>m。
不考虑节点数的增长,用堆实现合并时间复杂度至少需要O(mlogn),即一个节点一个节点插进去。
而左高树的可以在 O(log(mn)) 的时间复杂度下实现合并。

优势已经显现

撒,我们马上实现试试!

最大左高树实现及复杂度分析

最大左高树:是左高树也是大根树。
因为左高树需要表示优先级队列,需要维护节点的优先级,所以是一颗左高树的同时也需要是一颗大根/小根树。

节点类和最大左高树类

template <class T>
class HBLTNode
{friend MaxHBLT<T>;
public:HBLTNode(const T& e, const int s){data = e;this->s = s;leftChild = rightChild = NULL;}private:int s;T data;HBLTNode<T>* leftChild;HBLTNode<T>* rightChild;};// 最大HBLT类template <class T>
class MaxHBLT
{public:MaxHBLT(){root = NULL;}~MaxHBLT(){free(root);}const T& top(){if(!root) throw "Tree is empty.";}void push(const T& x);const T& pop();MaxHBLT<T>& meld(HBLTNode<T>& x){meld(root, x.root);x.root = NULL;return *this;}void initialize(T a[], int n);private:void free(HBLTNode* t);void meld(HBLTNode* x, HBLTNode* y);HBLTNode* root;
};

合并方法

template <class T>
void mexHBLT<T> :: meld(HBLTNode* x, HBLTNode* y)
{// 合并后左高树以x为根,返回x的指针if(y == NULL)return;if(x == NULL){x = y;return;}// x和y都不空,必要时交换x和y,直接交换节点地址,真ne到if(x->data < y->data)swap(x, y);// 目前x->data >= y->data// 继续在右路径合并meld(x->rightChild, y);// 因为swap函数不处理空对象,单独交换if(x->leftChild == NULL){x->leftChild = x->rightChild;x->rightChild = NULL;x->s = 1;}else // 如果右边的s(x)比左边大,不符合左高树规则,交换{if(x->leftChild->s < x->rightChild->s)swap(x->leftChild, x->rightChild);x->s = x->rightChild->s + 1;}
}

时间复杂度

遍历沿右路径进行,所以递归次数应该为两个树根节点的s(x)加起来,设两个树的节点数目为m、n。那么两颗树的s(x)最大为log(m+1)、log(n+1)(因为s(x)小于等于完全二叉树的高度)。
那么时间复杂度为O(logm+logn) = O(log(mn))

插入(push)、删除(pop)

template <class T>
void MaxHBLT<T> :: push(const T& x)
{HBLTNode<T> *q = new HBLTNode<T>(x, 1);meld(root,q);
}template class<T>
const T& MaxHBLT<T> :: pop()
{T res;if(root == NULL)throw "The tree is empty.";res = root->data;HBLTNode<T>* l = root->leftChild;HBLTNode<T>* r = root->rightChild;delete root;root = l;meld(root, R);return res;
}

时间复杂度

插入每次插入一个节点,逻辑为只有一个节点的树与原有的树合并,根据合并的时间复杂度,m = 1,插入时间复杂度为O(logn)。

删除的逻辑为删除根节点,分为两颗左高树,再将两颗树合并,时间复杂度为O(logn)。

初始化

template <class T>
void MaxHBLT<T> :: initialize(T a[], int n)
{Queue<HBLTNode<T>> q(n);free(root); //删除原来的树for(int i = 1; i <= n; i++){HBLTNode<T> *t = new HBLTNode(a[i], 1);q.push(t);}for(int i = 1; i <= n-1; i++){HBLTNode<T> *a = q.pop();HBLTNode<T> *b = q.pop();meld(a, b);q.push(a);}if(n > 0)root = q.pop();
}

时间复杂度:

初始化的逻辑为,假设有n个元素,提供一队列,每次pop出两颗树(一个节点也视为一颗左高树),合并后,加入队列,合并(n-1)次,队列中剩下的唯一一颗树变为实现完成的最大左高树。

为什么合并n-1次?

当n为偶数时
假设存在一个以2为公比的等比数列,由求和公式有以下等式成立:

第n项 = 前n-1项部分和 + 1

合并次数就是前n-1项部分和,节点个数便是第n项。
比如有8个元素,需要先合并4次,再合并2次,最后合并1次,共合并7次。

当n为奇数时
可视为在偶数的基础上加了一个元素,多一次合并操作,仍然还是需要合并n-1次。

左高树合并图解

因为左高树合并操作我没有找到很细致的图,在理解时捋的合并方法代码,不直观,便自己画了一个,希望可以帮助理解。

数据结构(十六)——左高树(含合并过程详细图解)相关推荐

  1. C++(数据结构与算法):42---优先级队列的实现(扩充二叉树、高度优先左高树(HBLT)、重量优先左高树(WBLT))

    本文代码下载: 方式1:公众号[多栖技术控小董]回复[3586]免费获取下载链接 方式2:CSDN下载链接:https://download.csdn.net/download/qq_41453285 ...

  2. 数据结构——左高树(C语言)

    介绍左高树之前,先简单介绍下扩充二叉树的概念.扩充二叉树一棵二叉树,其所有空的子树都由方形结点代替.方形结点称为外部结点,原来的结点称为内部结点. 设x是扩充二叉树的一个结点,并令left_child ...

  3. (1小时数据结构)数据结构c++描述(十九) --- 最大左高树

    定义 [最大H B LT ] 即同时又是最大树的HBLT: [最小HBLT ] 即同时又是最小树的HBLT. 有关最大树的定义在上一章节有解析:传送门 堆树的定义 最大左高树合并:(重要知识点) 上图 ...

  4. 数据结构与算法之左高树

    知识点来源于参考书籍<数据结构.算法与应用>,本人仅作整理与记录,方便日后复习查看. 左高树的定义: 设x是扩充二叉树的一个结点,并令left_child(x)和right_child(x ...

  5. 《数据结构、算法与应用 —— C++语言描述》学习笔记 — 优先级队列 — 左高树

    <数据结构.算法与应用 -- C++语言描述>学习笔记 - 优先级队列 - 左高树 一.左高树 1.外部节点 2.高度优先左高树 (1)定义 (2)特性 (3)HBLT 与 大小根树 3. ...

  6. 高度优先左高树(HBLT) - C语言

    相关概念: 左高树(leftist tree)将树中的节点分为两类: 外部节点:用于代替树中的空子树:其余节点均叫做内部节点.内部节点就是我们所能看到的树中的每个真实节点,如果某个节点的左子树为空,那 ...

  7. 趣学数据结构--第六章:树

    趣学数据结构---->第六章:树 二叉树 线索二叉树 树的应用 二叉树的深度 二叉树的叶子数 二叉树的结点数 三元组创建二叉树 遍历序列还原树 哈夫曼树 二叉树 二叉树的创建(询问创建以及补空创 ...

  8. SAP UI5 应用开发教程之五十六 - SAP UI5 树控件(tree)的开发试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 应用开发教程之一:Hello World SAP UI5 应用开发教程之二:SAP U ...

  9. 可并堆(左高树、左偏树)

    可并堆(左高树.左偏树) 左偏树相对于二叉堆,其插入,弹出,合并的时间复杂度都是对数级别的. 高度优先左偏树(HBLT) 考虑一颗二叉树,将其叶子节点的子节点补全,那么原来有的节点叫做内部节点,新增加 ...

最新文章

  1. html二级菜单的自动宽度,如何使用CSS控制二级导航菜单宽度?_html/css_WEB-ITnose
  2. windows清理_Windows系统高级清理工具,实力吊打360!
  3. linux 进程 控制终端,linux系统编程之进程(五):终端、作业控制与守护进程
  4. 使用fastjson提供的接口实现自定义的编解码器
  5. Exchange server 2010系列教程之三 发送邮件测试
  6. [转载] 一致性哈希
  7. 信息学奥赛C++语言:打印字母表
  8. 从零开始学习Sencha Touch MVC应用之六
  9. android通过手机热点通信
  10. 同一台电脑管理多个`SSH KEY`
  11. 单片机自动浇花器答辩记录_一个塑料瓶一颗螺丝,教你做自动浇花器,再不担心花草没人浇水了...
  12. 十六进制转字符串 java_JAVA十六进制与字符串的转换方法
  13. 小心了,京东订单详情会变?下单记得录屏
  14. 创新科技 新BMW 7系 有你夫复何求
  15. 【Small Problem In Work】word 大括号后面的公式对不齐的问题
  16. android系统铃声选择画面源码,gogo体育体验官网-官网首页
  17. 梁勇(Danniel Liang) java教材例题:java程序购买额按税率求营业税 java中数值保留2位小数的方法...
  18. 小程序生成二维码海报
  19. Linux分区命令-parted
  20. Kafka Confluent 简介

热门文章

  1. C++ std::accumulate
  2. 知乎|推荐10个大学生需要收藏的良心网站
  3. 经济寒冬之下如何逆袭?强烈推荐几位大牛!
  4. 马鞍山岩字头古树茶多少一斤?
  5. PostgreSQL练习
  6. solidworks 资料分享
  7. ati显卡驱动的安装 linux,Fedora 18 下ATI 显卡驱动的安装
  8. 2016 HCTF web writeup
  9. python遇到天猫反爬虫_selenium 淘宝登入反爬虫解决方案(亲测有效)
  10. slxrom+v.21+原生android+4.2,红米Note4X高通版 魔趣OS 安卓10 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...