0
点赞
收藏
分享

微信扫一扫

浅谈——堆(数据结构)

徐一村 2022-04-13 阅读 72

目录

一、堆的性质

二、堆的相关基础操作

        堆的创建

      堆的插入

        堆的删除

        获取堆顶元素

        堆的判空

        堆的有效元素个数

        堆的销毁 

三、堆排序

建堆


一、堆的性质


只要满足以下两点,它就是一个堆:

每个结点的值都大于或等于其左右孩子结点的值,我们叫做“大顶堆”。

每个结点的值都小于或等于其左右孩子结点的值,我们叫做“小顶堆”。


二、堆的相关基础操作


        堆的创建


// 堆的构建
void HeaPCreate(Heap* hp, HPDataType* a, int n)
{
	//申请一个和传入的数组一样大的空间保存堆
	hp->arry = (HPDataType*)malloc(sizeof(HPDataType)*n);
	if (NULL == hp->arry)
	{
		assert(hp);
		return;
	}
	memcpy(hp->arry, a, n * 4);
	hp->capacity = n;
	hp->size = n;
	for (int root = (n - 2) / 2; root >= 0; root--)
    {
		//用向下调整从下向上(从第一个非叶子节点开始)依次对堆中的节点进行调整
		AjustdownHeap(hp,root);
	}
}

      堆的插入

只能在尾插入然后进行向上调整

void HeapPush(HP* php, HPDataType x)
{
	assert(php);

	if (php->size == php->capacity)
	{
        //申请新空间
		size_t newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = realloc(php->a, sizeof(HPDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc failed\n");
			exit(-1);
		}
        //把a指向新的地址
		php->a = tmp;
        //更新容量
		php->capacity = newCapacity;
	}
    //将x放在堆尾
	php->a[php->size] = x;
	++php->size;

	// 向上调整,控制保持是一个小堆
	AdjustUp(php->a, php->size - 1);
}

void AdjustUp(HPDataType* a, size_t child)
{
    //找到他的父亲
	size_t parent = (child - 1) / 2;
    //到堆顶了就不需要再进行调整
	while (child > 0)
	{
        //如果孩子比父亲小,那就进行交换
		if (a[child] < a[parent])
			//if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

void Swap(HPDataType* pa, HPDataType* pb)
{
	HPDataType tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}


        堆的删除

只能删除堆顶的元素,其方法是将堆顶的元素和堆尾进行交换,删除堆尾的元素,然后将堆顶元素进行向下调整

// 删除堆顶的数据。(最小/最大)
void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);
    
    //交换堆顶  堆尾元素
	Swap(&php->a[0], &php->a[php->size - 1]);
    //删除堆尾元素
	--php->size;

	AdjustDown(php->a, php->size, 0);
}

void AdjustDown(HPDataType* a, size_t size, size_t root)
{
	size_t parent = root;

    //默认是左孩子
	size_t child = parent * 2 + 1;

    //走到堆尾就结束,不用再进行调整
	while (child < size)
	{
		// 1、选出左右孩子中小的那个
		if (child + 1 < size && a[child + 1] < a[child])
		{
			++child;
		}

		// 2、如果孩子小于父亲,则交换,并继续往下调整
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

        获取堆顶元素

HPDataType HeapTop(HP* php)
{
	assert(php);
    //数组长度大于0 才能运行,否则非法访问
	assert(php->size > 0);

	return php->a[0];
}

        堆的判空

bool HeapEmpty(HP* php)
{
	assert(php);

	return php->size == 0;
}

        堆的有效元素个数

size_t HeapSize(HP* php)
{
	assert(php);

	return php->size;
}

        堆的销毁 

void HeapDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

三、堆排序

建堆

升序:建大堆(不能建小堆)

降序:建小堆

我们可以直接对数组建堆,使数组满足堆的性质

例如:

int main()
{
	int a[] = { 4, 2, 7, 8, 5, 1, 0, 6 };
	HeapSort(a,sizeof(a)/sizeof(a[0]));
	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}


void HeapSort(int* a, int n)
{
	assert(a);
    //我们可以把数组看成依次插入n个数
    //每次对他们进行向上调整就可以形成一个堆
	/*for(int i = 1;i<n;i++)
	{
		AdjustUp(a, i);
	}*/

    
    //向下调整
	//找到最后一个数的父亲,然后进行向下调整
    //依次往上走,直到走到根节点
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
    size_t end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		--end;
	}
}

 2.top-k问题:

TOP-K 问题:即求数据结合中前 K 个最大的元素或者最小的元素,一般情况下数据量都比较大 。
比如:专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等。
对于 Top-K 问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了 ( 可能数据都不能一下子全部加载到内存中 ) 。最佳的方式就是用堆来解决,

基本思路如下:

 点个赞吧!

 

举报

相关推荐

数据结构——堆

数据结构--堆

数据结构-堆

数据结构:堆

堆(数据结构)

【数据结构】堆

浅谈数据结构

数据结构---堆---简单

0 条评论