纸上谈兵: 左倾堆 (leftist heap)

  • 时间:
  • 浏览:0
  • 来源:大发快3_快3在线稳定计划_大发快3在线稳定计划

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

大伙很久讲解了堆(heap)的概念。堆是有有三个小多优先队列。每次从堆中取出的元素有的是堆中优先级最高的元素

在很久的文章中,大伙基于完整二叉树(complete binary tree)实现了堆,很久的堆叫做二叉堆(binary heap)。binary heap有有有三个小多基本要求: 每个节点的优先级大于有有三个小多子节点的优先级。在你你这个 要求下,堆的根节点始终是堆的元素中优先级最高的元素。此外,大伙实现了delete_min()操作,从堆中取出元素;insert()操作,向堆中插入元素。

现在,大伙考虑下面的难题报告 : 咋样合并(merge)有有三个小多堆呢? 有有三个小多方案是从第有有三个小多堆中不断取出有有三个小多元素,并插入到第三个小堆中。很久,大伙可不也能量级为n的操作。大伙下面要实现更有速度单位的合并。

左倾堆 (Leftist Heap)

左倾堆基于二叉树(binary tree)。左倾堆的节点满足堆的基本要求,即(要求1)每个节点的优先级大于子节点的优先级。与二叉堆不同,左倾堆并有的是完整二叉树。二叉堆是非常平衡的树底部形态,它的每一层都被填满(除了最下面一层)。左倾堆则是维持并有的是不平衡的底部形态: 它的左子树节点往往比右子树有更多的节点。

不平衡

左倾堆的每个节点有有有三个小多附加信息,即null path length (npl)。npl是从有有三个小多节点到有有三个小多最近的不满节点的路径长度(不满节点:有有三个小多子节点相当于有有有三个小多为NULL)。有有三个小多叶节点的npl为0,有有三个小多NULL节点的npl为-1。

各个节点的npl (这里显示的有的是元素值)

根据npl的定义,大伙有推论1: 有有三个小多节点的npl等于子节点npl中最小值加1: npl(node) = min(npl(lchild), npl(rchild)) + 1

有了npl的概念,大伙可不也能完整的定义左倾堆。左倾堆是有有三个小多符合下面要求的二叉树:

  • 要求1: 每个节点的优先级大于子节点的优先级
  • 要求2: 对于任意节点的左右有有三个小多子节点,右子节点的npl不大于左子节点的npl

左倾堆的性质

从上面的要求1和2可不也能知道,左倾堆的任意子树也是有有三个小多左倾堆

原因左倾堆的底部形态,左倾堆的右侧路径(right path)较短。右侧路径是指大伙从根节点开始英文英文,不断前往右子节点所构成的路径。对于有有三个小多左倾堆来说,右侧路径上节点数不大于任意许多路径上的节点数,咋样让,将违反左倾堆的要求2

大伙还可不也能证明推论2,原因有有三个小多左倾堆的右侧路径上有r个节点,那么 该左倾堆将相当于有2r-有有三个小多节点。大伙采用归纳法证明:

  • r = 1, 右侧路径上有有有三个小多节点,可是相当于有21-有有三个小多节点
  • 假设任意r, 左倾堆相当于有2r-1节点。那么 对于有有三个小多右侧路径节点数为r+1的左倾堆来说,根节点的右子树的右侧路径有r个节点。根节点的左子树的右侧路径相当于有r个节点。根据假设,该左倾堆将包括: 
    • 右子树:相当于有2r-1个节点
    • 左子树: 相当于有2r-1个节点
    • 有有三个小多根节点
  • 咋样让,对于r+1,整个左倾堆相当于有2r+1-有有三个小多节点。证明完成

换句话说,有有三个小多n节点的的左倾堆,它的右侧路径最多有log(n+1)个节点。原因对右侧路径进行操作,其冗杂度将是log(n)量级。

大伙将沿着右侧路径进行左倾堆的合并操作。合并采用递归。合并如下:

  1. (base case) 原因有有三个小多空左倾堆与有有三个小多非空左倾堆合并,返回非空左倾堆
  2. 原因有有三个小多左倾堆都非空,那么 比较有有三个小多根节点。取较小的根节点为新的根节点(满足要求1),合并较小根节点堆的右子堆与较大根节点堆。
  3. 原因右子堆npl > 左子堆npl,互换右子堆与左子堆。
  4. 更新根节点的npl = 右子堆npl + 1

上面的合并算法调用了合并操作自身,可是是递归。原因大伙沿着右侧路径递归,可是冗杂度是log(n)量级。

左倾堆的实现

上面可不也能看多,左倾堆可不也能相对高效的实现合并(merge)操作。

许多的堆操作,比如insert, delete_min都可不也能在merge基础上实现:

  • 插入(insert): 将有有三个小多单节点左倾堆(新增节点)与有有三个小多已有左倾堆合并
  • 删除(delete_min): 删除根节点,将剩余的左右子堆合并
/* By Vamei */

