优先队列(堆) -数据结构(C语言实现)

数据结构与算法分析

优先队列

模型

  • Insert(插入) == Enqueue(入队)
  • DeleteMin(删除最小者) == Dequeue(出队)

基本实现

  • 简单链表:在表头插入,并遍历该链表以删除最小元

    时间代价昂贵

  • 二叉查找树

    二叉查找树支持许多不需要的操作,实现麻烦,不值得
    最合适:二叉堆


二叉堆

堆的两种性质

结构性

  • 完全二叉树:除底层外完全填满,底层也是从左至右填
  • 完全二叉树的高为
  log N
  • 分布很有规律可以用数组实现

左儿子 = 2i

右儿子 = 2i + 1

堆序性

  • 树的最小元应该在根节点上
  • 每个节点X,X的父亲的关键字应该小于或等于X的关键字

实现

优先队列的声明

struct HeapStrcut ;
typedef struct HeapStruct *PriorityQueue ;

PriorityQueue Intialize(int MaxElement) ;
void Destory(PriorityQueue H) ;
void MakeEmpty(PriorityQueue H) ;
void Insert(ElementType X, PriorityQueue H) ;
ElementType DeleteMin(PriotityQueue H) ;
ElementType Find(PritityQueue H) ;
int IsEmpty(PriorityQueue H) ;
int IsFull(PriorityQueue H) ;

srtuct HeapStruct
{
    int Capacity ;
    int Size l
    ElementType *Elements ;
}

初始化

PriorityQueue Intialize(int MaxElement)
{
    PriorityQueue H ;
    H->Elements = malloc((MaxElement + 1) * sizeof(ElementType) ;
    if(H->Elements == NULL)
        FatalError("内存不足");
    H->Capacity = MaxElement ;
    H->Size = 0;
    H->Elements[0] = MinData ;//在根节点赋一个绝对的小的值

    return H ;
}

Insert操作

上滤

void Insert(ElementType X, PriorityQueue H)
{
    int i ;
    if(IsFull(H))
        Error("堆满") ;

    for(i = ++H->Size;H->Elements[i/2] > X;i/2)
        H->Elenemts[i] = H->Elements[i/2] ;
    H->Elements[i] = X ;

    return H ;
}

Delete函数

下滤

先拿到最后一个元素,和当前被删除后剩下的空穴的最小儿子比较,如果儿子小则换至空穴,继续下滤,反之将最后一个元素放置空穴结束下滤

ElementType Insert(PriorityQueue H)
{

    int i,Child ;
    ElementType MinElement,LastElement ;

    if(IsEmpty(H))
    {
        Error("堆为空") ;
        return H->Elements[0] ;
    }
    MinElement = H->Elements[1];
    LastElement = H->Elements[H->Size--] ;
    for(i = 1; i * 2 <= H->Size;i = Child)
    {
        Child = i * 2;
        if(Child != H->Size && H->Element[Child] > H->Elements[Child + 1])
            Child ++ ;

        if(LastElement > H->Elements[Child)
            H->Elements[i] = H->Elements[Child] ;
        else break ;
    }
    H->Elements[i] = LastElement ;

    return MinElenemt;
}

左式堆

性质

高效支持Merge操作

和二叉树唯一区别在于:左式堆不是理想平衡的

对于堆中的每一个节点X,左儿子的零路径长NPL大于右儿子的零路径长NPL

- 零路径长(NPL):从该节点到一个没有两个儿子的节点的最短路径长

左式堆的类型声明

PriorityQueue Intailize(void) ;
ElementType FindMin(PriorityQueue H) ;
int IsEmpty(PriorityQueue H) ;
PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2) ;

#define Insert(X,H) (H = Insert1(X,H)) ; //为了兼容二叉堆

PriorityQueue Insert1(ElementType, PriorityQueue H) ;
PriorityQueue DeleteMin(PriorityQueue H) ;

sturct TreeNode
{
    ElementType Element ;
    PriorityQueue Left ;
    PriorityQueue Right ;
    int Npl ;
}

Merge操作

驱动程序

PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2)
{
    if(H1 == NULL)
        return H2 ;
    eles if(H2 == NULL)
        return H1 ;
    else if(H1->Element > H2->Element)
        return Merge1(H1,H2) ;
    else
        return Merge1(H1S,H2) ;
}

实际操作

PriorityQueue Merge1(PriortyQueue H1,PriorityQueue H2)
{
    if(H1->Left == NULL)
        H1->Left = H2 ;
    else
    {
        H2->Right = Merge1(H1->Right,H2) ;
        if(H1->Left->Npl < H1->Right->Npl)
            SwapChildren(H1) ;
        H1->Npl = H1->Right->Npl + 1;
    }

    return H1 ;
}

