数据结构——二叉树——堆以及堆排序(顺序实现和递归实现)

5 篇文章 0 订阅
1 篇文章 0 订阅
 

#include <stdio.h>

#include <stdlib.h>

#include <stdbool.h>

#define TYPE int

#define SWAP(a,b) {typeof(a) t=(a);(a)=(b);(b)=t;}

// 大顶堆

typedef struct Heap

{

TYPE* arr;

size_t cal;

size_t cnt;

}Heap;

Heap* create_heap(size_t cal)

{

Heap* heap = malloc(sizeof(Heap));

heap->arr = malloc(sizeof(TYPE)*cal);

heap->cal = cal;

heap->cnt = 0;

return heap;

}

// 满堆

bool full_heap(Heap* heap)

{

return heap->cnt >= heap->cal;

}

// 空堆

bool empty_heap(Heap* heap)

{

return 0 == heap->cnt;

}

// 添加

bool add_heap(Heap* heap,TYPE data)

{

if(full_heap(heap)) return false;

heap->arr[heap->cnt++] = data;

// 添加位置进行调整重新形成堆

int i = heap->cnt; //编号

while(i > 1)

{

if(data > heap->arr[i/2-1])

{

SWAP(heap->arr[i-1],heap->arr[i/2-1]);

i = i/2;

}

else

break;

}

return true;

}

// 删除 删除堆顶

bool del_heap(Heap* heap)

{

if(empty_heap(heap)) return false;

// 交换堆顶与末尾 并删除末尾

SWAP(heap->arr[0],heap->arr[heap->cnt-1]);

heap->cnt--;

// 从上往下调整

int i = 1; //编号

while(i <= heap->cnt)

{

// 有右子树

if(i*2+1 <= heap->cnt)

{

//右子树最大 交换右根

if(heap->arr[i*2] > heap->arr[i*2-1] &&

heap->arr[i*2] > heap->arr[i-1])

{

SWAP(heap->arr[i*2],heap->arr[i-1]);

i = i*2+1;

}

//左子树最大,交换左根

else if(heap->arr[i*2-1] > heap->arr[i-1])

{

SWAP(heap->arr[i*2-1],heap->arr[i-1]);

i = i*2;

}

//根最大

else

break;

}

// 没有右,有左子树

else if(i*2 <= heap->cnt)

{

// 左比根大,交换左根

if(heap->arr[i*2-1] > heap->arr[i-1])

{

SWAP(heap->arr[i*2-1],heap->arr[i-1]);

i = i*2;

}

// 左比根小,结束

else

break;

}

//没有左右

else

break;

}

return true;

}

// 遍历

void show_heap(Heap* heap)

{

for(int i=0; i<heap->cnt; i++)

{

printf("%d ",heap->arr[i]);

}

printf("\n");

}

// 堆顶

TYPE top_heap(Heap* heap)

{

return heap->arr[0];

}

// 堆排序 顺序实现

void sort_heap(int* arr,int len)

{

// 把数组调成堆结构

for(int i=1; i<=len; i++)

{

int j=i;

while(j > 1)

{

if(arr[j-1] > arr[j/2-1])

{

SWAP(arr[j-1],arr[j/2-1]);

j = j/2;

}

else

break;

}

}

// 删除堆顶,直到堆为空

while(len > 1)

{

// 交换堆顶 末尾

SWAP(arr[0],arr[len-1]);

len--;

//从上往下调整

int i = 1;

while(i <= len)

{

if(i*2+1 <= len)

{

if(arr[i*2] > arr[i*2-1]

&& arr[i*2] > arr[i-1])

{

SWAP(arr[i*2],arr[i-1]);

i = i*2+1;

}

else if(arr[i*2-1] > arr[i-1])

{

SWAP(arr[i*2-1],arr[i-1]);

i = i*2;

}

else

break;

}

else if(i*2 <= len)

{

if(arr[i*2-1] > arr[i-1])

{

SWAP(arr[i*2-1],arr[i-1]);

i = i*2;

}

else

break;

}

else

break;

}

}

}

// 从top下标 到end下标 从上往下调整成堆结构

void _sort_heap_recursion(int* arr,int top,int end)

{

if(top >= end) return;

int max = top+1; // max是左右根中最大值的编号

int l = max*2;

int r = max*2+1;

if(l-1 <= end && arr[l-1] > arr[max-1])

{

// 有左子树,且左子树大于max的值,更新max

max = l;

}

if(r-1 <= end && arr[r-1] > arr[max-1])

{

// 有右子树,且右子树大于max的值,更新max

max = r;

}

if(max-1 != top)

{

// max是左右根中最大的,交换根与max

SWAP(arr[top],arr[max-1]);

_sort_heap_recursion(arr,max-1,end);

}

}

// 堆排序 递归实现

void sort_heap_recursion(int* arr,int len)

{

// 把数组调成堆结构

for(int i=2; i<=len; i++)

{

int j=i;

while(j > 1)

{

if(arr[j-1] > arr[j/2-1])

{

SWAP(arr[j-1],arr[j/2-1]);

j = j/2;

}

else

break;

}

}

for(int i=len-1; i>0; i--)

{

SWAP(arr[0],arr[i]);

_sort_heap_recursion(arr,0,i-1);

}

}

void show_arr(int* arr,int len)

{

for(int i=0; i<len; i++)

{

printf("%d ",arr[i]);

}

printf("\n");

}

int main(int argc,const char* argv[])

{

int arr[10] = {};

for(int i=0; i<10; i++)

{

arr[i] = rand()%100;

}

sort_heap_recursion(arr,10);

show_arr(arr,10);

/*

Heap* heap = create_heap(20);

for(int i=0; i<10; i++)

{

add_heap(heap,rand()%100);

}

show_heap(heap);

add_heap(heap,99);

show_heap(heap);

while(!empty_heap(heap))

{

printf("%d \n",top_heap(heap));

del_heap(heap);

}

*/

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xiaoyu1381

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

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

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

打赏作者

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

抵扣说明:

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

余额充值