堆排序

本文深入解析了堆排序的核心机制,包括堆的调整、建堆和删除操作。详细阐述了如何通过调整子树使之成为大顶堆或小顶堆,以及如何基于此实现堆排序算法。同时提供了代码实现,包括模板函数和具体实例,帮助读者理解和实践堆排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 


        堆排序一直没有搞的很明白!今天总算搞定了。其实核心在于“堆的调整”。接口形如adjust_heap(*p, int n, int i),一个T类型的,长度为n的数组,将以i为根节点的子树调整为大顶堆或者小顶堆。原理可以这么想:根节点T[i]有左孩子T[2*i+1]和右孩子T[2*i+2],假如左孩子已经是一个大顶堆,右孩子也是大顶堆,而且:

    T[i] > T[2*i+1]

    T[i] > T[2*i+2]

那么,根据堆的定义,T[i]就是一个大顶堆了。

 

    堆排序首先定义了这么一个“堆的调整”操作,随后的算法都是基于此的。堆以数组存储,a[N],最后一个元素为a[N-1],其父节点为a[(N-1-1)/2],将a[(N-1-1)/2]调整为大顶堆,然后向前走,将a[(N-1-1)/2-1]、a[(N-1-1)/2-2]、。。。a[2]、a[1]、a[0]调整为大顶堆。最后整个数组是一个大顶堆。

    随后删除元素。删除堆顶,将a[0]与最后一个元素a[N-1]交换,此时a[N-1]为最大值,随后对a[0]至a[N-2]范围的元素做“堆的调整”操作,调整为堆后,又删除堆顶,得到第二大的元素。。。。最后数组呈现递增排列。

    所谓“堆的调整”就是,左孩子和右孩子都已经是堆了,根节点是新来的,此时需要自上而下调整一遍。

复杂度:一次堆的调整为log(n),建堆需要n Log(n)。删除元素为O(1),重新调整N次,复杂度也是n*log(n),最终复杂度为n*log(n)。

 

 

// 堆排序
// 堆的调整、建堆、删除

#include <stdio.h>
#include <stdlib.h>

template<typename T>
int is_heap(T *tp, int nLen);
template<typename T>
void adjust_heap(T *tp, int nLen, int pos);
template<typename T>
void make_heap(T *tp, int nLen);
template<typename T>
void heap_sort(T *tp, int nLen);

const int N=20;
int main()
{
	int ap[N];
	int i;
	for (i=0;i<N;i++)
	{
		ap[i]=rand()%100;
		printf("%d ", ap[i]);
	}
	printf("\n");

	heap_sort(ap,N);

	printf("排序后:\n");
	for (i=0;i<N;i++)
	{
		printf("%d ", ap[i]);
	}
	printf("\n");


	return 0;
}

//----------------------------------------
// 交换元素
template<typename T>
void _swap(T &a, T&b)
{
	T tmp;
	tmp=a;
	a=b;
	b=tmp;
}

// 堆的调整
template<typename T>
void adjust_heap(T *tp, int nLen, int pos)
{
	int i=pos;
	int j=2*i+1;
	for ( ;j<nLen; )
	{
		if (j+1<nLen && tp[j+1]<tp[j])
			j++;

		if (tp[i] < tp[j])
		{
			
			break;
		}
		_swap(tp[i], tp[j]);
		i=j;
		j=2*j+1;
	}
}

// 建堆
template<typename T>
void make_heap(T *tp, int nLen)
{
	int i;
	for (i=(nLen-1-1)/2; i>=0; i--)
	{
		adjust_heap(tp, nLen, i);
	}
	if (is_heap(tp,nLen))
	{
		printf("IS a HEAP\n");
	}else
	{
		printf("NOT a HEAP\n");
	}
}

// 排序
template<typename T>
void heap_sort(T *tp, int nLen)
{
	make_heap(tp, nLen);
	int i;
	for (i=nLen-1; i>=1; i--)
	{
		_swap(tp[0], tp[i]);
		adjust_heap(tp, i, 0);
	}
}

// 判断是否为堆
template<typename T>
int is_heap(T *tp, int nLen)
{
	int i;
	for (i=0; 2*i+1<nLen; i++)
	{
		if (tp[i]>tp[2*i+1])
			return 0;
		if (2*i+2<nLen && tp[i]>tp[2*i+2])
			return 0;
	}
	return 1;
}


 

 

ref:

http://blog.youkuaiyun.com/fly_yr/article/details/8550701

http://blog.sina.com.cn/s/blog_5115d58c0100vr26.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值