Insert操作

PriorityQueue Insert(ElementType X,PriorityQueue H)
{
    PriorityQueue SinglNode ;
    SinglNode = malloc(sizeof(TreeNode)) ;
    if(SinglNode == NULL)
        FatalError("内存不足") ;
    else
    {
        SingleNode->Element = X ;
        SingleNode->Npl = 0 ;
        SingleNode->Left = SingleNode->Right = NULL ;
        Merge(SingleNode,H) ;
    }
    return H ;
}

Delete操作

PriorityQueue DeleteMin1(PriorityQueue H)
{
    PriorityQueue LeftHeap,RightHeap ;

    if(IsEmpty(H))
        FatalError("队列为空") ;
    else
    {
        LeftHeap = H1->Left ;
        RightHeap = H1->Right ;
        free(H) ;
        Merge(LeftHeap,RightHeap) ;
    }
}

二项队列

结构

  • 二项队列是堆序树的集合,称为森林
  • 堆序中每颗树都是有约束的树,称为二项树
  • 高度为k的二项树有一颗二项树Bk-1附接到另一颗二项树Bk-1的根上

二项队列的实现

二项队列将是二项树的数组

二项树的每个节点包含数据,第一个儿子和兄弟

二项队列的类型声明 `

typedef struct BinNode *Position ;
typedef struct Collection *BinQueue ;

struct BinNode
{
    ElementType Element ;
    Position LeftChild ;
    Position NextBiling ;
}

typedef Position BinTree ;

struct Collection
{
    int CurrentSize ;
    BinTree TheTrees[MaxTree] ;
}

Merge操作

合并两个相同大小的两颗二项树

BinTree ConbineTrees(BinTree T1,BinTree T2)
{
    if(T1->Element > T2->Element)
        return CombineTree(T2,T1) ;
    T2->NextBling = T1->LeftChild ;
    T1->LeftChild = T2 ;

    return T1 ;
}

合并两个优先队列

BinQueue Merge(BinQueue H1,BinQueue H2)
{
    BinTree T1,T2,Carry = NULL ;
    int i ,j ;
    if(H1->CurrentSize + H2->CurrentSize > Capacity)
        Error("合并后过大") ;

    H1->CurrentSize += H2->CurrentSize ;
    for(i = 0;j = 1;j <= H1->CurrentSize; i++,j *= 2)
    {
        T1 = H1->TheTree[i] ;
        T2 = H2->TheTree[i] ;

        switch(!!T1 + 2 * !!T2 + 4 * !!Carry)
        {
            case 0 : //空树
            case 1:
                break ; //只有H1
            case 2:
                H1->TheTree[i] = T2
                H2->TheTree[i] = NULL ;
                break ;
            case 4:
                H1->TheTree[i] = Carry ;
                Carry = NULL ;
            case 3: //h1 and h2
                Carry = CombineTrees(T1,T2) ;
                H1->TheTree[i] = H1->TheTree[i] = NULL ;
                break ;
            case 5: //h1 and carry
                Carry = ConbineTrees(T1,Carry) ;
                H1->TheTrees[i] = NULL ;
            case 6:
                Carry = ConbineTrees(T2,Carry) ;
                H2->TheTrees[i] = NULL ;
            case 7: //都有
                H1->TheTree[i] = Carry ;
                Carry = CombineTrees(T1,T2) ;
                H2->TheTrees[i] = NULL ;
                break ;

        }

    }
    return H1 ;
}

总结

优先队列可以用二叉堆实现,简单快速

但考虑到Merge操作,又延申了左式堆和二次队列

原文地址:https://www.cnblogs.com/secoding/p/9609369.html

时间: 2024-07-29 23:08:40

优先队列(堆) -数据结构(C语言实现)的相关文章

堆数据结构+堆排序+最大优先队列的堆的实现

对于堆排序,首先要先知道什么是堆数据结构,堆数据结构就是一个完全二叉树,但是它有自己的性质. 例如最大堆的性质为:A[PARENT[i]]>=A[i]:即每一个结点的值大于等于其左右孩子的值,小于等于其父节点的值.我们在这里只讨论最大堆的情况.我们知道一颗完全二叉树对应一个最大堆的形式,我们要做的就是将二叉树转化为最大堆,这就是所谓的最大堆的维护,我们定义函数MaxheapFY(A,i)来进行操作. 代码: /** *MaxheapFY(A,i):维护位置i最大堆性质,此时假设left(i)和r

优先队列(堆)

优先队列(priority queue)是允许至少两种操作的数据结构:Insert及DeleteMin(删除最小者).相当于队列中的Enqueue.Dequeue操作. 优先队列可以用链表.二叉查找树.二叉堆等实现. 二叉堆 1. 结构性质 堆(heap)是一棵完全被填满的二叉树,有可能的例外是在底层,底层上的元素从左向右填入.这样的树称之为完全二叉树. 一棵高为h的完全二叉树有2h到2h+1-1个节点.完全二叉树的高为logN. 完全二叉树可以用数组来表示,如果从0开始,对于数组中任意i位置的

《数据结构-C语言版》(严蔚敏,吴伟民版)课本源码+习题集解析使用说明

先附上文档归类目录: 课本源码合辑  链接??? <数据结构>课本源码合辑 习题集全解析  链接??? <数据结构题集>习题解析合辑 博主有话说: 01.自学编程,难免思路阻塞,所以从今天起,我(StrayedKing)决定在本博客陆续更新严蔚敏,吴伟民版<数据结构-C语言版>各章节的课本源码和配套习题集答案解析,目的是为了整理数据结构中的知识点,并与网友交流意见,集思广益,共同进步.        ★注★ 左侧随笔分类下用两个栏目:<课本源码>.<习

数据结构C语言实现——线性链表

declaration.h #ifndef DECLARATION_H_INCLUDED #define DECLARATION_H_INCLUDED #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define ElemType int typedef ElemType* Triplet; typedef int Status; type

实现基于数据结构的语言

创建任何 DSL 都应该从定义需要解决的问题开始.这里,我们需要定义一个 DSL 库(有时也称为组合库,combinators library),用于二维图形,这是一个很明显的选择.这个示例演示如何用大量简单的基本图形构建出复杂的结构.在计算机屏幕上的图像本质上就是线条和多边形的集合,尽管显示出来的图形可能极其复杂.这个示例用四个模块表现:第一,清单 12-1,提供创建图片的基本操作(primitives):第二,清单12-2,如何实现解释图片:清单 12-3 和清单 12-4 用示例演示如何使

堆 (数据结构)

堆 (数据结构)[工程下载>>>] 堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权.堆即为解决此类问题设计的一种数据结构. 1.1 逻辑定义 n个元素序列k1,k2...ki...kn,当且仅当满足下列关系时称之为堆: (ki<=k2i,ki<=k2i+1)或者(k

数据结构c语言版串的操作

#include<stdio.h> #include<malloc.h> #include<string.h> //定义字符串的结构体 typedef struct { char *str;//字符串 int maxLength;//最大可以存放字符的长度 int length;//目前的字符长度 }DString; //1.初始化操作 //初始化操作用来建立和存储串的动态数组空间以及给相关的数据域赋值 void Initiate(DString *s,int max,

堆的C语言实现

在C++中,可以通过std::priority_queue来使用堆. 堆的C语言实现: heap.c 1 /** @file heap.c 2 * @brief 堆,默认为小根堆,即堆顶为最小. 3 */ 4 #include <stdlib.h> /* for malloc() */ 5 #include <string.h> /* for memcpy() */ 6 typedef int heap_elem_t; // 元素的类型 7 8 /** 9 * @struct 10

数据结构C语言实现介绍

刚刚结束的大二上学期学习了数据机构C语言版这门课,在接下来的一个月中准备把课程的代码和知识点总结一下,就有了这个专题:数据结构C语言实现,在这里我将用C语言实现最基本的数据结构以及一些基本的算法,以下是我这个专题的内容: 1. 数据结构及算法简介: 主要介绍数据结构及算法的基础知识,一些基本的概念和术语,以及算法的定义.算法的特性.算法的时间复杂度和空间复杂度 2.顺序表的定义及算法实现: 主要介绍顺序表的定义及特点,实现顺序表的存储结构以及基本操作 3.单链表的定义及算法实现:  主要介绍单链

深入浅出数据结构C语言版(15)——优先队列(堆)

在普通队列中,元素出队的顺序是由元素入队时间决定的,也就是谁先入队,谁先出队.但是有时候我们希望有这样的一个队列:谁先入队不重要,重要的是谁的"优先级高",优先级越高越先出队.这样的数据结构我们称之为优先队列(priority queue),其常用于一些特殊应用,比如操作系统控制进程的调度程序. 那么,优先队列该如何实现呢?我们可以很快给出三种解决方案. 1.使用链表,插入操作选择直接插入到表头,时间复杂度为O(1),出队操作则遍历整个表,找到优先级最高者,返回并删除该结点,时间复杂度