【数据结构初阶】二叉树(2)

二叉树顺序结构

    • 1.二叉树的顺序结构及实现
      • 1.1二叉树的顺序结构
    • 1.2 堆的概念及结构
      • 1.3 堆的实现
      • 1.3.1向上调整
      • 1.3.2向下调整
      • 1.3.3交换函数
      • 1.3.4打印
      • 1.3.5初始化
      • 1.3.6销毁
      • 1.3.7插入
      • 1.3.8删除
      • 1.3.9获得堆顶元素
      • 1.3.10判断是否为空
      • 1.3.6 堆的代码实现
    • 1.3.2堆的创建
    • 1.3.3 建堆时间复杂度
    • 1.4 堆的应用
      • 1.4.1 堆排序

1.二叉树的顺序结构及实现

1.1二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

在这里插入图片描述

1.2 堆的概念及结构

如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储
在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,
2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
    在这里插入图片描述
    练习题:
    1.下列关键字序列为堆的是:()
    A 100,60,70,50,32,65
    B 60,70,65,50,32,100
    C 65,100,70,32,50,60
    D 70,65,100,32,50,60
    E 32,50,100,70,65,60
    F 50,100,70,65,60,32
    2.已知小根堆为8,15,10,21,34,16,12,删除关键字 8 之后需重建堆,在此过程中,关键字之间的比较次
    数是()。
    A 1
    B 2
    C 3
    D 4
    3.一组记录排序码为(5 11 7 2 3 17),则利用堆排序方法建立的初始堆为
    A(11 5 7 2 3 17)
    B(11 5 7 2 17 3)
    C(17 11 7 2 3 5)
    D(17 11 7 5 3 2)
    E(17 7 11 3 5 2)
    F(17 7 11 3 2 5)
    4.最小堆[0,3,2,5,7,4,6,8],在删除堆顶元素0之后,其结果是()
    A[3,2,5,7,4,6,8]
    B[2,3,5,7,4,6,8]
    C[2,3,4,5,7,8,6]
    D[2,3,4,5,6,7,8]

练习题答案
1.A 2.C 3.C 4.C

1.3 堆的实现

1.3.1向上调整

在这里插入图片描述

向上调整前提:前面数据是堆

