Simple explanation of the heap - C language version [data structure]

Binary tree concept blog : http://t.csdn.cn/XIW84

Table of contents

1. Understanding the heap

1.1 The concept of heap

1.2 The nature of the heap:

1.3 Structure picture of the heap

1.3.1 Small heaps

1.3.2 Large heaps

2. Implementation of the heap

2.1 Insert data into the heap

2.2 Up-tuning function

2.3 Heap deletion

2.4 Down adjustment

3. Application of the heap

3.1 Building a heap (two ways)

3.1.1 Heap building method 1

3.1.2 Heap building method 2

3.2 Heap sort 

3.3 The TOP-K problem of the heap


1. Understanding the heap

1.1 The concept of heap

1.2 The nature of the heap:

The value of a node in the heap is always not greater than or not less than the value of its parent node;

The heap is always a complete binary tree.

1.3 Structure picture of the heap

1.3.1 Small heaps

 Small heaps satisfy the following conditions

1.3.2 Large heaps

The following conditions are satisfied

 Note that it is not necessarily stored from large to small, from small to large! ! !


What is the role of the heap?

Let's talk about it in detail, don't go away! ! !



2. Implementation of the heap

2.1 Insert data into the heap

void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType)*newcapacity);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

		php->a = tmp;
		php->capacity = newcapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

important point! ! !

If our heap is a small heap at the beginning, but after inserting data, we want to keep it as a small heap. We need to compare the size of the inserted data with its parent. There are two situations for comparison:

1. If the inserted data is larger than the father, then no adjustment is required

2. If the inserted data is smaller than the father, it needs to be adjusted   

  If adjustment is required, we need to use the upward adjustment algorithm to keep the heap after inserting data or a small heap


2.2 Up-tuning function

void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;//求出插入数据的父亲位置下标
	
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;//将父亲的下标给孩子,向上调整
			parent = (child - 1) / 2;//再算出此时插入数据的父亲下标
		}
		else
		{
			break;
		}
	}
}

2.3 Heap deletion

Can you use overwrite delete - no! ! !

Using overwrite delete will disrupt the subscript relationship between parent and child, and the parent-child relationship will be completely messed up, so we use the following method to delete data


1. First exchange the data with the subscript 0 and the data with the largest subscript

2. Then directly size--

3. Then you need to use the downward adjustment algorithm to adjust the heap to a small heap

void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&(php->a[0]), &(php->a[php->size - 1]));1.交换
	php->size--;//2. 删除堆顶元素

	AdjustDwon(php->a, php->size, 0);//向下调整,保证还是小堆
}

2.4 Down adjustment

void AdjustDwon(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		// 选出左右孩子中小那个
        //这里的if里面的判断大小尽量写成小于是小堆,大于是大堆
		if (child+1 < size && a[child+1] < a[child])
		{
			++child;
		}

		// 孩子跟父亲比较
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}	
}


3. Application of the heap

3.1 Building a heap (two ways)

3.1.1 Heap building method 1

Use the method of inserting elements to adjust the heap upwards 

void AdjustUp(HPDataType* a, int child)
{
	int 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 HeapSort(int* a, int n)//传一个数组过来,还有元素个数
{
	// 建堆方式1:O(N*logN)
	for (int i = 1; i < n; ++i)
	{
		AdjustUp(a, i);//从插入的第二个元素开始
	}
}

Time complexity of heap building method 1 - dislocation subtraction method


3.1.2 Heap building method 2

Use Down Adjustment to Build Heaps

Method: Find the parent of the last element, and adjust downward from this position                                    

void HeapSort(int* a, int n)
{

	// 建堆方式2:O(N)
	for (int i = (n-1-1)/2; i >= 0; --i)
	{
		AdjustDwon(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDwon(a, end, 0);
		--end;
	}
}

Time complexity of heap building method 2 - dislocation subtraction method



3.2 Heap sort 

Sort in ascending order, build a large pile, and then adjust downward

Why build a large pile?

Build a large heap, the top element of the heap is the largest number, let the top element of the heap exchange with the last element, and then adjust downwards, note: when adjusting downwards here, the adjusted array size is -1, that is, the adjustment just before the exchange The data


Sort in descending order, build a small pile, and then adjust downward

void HeapSort(int* a, int n)
{

	// 建堆方式2:O(N)
	for (int i = (n-1-1)/2; i >= 0; --i)
	{
		AdjustDwon(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);//这里的end是9,传过去向下调整的元素个数也是9,
                             //就不会调整刚刚从堆顶传下来的数据
		AdjustDwon(a, end, 0);
		--end;
	}

3.3 The TOP-K problem of the heap

TOP-K problem: Find the top K largest elements or smallest elements in the data combination. Generally, the amount of data is relatively large.

For example: the top 10 professional players, the world's top 500, the rich list, the top 100 active players in the game, etc.

Implementation idea: 

This space complexity is very small


Notice:

           To find the top k largest numbers is to build a small heap

           Explanation: Since the first k numbers created are small heaps, the subsequent nk numbers may be larger than the value at the top and larger than the elements at the top of the heap, replace the elements at the top of the heap, and then adjust downwards to keep the top k The number is a small pile, and then compare...

           To find the first k smallest numbers is to build a large pile (same as above )


 Code:

void PrintTopK(int* a, int n, int k)
{
	// 1. 建堆--用a中前k个元素建堆
	int* kMinHeap = (int*)malloc(sizeof(int)*k);
	assert(kMinHeap);
	for (int i = 0; i < k; ++i)//将a数组里面前10个数赋值给KMinHeap
	{
		kMinHeap[i] = a[i];
	}
	for (int i = (k - 1 - 1) / 2; i >= 0; --i)//向下调整建堆,建立k个数的小堆
	{
		AdjustDwon(kMinHeap, k, i);
	}

	// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换
	for (int j = k; j < n; ++j)
	{
		if (a[j] > kMinHeap[0])
		{
			kMinHeap[0] = a[j];
			AdjustDwon(kMinHeap, k, 0);//再向下调整,保持前k个数是小堆
		}
	}

	for (int i = 0; i < k; ++i)
	{
		printf("%d ", kMinHeap[i]);
	}
	printf("\n");
}

void TestTopk()
{    
    //随机生成一万个数字,每个数字%1百万,这一万都是比一百万小的数字,
    //我们将其中的10个数改为比一百万大的值
	int n = 10000;
	int* a = (int*)malloc(sizeof(int)*n);
	srand(time(0));
	for (int i = 0; i < n; ++i)
	{
		a[i] = rand() % 1000000;
	}
	a[5] = 1000000 + 1;
	a[1231] = 1000000 + 2;
	a[531] = 1000000 + 3;
	a[5121] = 1000000 + 4;
	a[120] = 1000000 + 5;
	a[99] = 1000000 + 6;
	a[0] = 1000000 + 7;
	a[76] = 1000000 + 8;
	a[423] = 1000000 + 9;
	a[3144] = 1000000 + 10;

	PrintTopK(a, n, 10);
}


This article is about the implementation of the sequential storage structure (heap) of the binary tree. In the next issue, we will talk about the chained storage structure of the binary tree. Remember to support Xiaoyu then! ! !

If you think the article is good, I look forward to your one-click triple link. Your encouragement is the source of motivation for my creation. Let us work together and see you at the top! ! !

Supongo que te gusta

Origin blog.csdn.net/qq_58286439/article/details/130561804
Recomendado
Clasificación