/* 
 * leftist heap
 * bassed on binary tree 
 */

#include <stdio.h>
#include <stdlib.h>

typedef struct node *position;
typedef int ElementTP;

struct node {
    ElementTP element;
    int npl;
    position lchild;
    position rchild;
};

typedef struct node *LHEAP;

LHEAP insert(ElementTP, LHEAP);
ElementTP find_min(LHEAP);
LHEAP delete_min(LHEAP);
LHEAP merge(LHEAP, LHEAP);
static LHEAP merge1(LHEAP, LHEAP);
static LHEAP swap_children(LHEAP);

int main(void)
{
    LHEAP h1=NULL;
    LHEAP h2=NULL;
    h1 = insert(7, h1);
    h1 = insert(3, h1);
    h1 = insert(5, h1);

    h2 = insert(2, h2);
    h2 = insert(4, h2);
    h2 = insert(8, h2);

    h1 = merge(h1, h2);
    printf("minimum: %d\n", find_min(h1));
    return 0;
}

/*
 * insert:
 * merge a single-node leftist heap with a leftist heap
 * */
LHEAP insert(ElementTP value, LHEAP h)
{
    LHEAP single;
    single = (position) malloc(sizeof(struct node));

    // initialze
    single->element  = value;
    single->lchild   = NULL;
    single->rchild   = NULL;

    return  merge(single, h);
}

/*
 * find_min:
 * return root value in the tree
 * */
ElementTP find_min(LHEAP h)
{
    if(h != NULL) return h->element;
    else exit(1);
}

/*
 * delete_min:
 * remove root, then merge two subheaps
 * */
LHEAP delete_min(LHEAP h)
{
    LHEAP l,r;
    l = h->lchild;
    r = h->rchild;
    free(h);
    return merge(l, r);
}

/*
 * merge two leftist heaps
 * */
LHEAP merge(LHEAP h1, LHEAP h2) 
{

    // if one heap is null, return the other
    if(h1 == NULL) return h2;
    if(h2 == NULL) return h1;

    // if both are not null
    if (h1->element < h2->element) { 
        return merge1(h1, h2);
    }
    else {
        return merge1(h2, h1);
    }
}

// h1->element < h2->element
static LHEAP merge1(LHEAP h1, LHEAP h2)
{
    if (h1->lchild == NULL) { 
        /* h1 is a single node, npl is 0 */
        h1->lchild = h2; 
    /* rchild is NULL, npl of h1 is still 0 */
    }
    else {
        // left is not NULL
    // merge h2 to right
    // swap if necessary
        h1->rchild = merge(h1->rchild, h2);
    if(h1->lchild->npl < h1->rchild->npl) {
        swap_children(h1);
    }
        h1->npl = h1->rchild->npl + 1; // update npl
    }
    return h1;
}

// swap: keep leftist property
static LHEAP swap_children(LHEAP h) 
{
    LHEAP tmp;
    tmp       = h->lchild;
    h->lchild = h->rchild;
    h->rchild = tmp;
}

总结

左倾堆利用不平衡的节点分布,让右侧路径保持比较短的情况汇报,从而提高合并的速度单位。

在合并过程,通过左右互换,来恢复左倾堆的性质。

欢迎继续阅读“纸上谈兵: 算法与数据底部形态”系列。

猜你喜欢

微软发布Office 2019正式版,吸引未升级365的用户

IT之家9月25日消息微软在今天早些然后正式发布了Office2019forWindowsandMac。此次更新,是对过去三年在Office365里所有功能进行整合,包括对Wo

2020-01-23

CFC赫塔VSSC斯塔肯免费视频直播,CFC赫塔VSSC斯塔肯比赛集锦,CFC赫塔VSSC斯塔肯录像,CFC赫塔VSSC斯塔肯首发阵容

首页新闻视频直播数据APP懂球号直播君广告合作协议协议 CFC赫塔08-1820:00德高联赛1-5已现在刚刚刚刚开始SC斯塔肯直播君|分析|集锦暂无数据近期比赛亚特兰大意甲

2020-01-22

Spring Boot WebFlux 增删改查完整实战 demo

前言上一篇基于功能性端点去创建另5个 简单服务,实现了Hello。這個篇用SpringBootWebFlux的注解控制层技术创建另5个 CRUDWebFlux应用,让开发更

2020-01-22

住建部关于中国建筑业发展环境的分析

中国建筑业发展环境分析住房和城乡建设部建筑市场监管司住房和城乡建设部政策研究中心一、宏观经济环境(一)中国特色社会主义进入新时代2017年10月18日,中国共产党第十九次全国代

2020-01-22

星巴克外卖已覆盖2000家门店 通过阿里覆盖6亿会员

《星巴克外卖已覆盖60 0家门店通过阿里覆盖6亿会员》文章由于归档,不再展示相关内容,编辑建议你查看最新于此相关的内容:阿里巴巴LOGO设计者盛一飞:互联网的美工师对占据

2020-01-22