# 堆 Heap  

优先队列(Priority Queue)  

结构性:用 *数组* 表示的完全二叉树;  

有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)  

    * “最大堆(MaxHeap)”,也称“大顶堆”:最大值  

    * “最小堆(MinHeap)”,也称“小顶堆” :最小值  

主要操作有:  

• MaxHeap Create( int MaxSize ):创建一个空的最大堆。  

• Boolean IsFull( MaxHeap H ):判断最大堆H是否已满。  

• Insert( MaxHeap H, ElementType item ):将元素item插入最大堆H。  

• Boolean IsEmpty( MaxHeap H ):判断最大堆H是否为空。  

• ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高优先级)。  

## 结构

```c

typedef struct HNode *MaxHeap;

struct HNode {

    ElementType *Elements; // 存储堆元素的数组

    int Size;   // 堆的当前元素的个数

    int Capacity  // 堆的最大容量

}

```

## 创建

```c

MaxHeap CreateHeap(int Maxsize)

{

    MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));

    H->Elements = malloc((MaxSize+1) * sizeof(ElementType)); // 因为这里是一个数组,需要分配空间

    H->Size = 0; // 当前是空的

    H->Capacity = MaxSize;  // 堆的最大容量

    H->Elements[0] = MaxSize; /* 定义“哨兵”为大于堆中所有可能元素的值,便于以后操作 */

    return H;

}

```

## 插入

将新增结点插入到从其父结点到根结点的有序序列中  

将新item放在最后的位置Size+1, 然后跟他的父节点i/2比较,不断把父节点往下(子节点)移动,直到其父节点大于item

```c

void InsertHeap(MaxHeap H, ElementType item)

{

    int i;

    if (IsFull(H)){

        printf("FULL\n");

        return;

    }

    i = ++H->Size;  // H->Size++; i = H->Size; 把新增元素放在末尾H->Size++的位置上

    for(; H->Elements[i/2] < item; i/=2){  // 其父节点小于它

        H->Elements[i] = H->Elements[i/2]; // 把它的父节点,向下过滤, 插入的item向上过滤

    }

    // 当它的父结点[i/2]比它大的时候, 跳出循环

    H->Elements[i] = item;  // 填上item

}


```

# 删除  

取出根结点(最大值)元素,同时删除堆的一个结点。  

* 最后的元素替补根的位置

* 有序化, 父结点和更大的那个子结点比较,将子结点不断往上移, 直到父结点不子结点大  

```c

ElementType DeleteMax(MaxHeap H)

{

    int parent, child;

    ElementType MaxItem, temp;

    if(IsEmpty(H)){

        printf("Empty\n");

        return;

    }

    MaxItem = H->Elements[1]; // 取出最大值

    /* 用最大堆中最后一个元素从根节点开始向上过滤下层节点 */

    temp = H->Elements[Size];  // 把堆中最后一个值,交给temp

    Size--;

    for(parent=1; parent*2 <= H->Size; parent=child)

    {

        child = parent*2  // 左儿子

        /* child=左右儿子中大的那个, 当右儿子存在,且右儿子的值比左儿子大时,让child=右儿子 */

        if((child!= H->Size) &&

        (H->Elements[child] < H->Elements[child+1]))

            child++;

       

        /* 当temp比child的值大时跳出循环 */

        if (temp >= Elements[child])

            break;

        else

            H->Elements[parent] = H->Elements[child]; //当parent < child,这个parent位置上变为child的值

    }

    H->Elements[parent] = temp;

    return MaxItem;

}

```

# 堆排序  

方法1:通过插入操作,将N个元素一个个相继插入到一个初 始为空的堆中去,其时间代价最大为O(N logN)。

方法2:在线性时间复杂度下建立最大堆。O(N)  

