堆的实现(堆的插入、堆的删除等)超级全

堆的实现(堆的插入、堆的删除等)超级全

在这里插入图片描述

文章目录

  • 堆的实现(堆的插入、堆的删除等)超级全
    • 一、前期基础知识
      • 1.树结构
        • ①树的定义
        • ②树的相关概念
        • ③二叉树
        • ④满二叉树和完全二叉树
          • a.满二叉树
          • b.完全二叉树
        • ⑤二叉树的性质
        • ⑥二叉树顺序结构的存储和链式结构的存储
          • a.顺序结构存储
          • b.链式结构存储
      • 2.堆结构
    • 二、堆结构/二叉树顺序结构存储的实现
      • 1.堆的初始化
      • 2.堆的销毁
      • 3.堆的插入
      • 4.堆的删除
      • 5.取堆顶数据
      • 6.堆的数据个数
      • 7.堆的判空

一、前期基础知识

1.树结构

①树的定义

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

②树的相关概念

在这里插入图片描述
节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6。
叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点。
非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点。
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6。
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4。
n个结点的树,有n-1条边。

一棵树有以下三部分组成
根节点,无前驱结点。
叶结点,度为0,又称终端结点
非终端节点,分支节点,度不为0

一棵树是由根节点和n颗子树构成的,子树一定不能相交,除了根节点外,每一个结点都有且仅有一个父节点。

如果不是树结构,那就是图结构。

③二叉树

每一个结点的度不一定都是2,整个二叉树里不存在度大于2的结点。

  1. 或者为空
  2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成

在这里插入图片描述
在这里插入图片描述

④满二叉树和完全二叉树
a.满二叉树

满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是2 ^ k - 1 ,则它就是满二叉树。

b.完全二叉树

完全二叉树
前(n - 1)层是满的
最后一层不满,但是从左到右必须连续排布,最少1个,最多2 ^ (n - 1)个。

⑤二叉树的性质
  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2 ^ (i - 1)个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2 ^ h - 1
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为n0 , 度为2的分支结点个数为n2 ,则有n0 = n2 + 1
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h= log2底(n + 1)。(ps: 是log以2为底,n+1为对数)
  5. 将二叉树的每一个结点按层次从0到n编号:
    0
    1 2
    3 4 5 6
    7 8 (7,8为3的子节点)
    举个例子,这就是一个完全二叉树,0 = (1 - 1) / 2, 0 = (2 - 1) / 2,所以parent = (child - 1) / 2, leftchild = parent * 2 + 1, rightchild = leftchild + 1。
    但是注意,一定要在范围里。
⑥二叉树顺序结构的存储和链式结构的存储
a.顺序结构存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
在这里插入图片描述

b.链式结构存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,二叉链就是两个指针+数据域,三叉链就是两个指针+指向父节点+数据域,我们暂时先不做重点讲解,后续笔者会进行讲解。

2.堆结构

1.一段连续的数组数据看作完全二叉树
2.必须是小堆或者大堆
小堆:任意一个父节点小于等于子节点
大堆:任意一个父节点大于等于子节点

typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;

大家不妨再思考一下,数据结构的目的到底是什么,就是为了方便我们在内存中管理数据,再加上一些可以实现对这段数据进行操作的接口函数来实现我们的目的。

二、堆结构/二叉树顺序结构存储的实现

1.堆的初始化

void HPIni(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}

2.堆的销毁

void HPDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = 0;php->capacity = 0;
}

3.堆的插入

void Swap(HPDataType* p1, HPDataType* p2)
{assert(p1 && p2);HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void HPAdjustUp(HPDataType* p, int child)
{assert(p);int parent = (child - 1) / 2;while (child > 0){if (p[child] < p[parent]){Swap(( & p[child]), ( & p[parent]));child = parent;parent = (parent - 1) / 2;}else{break;}}
}void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * (php->capacity);HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc");exit(-1);}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;HPAdjustUp(php->a, (php->size - 1));
}

当你插入一个新的数据到堆里后,一定要记得你的结构实际是一个二叉树,而且以小堆为例,如果你插入的数据,比这个结点的父节点小,那就需要向上调整。

4.堆的删除

