数据结构——二叉树

在这里插入图片描述

堆的简易建立

  • 前言
  • 堆的顺序表实现
    • 一、Heap.h头文件
      • 向下调整算法复杂度
      • 向上调整算法复杂度
    • 二、Heap.c功能函数文件
    • 三、Test.c测试函数文件
    • 四、运行结果展示
    • 五、完整代码展示
  • 二叉树的链表实现
    • 回顾二叉树的概念
    • 链式二叉树代码模拟
    • 二叉树的遍历
  • 总结


前言

现在我们开始学习堆的建立!
相对于以前学的数据结构,堆无疑是更为复杂的!
但没关系,一起加油,这些都是小困难!芜湖~


在前面我们对于堆这个概念有了大概的认知;
现在我们来用代码实现一下吧!

堆的顺序表实现

我们用大根堆来进行代码实现!

一、Heap.h头文件

  1. 头文件的声明
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
  1. 堆的接口实现
typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;

前面的文章提到了堆的顺序表存储结构!
如果不了解可以看看之前的文章!

文章链接
在这里插入图片描述

  1. 向上调整和向下调整函数声明
//向上调整
void AdjustUp(HPDataType* a, int child);
//向下调整
void AdjustDown(HPDataType* a, int n, int parent);

前文对于两种调整方法同样也给出了详细的讲解!
不了解的可以先看看前面的文章!

文章链接

向下调整算法复杂度

在这里插入图片描述

向上调整算法复杂度

在这里插入图片描述

  1. 初始化堆和顺序表以及打印销毁函数的声明
//打印堆
void HeapPrint(HP* php);
//初始化堆
void HeapInit(HP* php);
//初始化顺序表
void HeapInitArray(HP* php, int* a, int n);
//销毁
void HeapDestroy(HP* php);
  1. 交换结点以及判空函数的声明
//交换结点内容
void Swap(HPDataType* p1, HPDataType* p2);
//判空
bool HeapEmpty(HP* php);
  1. 插入删除以及找出堆顶元素函数的声明
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//堆顶元素
HPDataType HeapTop(HP* php);

二、Heap.c功能函数文件

  1. 头文件的声明
#include "Heap.h"
  1. 向上调整和向下调整函数的定义
//向上调整
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;}}
}
  1. 初始化堆和顺序表以及打印销毁函数的定义
//初始化堆
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;//长度php->capacity = 0;//容量
}//初始化顺序表
void HeapInitArray(HP* php, int* a, int n)
{assert(php);assert(a);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");exit(-1);}php->size = n;php->capacity = n;memcpy(php->a, a, sizeof(HPDataType) * n);//将数组a中的数据复制到存储堆的顺序表中// 建堆for (int i = 1; i < n; i++){AdjustUp(php->a, i);//将顺序表中的数据依次向上调整}
}//打印
void HeapPrint(HP* php)
{assert(php);for (size_t i = 0; i < php->size; i++){printf("%d ", php->a[i]);}printf("\n");
}//销毁
void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}
  1. 交换结点以及判空函数的定义
//交换结点内容
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}//判空
bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}
  1. 插入删除以及找出堆顶元素函数的定义
//插入
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 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];
}

三、Test.c测试函数文件

1.排序函数的定义

