还在用老掉牙的冒泡排序吗?快试试堆排序吧!


前言

冒泡排序具有很强的局限性,在具体使用的时候并不方便

例如:冒泡排序的时间复杂度为O(N^2),也就代表着100w的数据,如果用冒泡排序的话,需要进行1w亿次


为了提高排序的速度,我们可以采用堆排序

一、堆排序的思路

利用堆的性质
大堆:每个结点的值都大于或等于其左右孩子结点的值
小堆 :每个结点的值都小于或等于其左右孩子结点的值
将堆顶的元素保留起来,放在合理的位置
只要堆始终被维护这,那我们就一直可以获得堆中的最值
依次来进行排序
堆排序的时间复杂度为O(N*logN)

二、使用方法

1.利用现有的堆保存堆顶的数据

代码如下(示例):



void HeapSort(int* a, int n)
{
	//在有现成的堆的情况
	//把数组导入堆中去
	//把pop堆顶出来的元素存到a里面
	
	HeapInit(&hp);
	
	for (int i = 0; i < n; i++)
	{
		//插入元素
		HeapPush(&hp, a[i]);
	}

	//将堆里面的数据再重新拷贝回数组中
	for (int i = 0; i < n; i++)
	{
		a[i] = HeapTop(&hp);
		HeapPop(&hp);
	}

//以下是建堆时需要的自定义函数
//堆的初始化
void HeapInit(Heap* hp)
{
	hp->_capacity = 4;
	hp->_size = 0;
	HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * 4);
	if (!tmp)
	{
		perror("malloc");
		return;
	}
	hp->_a = tmp;
}

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	AdjustCapacity(hp);
	//第一步插入
	hp->_a[hp->_size] = x;
	hp->_size++;
	//第二步调整
	AdjustUp(hp->_a, hp->_size - 1);
}


// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));

	//交换首尾
	Swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;
	//调整
	AdjustDown(hp->_a, hp->_size, 0);
}

// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	if (HeapEmpty(hp))
	{
		return -1;
	}
	return hp->_a[0];
}

2.把原有的数组调整为堆,将top元素放数组尾

代码如下(示例):

void HeapSort(int* a, int n)
{
	//当要调整的元素只剩一个时,就意味着调整完了
	while (n != 1)
	{
		//从最后一个叶子节点的父节点开始依次向下调整
		//调整顺序不断向上
		for (int i = (n - 1 - 1) / 2; i >= 0; i--)
		{
			AdjustDown(a, n, i);
		}
		Swap(&a[0], &a[n - 1]);
		n--;
	}
}
//以下是需要使用到的自定义函数
//交换两个元素
void Swap(HPDataType* a, HPDataType* b)
{
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向下调整
void AdjustDown(int *a, int n, int parent)
{
	assert(a);
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (a[child] > a[child + 1] && child + 1 < n)
		{
			child++;
		}

		if (a[child] < a[parent])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}

	}
}

总结

以上就是今天要讲的堆排序的内容,本文仅仅简单介绍了堆排序的使用,能够有效的解决排序速度慢的问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值