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

数据结构:二叉树、堆

目录

一.树的概念

二、二叉树

1.二叉树的概念

2.特殊类型的二叉树

3.二叉树的性质

4.二叉树存储的结构

三、堆

1.堆的概念

2.堆的实现

Heap.h

Heap.c


一.树的概念

 注意,树的同一层中不能有关联,否侧就不是树了,就变成图了,例如:

由于B和C存在关联,这就不是树了。 

有关树的一些重要概念:

二、二叉树

1.二叉树的概念

二叉树由一个根节点加上两棵别称为左子树和右子树的二叉树组成

它具有两个特点:不存在度大于2的节点;子树有左右之分,次序不能颠倒,故二叉树是有序树

各类型二叉树集合:

2.特殊类型的二叉树

满二叉树:所有非叶子节点都有两个子节点,且所有叶子节点都在同一层

完全二叉树:除了最后一层,每一层都是满的,且最后一层的叶子节点都尽可能靠左排列 

二叉排序树:左子树所有节点的值小于根节点的值,右子树所有节点的值大于根节点的值,且左右子树也分别是二叉排序树

3.二叉树的性质

(1) 对于具有n个节点的完全二叉树,如果按照从上到下从左到右的顺序对所有节点从0开始编号,则序号为i的节点有:其双亲节点序号为(i-1)/2;其左孩子节点序号为i*2+1,右孩子节点序号为i*2+2,注意i*2+1和i*2+2要小于n,合法性

(2)规定根节点层数为1,具有n个节点的满二叉树深度为h=log2(n+1)

(3)规定根节点层数为1,第i层最大节点数为2^(i-1)

(4)规定根节点层数为1,深度为h的二叉树的最大节点数为2^h-1

4.二叉树存储的结构

分为顺序存储结构和链式存储结构,其中用顺序存储结构来实现完全二叉树就是接下来重点介绍的堆。

链式存储:用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。

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

、堆

1.堆的概念

堆可以看作一种特殊类型的完全二叉树,分为大堆和小堆,根节点最大的称为大堆,根节点最小的称为小堆。

大堆:谁大谁当爹,但兄弟间无绝对大小关系

小堆:谁小谁当爹,但兄第间无绝对大小关系

2.堆的实现

升序:建大堆

降序:建小堆

接下来给出建小堆的代码实现:

Heap.h

#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<stdbool.h>typedef int HDataType;
typedef struct Heap
{HDataType* arr;int size;int capacity;
}Heap;//堆的初始化
void HeapInit(Heap* obj);
// 堆的插入
void HeapPush(Heap* obj, HDataType x);
// 堆的删除
void HeapPop(Heap* obj);
// 取堆顶的数据
HDataType HeapTop(Heap* obj);
// 堆的数据个数
int HeapSize(Heap* obj);
// 堆的判空
bool HeapEmpty(Heap* obj);
// 堆的销毁
void HeapDestroy(Heap* obj);

Heap.c