// 升序
void HeapSort(int* a, int n)
{// 建堆 (大堆)or  (小堆)for (int i = 1; i < n; i++){AdjustUp(a, i);}int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

2.主函数的定义

int main() {int a[] = { 2,3,5,7,4,6,8 };HP hp;HeapInit(&hp);HeapSort(a, sizeof(a) / sizeof(int));HeapInitArray(&hp, a, sizeof(a) / sizeof(a[0]));HeapPush(&hp,9);//插入9HeapPush(&hp, 10);//插入10HeapPop(&hp);//删除10HeapPrint(&hp);HeapDestroy(&hp);return 0;
}

四、运行结果展示

在这里插入图片描述

五、完整代码展示

1.Heap.h头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;//向上调整
void AdjustUp(HPDataType* a, int child);
//向下调整
void AdjustDown(HPDataType* a, int n, int parent);
//交换结点内容
void Swap(HPDataType* p1, HPDataType* p2);
//打印堆
void HeapPrint(HP* php);
//初始化堆
void HeapInit(HP* php);
//初始化顺序表
void HeapInitArray(HP* php, int* a, int n);
//销毁
void HeapDestroy(HP* php);
//插入
void HeapPush(HP* php, HPDataType x);
//删除
void HeapPop(HP* php);
//堆顶元素
HPDataType HeapTop(HP* php);
//判空
bool HeapEmpty(HP* php);

2.Heap.c头文件

#include "Heap.h"//初始化堆
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}//初始化顺序表
void HeapInitArray(HP* php, int* a, int n)
{assert(php);assert(a);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");exit(-1);}php->size = n;php->capacity = n;memcpy(php->a, a, sizeof(HPDataType) * n);// 建堆for (int i = 1; i < n; i++){AdjustUp(php->a, i);}
}//销毁
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;
}

3.Test.c头文件

#include"Heap.h"
// 升序
void HeapSort(int* a, int n)
{// 建堆 (大堆)or  (小堆)for (int i = 1; i < n; i++){AdjustUp(a, i);}int end = n - 1;while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}int main() {int a[] = { 2,3,5,7,4,6,8 };HP hp;HeapInit(&hp);HeapSort(a, sizeof(a) / sizeof(int));HeapInitArray(&hp, a, sizeof(a) / sizeof(a[0]));HeapPush(&hp,9);HeapPush(&hp, 10);HeapPop(&hp);HeapPrint(&hp);HeapDestroy(&hp);return 0;
}

二叉树的链表实现

回顾二叉树的概念

  1. 空树
  2. 非空:根节点,根节点的左子树、根节点的右子树组成的
    在这里插入图片描述

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的

链式二叉树代码模拟

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;
BTNode* CreatBinaryTree()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->_left = node2;node1->_right = node4;node2->_left = node3;node4->_left = node5;node4->_right = node6;return node1;
}

当然,这只是一个形象模拟,二叉树真正的创建过程不是这样的哦!

二叉树的遍历

前序、中序以及后序遍历

学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。
遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
  2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
  3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。

// 二叉树前序遍历
void PreOrder(BTNode* root);
// 二叉树中序遍历
void InOrder(BTNode* root);
// 二叉树后序遍历
void PostOrder(BTNode* root);

在这里插入图片描述
我们现在来用前序遍历为例深度了解一下二叉树的递归遍历吧!

在这里插入图片描述在这里插入图片描述
现在我们已经对于链式二叉树有了基本的了解啦!
后面我会带来一些链式二叉树的题型!
请持续关注!!!


总结

只要一直在学习!
那我们就一直在路上!
终点未知,但努力终有回声!

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

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

相关文章

C语言入门Day_19 初识函数

目录 1.函数的定义 2.函数的调用 3.易错点 4.思维导图 前言&#xff1a; printf()我们已经很熟悉了&#xff0c;它有一个特定的功能&#xff0c;就是在屏幕上输出一行文字。之前的课程我们都称呼printf()为一个功能&#xff0c;实际上ta在编程中有个特定的名字——函数。 …

获取Windows 10中的照片(旧版)下载

Windows 10中的新版照片应用&#xff0c;目前发现无法直接打开部分iOS设备上存储的照片。需要使用照片&#xff08;旧版&#xff09;才行。 但目前应用商店中无法直接搜索到照片&#xff08;旧版&#xff09;&#xff0c;因此笔者提供如下链接&#xff0c;可以直接访问并呼出W…

C++零碎记录(十三)

