数据结构——堆(Heap)

        堆是一种完全二叉树,不适合链式存储。由根结点的数据可以分为大顶堆(大根堆)和小顶堆(小根堆),大顶堆的根节点比左右子树大;相反,小顶堆的根节点比左右子树小。在实际应用中,堆可以实现优先队列的效果。

#define TYPE int
#define swap(a,b) {typeof(a) t=(a); (a)=(b); (b)=t;}

注意上面定义的宏表示两个数据的交换,格式只适用Linux系统,下面来设计一下堆结构:

typedef struct Heap
{
	TYPE *arr;
	int cap;
	int cnt;
}Heap;

根据堆的特性我们有下面多个操作:

创建

//创建
Heap *create_heap(int cap)
{
	Heap *heap=malloc(sizeof(Heap));
	heap->arr=malloc(sizeof(TYPE)*cap+1);
	heap->cap=cap;
	heap->cnt=0;
	return heap;
}

空堆

//空堆
bool empty_heap(Heap *heap)
{
	return !heap->cnt;	
}

满堆

//满堆
bool full_heap(Heap *heap)
{
	return heap->cnt==heap->cap;	
}

添加

//添加
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(heap->arr[i/2]<heap->arr[i])
		{
			swap(heap->arr[i/2],heap->arr[i]);		
		}
		i/=2;
	}
	return true;
}

删除

//删除
bool del_heap(Heap *heap)
{
	if(empty_heap(heap)) return false;
	//堆顶与末尾交换
	swap(heap->arr[1],heap->arr[heap->cnt]);
	//删除末尾
	heap->cnt--;

	//从上往下进行调整为堆
	int i=1;
	while(i<heap->cnt)
	{
		//保证有右子树,比较左右根,谁大谁与根交换,然后继续调整交换后的一边
		if(i*2+1<heap->cnt)
		{
			//假如左右相等,把其中一个交换到根即可
			if(heap->arr[i*2+1]>=heap->arr[i*2] && heap->arr[i*2+1]>heap->arr[i])
			{
				swap(heap->arr[i*2+1],heap->arr[i]);
				i=i*2+1;
			}
			else if(heap->arr[i*2]>heap->arr[i*2+1] && heap->arr[i*2]>heap->arr[i])
			{
				swap(heap->arr[i*2],heap->arr[i]);
				i=i*2;
			}
			else break;
		}
		//保证有左子树,比较根与左,如果左大,交换左和根,调整左边
		else if(i*2<heap->cnt)
		{
			if(heap->arr[i*2]>heap->arr[i])
			{
				swap(heap->arr[i*2],heap->arr[i]);
				i=i*2;
			}
			else break;
		}
		//没有左右子树,说明调整结束
		else break;
	}
	return true;
}

查看全部

//查看全部
void show_heap(Heap *heap)
{
	for(int i=1;i<=heap->cnt;i++)
	{
		printf("%d ",heap->arr[i]);
	}
	printf("\n");
}

堆顶

//堆顶
TYPE top_heap(Heap *heap)
{
	return heap->arr[1];
}

堆排序(循环迭代)

//堆排序 循环实现
void sort_heap(int *arr,int len)
{
	//把数组调整为堆结构
	for(int i=1;i<=len;i++)
	{
		int j=i;
		while(j>1)
		{
			if(arr[j/2]<arr[j])
			{
				swap(arr[j / 2], arr[j]);
				j=j/2;
			}
			else break;
		}
	}
	//删除堆顶,直到堆为空
	while(len>=1)
	{
		swap(arr[1],arr[len]);
		len--;

		int i=1;
		//从上向下调整
		while(i<=len)
		{
			if(i*2+1<=len)
			{
				if(arr[i*2+1]>=arr[i*2] && arr[i*2+1]>arr[i])
				{
					swap(arr[i*2+1],arr[i]);
					i=i*2+1;
				}
				else if(arr[i*2]>arr[i*2+1] && arr[i*2]>arr[i])
				{
					swap(arr[i*2],arr[i]);
					i=i*2;
				}
			}
			else if(i*2<=len)
			{
				if(arr[i*2]>arr[i])
				{
					swap(arr[i*2],arr[i]);
					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;//假设top为最大值,max为左右根中最大值的编号
	int l=max*2;//左子树编号
	int r=max*2+1;//右子树编号
	if(l<=end && arr[l]>arr[max])
	{
		//有左子树,且左比最大值大,更新最大值编号
		max=l;
	}
	if(r<=end && arr[r]>arr[max])
	{
		//有右子树,且右比最大值大,更新最大值编号
		max=r;
	}
	if(top!=max)
	{
		//最大值不是根,则交换根与最大值,继续对最大值位置向下调整
		swap(arr[max],arr[top]);
		_sort_heap_recursion(arr,max,end);
	}
}
//堆排序 递归实现
void sort_heap_recursion(int *arr,int len)
{
	for(int i=1;i<=len;i++)
	{
		//从头遍历每个值,从下向上调整
		int j=i;
		while(j>1)
		{
			if(arr[j/2]<arr[j])
			{
				swap(arr[j/2],arr[j]);
				j=j/2;
			}
			else break;
		}
	}
	for(int i=len;i>0;i--)
	{
		swap(arr[1],arr[i]);
		//从上到下递归调整,从0调整到i-1
		_sort_heap_recursion(arr,1,i-1);
	}
}

综上所述,堆也是一种排序算法,在实际应用中很有参考价值。

over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值