【数据结构】二叉树-堆(下)-链式二叉树

devtools/2024/10/11 3:25:55/

在这里插入图片描述
个人主页~

二叉树-堆(上)
栈和队列


二叉树

  • 四、堆的代码实现
    • Heap.h
    • Heap.c
    • test.c
  • 五、堆的应用
    • 堆排序思想进行排序
  • 六、二叉树链式结构的实现
    • BTree.h
    • BTree.c
    • test.c

四、堆的代码实现

Heap.h

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}Heap;
// 堆的初始化
void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);
//向上调整算法
void AdjustUp(HPDataType* a, int child); 
//向下调整算法
void AdjustDown(HPDataType* a, int n, int parent);

Heap.c

#include "Heap.h"//交换函数
void Swap(HPDataType* n1, HPDataType* n2)
{HPDataType* tmp = *n1;*n1 = *n2;*n2 = tmp;
}
//初始化
void HeapInit(Heap* hp)
{assert(hp);hp->a = NULL;hp->capacity = hp->size = 0;
}
//销毁
void HeapDestory(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = hp->size = 0;
}
//入堆
void HeapPush(Heap* hp, HPDataType x)
{assert(hp);if(hp->capacity == hp->size)//检查当容量和数据个数相等时{int newcapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;//检查容量是否为0,若为0则赋值newcapacity为4,若不为0则赋值为原来的两倍HPDataType* tmp = (HPDataType*)realloc(hp->a, newcapacity);//以newcapacity为大小开辟空间if (tmp == NULL){perror("realloc fail");return;}hp->a = tmp;hp->capacity = newcapacity;}hp->a[hp->size] = x;hp->size++;AdjustUp(hp->a, hp->size - 1);//向上调整建堆
}
//出堆
void HeapPop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));Swap(&hp->a[0], &hp->a[hp->size - 1]);//交换堆顶与最后一个元素hp->size--;//删除当前的最后一个元素,也就是原堆顶数AdjustDown(hp->a, hp->size, 0);//向下调整调整堆
}
//堆顶元素
HPDataType HeapTop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));return hp->a[0];
}
//堆的元素个数
int HeapSize(Heap* hp)
{assert(hp);return hp->size;
}
//判断堆是否为空
int HeapEmpty(Heap* hp)
{assert(hp);return hp->size == 0;
}
//向上调整
void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//通过子节点找到父节点,这里不管是左孩子还是右孩子都可以找到父节点,因为除法有向下取整的特性//while (parent >= 0)while (child > 0)//这里用子节点作为循环条件,因为child可能调整到根节点上{if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 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[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}

test.c

#include "Heap.h"int main()
{Heap h;HeapInit(&h);HeapPush(&h, 1);HeapPush(&h, 4);HeapPush(&h, 7);HeapPush(&h, 2);HeapPush(&h, 5);HeapPush(&h, 9);printf("%d\n", HeapTop(&h));HeapPop(&h);printf("%d", HeapTop(&h));HeapDestory(&h);return 0;
}

在这里插入图片描述

五、堆的应用

堆排序思想进行排序

我们在上面实现了堆,如果想要升序数组就建大堆,降序数组就建小堆
但建堆并不意味着建完就可以了,想要升序/降序数组的话,建完大堆/小堆后用向下调整算法将堆调整成小堆/大堆,这样调整出来的堆就是一个升序/降序数组

在排序当中,堆排序是一种时间复杂度较低的排序,要远优于冒泡排序,在使用堆排序时,要使用向下调整算法,这样我们就可以最大限度的减少时间的使用

在堆排序中有一个很经典的问题就是TopK问题,即一堆数据,个数为n(n>>k),求这堆数据中最大/最小的k个数据
如果是求前k个最大的元素,则用前k个元素建小堆
如果是求前k个最小的元素,则用前k个元素建大堆
然后再用剩下的n-k个元素一次与堆顶元素来比较,不满足则替换堆顶元素
也就是说,我们用求前k个最大数据来举例,我们先将整组数据的前k个元素建一个小堆,小堆的根是整个堆里最小的,用它来和剩余的n-k个元素比较,如果剩余的元素中的某一个比小堆根大,那么就替换掉,再用向下调整算法调整,这样一来,最大的数据都沉底了,堆中最小的数据继续与剩余的数据比较,重复上述步骤,当所有剩余元素都比完了之后,剩下的这个小堆就是前k个最大数

六、二叉树链式结构的实现

BTree.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}BTNode;// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int* pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode* root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);

BTree.c