(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性  

(2)调整各结点位置,以满足最大堆的有序特性。  

```c

void BuildHeap(MaxHeap H){

    int i;

    for(i = H->Size/2; i>0; i--)

    {// 从最后一个结点的父节点开始,到根节点为止

        PercDown(H, i);

    }

}

// 下滤函数, 将Maxheap中以H->Data[p]为根的子堆调整为最大堆

void PercDown( MaxHeap H, int p)

{

    int parent, child;

    X = H->Data[p]; // 取出根节点的值

    for(parent =  p; parent*2 <= H->Size; parent = child)

    {

        child = parent * 2;

        if( (child != H->Size) && (H->Data[child] < H->Data[child+1]))

        {

            child++;

        }

        if (X > H->Data[child])

            break;

        else // 将X下滤

            H->Data[parent] = H->Data[child];

    }

    H->Data(parent) = X;

}

```

# 哈夫曼树与哈夫曼编码

带权路径WPL Weighted Path Length)长度最小, 最优二叉树.  

数据结构:

```c

typedef struct TreeNode *HuffmanTree;

struct TreeNode{

    int Weight;

    HaffmanTree left;

    HaffmantREE Right;

}

```

利用最小堆进行构造:

```c

HuffmanTree Huffman(MinHeap H)

{

    int i;

    HuffmanTree T;

    BuildMinHeap(H); // 将H->Elements[]按照权重调整为最小堆

    for(i=1; i < H->Size; i++) // 做size-1次合并

    {

        T = malloc(sizeof(struct TreeNode)); // 建立新结点

        /*从最小堆中删除一个结点,作为新T的左子结点*/

        T->Left = DeleteMin(H);

        T->Right = DeleteMin(H);

        /*计算新权值*/

        T->Weight = T->Left->Weight+T->Right->Weight;

        Insert( H, T ); /*将新T插入最小堆*/

    }

    T = Deletemin(H); // 最小堆中的最后一个元素就是指向Huffman树根节点的指针

    return T;

}

```

哈夫曼树的特点:

1. 没有度为1的结点

2. n个叶子结点的哈夫曼树共有2n-1个结点;  

    因为: n2= n0 -1,

    总结点数 = n0 + n2 = 2n0 - 1

3. 哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树;

4. 对同一组权值{w1 ,w2 , ...... , wn},存在不同构的两

# 集合及运算  

双亲表示法: 孩子指向父节点  

数据结构

```c

typedef struct

{

    ElementType Data;

    int Parent;  // 其父节点的下标

} SetType;

```

## 查找某个元素所在的集合  

用根节点表示

```c

int Find(SetType S[], ElementType X)

{

    /* 在数组S中查找值为X的元素所属的集合, MaxSize为数组最大长度 */

    int i;

    for(i=0; i<MaxSize && S[i].Data != X; i++)

    if (i >= MaxSize) // 未找到

        return -1;

    for(; S[i].Parent >= 0; i = s[i].Parent);  // 向上找它的父节点

    return i;

}

```

## 集合的并运算  

如果它们不同根,则将其中一个根结点的父结点指针设置成

   另一个根结点的数组下标。

```c

void Union( SetType S[], ElementType X1, ElementType X2 )

{

    int Root1, Root2;

    Root1 = Find(S, X1);

    Root2 = Find(S, X2);

    if( Root1 != Root2 )

        S[Root2].Parent = Root1;

}

```

为了使树更矮,合并时按秩合并  

直接用一个数组表示,不用之前的数据结构了

```c

#define MAXN 1000                  /* 集合最大元素个数 */

typedef int ElementType;           /* 默认元素可以用非负整数表示 */

typedef int SetName;               /* 默认用根结点的下标作为集合名称 */

typedef ElementType SetType[MAXN]; /* 假设集合元素下标从0开始 */

SetName Find(SetType S, ElementType X){

    for(; S[X] > 0; X=S[X]);

    return X.

}

void OldUnion(SetType S, SetName Root1, SetName Root2){

    S[Root2] = Root1;

}

void Union( SetType S, SetName Root1, SetName Root2 )

{ /* 这里默认Root1和Root2是不同集合的根结点 */

    /* 保证小集合并入大集合 */

    if ( S[Root2] < S[Root1] ) { /* 如果集合2比较大 */

        S[Root2] += S[Root1];     /* 集合1并入集合2  */

        S[Root1] = Root2;

    }

    else {                         /* 如果集合1比较大 */

        S[Root1] += S[Root2];     /* 集合2并入集合1  */

        S[Root2] = Root1;

    }

}

```

路径压缩