#include"Heap.h"void HeapInit(Heap* php)
{php->capacity = php->size = 0;php->arr = NULL;
}//扩容
void Exp(Heap* obj)
{if (obj->size == obj->capacity){int new_capeccity = obj->capacity == 0 ? 4 : obj->capacity * 2;HDataType* tem = (HDataType*)realloc(obj->arr, sizeof(HDataType) * new_capeccity);if (tem == NULL){assert("realloc");}obj->arr = tem;obj->capacity = new_capeccity;}
}//交换
void Swap(HDataType* child, HDataType* parent)
{HDataType tem = *child;*child = *parent;*parent = tem;
}//向上调整
//这里假设是小堆进行调整
//如果是大堆,将if处改为大于号即可
void UpAdjust(HDataType* p,int child)
{//通过计算找父母HDataType parent = (child - 1) / 2;while (child > 0){if (p[child] < p[parent]){//交换Swap(&p[child], &p[parent]);//交换后,将parent的位置给给child,继续计算下一个parentchild = parent;//把父母给孩子parent = (child - 1) / 2;//得到新的父母}else{break;}}
}//插入
//先向堆尾插入元素,再根据大堆还是小堆向上调整
void HeapPush(Heap* obj,HDataType x)
{assert(obj);Exp(obj);obj->arr[obj->size] = x;obj->size++;//这个时候我们需要向上UpAdjust(obj->arr, obj->size - 1);
}//向下调整
//这里假设是小堆
//如果是大堆,将两个if处改为大于号即可
void DownAdjust(HDataType* p,int n,int parent)
{//计算出左孩子int child = parent * 2 + 1;while (child < n){if (child + 1 < n && p[child + 1] < p[child]) {//如果右儿子小于左儿子,直接++到右儿子的位置++child;//child+1<n是为了避免越界访问,因为每次算出的是左孩子,堆尾不一定是右孩子}if (p[child] < p[parent])//如果child<parent,就交换,要把小的往上走{//这边操作一样,算法不同Swap(&p[child], &p[parent]);parent = child;//把孩子给父母child = parent * 2 + 1;//得到新的孩子}else{break;}}
}//删除堆顶元素
//这里是小堆,删的实际是最小元素
void HeapPop(Heap* obj)
{assert(obj);assert(obj->arr);assert(obj->size > 0);//堆内无元素则不存在删的问题//1.先交换堆顶和堆尾的元素,避免中间节点之间关系全部混乱Swap(&obj->arr[0], &obj->arr[obj->size - 1]);//2.删obj->size--;//3.这里我们假设的是小堆,而当前交换后显然不是小堆,故向下调整,将堆中次小元素调到堆顶DownAdjust(obj->arr, obj->size, 0);
}//获取堆顶元素
HDataType HeapTop(Heap* obj)
{assert(obj);return obj->arr[0];
}//获取堆中数据的个数
int HeapSize(Heap* obj)
{assert(obj);return obj->size;
}//判空
bool HeapEmpty(Heap* obj)
{assert(obj);return obj->size == 0;
}//堆的销毁
void HeapDestroy(Heap* obj)
{assert(obj);assert(obj->arr);free(obj->arr);obj->arr = NULL;obj->capacity = obj->size = 0;
}

test.c

 cl:以上代码和顺序表的实现是很相似的,最大区别是堆独有的特点,也就是建堆,堆尾插入元素时进行向上调整,堆顶删除元素时进行向下调整,这两步是最关键的算法,是保证堆的特点(大小堆)的关键。

http://www.lryc.cn/news/464625.html

相关文章:

  • hi3798mv100 linux 移植
  • Docker-Harbor概述及构建
  • 部署项目最新教程
  • linux证明变量扩展在路径名扩展之前执行
  • CentOS 7.9安装MySQL
  • MacOS虚拟机安装Windows停滞在“让我们为你连接到网络”,如何解决?
  • 黑马程序员Java笔记整理(day03)
  • centos7更换阿里云镜像源操作步骤及命令
  • 冲刺大厂 | 一个线程调用两次start()方法会出现什么现象?
  • leaflet(一)初始化地图
  • Unity开发Hololens项目
  • 立志最细,FreeRtos的中断管理(Interrupt Management)函数,详解!!!
  • 作业2-线性回归的Matlab代码实现
  • 用jQuery在canvas上绘制绝对定位的元素
  • Android中 tools:text 和 android:text区别
  • Wordpress GutenKit 插件 远程文件写入致RCE漏洞复现(CVE-2024-9234)
  • Redis历史漏洞未授权RCE复现
  • Greenhills学习总结
  • 【深入学习Redis丨第八篇】详解Redis数据持久化机制
  • 【27续】c++项目练习
  • Lazarus Query转EXCEL功能
  • AnaTraf | 深入探讨DNS流量分析:保障网络稳定性的关键
  • P1017 [NOIP2000 提高组] 进制转换
  • 计算机网络—vlan(虚拟局域网)
  • C++头文件大全及解释
  • 基于 Django 的电商比价系统
  • Excel重新踩坑2:Excel数据类型;自定义格式(设置显示格式);分列操作;其他常用操作;一些重要操作
  • python从0快速上手(十四)数据库操作
  • 【热门主题】000004 案例 Vue.js组件开发
  • Ingress-nginx中HTTPS的强制转发