二叉堆

  • 概念

        二叉堆是一种特殊的堆,二叉堆是完全二元树或者是近似完全二元树。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

  • 作用:增加存储效率

         ​​​​​​​一个数插入到10000个数的数组中,在顺序排列结构的数组里,挨个比较的方法来确定新插入数的位置,最坏的情况得比较10000次;如果用二叉堆的结构,节点比较,最坏的情况则需要比较13次。
         有时候,我们需要的仅仅是最大值(最小值),比如在A*寻路里面,取最小F值,就可以应用到二叉堆。

  • 存储

​​​​​​​       二叉堆一般用数组来表示。例如,根节点在数组中的位置是0,第n个位置的子节点分别在2n+1和 2n+2。因此,第0个位置的子节点在1和2,1的子节点在3和4。以此类推。这种存储方式便於寻找父节点和子节点。

  •  基本操作
#pragma once
#include<assert.h>
#include <string.h>
#include "assert.h"
#include <stdio.h>

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}

//向下调整
void AdjustDownBig(int array[], int size, int root)
{
	int max = 0;
	while (1)
	{
		int left = 2 * root + 1;
		int right = 2 * root + 2;
		if (left >= size)
		{
			return;
		}

		if (right < size && array + right > array + left)
		{
			max = right;
		}
		else
		{
			max = left;
		}
		if (array + root >= array + max )
		{
			return;
		}
		Swap(array + root, array + max);
		root = max;
	}
}

void AdjustDownSmall(int array[], int size, int root)
{
	
	while (2 * root + 1 < size)
	{
		int min;
		if (2 * root + 2 < size && array[2 * root + 2] < array[2 * root + 1])
		{
			min = 2 * root + 2;
		}
		else
		{
			min = 2 * root + 1;
		}

		if (array [root] <= array[min])
		{
			return;
		}

		Swap(array + root, array + min);
		root = min;
	}
}



//向上调整O(logN)
void AdjustUpBig(int array[], int size, int child)
{
	while (child > 0)
	{
		int parent = (child - 1) / 2;
		if (array + child <= array + parent)
		{
			return;
		}

		Swap(array + child, array + parent);
		child = parent;
		
	}
}

//------------------------------------------//
//创建堆及堆的操作
//建大堆
void CreateHeapBig(int array[], int size)
{
	for (int i = (size - 2) / 2; i >= 0; i--)
	{
		AdjustDownBig(array, size, i);
    }
}

//建小堆
void CreateHeapSmall(int array[], int size)
{
	for (int i = (size - 2) / 2; i >= 0; i--)
	{
		AdjustDownSmall(array, size, i);
	}
}

typedef struct Heap
{
	int array[100];
	int size;
}Heap;


void HeapInit(Heap* pH,int array[],int size)
{
	assert(size <= 100);
	memcpy(pH->array, array, sizeof(int)*size);
	pH->size = size;

	CreateHeapBig(pH->array, pH->size);
}


//取最值
int HeapTop(Heap* pH)
{
	assert(pH->size > 0);
	return pH->array[0];
}

//o(logn)
void HeapPop(Heap* pH)
{
	assert(pH->size > 0);
	pH->array[0] = pH->array[pH->size - 1];
	pH->size--;

	AdjustDownBig(pH->array, pH->size, 0);
}


void HeapPush(Heap* pH,int data)
{
	assert(pH->size < 100);
	pH->array[pH->size] = data;
	pH->size++;

	AdjustUpBig(pH->array, pH->size, pH->size - 1);
}





#include <stdio.h>
void test()
{
	int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
	int size = sizeof(array) / sizeof(int);
	CreateHeapBig(array, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");
	
	Heap heap;
	HeapInit(&heap,array,size);
	printf("%d\n", HeapTop(&heap));
	HeapPush(&heap, 90);
	printf("%d\n", HeapTop(&heap));
	HeapPop(&heap);
	printf("%d\n", HeapTop(&heap));
}


void test2()
{
	int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
	int size = sizeof(array) / sizeof(int);
	CreateHeapSmall(array, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", array[i]);
	}
	printf("\n");
}

  • 应用

       ​​​​​​​海量数据TopK问题

       100亿个数据中找出最大的前k个?

思路:用打擂台的思想,把100亿个数的前k个建一个小堆,然后用小堆的根节点的数据和其余的海量数据比较,如果比根节点大那么久替换根节点,并且小堆重新排序。否则继续和海量数据比较。

代码如下:由于电脑性能问题,只用10万数据测试。

#pragma once

#include "Heap.h"
#include <stdlib.h>
//海量数据TopK问题,
void TopK(int array[], int size, int k)
{
	int *heap = (int*)malloc(sizeof(int)*k);
	for (int i = 0; i < k; i++) 
	{
		heap[i] = array[i];
	}
	CreateHeapSmall(heap, k);
	for (int j = k; j < size; j++)
	{
		if (array[j] < heap[0])
		{
			continue;
		}
		else
		{
			heap[0] = array[j];
			AdjustDownSmall(heap, k, 0);
		}
	}
	for (int z = 0; z < k; z++)
	{
		printf("%d ", heap[z]);
	}
	printf("\n");
	free(heap);
}




void test3()
{
	int array[100000];
	for (int i = 0; i < 100000; i++) 
	{
		array[i] = i;
	}

	TopK(array, 100000, 10);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉堆是一种特殊的二叉树数据结构,它满足以下两个条件: 1. 父节点的值总是大于或等于(或小于或等于)其子节点的值。 2. 二叉堆是一棵完全二叉树,即除了最底层,其他层的节点个数都是满的,并且最底层的节点都尽可能地左对齐。 在Python中,我们可以使用内置的heapq模块来实现二叉堆。heapq模块提供了一些函数来操作堆,例如heappush、heappop、heapify等。 以下是一个简单的示例代码,演示如何使用heapq模块来构建和操作二叉堆: ```python import heapq # 创建一个空的二叉堆 heap = [] # 向堆中插入元素 heapq.heappush(heap, 5) heapq.heappush(heap, 2) heapq.heappush(heap, 10) heapq.heappush(heap, 1) # 弹出堆中的最小元素 min_element = heapq.heappop(heap) print(min_element) # 输出: 1 # 查看堆中的最小元素(不弹出) min_element = heap[0] print(min_element) # 输出: 2 # 将列表转换为堆 nums = [4, 8, 3, 6, 1] heapq.heapify(nums) # 弹出堆中的最小元素 min_element = heapq.heappop(nums) print(min_element) # 输出: 1 ``` 上述代码中,我们首先创建了一个空的二叉堆,然后使用heappush函数向堆中插入元素。通过heappop函数,我们可以弹出堆中的最小元素。如果只是查看最小元素而不弹出,可以直接访问heap[0]。还可以使用heapify函数将一个普通的列表转换为二叉堆。 希望这个简单的示例能帮助你理解Python中二叉堆的概念和使用方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值