概要

本章介绍斜堆。和以往一样,本文会先对斜堆的理论知识进行简单介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现;实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可。若文章有错误或不足的地方,请不吝指出!

目录
1. 斜堆的介绍
2. 斜堆的基本操作
3. 斜堆的C实现(完整源码)
4. 斜堆的C测试程序

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3638493.html


更多内容:数据结构与算法系列 目录

 

斜堆的介绍

斜堆(Skew heap)也叫自适应堆(self-adjusting heap),它是左倾堆的一个变种。和左倾堆一样,它通常也用于实现优先队列。它的合并操作的时间复杂度也是O(lg n)。

相比于左倾堆,斜堆的节点没有"零距离"这个属性。除此之外,它们斜堆的合并操作也不同。斜堆的合并操作算法如下:
(01) 如果一个空斜堆与一个非空斜堆合并,返回非空斜堆。
(02) 如果两个斜堆都非空,那么比较两个根节点,取较小堆的根节点为新的根节点。将"较小堆的根节点的右孩子"和"较大堆"进行合并。
(03) 合并后,交换新堆根节点的左孩子和右孩子。
        第(03)步是斜堆和左倾堆的合并操作差别的关键所在,如果是左倾堆,则合并后要比较左右孩子的零距离大小,若右孩子的零距离 > 左孩子的零距离,则交换左右孩子;最后,在设置根的零距离。

 

斜堆的基本操作

1. 头文件

#ifndef _SKEW_HEAP_H_
#define _SKEW_HEAP_H_

typedef int Type;

typedef struct _SkewNode{
    Type   key;                // 关键字(键值)
    struct _SkewNode *left;    // 左孩子
    struct _SkewNode *right;   // 右孩子
}SkewNode, *SkewHeap;

// 前序遍历"斜堆"
void preorder_skewheap(SkewHeap heap);
// 中序遍历"斜堆"
void inorder_skewheap(SkewHeap heap);
// 后序遍历"斜堆"
void postorder_skewheap(SkewHeap heap);

// 获取最小值(保存到pval中),成功返回0,失败返回-1。
int skewheap_minimum(SkewHeap heap, int *pval);
// 合并"斜堆x"和"斜堆y",并返回合并后的新树
SkewNode* merge_skewheap(SkewHeap x, SkewHeap y);
// 将结点插入到斜堆中,并返回根节点
SkewNode* insert_skewheap(SkewHeap heap, Type key);
// 删除结点(key为节点的值),并返回根节点
SkewNode* delete_skewheap(SkewHeap heap);

// 销毁斜堆
void destroy_skewheap(SkewHeap heap);

// 打印斜堆
void print_skewheap(SkewHeap heap);

#endif

SkewNode是斜堆对应的节点类。

 

2. 合并

/* 
 * 合并"斜堆x"和"斜堆y"
 *
 * 返回值:
 *     合并得到的树的根节点
 */
SkewNode* merge_skewheap(SkewHeap x, SkewHeap y)
{
    if(x == NULL)
        return y;
    if(y == NULL)
        return x;

    // 合并x和y时,将x作为合并后的树的根;
    // 这里的操作是保证: x的key < y的key
    if(x->key > y->key)
        swap_skewheap_node(x, y);

    // 将x的右孩子和y合并,
    // 合并后直接交换x的左右孩子,而不需要像左倾堆一样考虑它们的npl。
    SkewNode *tmp = merge_skewheap(x->right, y);
    x->right = x->left;
    x->left  = tmp;

    return x;
}

merge_skewheap(x, y)的作用是合并x和y这两个斜堆,并返回得到的新堆。merge_skewheap(x, y)是递归实现的。

 

3. 添加

/* 
 * 新建结点(key),并将其插入到斜堆中
 *
 * 参数说明:
 *     heap 斜堆的根结点
 *     key 插入结点的键值
 * 返回值:
 *     根节点
 */
SkewNode* insert_skewheap(SkewHeap heap, Type key)
{
    SkewNode *node;    // 新建结点

    // 如果新建结点失败,则返回。
    if ((node = (SkewNode *)malloc(sizeof(SkewNode))) == NULL)
        return heap;
    node->key = key;
    node->left = node->right = NULL;

    return merge_skewheap(heap, node);
}

insert_skewheap(heap, key)的作用是新建键值为key的结点,并将其插入到斜堆中,并返回堆的根节点。

 

4. 删除

/* 
 * 取出根节点
 *
 * 返回值:
 *     取出根节点后的新树的根节点
 */
SkewNode* delete_skewheap(SkewHeap heap)
{
    SkewNode *l = heap->left;
    SkewNode *r = heap->right;

    // 删除根节点
    free(heap);

    return merge_skewheap(l, r); // 返回左右子树合并后的新树
}

delete_skewheap(heap)的作用是删除斜堆的最小节点,并返回删除节点后的斜堆根节点。

 

注意关于斜堆的"前序遍历"、"中序遍历"、"后序遍历"、"打印"、"销毁"等接口就不再单独介绍了。后文的源码中有给出它们的实现代码,Please RTFSC(Read The Fucking Source Code)!

 

斜堆的C实现(完整源码)

斜堆的头文件(skewheap.h)

 1 #ifndef _SKEW_HEAP_H_
 2 #define _SKEW_HEAP_H_
 3 
 4 typedef int Type;
 5 
 6 typedef struct _SkewNode{
 7     Type   key;                    // 关键字(键值)
 8     struct _SkewNode *left;    // 左孩子
 9     struct _SkewNode *right;    // 右孩子
10 }SkewNode, *SkewHeap;
11 
12 // 前序遍历"斜堆"
13 void preorder_skewheap(SkewHeap heap);
14 // 中序遍历"斜堆"
15 void inorder_skewheap(SkewHeap heap);
16 // 后序遍历"斜堆"
17 void postorder_skewheap(SkewHeap heap);
18 
19 // 获取最小值(保存到pval中),成功返回0,失败返回-1。
20 int skewheap_minimum(SkewHeap heap, int *pval);
21 // 合并"斜堆x"和"斜堆y",并返回合并后的新树
22 SkewNode* merge_skewheap(SkewHeap x, SkewHeap y);
23 // 将结点插入到斜堆中,并返回根节点
24 SkewNode* insert_skewheap(SkewHeap heap, Type key);
25 // 删除结点(key为节点的值),并返回根节点
26 SkewNode* delete_skewheap(SkewHeap heap);
27 
28 // 销毁斜堆
29 void destroy_skewheap(SkewHeap heap);
30 
31 // 打印斜堆
32 void print_skewheap(SkewHeap heap);
33 
34 #endif
View Code

相关文章:

  • 2021-04-03
  • 2021-12-21
  • 2022-12-23
  • 2021-09-21
猜你喜欢
  • 2021-08-28
  • 2022-12-23
  • 2021-12-15
  • 2021-09-28
  • 2021-11-27
  • 2021-07-14
相关资源
相似解决方案