三、堆
堆结构介绍
大顶堆(大根堆):根节点的值比左右子树都大,同时左右子树都满足该规则
小顶堆(小根堆):根节点的值比左右子树都小,同时左右子树都满足该规则
堆结构是一种特殊的完全二叉树,它与堆内存是两种概念
堆结构的根节点一定是整棵树中的最大值、最小值
堆结构如何存储:
首先堆结构是一种完全二叉树,并且需要在使用的时候频繁地找双亲节点进行比较,所以链式不好找双亲节点,因此堆结构非常适合用顺序存储,通过二叉树性质5来实现找双亲:
性质5:
有一个n个结点的完全二叉树,结点按照从上到下从左到右的顺序排序为1~n。
1、i > 1时,i/2就是它的双亲结点。
2、i*2是i的左子树,当i*2>n时,则i没有左子树。
3、2*i+1是i的右子树,2*i+1>n时,则i没有
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
#define SWAP(a,b) do{typeof(a) t=(a); (a)=(b); (b)=t;}while(0)
// 设计堆结构
typedef struct Heap
{
TYPE* ptr;
size_t cap; // 容量
size_t cnt; // 个数
}Heap;
// 创建堆结构
Heap* create_heap(size_t cap)
{
Heap* heap = malloc(sizeof(Heap));
heap->ptr = malloc(sizeof(TYPE)*cap);
heap->cap = cap;
heap->cnt = 0;
return heap;
}
// 满堆
bool full_heap(Heap* heap)
{
return heap->cnt >= heap->cap;
}
// 空堆
// 添加 每次添加前 heap一定满足堆结构
bool add_heap(Heap* heap,TYPE data)
{
if(full_heap(heap)) return false;
// 把添加的值放入堆的末尾
heap->ptr[heap->cnt++] = data;
// 在添加的位置可能与它的双亲节点不构成堆结构 需要向上调整
int index = heap->cnt; // 添加的位置的编号
// 有双亲节点
while(index > 1)
{
// 插入的值比双亲大 要交换
if(heap->ptr[index-1] > heap->ptr[index/2-1])
{
SWAP(heap->ptr[index-1],heap->ptr[index/2-1]);
index /= 2;
continue;
}
return true;
}
return true;
}
// 堆排序 循环实现
void heap_sort(int* arr,size_t len)
{
// 先把数组从下往上调成堆结构
for(int i=1; i<=len; i++)
{
// i j 是编号
int j = i;
while(j > 1)
{
if(arr[j-1] > arr[j/2-1])
{
SWAP(arr[j-1],arr[j/2-1]);
j /= 2;
continue;
}
break;
}
}
// 在堆结构中有两个以上元素,需要进行堆排序
while(len > 1)
{
// 交换堆顶和末尾
SWAP(arr[0],arr[len-1]);
// 删除末尾
len--;
// 从堆顶编号1开始 自上而下重新判断调成堆结构
int i = 1;
while(i-1 < len)
{
// 当右子树存在 左子树必定存在
if(i*2 < len)
{
// 右大于等于左 且比根大 交换根和右
if(arr[i*2] >= arr[i*2-1] && arr[i*2] > arr[i-1])
{
SWAP(arr[i-1],arr[i*2]);
// 更新编号 往右子树继续调整
i = i*2+1;
}
// 左比右大 且比根大 交换根和左
else if(arr[i*2-1] > arr[i*2] && arr[i*2-1] > arr[i-1])
{
SWAP(arr[i-1],arr[i*2-1]);
// 往左子树调整
i = i*2;
}
// 根是最大的
else
break;
}
// 有左子树 没有右子树
else if(i*2-1 < len)
{
// 左比根大 交换
if(arr[i*2-1] > arr[i-1])
{
SWAP(arr[i*2-1],arr[i-1]);
}
break;
}
// 没有左右
else
break;
}
// 继续步骤1 直到个数剩下1个结束
}
}
// 查看
void show_heap(Heap* heap)
{
for(int i=0; i<heap->cnt; i++)
{
printf("%d ",heap->ptr[i]);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
int arr[15] = {};
for(int i=0; i<15; i++)
{
arr[i] = rand()%100;
}
heap_sort(arr,15);
for(int i=0; i<15; i++)
{
printf("%d ",arr[i]);
}
/*
Heap* heap = create_heap(10);
for(int i=0; i<15; i++)
{
int data = rand()%100;
printf("%d ",data);
add_heap(heap,data);
}
printf("\n");
show_heap(heap);
*/
}
右子树