1.什么是二叉树 | 堆
树
是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
所谓
二叉树
,就是其所有的根的分支(度),
都没有大于2的。
所以二叉树的分支范围就是
0 ~ 2。
2.堆的实现
2.1 Heap.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int HPDatatype;
typedef struct Heap
{
HPDatatype* a;
int size;
int capacity;
}HP;
void HeapPrint(HP* php);//堆的数据打印
void HeapInit(HP* php);//堆的初始化
void HeapDestory(HP* php);//堆销毁
void HeapPop(HP* php);//删除堆顶元素
void HeapPush(HP* php,HPDatatype x);//堆尾插入元素
HPDatatype HeapTop(HP* php);//获取堆顶元素
bool HeapEmpty(HP* php);//判断堆是否为空
int HeapSize(HP* php);//获取堆的数据量
void Swap(int* a, int* b);//调换堆中数据
void AdjustUp_sHeap(HPDatatype* a, int child);//小堆向上调整
void AdjustDown_sHeap(HPDatatype* a, int size, int parent);//小堆向下调整
void AdjustUp_bigHeap(HPDatatype* a, int child);//大堆向上调整
void AdjustDown_bigHeap(HPDatatype* a, int size, int parent);//大堆向下调整
2.2 Heap.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"heap.h"
void HeapPrint(HP* php)
{
for (int i = 0; i < php->size; i++)
{
printf("%d ",php->a[i]);
}
printf("\n");
}
void Swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void CheckCapacity(HP* php)
{
int newcapacity = 0;
if (php->capacity == php->size)
{
newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HPDatatype* tmp = (int*)realloc(php->a, sizeof(HPDatatype) * newcapacity);;
if (NULL == tmp)
{
printf("calloc fail\n");
exit(-1);
}
php->a = tmp;
php->capacity = newcapacity;
}
return;
}
void HeapInit(HP* php)
{
php->a = NULL;
php->capacity = php->size = 0;
}
void HeapDestory(HP* php)
{
assert(php);
free(php->a);
php->a = NULL;
php->capacity = php->size = 0;
}
void HeapPop(HP* php)//删除堆顶的数据
{
assert(!HeapEmpty(php));
assert(php);
Swap(&(php->a[0]), &(php->a[php->size - 1]));
php->size--;
AdjustDown_sHeap(php->a, php->size, 0);//删除以后向下调整
}
void HeapPush(HP* php, HPDatatype x)
{
assert(php);
CheckCapacity(php);
php->a[php->size] = x;
php->size++;
AdjustUp_sHeap(php->a, php->size - 1);
}
HPDatatype HeapTop(HP* php)
{
assert(!HeapEmpty(php));
assert(php);
return php->a[0];
}
bool HeapEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
int HeapSize(HP* php)
{
assert(php);
return php->size;
}
//小堆向上调整
void AdjustUp_sHeap(HPDatatype* a, int child)//child是孩子的坐标不是存储的值
{
int 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 AdjustDown_sHeap(HPDatatype* a, int size, int parent)//child是孩子的坐标不是存储的值
{
int child = parent * 2 + 1;
while (child < size)
{
if (child + 1 < size)//防止越界
child = a[child] < a[child + 1] ? child : child + 1;
//if (child + 1 < size && a[child + 1] < a[child])
//++child;
if (a[child] < a[parent])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//大堆向上调整
void AdjustUp_bigHeap(HPDatatype* a, int child)//child是孩子的坐标不是存储的值
{
int 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 AdjustDown_bigHeap(HPDatatype* a, int size, int parent)//child是孩子的坐标不是存储的值
{
int child = parent * 2 + 1;
while (child < size)
{
if (child + 1 < size)//防止越界
child = a[child] > a[child + 1] ? child : child + 1;
//if (child + 1 < size && a[child + 1] < a[child])
//++child;
if (a[child] > a[parent])
{
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
2.3 Test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"heap.h"
//测试TopK问题
void PrintTopK(int* a, int n, int k)
{
HP hp;
HeapInit(&hp);//小堆
for (int i = 0; i < k; i++)
{
HeapPush(&hp, a[i]);
}
for (int i = k; i < n; i++)
{
if (a[i] > HeapTop(&hp))//如果值比堆顶的值大,就交换,然后向下调整
{
HeapPop(&hp);//
HeapPush(&hp, a[i]);
}
}
HeapPrint(&hp);
HeapDestory(&hp);
}
//测试TopK问题
void testtopk(){
int n = 10000;
int* a = (int*)malloc(sizeof(int) * n);
srand(time(0));
for (size_t i = 0; i < n; ++i)
{
a[i] = rand() % 1000000;
}
a[5] = 1000000 + 1;
a[1231] = 1000000 + 2;
a[531] = 1000000 + 3;
a[5121] = 1000000 + 4;
a[115] = 1000000 + 5;
a[4] = 1000000 + 6;
a[3] = 1000000 + 7;
a[2] = 1000000 + 8;
a[1] = 1000000 + 9;
a[0] = 1000000 + 10;
PrintTopK(a, n, 10);
}
//堆排序的实现
//升序建大堆
//降序建小堆ASA
void HeapSort(int* a,int n)
{
//直接把a构建成堆 小堆 方法1
//for (int i = 1; i < n; i++)
//{
//AdjustUp_sHeap(a, i);
//}
//Printarr(a, n);
//直接把a构建成堆 小堆 方法2
for (int i = ((n-1-1) / 2) ; i >= 0; --i)
{
//printf("%d", i);
AdjustDown_bigHeap(a, n, i);//最后一个开始非叶子结点依次往上做向下调整。
}
int end = n - 1;
while ( end >= 0)
{
Swap(&a[0], &a[end]);//
AdjustDown_bigHeap(a, end, 0);//调堆,end是元素个数,最后一个数的下表是 个数 - 1
printf("end= %d\n", end);
--end;
}
Printarr(a, n);
}
int main()
{
//testtopk();
//testtopk();
int a[] = { 27,15,19,18,28,34,65,49,25,37 };
HeapSort(a, sizeof(a) / sizeof(a[0]));
return 0;
}