【数据结构】二叉树堆排序,TopK详解(第二章)

🎆前言🎆

✨笔者也仅是大一萌新,写博客为了记录和巩固知识✨

🥰赠人玫瑰,手留余香,欢迎各位读者进行交流和建议🥰

🌹能与大家一起学习,一起进步是我的荣幸🌹

🤞如果这篇文章有帮助到您,还请留个赞支持一下哦🤞



preview


🔎目录:

  1. 🔎二叉树的顺序结构
  2. 🔎堆的概念和结构
  3. 🔎实现堆的方法
  4. 🔎实现堆排序
  5. 🔎实现TopK
  6. 🔎总代码

🔎 二叉树的顺序结构:

普通的二叉树不适合用数组来存储,因为可能会存在大量的空间浪费,所以适合使用顺序结构存储的通常为完全二叉树。而堆就是使用顺序结构来存储的(这里的堆和我们学内存的堆是不同的,一个是数据结构,一个是操作系统中管理内存的一块区域分段)。

image-20220413151303894


🔎 堆的概念和结构:

一个完全二叉树以顺序存储的方法存入一个一维数组中,那么这个堆可以分为:

大堆/大根堆:树中的父亲都大于等于孩子

小堆/小根堆:树中的父亲都小于等于孩子

堆主要用来解决:堆排序TopK

堆的性质:
  • 堆中某个结点的值总是不大于或不小于父亲的值
  • 总是一棵完全二叉树

image-20220413155810439


🔎 实现堆的方法

建堆的时间复杂度

image-20220415123855541


函数声明

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

typedef int HPDataType;
typedef struct Heap
{
    
	HPDataType* a;
	size_t size;
	size_t capacity;
}HP;
void Swap(HPDataType* pa, HPDataType* pb); //交换函数
void HeapPrint(HP* php); //打印函数
void HeapInit(HP* php); //初始化
void HeapDestroy(HP* php); //清空
void HeapPush(HP* php, HPDataType x); //插入
void HeapPop(HP* php); //删除
bool HeapEmpty(HP* php); //判空
size_t HeapSize(HP* php); //树的大小
HPDataType HeapTop(HP* php); //根结点
void AdjustUp(HPDataType* a, size_t child); //向上调整
void AdjustDown(HPDataType* a, size_t size, size_t root); //向下调整

交换函数

注意:形参接收实参的值,如果不用return的话出了该函数就会被销毁,必须要接收地址才能改变实参的值

void Swap(HPDataType* pa, HPDataType* pb) //交换
{
    
	HPDataType tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}

打印函数

直接进行遍历打印即可

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

初始化

防止杂乱数据出现我们都先置空

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

清空函数

在释放空间后也要把指针置空防止出现野指针

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

插入函数

要注意的是,我们不能像之前的线性表那样,只把数据放进去,在树中我们还需要进行调整,不然会破坏树的结构(比如:我在一个父节点为100的小堆中插入一个99,那么结构显然是不对的),这时我们需要用到向上调整法

void HeapPush(HP* php, HPDataType x) //时间复杂度O(logN)
{
    
	assert(php);
	if (php->size == php->capacity) //朴实无华的扩容操作
	{
    
		size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = realloc(php->a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
    
			printf("realloc fail!");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x; //将x放入树中
	php->size++;
	AdjustUp(php->a, php->size - 1); //此时x在下标为size-1的位置
}

向上调整法:

思路:

为了不让树的结构被破坏,我们需要调整一下不符合规则的插入数据,而插入的这个数据影响的是它这条路径的所有祖先,如下图的100影响的是11-10-4,所以我们只需要将100与这条路径的数据进行对比,满足规则就停下来,不满足规则就继续对比

图示(大堆演示)

  • 57
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A.A呐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值