void HPAdjustDown(HP* p, int parent)
{assert(p);int child = parent * 2 + 1;//使用假设法while (child < (p->size)){if ((child + 1 < p->size) && (p->a[child + 1] < p->a[child]))//这个真的很重要,值得反复思考,进行交换{child = child + 1;}if (p->a[child] < p->a[parent]){Swap(&(p->a[child]), &(p->a[parent]));parent = child;child = child * 2 + 1;}else{break;}}
}void HPPop(HP* php)
{assert(php);assert(php->size > 0);Swap(&(php->a[0]), &(php->a[(php->size) - 1]));php->size--;HPAdjustDown(php, 0);
}

相信大家一定会有一些问题,因为堆的删除,是删除堆顶元素,大家可能会疑问,为什么不能直接头删。
原因有以下两点:
1.顺序表时间复杂度是O(N),过于复杂。
2.如果头删之后,整个数组是要向前挪一位的,整棵树的结构就全部改变了,父子关系,大小关系全部乱了,需要重新改。

所以我们重新选择一个方法,就是我们将堆顶元素和最后一个元素互换,再尾删,这样可以保证两颗子树从上到下的整个顺序都没有被改变,向下调整就只需要进入一颗子树继续调整就好啦。

5.取堆顶数据

HPDataType HPTop(HP* php)
{assert(php);assert(php->size > 0);//使用sizereturn php->a[0];
}

6.堆的数据个数

int HPSize(HP* php)
{assert(php);return (php->size);
}

7.堆的判空

bool HPEmpty(HP* php)
{assert(php);/*if (php->size == 0){return true;}else{return false;}*/return (php->size == 0);
}

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

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

相关文章

每日OJ题_算法_双指针_力扣11. 盛最多水的容器

力扣11. 盛最多水的容器 11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 难度 中等 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成…

2023 最新 PDF.js 在 Vue3 中的使用

因为自己写业务要定制各种 pdf 预览情况&#xff08;可能&#xff09;&#xff0c;所以采用了 pdf.js 而不是各种第三方封装库&#xff0c;主要还是为了更好的自由度。 一、PDF.js 介绍 官方地址 中文文档 PDF.js 是一个使用 HTML5 构建的便携式文档格式查看器。 pdf.js 是社区…

人工智能教程(二):人工智能的历史以及再探矩阵

目录 前言 更多矩阵的知识 Pandas 矩阵的秩 前言 在上一章中&#xff0c;我们讨论了人工智能、机器学习、深度学习、数据科学等领域的关联和区别。我们还就整个系列将使用的编程语言、工具等做出了一些艰难的选择。最后&#xff0c;我们还介绍了一点矩阵的知识。在本文中&am…

需求变更导致估算不精准 6大措施

需求变更可能导致估算不精准、项目成本增加、进度延迟等问题&#xff0c;如果不能准确地估算项目&#xff0c;往往会造成资源浪费和开发效率的降低&#xff0c;因此亟需解决因需求变更导致地估算不精准的问题。 一般来说&#xff0c;主要是从以下6个方面入手解决&#xff1a; 1…

【maven】【IDEA】idea中使用maven编译项目,报错java: 错误: 找不到符号 【2】

idea中使用maven编译项目,报错java: 错误: 找不到符号 错误状况展示: 如果报这种错,是因为项目中真的找不到报错的方法或者枚举 字段之类的,但实际是 : 点击 File Path

OSG粒子系统与阴影-雾效模拟(1)

虚拟现实中有很多效果&#xff0c;如雨效、雪效、雾效等&#xff0c;这些都可以通过粒子系统来实现。一个真实的粒子系统的模式能使三维场景达到更好的效果。 本章对OSG粒子系统的使用以及生成自定义粒子系统的方法进行了详细介绍最后还附带说明了阴影的使用方法。在实时的场景…

pairplot

Python可视化 | Seaborn5分钟入门(七)——pairplot - 知乎 (zhihu.com) Seaborn是基于matplotlib的Python可视化库。它提供了一个高级界面来绘制有吸引力的统计图形。Seaborn其实是在matplotlib的基础上进行了更高级的API封装&#xff0c;从而使得作图更加容易&#xff0c;不需…

红黑树详解

红黑树的概念与性质 前置知识 在学习红黑树之前&#xff0c;最好有二叉查找树和AVL树的基础&#xff0c;因为红黑树本质就是一种特殊的二叉查找树&#xff0c;而红黑树的操作中需要用到AVL树中旋转的相关知识。至于二叉查找树和AVL树&#xff0c;可以参考如下两篇博客&#xf…

