树是⼀种非线性的数据结构,它是由 n(n>=0) 个有限结点组成⼀个具有层次关系的集合。 具有以下特点:
树的表示有很多种,最常用的便是孩子兄弟表示法,其很好地解决了结点和结点之间的关系。
struct TreeNode
{
struct Node* child; // 左边开始的第⼀个孩⼦结点
struct Node* brother; // 指向其右边的下⼀个兄弟结点
int data; // 结点中的数据域
};
文件系统是计算机存储和管理文件的⼀种方式,它利用树形结构来组织和管理文件和文件夹。在文件系统中,树结构被广泛应用,它通过父结点和⼦结点之间的关系来表示不同层级的文件和文件夹之间的关联。
⼀棵二叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左子树和右子树的二叉树组成或者为空。
特点:
如果每⼀个层的结点数都达到最大值或满足结点总数是2k-1则这个二叉树就是满二叉树。 2k-1的公式推导:
总的结点数:20 + 21 + 22+……+2k-1 = 1 * (1 - 2k) / 1 - 2 = 2k-1
规定根结点的层数为 1:
顺序结构存储是使用数组来存储,在实现完全二叉树能减少空间浪费。
由于堆底层是用数组实现的,因此相似于顺序表,其结构定义如下:
typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{
HPDataType* arr;
int size;//有效数据个数
int capacity;//容量
}HP;
这些代码实现已经在顺序表中介绍到。
//堆的初始化
void HPInit(HP* php)
{
assert(php);
php->arr = NULL;
php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{
assert(php);
if (php->arr)
free(php->arr);
php->arr = NULL;
php->capacity = php->size = 0;
}
熟悉了堆的概念与结构后,我们清楚堆要不就是大根堆,要不就是小根堆。问题在于插入数据后,我们如何通过代码实现化成大根堆或者小根堆的形式?由此我们提出了向上(下)调整算法,也会带大家分析这两种算法哪种更好。
bool HPEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
由此我们引入了向下调整算法。
前提:左右⼦树必须是⼀个堆,才能调整。
HPDataType HPTop(HP* php)
{
assert(!HPEmpty(php));
return php->arr[0];
}
int HPSize(HP* php)
{
assert(php);
return php->size;
}
根据大O表示法,则O(n*log2n) --> 详见算法复杂度篇章
根据大O表示法可见时间复杂度为O(n)
因此==向下调整算法的时间复杂度更优==。
Heap.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<time.h>
typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{
HPDataType* arr;
int size;//有效数据个数
int capacity;//容量
}HP;
//堆的初始化
void HPInit(HP* php);
//堆的销毁
void HPDesTroy(HP* php);
//堆的插入数据
void HPPush(HP* php, HPDataType x);
//删除堆顶数据
void HPPop(HP* php);
//获取堆顶数据
HPDataType HPTop(HP* php);
//判空
bool HPEmpty(HP* php);
//求size
int HPSize(HP* php);
//向上调整
void AdjustUp(HPDataType* arr, int child);
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n);
//交换
void Swap(int* x, int* y);
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
//堆的初始化
void HPInit(HP* php)
{
assert(php);
php->arr = NULL;
php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{
assert(php);
if (php->arr)
free(php->arr);
php->arr = NULL;
php->capacity = php->size = 0;
}
//交换
void Swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
//向上调整
void AdjustUp(HPDataType* arr, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
//>:大堆
//<:小堆
if (arr[child] > arr[parent])
{
//交换
Swap(&arr[child], &arr[parent]);
child = parent;
parent = (child - 1) / 2;
}
else {
break;
}
}
}
//堆的插入数据
void HPPush(HP* php, HPDataType x)
{
assert(php);
//判断空间是否不足
if (php->size == php->capacity)
{
int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
//空间不足需要增容
HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newCapacity);
if (tmp == NULL)
{
perror("realloc fail!");
exit(1);
}
//realloc成功
php->arr = tmp;
php->capacity = newCapacity;
}
php->arr[php->size] = x;
//向上调整
AdjustUp(php->arr, php->size - 1);
php->size++;
}
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n)
{
int child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && arr[child] < arr[child + 1])
{
child++;
}
//>建小堆
//<建大堆
if (arr[parent] < arr[child])
{
Swap(&arr[parent], &arr[child]);
parent = child;
child = parent * 2 + 1;
}
else {
break;
}
}
}
//删除堆顶数据
void HPPop(HP* php)
{
assert(!HPEmpty(php));
Swap(&php->arr[0], &php->arr[php->size - 1]);
php->size--;
//向下调整
AdjustDown(php->arr, 0, php->size);
}
//获取堆顶数据
HPDataType HPTop(HP* php)
{
assert(!HPEmpty(php));
return php->arr[0];
}
//判空
bool HPEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
//求size
int HPSize(HP* php)
{
assert(php);
return php->size;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void test()
{
HP hp;
HPInit(&hp);
HPPush(&hp, 1);
HPPush(&hp, 3);
HPPush(&hp, 2);
HPPush(&hp, 4);
/*HPPop(&hp);
HPPop(&hp);
HPPop(&hp);
HPPop(&hp);*/
while (!HPEmpty(&hp))
{
printf("%d ", HPTop(&hp));
HPPop(&hp);
}
HPDesTroy(&hp);
}
void test01()
{
int arr[] = { 14,51,31,21,23,32 };
int n = sizeof(arr) / sizeof(arr[0]);
HP hp;
HPInit(&hp);
//调用push将数组中的数据建堆
for (int i = 0;i < n;i++)
{
HPPush(&hp, arr[i]);
}
int i = 0;
while (!HPEmpty(&hp))
{
arr[i++] = HPTop(&hp);
HPPop(&hp);
}
for (int i = 0;i < n;i++)
{
printf("%d ", arr[i]);
}
HPDesTroy(&hp);
}
int main()
{
test();
test01();
//int arr[] = { 14,51,31,21,23,32 };
//int n = sizeof(arr) / sizeof(arr[0]);
Bubblesort(arr,n);
//HeapSort(arr,n);
//for (int i = 0;i < n;i++)
//{
// printf("%d ", arr[i]);
//}
//CreateDate();
TopK();
return 0;
}