```c

SetName Find( SetType S, ElementType X )

{

    if ( S[X] < 0 ) /* 找到集合的根 */

        return X;

    else

        return S[X] = Find( S, S[X] ); /* 路径压缩 */

}

```

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93071.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93071.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/93071.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CS231n-2017 Lecture7训练神经网络(二)笔记

本节主要是神经网络的动态部分&#xff0c;也就是神经网络学习参数和搜索最优超参数的过程梯度检查&#xff1a;进行梯度检查&#xff0c;就是简单地把解析梯度与数值计算梯度进行比较&#xff0c;防止反向传播的逻辑出错&#xff0c;仅在调试过程中使用。有如下技巧 &#xff…

IntelliJ IDEA 中左上方未显示项目根目录问题

问题&#xff1a; 在IDEA中编写代码时&#xff0c;发现左上方只显示项目的子模块&#xff0c;未显示根项目名称。 如图所示&#xff0c;未显示子模块的根项目&#xff1a;问题分析 顶层根目录未被识别为项目根目录&#xff0c;需要手动添加识别。 问题解决 进入File – Project…

OpenCV 图像变换全解析:从镜像翻转到仿射变换的实践指南

前言处理图像时&#xff0c;翻转、旋转、平移等操作很常用。OpenCV 提供了简单的方法实现这些变换&#xff0c;本文带你快速学会用它做图像翻转和仿射变换。1 图像翻转(图像镜像旋转)在OpenCV中&#xff0c;图片的镜像旋转是以图像的中心为原点进行镜像翻转的。cv2.flip(img,fl…

【运维】Linux运维命令记录

重置root密码使用命令重新设置一下root账户的密码 passwd root根据提示设置一下密码&#xff0c;然后使用sudo -i 时输入密码就可以切换到root账户了ssh登陆以后&#xff0c;要用sudo -i命令给用户提权&#xff0c;提到超级管理员&#xff0c;然后输入密码才有用

PandasAI连接LLM进行智能数据分析

1. 引言 Pandas是一个数据分析开源组件库&#xff0c;提供了高性能、易用的数据结构和数据分析工具。它的核心的功能是其DataFrame对象&#xff0c;这是一个带有行和列标签的二维表格数据结构&#xff0c;支持缺失数据处理、时间序列功能、灵活的数据输入输出方法、数据对齐和…

Spring之【Bean的生命周期】

目录 1、生成BeanDefinition BeanDefinitionRegistry接口 DefaultListableBeanFactory实现类 2、合并BeanDefnition AbstractBeanFactory类 3、BeanFactoryPostProcessor的方法回调 AbstractApplicationContext类 PostProcessorRegistrationDelegate类 4、BeanPostPro…

搜狐新闻直播间适配HarmonyOs实现点赞动画

01背景介绍随着新闻客户端鸿蒙单框架系统适配工作的推进&#xff0c;从原来的基础功能到现在已经适配全功能的85%以上。与此同时&#xff0c;我们也在持续深入挖掘鸿蒙系统的特性&#xff0c;以提升整体应用的质量与用户体验。在这一过程中&#xff0c;动画作为增强交互与视觉体…

83、设置有人DTU设备USR-M100采集传感器数据,然后上传阿里云服务

基本思想:设置M100 采集传感器数据 一、首先将DTU设备USR-M100连接路由器上,然后使用python代码搜索同一局域网设备, import platform import sys import os import time import threadinglive_ip = 0def get_os():os = platform.system()if os == "Windows":re…

P1019 [NOIP 2000 提高组] 单词接龙

题目描述单词接龙是一个与我们经常玩的成语接龙相类似的游戏&#xff0c;现在我们已知一组单词&#xff0c;且给定一个开头的字母&#xff0c;要求出以这个字母开头的最长的“龙”&#xff08;每个单词都最多在“龙”中出现两次&#xff09;&#xff0c;在两个单词相连时&#…

详解力扣高频SQL50题之1633. 各赛事的用户注册率【简单】

传送门&#xff1a;1633. 各赛事的用户注册率 题目 用户表&#xff1a; Users -------------------- | Column Name | Type | -------------------- | user_id | int | | user_name | varchar | -------------------- user_id 是该表的主键(具有唯一值的列)。 该表中的每行包…