23. 多态 23.1 多态简介 ① 多态是C面向对象三大特性之一。 ② 多态分为两类&#xff1a; 1. 静态多态&#xff1a;函数重载和运算符重载属于静态多态&#xff0c;复用函数名。 2. 动态多态&#xff1a;派生类和 虚函数实现运行时多态。 ③ 静态多态和动态多态区别&#xff…

通过 chatgpt 协助完成网站数据破解

Chatgpt 的出现极大地提升了程序员的工作效率&#xff0c;常见的使用场景包括代码自动生成、代码静态检查等&#xff0c;那么 chatgpt 能否用于某些网站的数据破解工作呢&#xff1f; 问题 某天线上服务开始报警&#xff0c;原来是某个视频网站无法获取到其 cdn 地址导致的下…

K8s上安装gitlab-ce

文章目录 K8s上安装gitlab-ce操作如下gitlab-deployment.yml K8s上安装gitlab-ce 前言   使用pv-pvc来持久化gitlab的数据&#xff0c;配置&#xff0c;日志文件。   pod启动后需要需要修改external_url然后重启pod。 操作如下 mkdir -p /mnt/data01/gitlab ctr -n k8s.…

内外统一的边缘原生云基础设施架构——火山引擎边缘云

近日&#xff0c;火山引擎边缘云边缘计算架构师郭少巍在LiveVideoStack Con 2023上海站围绕火山引擎边缘云海量分布式节点和上百T带宽&#xff0c;结合边缘计算在云基础设施架构方面带来的挑战&#xff0c;分享了面对海量数据新的应用形态对低时延和分布式架构的需求&#xff0…

数据通信网络之IPv6以太网二层交换

文章及资源归档至【AIShareLab】&#xff0c;回复 通信系统与网络 可获取。 文章目录 一、目的二、环境及网络拓扑三、需求四、步骤 一、目的 掌握 VLAN、Trunk 的基础配置。掌握以太网链路聚合的基础配置。掌握路由器子接口的配置&#xff0c;以及通过子接口实现 VLAN 之间互…

4.1.8- Web 应用程序使用的组件进行指纹识别

Web 应用程序使用的组件进行指纹识别 IDWSTG-INFO-08 总结 毫不夸张地说&#xff0c;几乎所有可以想象的Web应用程序的想法都已经投入开发。随着全球大量自由和开源软件项目的积极开发和部署&#xff0c;应用程序安全测试很可能会遇到完全或部分依赖于这些知名应用程序或框架…

[uniapp]踩坑日记 unexpected character > 1或‘=’>1 报错

在红色报错文档里下滑&#xff0c;找到Show more 根据提示看是缺少标签&#xff0c;如果不是缺少标签&#xff0c;看看view标签内容是否含有<、>、>、<号,把以上符合都进行以<号为例做{{“<”}}处理

Java多线程并发面试题

文章目录 Java并发基础并行和并发有什么区别&#xff1f;说说什么是进程和线程&#xff1f;Java线程创建方式&#xff1f;Runnable和Callable接口的区别&#xff1f;为什么调用start()方法时会执行run()方法&#xff0c;不直接调用run()方法&#xff1f;sleep()和wait()的区别&…

5.11.Webrtc接口的设计原理

在上节课中呢&#xff0c;我向你介绍了web rtc的接口宏&#xff0c;那有很多同学会产生疑问啊&#xff0c;那觉得web rtc为什么要把接口设计的这么复杂&#xff1f;还非要通过宏来实现一个代理类&#xff0c;再通过代理类来调用到web rtc内部。 那为什么要这么设计呢&#xf…

【计算机视觉 | 目标检测】干货:目标检测常见算法介绍合集(四)

文章目录 四十六、Parallel Feature Pyramid Network四十七、ScanSSD四十七、RetinaMask四十八、CornerNet-Saccade四十九、CentripetalNet五十、Fast Focal Detection Network五十一、CornerNet-Squeeze五十二、Paddle Anchor Free Network五十三、Human Robot Interaction Pi…