#include "BTree.h"BTNode* BuyNode(BTDataType x)
{BTNode* new = (BTNode*)malloc(sizeof(BTNode));if (new == NULL){perror("malloc fail");return NULL;}new->data = x;new->left =  NULL;new->right = NULL;return new;
}BTNode* BinaryTreeCreate(BTDataType* a,int n, int* pi) 
{if (*pi >= n || a[*pi] == '#')//这里我们把#作为空的标识符{ // 如果到达数组末尾或遇到#,则返回NULL  (*pi)++;return NULL;}BTNode* node = BuyNode(a[*pi]);(*pi)++; // 移动到下一个节点  node->left = BinaryTreeCreate(a, n, pi); // 递归创建左子树  node->right = BinaryTreeCreate(a, n, pi); // 递归创建右子树  return node;
}void BinaryTreeDestory(BTNode* root)
{if (root == NULL)return;BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);
}int BinaryTreeSize(BTNode* root)
{//return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;if (root == NULL)return 0;return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}int BinaryTreeLeafSize(BTNode* root)
{if (root == NULL)return 0;if (root->left == NULL && root->right == NULL)return 1;return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}int BinaryTreeLevelKSize(BTNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->data = x)return root;BTNode* ret1 = BinaryTreeFind(root->left, x);if (ret1)return ret1;BTNode* ret2 = BinaryTreeFind(root->right, x);if (ret2)return ret2;return NULL;
}void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%c ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);}void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->left);printf("%c ", root->data);BinaryTreeInOrder(root->right);}void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BinaryTreeInOrder(root->left);BinaryTreeInOrder(root->right);printf("%c ", root->data);}

test.c

#include "BTree.h"int main()
{int i = 0;BTDataType val[] = { "ABD##E#H##CF##G##" };BTNode* tree = BinaryTreeCreate(val, 17, &i);BinaryTreePrevOrder(tree);printf("\n");BinaryTreeInOrder(tree);printf("\n");BinaryTreePostOrder(tree);printf("\n");printf("%d\n", BinaryTreeSize(tree));printf("%d\n", BinaryTreeLeafSize(tree));printf("%d\n", BinaryTreeLevelKSize(tree,3));BinaryTreeDestory(tree);return 0;
}

在这里插入图片描述


下一篇我们来详细剖析链式二叉树的实现~
在这里插入图片描述


http://www.ppmy.cn/devtools/46377.html

相关文章

(2) qml诞生的原因 和Qt Creator开发环境的介绍

文章目录 qml诞生原因Qt Quick应⽤程序Qt Creator环境1、MSVC2、MinGWMSVC的优缺点MinGW的优缺点 最后的选择延伸阅读 一些常用的快捷键统一格式化代码统一qml 语言的格式Locator 定位器帮助 qml诞生原因 可以在Qt5中开发的不同类型的经典应⽤程序。桌⾯应⽤程 序正在发⽣着改…

云实例初始化的行业标准:Cloud-Init

01 前言 Cloud-Init[1] 是跨平台云实例初始化的行业标准。它得到了所有主要公共云提供商的支持&#xff0c;适用于私有云基础设施的配置系统以及裸机安装。Cloud-Init 将在启动时识别其运行所在的云环境&#xff0c;读取来自云端提供的任何元数据&#xff0c;并据此初始化系…

拍视频麦克风什么牌子好?户外无线麦克风哪个牌子好,看本期文章

​无线领夹麦克风&#xff0c;作为现代音频技术的重要代表&#xff0c;已经广泛应用于各种场合。它不仅能提高演讲者的声音质量&#xff0c;还能增加演讲的互动性和生动性。然而&#xff0c;面对市场上众多的无线领夹麦克风产品&#xff0c;如何选择一款适合自己的设备成为了一…

旧手机翻身成为办公利器——PalmDock的介绍也使用

旧手机有吧&#xff01;&#xff01;&#xff01; 破电脑有吧&#xff01;&#xff01;&#xff01; 那恭喜你&#xff0c;这篇文章可能对你有点用了。 介绍 这是一个旧手机废物利用变成工作利器的软件。可以在 Android 手机上快捷打开 windows 上的文件夹、文件、程序、命…

Python笔记 - Exception chaining

在Python中&#xff0c;异常链接&#xff08;Exception Chaining&#xff09;是指在处理一个异常时抛出另一个异常的技术。这样可以保留原始异常的信息&#xff0c;同时提供新的异常信息。这种机制在调试和错误跟踪时特别有用&#xff0c;因为它保留了异常发生的完整上下文。 …

三维大场景管理-3Dtiles规范

简介 &#xff1a; 这篇文章都是三年前写的了&#xff0c;一直在笔记库存中&#xff0c;今天把他放出来。主要是讲Cesium 的3Dtiles 格式&#xff0c;当然3Dtiles主要是解决场景管理大场景的LOD实现的问题&#xff0c;不管是剔除渲染性能优化之Culling 剔除或者 LOD 、3Dtiles…

【面试】Java的前端编译器和后端编译器

目录 1. 说明2. 前端编译器2.1 主要功能2.2 工作原理 3. 后端编译器3.1 主要功能3.2 工作原理 1. 说明 1.在Java的编译过程中&#xff0c;编译器通常被划分为前端编译器和后端编译器&#xff0c;各自负责不同的任务。2.前端编译器主要负责源代码的词法分析、语法分析和语义检查…

LAMP集群分布式安全方案

实验目的 LAMP&#xff08;Linux Apache MySQL PHP&#xff09;是一种常见的Web应用程序堆栈&#xff0c;而LAMP集群是将多个服务器组合在一起以提供高可用性和可扩展性的解决方案。LAMP集群式安全方案的实验目的可以有以下几个方面&#xff1a; 1. 评估集群环境下的数据安…