1.左式堆的性质
我们把任一节点X的零路径长(null path length,NPL)Npl(X)定义为从X到一个没有两个儿子的节点的最短路径的长。因此,具有0个或1个儿子的节点的Npl为0,而Npl(NULL) = -1。
左式堆性质是:对于堆中的每一个节点X,左儿子的零路径长至少与右儿子的零路径长一样大。下图左边是左式堆,右边不是。
2.左式堆的操作
(1)合并
合并是左式堆最重要的操作。插入只是合并的特殊情况。下面采用递归来演示如何进行左式堆的合并。下图是左式堆H1和左式堆H2。
如果这两个堆中有一个堆是空的,那么我们可以返回另一个堆。否则为了合并这两个堆,我们需要比较它们的根。首先,我们将具有大的根值的堆与具有小的根值的堆的右子堆合并。在本例中,我们递归地将H2与H1中根在8处的右子堆合并。得到下图。
由于这棵树是递归形成的,而我们尚未对算法描述完毕,因此我们还不能说明该堆是如何得到的。不过,有理由假设,最后的结果是一棵左式堆,因为它是通过递归的步骤得到的。现在我们让这个新的堆成为H1的右儿子,得到下图。
虽然最后得到的堆满足堆序性质,但是,它不是左式堆,因为根的左子树的零路径长为1而根的右子树的零路径长为2。由于此时左右子树都是左式堆,所以只要交换根的左右儿子即可。下图得到最后的结果。
将算法的描述直接翻译成代码。除了增加Npl域之外,算法中的类型定义与二叉树是相同的。另外当交换左右子树的时候,注意更新Npl的值。
(2)插入
插入只是特殊的合并的特殊情况,因为我们可以把插入看成单节点堆与一个大的堆的Merge。
3.左式堆的实现
3.1 头文件
//
// LeftHeap.h
// LeftHeap
//
// Created by Wuyixin on 2017/5/31.
// Copyright © 2017年 Coding365. All rights reserved.
//
#ifndef LeftHeap_h
#define LeftHeap_h
#include <stdio.h>
/* 用来标记不合法的元素的值 */
extern const int ELEM_MIN;
struct TreeNode;
typedef struct TreeNode *PriorityQueue;
typedef int ElemType;
/* 初始化 */
PriorityQueue initialize();
/* 查找最小值 */
ElemType find_min(PriorityQueue h);
/* 是否空 */
int is_empty(PriorityQueue h);
/* 合并堆 */
PriorityQueue merge(PriorityQueue h1,PriorityQueue h2);
/* 插入元素 */
PriorityQueue insert(ElemType x,PriorityQueue h);
/* 删除最小元 */
PriorityQueue delete_min(PriorityQueue h);
/* 遍历 */
void print_heap(PriorityQueue h);
struct TreeNode
{
ElemType elem;
PriorityQueue left;
PriorityQueue right;
int npl;/*零路径长(null path length)*/
};
#endif /* LeftHeap_h */
3.2 实现文件
//
// LeftHeap.c
// LeftHeap
//
// Created by Wuyixin on 2017/5/31.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include "LeftHeap.h"
#include <stdlib.h>
#include <limits.h>
const int ELEM_MIN = INT_MIN;
void error(char* message){
printf("%s/n",message);
}
void fatal_error(char* message){
printf("%s/n",message);
exit(EXIT_FAILURE);
}
/* 初始化 */
PriorityQueue initialize(){
PriorityQueue h = (PriorityQueue)malloc(sizeof(struct TreeNode));
if (h == NULL)
fatal_error("out of space!!!");
h->left = NULL;
h->right = NULL;
h->npl = -1;//空节点
return h;
}
/* 查找最小值 */
ElemType find_min(PriorityQueue h){
if (is_empty(h)) return ELEM_MIN;
return h->elem;
}
/* 是否空 */
int is_empty(PriorityQueue h){
return h == NULL || h->npl == -1;
}
/* 是否头节点*/
int is_head(PriorityQueue h){
return h != NULL && h->npl == -1 && h->left == NULL && h->right == NULL;
}
static void swap_children(PriorityQueue h){
PriorityQueue temp = h->left;
h->left = h->right;
h->right = temp;
}
static PriorityQueue _merge(PriorityQueue h1,PriorityQueue h2){
/* 单节点,将h2赋给h1的左子树,左子树的节点数一定要大于等于右子树*/
if (h1->left == NULL)
h1->left = h2;
else{
h1->right = merge(h1->right, h2);/* 注意调用merge而不是_merge */
if (h1->left->npl < h1->right->npl)
swap_children(h1);
h1->npl = h1->right->npl + 1;
}
return h1;
}
/* 合并堆 */
PriorityQueue merge(PriorityQueue h1,PriorityQueue h2){
if (h1 == NULL)
return h2;
if (h2 == NULL)
return h1;
if (h1->elem < h2->elem)
return _merge(h1, h2);
else
return _merge(h2, h1);
}
/* 插入元素 */
PriorityQueue insert(ElemType x,PriorityQueue h){
if (is_head(h)){
h->elem = x;
h->npl = 0;
return h;
}
PriorityQueue singlenode = (PriorityQueue)malloc(sizeof(struct TreeNode));
if (singlenode == NULL)
fatal_error("out of space!!!");
else{
singlenode->elem = x;
singlenode->npl = 0;
singlenode->left = NULL;
singlenode->right = NULL;
h = merge(singlenode, h);
}
return h;
}
/* 删除最小元 */
PriorityQueue delete_min(PriorityQueue h){
if (is_empty(h)){
error("Priority queue is empty");
return h;
}
PriorityQueue left,right;
left = h->left;
right = h->right;
free(h);
return merge(left, right);
}
static void _print_heap(PriorityQueue h,int type){
if (!is_empty(h)){
char* s_type = "";
if (type == 1) s_type = "root";
else if(type == 2) s_type = "left";
else if (type == 3) s_type = "right";
printf("(elem:%d,npl:%d,type:%s) ",h->elem,h->npl,s_type);
_print_heap(h->left,2);
_print_heap(h->right,3);
}
}
/* 遍历 */
void print_heap(PriorityQueue h){
_print_heap(h, 1);
}
3.3 调用
//
// main.c
// LeftHeap
//
// Created by Wuyixin on 2017/5/31.
// Copyright © 2017年 Coding365. All rights reserved.
//
#include <stdio.h>
#include "LeftHeap.h"
int main(int argc, const char * argv[]) {
PriorityQueue h1 = initialize();
h1 = insert(1, h1);
h1 = insert(2, h1);
h1 = insert(3, h1);
h1 = insert(4, h1);
h1 = insert(5, h1);
print_heap(h1);
PriorityQueue h2 = initialize();
h2 = insert(6, h2);
h2 = insert(7, h2);
h2 = insert(8, h2);
h2 = insert(9, h2);
h2 = insert(10, h2);
printf("\n");
print_heap(h2);
printf("\n");
print_heap(merge(h1, h2));
return 0;
}