FROM stakater/java8-alpine 构建cocker镜像

在 Dockerfile 中&#xff0c;FROM stakater/java8-alpine 是第一条也是最核心的指令&#xff0c;它定义了构建新镜像所基于的「基础镜像」。以下是逐层解析&#xff1a;&#x1f50d; 关键字拆解 1. FROM —— 起点指令 ✅ 作用&#xff1a;声明当前镜像的起点&#xff08;父镜…

Word2Vec模型训练全流程解析:从数据预处理到实体识别应用

请添加图片描述 训练Word2Vec模型 概述 问题 我们如何训练Word2Vec模型&#xff1f;在特定数据集上训练Word2Vec模型何时是有利的&#xff1f; 目标 理解在自有数据上训练Word2Vec模型而非使用预训练模型的优势 Colab环境配置 运行以下代码以启用辅助函数并重新读取数据…

在Ubuntu上使用QEMU学习RISC-V程序(2)gdb调试

文章目录一、准备工作二、基本调试流程1. 设置断点2. 执行程序3. 查看源代码/汇编三、查看寄存器1. 查看通用寄存器2. 查看特殊寄存器四、查看内存1. 内存查看命令2. 内存修改命令五、调试实战示例六、高级调试技巧1. 条件断点2. 自动显示3. 内存断点&#xff08;观察点&#x…

不止于“亮”:一盏智慧路灯的技术进化史——塔能科技用“落地性”定义行业标准

在凌晨3点的园区道路之上&#xff0c;路灯会随着车辆的靠近而自动亮起&#xff0c;待车辆逐渐远去之后&#xff0c;又会缓缓地调暗下来&#xff1b;当电缆意外被触碰的时候&#xff0c;系统能够在短短3秒之内自动发出报警信息&#xff0c;并且推送出维修工单&#xff1b;而当一…

Redis的String数据类型底层实现

redis就是用c语言写&#xff0c;但redis的string并没有直接用c语言的string&#xff0c;而是自己搞了一个 SDS 结构体来表示字符串。SDS 的全称是 Simple Dynamic String&#xff0c;中文叫做“简单动态字符串”。想知道为什么这么做&#xff0c;我们先看看c语言的string是什么…

【音视频学习】四、深入解析视频技术中的YUV数据存储方式:从原理到实践

文章目录 引言 1. YUV 基础:为什么它比 RGB 更适合视频? 1.1 YUV 与 RGB 的核心区别 1.2 YUV色度下采样简介 2. YUV 的三大存储方式 方式一:平面格式(Planar) 方式二:半平面格式(Semi-Planar ) 方式三:打包格式(Packed YUV) 三种存储方式对比: 3. 如何选择合适的 Y…

前端项目组成

一、前端项目常见模块及功能&#xff08;以 Vue/React 通用结构为例&#xff09; 前端项目的模块本质是「按功能拆分的代码文件/文件夹」&#xff0c;就像盖房子的「砖、梁、窗」各司其职&#xff1a;模块类型功能说明&#xff08;大白话&#xff09;举个例子pages&#xff08;…

聚观早报 | 猿编程推动中美青少年AI实践;华为Pura 80数字版售价公布;iPhone 17 Air电池曝光

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。整理丨肖羽7月24日消息猿编程推动中美青少年AI实践华为Pura 80数字版售价公布iPhone 17 Air电池曝光亚马逊收购AI初创公司Bee蜂巢半固…

unittest 案例执行顺序详解

unittest 案例执行顺序详解在 unittest 框架中&#xff0c;测试用例的执行顺序有默认规则&#xff0c;也可通过自定义方式调整。以下是具体说明&#xff1a;一、默认执行顺序规则unittest 对测试用例的执行顺序遵循 “按测试方法名的 ASCII 码排序” 原则&#xff0c;具体逻辑如…

【web大前端】001_前端开发入门:创建你的第一个网页

前端开发入门&#xff1a;创建你的第一个网页 在当今数字化时代&#xff0c;网页已经成为人们获取信息和交流的重要平台。对于想要学习编程的人来说&#xff0c;前端开发往往是一个不错的起点。本文将带你通过简单的两步&#xff0c;创建属于你的第一个网页程序。 点击这里去…