当前位置: 首页 > news >正文

堆和二叉树的概念和操作

目录

1.树的概念

 1.1数的表示

1.2二叉树

 1.3特殊的二叉树

1.3.1满二叉树

 1.3.2完全二叉树

1.3.3 二叉树存储结构

 2.堆

2.1堆的实现

初始化和销毁

 堆的插入

 堆的向上调整算法​编辑

​编辑

 堆的删除

 出堆顶


1.树的概念

树是非线性的数据结构,有限节点具有的层次关系的集合。

根节点:有且只有一个根节点,没有前驱。其余节点被分成互不相交的树

除根节点外每个节点都有一个前驱节点。

⼀棵N个结点的树有N-1条边

 ⽗结点/双亲结点若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的父结点

⼦结点/孩⼦结点个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点

结点的度:⼀个结点有⼏个孩⼦,他的度就是多少;⽐如A的度为6,F的度为2,K的度为0

树的度:⼀棵树中,最⼤的结点的度称为树的度; 如上图:树的度为 6

叶⼦结点/终端结点度为 0 的结点称为叶结点; 如上图: B、C、H、I... 等结点为叶结点

分⽀结点/⾮终端结点:度不为 0 的结点; 如上图: D、E、F、G... 等结点为分⽀结点(非叶子节点

兄弟结点:具有相同⽗结点的结点互称为兄弟结点(亲兄弟); 如上图: B、C 是兄弟结点

结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推;

树的⾼度或深度:树中结点的最⼤层次; 如上图:树的⾼度为 4

结点的祖先:从根到该结点所经分⽀上的所有结点;如上图: A 是所有结点的祖先

路径:⼀条从树中任意节点出发,沿⽗节点-⼦节点连接,达到任意节点的序列;⽐如A到Q的路径为: A-E-J-Q;H到Q的路径H-D-A-E-J-Q

⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙

森林:由 m(m>0) 棵互不相交的树的集合称为森林;

 1.1数的表示

孩子兄弟表示法

struct TreeNode 
{
Struct Node * child; //第一个孩子节点struct Node  * brother ;//孩子的兄弟节点int  data;//数据域
}

1.2二叉树

二叉树是树形结构的一种。最常⽤的就是⼆叉树,⼀棵⼆叉树是结点的⼀个有限集合,该集合由⼀个根结点 加上两棵别称为左⼦树和右⼦树的⼆叉树组成或者为空。

1. ⼆叉树不存在度⼤于 2 的结点

2. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树

注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成的

 1.3特殊的二叉树

1.3.1满二叉树

每⼀个层的结点数都达到最⼤值,则这个⼆叉树就是满⼆叉树。如果⼀ 个⼆叉树的层数为 K

且节点总数为2的k次方-1,这个就是满二叉树。

 1.3.2完全二叉树

完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为 K 的,有 n 个 结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从 1 ⾄ n 的结点⼀⼀对应时称 之为完全⼆叉树。要注意的是满⼆叉树是⼀种特殊的完全⼆叉树。

除了第k层  每层节点的个数都达到最大个数 ,第k层的个数不一定是最大节点个数

 完全二叉树的结点的顺序是从左到右的。

完全二叉树是满二叉树的一种 ,完全二叉树不一定是满二叉树,满二叉树一定是完全二叉树

根据满⼆叉树的特点可知:

1)若规定根结点的层数为 1 ,则⼀棵⾮空⼆叉树的第i层上最多有 2 的i−1 次方个结点

2)若规定根结点的层数为 1 ,则深度为 h 的⼆叉树的最⼤结点数是 2 的h次方 -1 比特就业课

3)若规定根结点的层数为 1 ,具有 n 个结点的满⼆叉树的深度 h= log 2 (n+1) ( log 以2为底, n+1 为对数)

1.3.3 二叉树存储结构

二叉树有两种存储机构 :顺序结构 、链式结构。

顺序结构

顺序结构存储就是使⽤数组来存储,⼀般使⽤数组只适合表⽰完全⼆叉树,因为不是完全⼆叉树会有空间的浪费,完全⼆叉树更适合使⽤顺序结构存储。

通常把堆(⼀种⼆叉树)使⽤顺序结构的数组来存储,需要注意的是这⾥的堆和操作系统 虚拟进程地址空间中的堆是两回事,⼀个是数据结构,⼀个是操作系统中管理内存的⼀块区域分段

链式存储

 链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别⽤来给出该结点左孩⼦和右孩 ⼦所在的链结点的存储地址

 2.堆

堆分为大根堆和小跟堆

堆也是一种特殊的二叉树,⼀般堆使⽤顺序结构的数组来存储数据。

 上面可以得出 小根堆的父节点比子节点要小,大根堆的父节点比子节点要大。

堆总是完全二叉树

二叉树性质

对于具有 n 个结点的完全⼆叉树,如果按照从上⾄下从左⾄右的数组顺序对所有结点从 0 开始编号,则对于序号为 i 的结点有:

用下标来进行

1. 若 i>0 , i 位置结点的双亲序号: (i-1)/2 ; i=0 , i   为根结点编号,⽆双亲结点   子节点求出 父节点