Matplotlib图形注释_Python数据分析与可视化

Matplotlib图形注释 添加注释文字、坐标变换 有的时候单单使用图形无法完整清晰的表达我们的信息&#xff0c;我们还需要进行文字进行注释&#xff0c;所以matplotlib提供了文字、箭头等注释可以突出图形中重点信息。 添加注释 为了使我们的可视化图形让人更加容易理解&#…

长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xff1a; 输入&#x…

MySQL 有多个普通索引时会取哪一个索引?

我们都知道MySQL在查询时底层会进行索引的优化&#xff0c;假设有两个普通索引&#xff0c;且where 后面也根据这两个普通索引查询数据&#xff0c;那么执行查询语句时会使用到那个索引&#xff1f; 为了方便演示&#xff0c;新建users表&#xff0c;新建idx_name、idx_city这两…

前端vue导出PPT,使用pptxgen.js

前言 公司新需求需要导出ppt给业务用&#xff0c;查阅资料后发现也挺简单的&#xff0c;记录一下。 如有不懂的可以留言&#xff01;&#xff01;&#xff01; 1.安装包 npm install pptxgenjs --save2.引入包 在需要使用的文件中引入 import Pptxgenfrom "pptxgenjs&…

Oracle研学-介绍及安装

一 ORACLE数据库特点: 支持多用户&#xff0c;大事务量的事务处理数据安全性和完整性控制支持分布式数据处理可移植性(跨平台&#xff0c;linux转Windows) 二 ORACLE体系结构 数据库&#xff1a;oracle是一个全局数据库&#xff0c;一个数据库可以有多个实例&#xff0c;每个…

nodejs+vue+python+PHP+微信小程序-留学信息查询系统的设计与实现-安卓-计算机毕业设计

1、用户模块&#xff1a; 1&#xff09;登录&#xff1a;用户注册登录账号。 2&#xff09;留学查询模块&#xff1a;查询学校的入学申请条件、申请日期、政策变动等。 3&#xff09;院校排名&#xff1a;查询国外各院校的实力排名。 4&#xff09;测试功能&#xff1a;通过入学…

python-选择排序

选择排序是一种简单直观的排序算法&#xff0c;它的基本思想是每一轮选择未排序部分的最小元素&#xff0c;然后将其放到已排序部分的末尾。这个过程持续进行&#xff0c;直到整个数组排序完成。(重点&#xff1a;通过位置找元素) 以下是选择排序的详细步骤和 Python 实现&…

HarmonyOS应用开发实战—登录页面【ArkTS】

文章目录 本页面实战效果预览图一.HarmonyOS应用开发1.1HarmonyOS 详解1.2 ArkTS详解二.HarmonyOS应用开发实战—登录页面【ArkTS】2.1 ArkTS页面源码2.2 代码解析2.3 心得本页面实战效果预览图 一.HarmonyOS应用开发 1.1HarmonyOS 详解 HarmonyOS(鸿蒙操作系统)是华为公司…

js粒子效果(一)

效果: 代码: <!doctype html> <html> <head><meta charset"utf-8"><title>HTML5鼠标经过粒子散开动画特效</title><style>html, body {position: absolute;overflow: hidden;margin: 0;padding: 0;width: 100%;height: 1…

DELL MD3600F存储重置管理软件密码

注意&#xff1a;密码清除可能会导致业务秒断&#xff0c;建议非业务时间操作 针对一台控制器操作即可&#xff0c;另一控制器会同步操作 重置后密码为空&#xff01; 需求&#xff1a;重置存储管理软件密码 管理软件中分配物理磁盘时提示输入密码(类似是否了解风险确认操作的提…

io.lettuce.core.RedisCommandExecutionException

io.lettuce.core.RedisCommandExecutionException: ERR invalid password ERR invalid password-CSDN博客 io.lettuce.core.RedisCommandExecutionException /** Copyright 2011-2022 the original author or authors.** Licensed under the Apache License, Version 2.0 (the…

Rust UI开发(一):使用iced构建UI时,如何在界面显示中文字符

注&#xff1a;此文适合于对rust有一些了解的朋友 iced是一个跨平台的GUI库&#xff0c;用于为rust语言程序构建UI界面。 iced的基本逻辑是&#xff1a; UI交互产生消息message&#xff0c;message传递给后台的update&#xff0c;在这个函数中编写逻辑&#xff0c;然后通过…