数据结构(特殊二叉树-堆结构(树))

三、堆
堆结构介绍

大顶堆(大根堆):根节点的值比左右子树都大,同时左右子树都满足该规则

小顶堆(小根堆):根节点的值比左右子树都小,同时左右子树都满足该规则

堆结构是一种特殊的完全二叉树,它与堆内存是两种概念

堆结构的根节点一定是整棵树中的最大值、最小值

堆结构如何存储:

首先堆结构是一种完全二叉树,并且需要在使用的时候频繁地找双亲节点进行比较,所以链式不好找双亲节点,因此堆结构非常适合用顺序存储,通过二叉树性质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);
	*/
}

右子树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值