void AdjustUp(HPDateType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent]){swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

1.3.2向下调整

int array[] = {27,15,19,18,28,34,65,49,25,37};

现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

在这里插入图片描述

void AdjustDown(HPDateType* a, int n, int parent)
{int child = parent * 2 + 1;while (child > 0){if ((child + 1 > n) && a[child + 1] > a[child]){child++;}if (a[parent] > a[child]){swap(&a[parent], &a[child]);child = parent;parent = parent * 2 + 1;}else{break;}}
}

1.3.3交换函数

void swap(HPDateType* p1, HPDateType* p2)
{HPDateType tmp = *p1;*p1 = *p2;*p2 = tmp;
}

1.3.4打印

void HeapPrint(HP* php)
{assert(php);for(size_t i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}

1.3.5初始化

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

1.3.6销毁

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

1.3.7插入

先插入一个10到数组的尾上,再进行向上调整算法直到满足堆。
在这里插入图片描述

void HeapPush(HP* php, HPDateType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDateType* tmp = (HPDateType*)realloc(php->a, sizeof(HPDateType) * newCapacity);php->capacity = newCapacity;php->a = tmp;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

1.3.8删除

删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
在这里插入图片描述

void HeapPop(HP* php)
{assert(php);assert(php->size > 0);swap(&php->a[0], &php->a[php->size]);php->size--;AdjustDown(php->a, php->size, 0);
}

1.3.9获得堆顶元素

HPDateType HeadTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}

1.3.10判断是否为空

bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

1.3.6 堆的代码实现

Heap.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>typedef int HPDateType;
typedef struct Heap
{HPDateType* a;int size;int capacity;
}HP;//向上调整
void AdjustUp(HPDateType* a, int child);
//向下调整
void AdjustDown(HPDateType* a, int n, int parent);
//交换函数
void swap(HPDateType* p1, HPDateType* p2);
//打印
void HeapPrint(HP* php);
//初始化
void HeapInit(HP* php);
//销毁
void HeapDestroy(HP* php);
//插入
void HeapPush(HP* php, HPDateType x);
//删除
void HeapPop(HP* php);
//获得堆顶元素
HPDateType HeapTop(HP* php);
//判断是否为空
bool HeapEmpty(HP* php);

Heap.c

#include"Heap.h"void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}void AdjustDown(HPDataType* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){// 找出小的那个孩子if (child + 1 < n && a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);// 继续往下调整parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapPush(HP* php, HPDataType x)
{assert(php);// 扩容if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newCapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}void HeapPrint(HP* php)
{assert(php);for (size_t i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}void HeapPop(HP* php)
{assert(php);assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HeapTop(HP* php)
{assert(php);assert(php->size > 0);return php->a[0];
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

test.c

int main()
{int a[] = { 65,100,70,32,50,60 };HP hp;HeapInit(&hp);for(int i = 0; i < sizeof(a) / sizeof(int); i++){HeapPush(&hp, a[i]);}HeapPrint(&hp);return 0;
}

利用堆的代码,我们可以将数组排成有序,如下:

int main()
{int a[] = { 2,3,5,7,4,6,8,65,100,70,32,50,60 };HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a)/sizeof(int); i++){HeapPush(&hp, a[i]);}HeapPrint(&hp);int k = 5;while (!HeapEmpty(&hp) && k--){printf("%d ", HeapTop(&hp));HeapPop(&hp);}HeapDestroy(&hp);return 0;
}

1.3.2堆的创建

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

int a[] = {1,5,3,8,7,6};

在这里插入图片描述

1.3.3 建堆时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):
在这里插入图片描述
因此:建堆的时间复杂度为O(N)。

1.4 堆的应用

1.4.1 堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

  1. 建堆
    升序:建大堆
    降序:建小堆

建堆有两种方法:
(1)使用向上调整,插入数据的思想建堆。插入数据到新的数组,就是在不断插入的过程中向上调整实现排序

void Swap(HPDataType* pa, HPDataType* pb)
{HPDataType tmp = *pa;*pa = *pb;*pb = tmp;
}
void AdjustUp(HPDataType* a, size_t child)
{size_t parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;//跳出循环}}
}
void HeapSort(int* a, int n)
{//升序,建大堆,向上size_t i = 0;for (i = 1; i < n; ++i){AdjustUp(a, i);}
}int main()
{int a[] = { 4, 3, 10 , 2, 5, 9 };HeapSort(a, sizeof(a) / sizeof(int));for (int i = 0; i < sizeof(a) / sizeof(int); i++){printf("%d ", a[i]);}printf("\n");return 0;
}

(2)使用向下调整,从倒数第一个非叶子节点开始,即最后一个节点的父亲,即[(size-1-1)/ 2 ]【找到这个父亲的节点,向下排序,然后这个父亲节点依次减一【就找到各个小堆,依次向下排序,就成为了一个堆。

void HeapSort(int* a, int n)
{//升序,建堆,向上/*int i = 0;for (i = 1; i < n; ++i){AdjustUp(a, i);}*///向下int i = 0;for (i = (n - 2) / 2; i >= 0; --i){AdjustDown(a, i, n);}
}

💘不知不觉,【数据结构初阶】二叉树(2)以告一段落。通读全文的你肯定收获满满,让我们继续为数据结构学习共同奋进!!!

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

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

相关文章

怎么修复MSVCR110.dll文件?全面解析MSVCR110.dll缺失修复方法

MSVCR110.dll文件缺失问题在Windows操作系统用户中相当普遍&#xff0c;经常导致应用程序启动失败或崩溃。MSVCR110.dll是Microsoft Visual C Redistributable for Visual Studio 2012的一部分&#xff0c;且应用程序通常依赖这个DLL文件来执行C库中的代码。文件的丢失可能源自…

【代码随想录】刷题笔记Day39

前言 下午答疑课过于无聊了&#xff0c;后台在跑代码也写不了作业&#xff0c;再刷点题吧~难得一天两篇 56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 和之前重叠区间是同个类型&#xff0c;和res里的元素比较&#xff0c;重叠就更新res里最后元素的最右边界 class…

VS2020使用MFC开发一个贪吃蛇游戏

背景&#xff1a; 贪吃蛇游戏 按照如下步骤实现:。初始化地图 。通过键盘控制蛇运动方向&#xff0c;注意重新设置运动方向操作。 。制造食物。 。让蛇移动&#xff0c;如果吃掉食物就重新生成一个食物&#xff0c;如果会死亡就break。用蛇的坐标将地图中的空格替换为 #和”将…

常用JavaScript库

一、认识前端工具库 1.前端工具类库 jQuery是一个快速、小型且功能丰富的 JavaScript 库&#xff0c;它使HTML文档遍历和操作、事件处理、动画和 AJAX 之类的事情变得 更加简单。当时jQuery库不但简化了代码&#xff0c;而且提供出色的跨浏览器支持&#xff0c;其极大的提高了…

黑马头条-day10-xxl-job热点文章计算

目录 一.需求分析 实现思路 定时计算 定时任务框架-xxljob 二. 学习目录 分布式任务调度 1 xxl-Job简介 2 XXL-Job-环境搭建 2.1调度中心环境要求 2.2源码仓库地址 2.3 初始化“调度数据库” 2.4配置部署“调度中心” 3.配置部署调度中心-docker安装 4.简单实例 创建…

每周一算法:邻值查找

给定一个长度为 n n n的序列 A A A&#xff0c; A A A中的数各不相同。 对于 A A A 中的每一个数 A i A_i Ai​&#xff0c;求&#xff1a; m i n 1 ≤ j < i ∣ A i − A j ∣ min_{1≤j<i}|A_i−A_j| min1≤j<i​∣Ai​−Aj​∣&#xff0c;以及令上式取到最小值的…

40G多模光模块QSFP-40G-SR4优势及应用领域介绍

QSFP-40G-SR4光模块是一种常用的光纤传输解决方案。传输速率40G&#xff0c;SR代表短距离多模光纤&#xff08;Short Range Multimode Fiber&#xff09;&#xff0c;4表示有四个光纤通道。这种光模块采用MPO/MTP多模光纤连接器来实现高速传输&#xff0c;传输距离可以达到300米…

WU反走样算法

WU反走样算法 由离散量表示连续量而引起的失真称为走样&#xff0c;用于减轻走样现象的技术成为反走样&#xff0c;游戏中称为抗锯齿。走样是连续图形离散为想想点后引起的失真&#xff0c;真实像素面积不为 零。走样是光栅扫描显示器的一种固有现象&#xff0c;只能减轻&…

【Echarts】使用echarts和echarts-wordcloud生成词云图

一、下载echarts和echarts-wordcloud 地址&#xff1a;https://download.csdn.net/download/qq_25285531/88663006 可直接下载放在项目中使用 二、词云数据 词云数据是对象的格式&#xff0c;可以从后端获取&#xff0c;这里以下面数据为例 {"visualMap": 199,&…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)EventLoop初始化

这个Dispatcher是一个事件分发模型&#xff0c;通过这个模型,就能够检测对应的文件描述符的事件的时候,可以使用epoll/poll/select,前面说过三选一。另外不管是哪一个底层的检测模型,它们都需要使用一个数据块,这个数据块就叫做DispatcherData。除此之外,还有另外一个部分,因为…

vue3 vue3-print-nb 实现打印功能

vue3 vue3-print-nb 实现打印功能 效果 vue3-print-nb 文档 安装 pnpm add vue3-print-nbtypescript 中 xx.d.ts declare module "vue3-print-nb";配置 全局配置 src/main.ts import print from "vue3-print-nb";const app createApp(App); app.us…

Leetcode2928. 给小朋友们分糖果 I

Every day a Leetcode 题目来源&#xff1a;2928. 给小朋友们分糖果 I 解法1&#xff1a;暴力 枚举 3 位小朋友的糖果数&#xff0c;范围为 [0, limit]&#xff0c;分别记为 i、j、k。 当满足 i j k n 时&#xff0c;答案 1。 代码&#xff1a; /** lc appleetcode.c…

引领制造业迈向智能化新时代,SIA上海智能工厂展助力行业蓬勃发展

当今制造业迎来了数字化革命的潮流&#xff0c;其中智能工厂作为其中的一个关键角色&#xff0c;正在推动着制造业的转型和升级。智能工厂不仅仅是一个集成了先进技术的制造厂房&#xff0c;更是数字化时代制造业发展的崭新范本。本文将探讨智能工厂在现代制造业中的重要作用。…

SecuSphere:一款功能强大的一站式高效DevSecOps安全框架

关于SecuSphere SecuSphere是一款功能强大的一站式高效DevSecOps解决方案&#xff0c;DevSecOps作为一个经过针对性设计的集中式平台&#xff0c;可以帮助广大研究人员管理和优化漏洞管理、CI/CD管道集成、安全评估和DevSecOps实践。 SecuSphere是一个功能全面的DevSecOps平台…

RK3568驱动指南|第八篇 设备树插件-第83章 设备树插件驱动分析实验

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

IDEA 控制台中文出现乱码问题解决

一、问题概述 请看下图 二、问题分析 IDEA控制台输出乱码一般会有三种来源&#xff1a; ① IDEA本身编码错误 ② Tomcat日志输出编码错误 ③ 项目本身原因。 终极原因&#xff1a;IDEA编码和Tomcat编码不一致&#xff0c;统一设置为UTF-8即可。 三、解决思路 修改…

Superset二次开发之环境部署(Windows版)

本地环境版本介绍: 编号 名称 版本 1supersetv3.0.0rc32Pythonv3.10.123Nodev16.20.24npmv8.19.45Anacondav3 1.下载源码 #下载源码 git clone https://github.com/apache/superset.git ##速度慢可替换为 https://gitclone.com/github.com/apache/superset.git #进入项目目录…

在Go中解析HTTP请求中的表单数据

想象一下&#xff0c;你收到了一封神秘的信件&#xff0c;信上写着&#xff1a;“在HTTP请求的表单数据中&#xff0c;隐藏着一座宝藏&#xff0c;等待勇敢的冒险者前来寻找。” 你知道&#xff0c;这封信正是冲着你来的&#xff01;今天&#xff0c;我们将使用Go语言作为我们的…

VMware17Pro虚拟机安装Linux CentOS 7.9(龙蜥)教程(超详细)

目录 1. 前言2. 下载所需文件3. 安装VMware3.1 安装3.2 启动并查看版本信息3.3 虚拟机默认位置配置 4. 安装Linux4.1 新建虚拟机4.2 安装操作系统4.2.1 选择 ISO 映像文件4.2.2 开启虚拟机4.2.3 选择语言4.2.4 软件选择4.2.5 禁用KDUMP4.2.6 安装位置配置4.2.7 网络和主机名配置…

web自动化测试的智能革命:AI如何推动软件质量保证的未来

首先这个标题不是我取的&#xff0c;是我喂了关键字让AI给取的&#xff0c;果然非常的标题党&#xff0c;让人印象深刻&#xff0c;另外题图也是AI自动生成的。 先简单回顾一下web自动化测试的一些发展阶段 QTP时代 很多年前QTP横空出世的时候&#xff0c;没有人会怀疑这种工…