左倾堆

左倾堆(或左偏树)和之前记录过的二叉堆一样,是堆的一种;和普通的二叉堆不同,它是一种可合并堆。可合并堆相比于普通的二叉堆在对两个堆进行合并的操作上具有很大的优势:对于基本的二叉堆合并,时间复杂度为O(n), 而对于可合并堆,其时间复杂度为O(log2n).

左倾堆性质

左倾堆(也叫左偏树),是一种可合并堆.它有以下性质:

  1. 每个节点含有左子结点指针、右子节点指针、键值key、NPL(Null Path Length,表示当前节点到最近的一个不满子节点的长度,不满节点指的是节点含有少于两个子节点
  2. 每个节点的键值都小于其左右子节点的键值(最小堆的性质)
  3. 每个节点的左子节点的NPL 大于等于 右子节点的NPL
  4. 节点的NPL值等于其右子节点的NPL值 + 1
  5. 左倾堆的左右子节点及其下方节点构成的堆也分别都是左倾堆
  6. 叶子节点的NPL值等于0,空节点的NPL值等于 -1

左倾堆合并

可合并堆相比普通二叉堆在进行堆的合并上具有很大优势,对于左倾堆而言,合并操作为核心操作,像插入、删除操作等都可以在合并操作的基础上完成:插入操作可以将新插入的元素视为一个堆,然后进行两个左倾堆的合并;删除操作(堆的删除总是从堆顶位置取出元素)去除堆顶元素之后,将堆顶元素的左子堆和右子堆进行合并。 
    左倾堆的合并过程为:

  1. 如果一个空左倾堆和一个非空左倾堆进行合并,直接返回非空左倾堆
  2. 如果两个左倾堆都非空,比较两个堆的根节点,去除较小的堆的根节点作为新的根节点。然后将“较小堆”的根节点的右子节点(和它下方的堆)和“较大堆”进行合并(递归)
  3. 如果新堆的右子节点的NPL大于左子结点的NPL,则交换左右子节点
  4. 设置新堆的根节点的NPL = 右子节点的NPL + 1

关于堆合并的具体过程,可以参考 左倾堆-图文解析

实现(c++)

二叉堆和可合并堆经常用在优先队列(priority queue)中,下面的代码就进行了堆的合并、元素的入队和出队

#include<iostream>
using namespace std;

struct TreeNode{
	int key;
	int npl;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int k){
		key = k;
		npl = 0;
		left = right = NULL;
	}
};
void Swap(TreeNode* node1, TreeNode* node2){
	TreeNode* tmp = node1;
	node1 = node2;
	node2 = tmp;
}

//左倾堆的合并操作
TreeNode* Merge(TreeNode* heap1, TreeNode* heap2){
	//如果其中一个为空堆,则直接返回另外一个
	if (!heap1)
		return heap2;
	if (!heap2)
		return heap1;
	//选择“较小堆”,将其根节点作为新堆的根节点
	if (heap1->key > heap2->key){
		Swap(heap1, heap2);
	}
	//将较小堆的右子堆和较大堆进行合并,并置为较小堆的右子堆
	heap1->right = Merge(heap1->right, heap2);
	if (heap1->left == NULL || (heap1->left && heap1->right && heap1->left->npl < heap1->right->npl)){ //如果堆的根节点的左子结点的npl小于右子节点的npl,则交换左右子节点
		Swap(heap1->left, heap1->right);
	}

	if (heap1->right == NULL)
		heap1->npl = 1;
	else
		heap1->npl = heap1->right->npl + 1; //新堆的npl设为右子节点的npl +1
	return heap1;
}

//将元素k插入堆 heap中,即元素入队。 注意这里使用指针的引用
void Enqueue(TreeNode*& heap, int k){
	if (!heap){
		heap = new TreeNode(k);
		return;
	}
	TreeNode* new_heap = new TreeNode(k);
	heap = Merge(heap, new_heap);
}

//元素出队,注意这里使用指针的引用
int Dequeue(TreeNode*& heap){
	int result = heap->key;
	heap = Merge(heap->left, heap->right);
	return result;
}
时间: 2024-10-12 18:28:23

左倾堆的相关文章

10、【堆】左倾堆