2. 若 2i+1=n 否则⽆左孩⼦ 

3. 若 2i+2=n 否则⽆右孩

2.1堆的实现

初始化和销毁

 

 

 堆的插入

大家可以来实现一下 这个很类似于单链表的插入

 堆的向上调整算法

 经过调试后可以看出是小根堆


 小根堆的展示方法

 

 堆的删除

先交换首尾结点 ,后删除尾结点,堆顶向下调整 直至child >n

 下面我们可以把数组里的数据拆解一下

 出堆顶

 可以将下面的堆进行排序

 

 结果是没问题的 得出的是小根堆

 这节课就告一段落了,下个章节见

Heap.c

#define _CRT_SECURE_NO_WARNINGS
#include "Heap.h"
//初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->capacity = php->size = 0;}
//销毁
void HPDestory(HP* php)
{assert(php);if (php->arr){free(php->arr);}php->arr = NULL;php->capacity = php->size = 0;}
//交换数据
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;}
//向上调整算法
void AdjustUp(HPDatatyp* arr, int child)
{int  parent = (child - 1) / 2;while (child > 0)//当child为0的时候 说明走到了根节点{if (arr[child] < arr[parent]){Swap(&arr[parent], &arr[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void  HPPush(HP* php,HPDatatyp x)
{assert(php);//判断空间是否足够if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDatatyp* tmp = (HPDatatyp*)realloc(php->arr, newcapacity * sizeof(HPDatatyp));if (tmp == NULL){perror("realloc fail");exit(1);}php->arr = tmp;php->capacity = newcapacity;}php->arr[php->size] = x;AdjustUp(php->arr , php->size );++php->size;
}//向下调整
void  AdjustDown(HPDatatyp* arr, int parent, int n)
{int child = parent * 2 + 1;//左右孩子中找最小的孩子 和父结点比较while (child <n){if (child +1  <n && arr[child] > arr[child + 1]){child++;}if (arr[child] < arr[parent]){Swap(&arr[child], &arr[parent]);//这里记得要传地址parent = child ;child = parent * 2 + 1;}//如果child大于parent 那么就跳出else{break;}}}
void HPPop(HP* php)
{assert(php && php->size);Swap(&php->arr[0], &php->arr[php->size - 1]);//第一步交换首尾结点--php->size;AdjustDown(php->arr, 0, php->size); //向下调整}
bool HPEmpty(HP* php)//堆为空
{assert(php);return  php->size == 0;}HPDatatyp  HPTop(HP* php) // 出堆顶
{assert(php && php->size);return php->arr[0];}

 Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef int HPDatatyp;typedef struct Heap
{HPDatatyp* arr; int size;//个数int capacity; //容量}HP;void HPInit(HP* php);void HPDestory(HP* php);//插入数据void  HPPush(HP* php,HPDatatyp x);//删除数据void HPPop(HP* php);//出堆顶HPDatatyp   HPTop(HP* php);//堆空bool HPEmpty(HP* php);

text,c

#define _CRT_SECURE_NO_WARNINGS
#include "Heap.h"
void HPtext()
{HP  hp;HPInit(&hp);int arr[] = { 12,34,56,32,43,25,45 };for (int  i = 0; i <= 6; i++){HPPush(&hp, arr[i]); }//HPPop(&hp);while (!HPEmpty(&hp)){printf("%d ", HPTop(&hp));HPPop(&hp);}HPDestory(&hp);}
int main()
{HPtext();return 0;
}

相关文章:

  • 【算法笔记】贪心算法
  • node20的安装和vue的入门准备
  • Python语言基础知识详解:分支结构控制语句
  • babel和loader的关系
  • 【数据挖掘】时间序列预测-时间序列的平稳性
  • 猿人学web端爬虫攻防大赛赛题第15题——备周则意怠-常见则不疑
  • DeepSeek:重构人类文明的智能引擎
  • 使用CubeMX新建USART1不定长接收工程
  • log4cpp 编译说明文档
  • Transformer数学推导——Q25 分析视觉-语言模型中区域注意力(Region Attention)的边界框投影公式
  • 机器学习day2-seaborn绘图练习
  • RagFlow文档切块提升
  • 基于亚马逊云科技搭建企业问答系统
  • LeetCode42_接雨水
  • 北冰洋:突破热力极限!99℃离心热泵机组,开启工业节能新时代!
  • GCC 15.1 发布,包含 COBOL 编译器及多项其他改进
  • 再学GPIO(一)
  • Java 设计模式
  • deepSeek浅谈对vue的mixin的理解,用于什么应用场景?
  • Vue3 通过Vue3-Print-Nb在线工单打印 模板打印 自定义打印 打印下载
  • 美乌总统梵蒂冈会谈,外交部:望有关各方继续通过对话谈判解决危机
  • 解放日报头版头条:“五个中心”蹄疾步稳谱新篇
  • 我国已形成完整人工智能产业体系,专利申请量位居全球首位
  • 中国海警局新闻发言人就菲律宾非法登临铁线礁发表谈话
  • 一周观展|五一假期将到,特展大展陆续开幕
  • 最大规模的陈逸飞大展启幕:回望他,回望一个时代