一.左倾堆的介绍 左倾堆(leftist tree 或 leftist heap),又被成为左偏树.左偏堆,最左堆等.它和二叉堆一样,都是优先队列实现方式.当优先队列中涉及到"对两个优先队列进行合并"的问题时,二叉堆的效率就无法令人满意了,而本文介绍的左倾堆,则可以很好地解决这类问题. 左倾堆的定义 左倾堆是一棵二叉树,它的节点除了和二叉树的节点一样具有左右子树指针外,还有两个属性:键值和零距离.(01) 键值的作用是来比较节点的大小,从而对节点进行排序.(02) 零距离(英文名NPL

左倾堆C++实现

1 #include <iostream> 2 #include <vector> 3 #include <queue> 4 using namespace std; 5 template <typename T> 6 class LeftlistNode 7 { 8 public: 9 T key; 10 int npl; 11 LeftlistNode* left; 12 LeftlistNode* right; 13 14 LeftlistNode(T

探秘堆结构

一.概述 此处所说的堆为数据结构中的堆,而非内存分区中的堆.堆通常可以被看做是树结构,满足两个性质:1)堆中任意节点的值总是不大于(不小于)其子节点的值:2)堆是一棵完全树.正是由于这样的性质,堆又被称为优先队列.根据性质一,将任意节点不大于其子节点的堆称为最小堆或最小优先队列,反之称为最大堆或最大优先队列.优先队列在操作系统作业调度的设计中有着举足轻重的作用.之前写了一篇优先队列的文章,详见算法导论第六章优先队列. 常见的堆结构,有二叉堆.左倾堆.斜堆.二项堆.斐波那契堆等.斐波那契堆在前文算

左式堆的实现与详解

定义:左式堆(Leftist Heaps)又称作最左堆.左倾堆,是计算机语言中较为常用的一个数据结构.左式堆作为堆的一种,保留了堆的一些属性.第1,左式堆仍然以二叉树的形式构建:第2,左式堆的任意结点的值比其子树任意结点值均小(最小堆的特性).但和一般的二叉堆不同,左式堆不再是一棵完全二叉树(Complete tree),而且是一棵极不平衡的树. 性质: 零路径长:从X到一个不具有两个儿子的结点的最短路径的长. 1. 任一结点的零路径长比他的诸儿子结点的零路径长的最小值多1 2. 父节点属性值小

堆之左式堆和斜堆

d-堆 类似于二叉堆,但是它有d个儿子,此时,d-堆比二叉堆要浅很多,因此插入操作更快了,但是相对的删除操作更耗时.因为,需要在d个儿子中找到最大的,但是很多算法中插入操作要远多于删除操作,因此,这种加速是现实的. 除了不能执行find去查找一般的元素外,两个堆的合并也很困难. 左式堆 左式堆可以有效的解决上面说的堆合并的问题.合并就涉及插入删除,很显然使用数组不合适,因此,左式堆使用指针来实现.左式堆和二叉堆的区别:左式堆是不平衡的.它两个重要属性:键值和零距离 零距离(英文名NPL,即Nul

堆之二叉堆

堆的定义 堆通常是一个可以被看做一棵树,它满足下列性质: 堆中任意节点的值总是不大于(不小于)其子节点的值: 堆总是一棵完全树. 将任意节点不大于其子节点的堆叫做最小堆或小根堆,而将任意节点不小于其子节点的堆叫做最大堆或大根堆.常见的堆有二叉堆.左倾堆.斜堆.二项堆.斐波那契堆等等. 二叉堆 堆有两种性质:结构性和堆序性 结构性:堆是一颗完全二叉树.若设完全二叉树的高度是h,则它的节点数是2^h到2^(h+1) - 1:则节点数为N的完全二叉树的高度O(logn). 完全二叉树中父子节点位置关系

二项堆(一)之 图文解析 和 C语言的实现

概要 本章介绍二项堆,它和之前所讲的堆(二叉堆.左倾堆.斜堆)一样,也是用于实现优先队列的.和以往一样,本文会先对二项堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理一样,选择其中之一进行了解即可.若文章有错误或不足的地方,请不吝指出! 目录1. 二项树的介绍2. 二项堆的介绍3. 二项堆的基本操作4. 二项堆的C实现(完整源码)5. 二项堆的C测试程序 转载请注明出处:http://www.cnblogs.com/skywan

算法导论第十九章 斐波那契堆

<算法导论>第二版中在讨论斐波那契堆之前还讨论了二项堆,但是第三版中已经把这块的内容放到思考题中,究极原因我想大概是二项堆只是个引子,目的是为了引出斐波那契堆,便于理解,而且许多经典的算法实现都是基于斐波那契堆,譬如计算最小生成树问题和寻找单源最短路径问题等,此时再把二项堆单独作为一章来讲显然没有必要.类似的堆结构还有很多,如左倾堆,斜堆,二项堆等,下次我打算开一篇博客来记录下它们的异同点. 一.摊还分析(第十七章) 这些高级的数据结构的性能分析一般是基于一个技术——摊还分析,可以理解成一种时

My集合框架第六弹 左式堆

左式堆(Leftist Heaps)又称作最左堆.左倾堆.左式堆作为堆的一种,保留了堆的一些属性. 第1,左式堆仍然以二叉树的形式构建: 第2,左式堆的任意结点的值比其子树任意结点值均小(最小堆的特性).但和一般的二叉堆不同,左式堆不再是一棵完全二叉树(Complete tree),而且是一棵极不平衡的树. package com.wpr.collection; /** * 左式堆:二叉堆缺点,首先,只能查找最小元素:其次,将两个堆合并的操作很麻烦 * 注意:所有支持有效合并的高级数据结构都需要