Implementation of heap + heap sort

          Let's get straight to the point and get to the point! !

content

One, the definition of heap

1. Concept

2. Nature

3. Structure

Second, the realization of the heap

definition

initialization and destruction

data enqueue

Heap insertion diagram

swap function 

Upscale function 

out of the heap

diagram

Downward adjustment function

Downward adjustment function optimization

 Heap empty judgment, heap length, heap top element

Heap element print 

Third, heap sort


One, the definition of heap

1. Concept

A heap is a complete binary tree that can be self-balancing. The storage structure is continuous and can be regarded as a sequence table.

2. Nature

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

The heap with the largest root node is called the max heap or the big root heap, and the heap with the smallest root node is called the min heap or the small root heap.

3. Structure

The logical structure of the heap is a complete binary tree, but in fact the storage in the memory is continuous, so to achieve it, you can think of using a sequence table to achieve it.

Second, the realization of the heap

definition

Remember to redefine data types

Based on the above, we implement the heap with a sequential list

size records the number of valid elements, and capacity records the space size

typedef int HPDataType;

typedef struct Heap
{
	HPDataType* a;
	size_t size;
	size_t capacity;
}HP;

initialization and destruction

The address a pointing to the beginning of the sequence table is empty

The space size and the number of valid elements are both 0

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

Because the space is continuously opened up, only the starting address needs to be released, and the following space will be released accordingly.

Then set the space and the number of elements to 0 

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

data enqueue

data into the heap = insertion order table

First judge whether the space size is enough, give 4 initial spaces, and then expand twice the original capacity each time

Use realloc for expansion, remember to judge, here I am more violent and directly assert

Remember to update the space size

Note: The heap has a large heap and a small heap. After inserting data, you must ensure that the structure of the heap is still a large heap or a small heap

Whether it is a large heap or a small heap, the maximum or minimum data is at the top of the heap. If the inserted data does not conform to the structure of the heap, the data must be adjusted upwards. is the adjustment between the child node and the parent node

Heap insertion diagram

swap function 

It can be seen from the figure that two numbers must be exchanged, then we write a separate exchange function

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

The following is the code for inserting data. For simplicity, we take out the upward adjustment separately

Upscale function 

Note: The storage structure is a sequence table, and the subscript starts from 0. If the size of the sequence table is 1 and the valid data is 1, then the data is at the position where the subscript is 0, so child=php->size-1, where child and parent is the element subscript.

//向上调整
void Up(HPDataType* a,size_t child)
{
	size_t 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;
		}
	}
}
void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	//插入元素
	if (php->size==php->capacity)
	{
		size_t newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
		HPDataType* tmp = (HPDataType*)realloc(php->a,sizeof(HPDataType)*newcapacity);
		assert(tmp);
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;
	//保证是堆的结构
	//向上调整
	size_t child = php->size - 1;
	//size_t parent = (child-1) / 2;
	//while (child>0)
	//{
	//	if (php->a[child] < php->a[parent])
	//	{
	//		//HPDataType data = php->a[parent];
	//		//php->a[parent] = php->a[child];
	//		//php->a[child] = data;
	//		swap(&php->a[child], &php->a[parent]);
	//		child = parent;
	//		parent = (child - 1) / 2;
	//	}
	//	else
	//	{
	//		break;
	//	}
	//}

	Up(php->a,child);
}

out of the heap

Deleting the heap is to delete the data at the top of the heap, change the last data of the data root at the top of the heap, and then delete the last data of the array, and then adjust the algorithm downward.

diagram

After the exchange, the structure of the heap is maintained, and the data, that is, the top element of the heap, must be exchanged with its smallest or largest child (depending on whether it is a large heap or a small heap, a small heap and a small child, and a large heap and a large child) 

Downward adjustment function

The downward adjustment must be performed cyclically. Both the left child and the right child must be smaller than the valid number size, and the left child must be smaller than the right child. The judgment condition only needs the right child to be smaller than the size.

The code takes the small heap as an example:

      I divided two logic lines (somewhat cumbersome, with optimizations below):

      The left child is small and the right child is small

      Exchange data, update the subscripts of the parent node and the two child nodes

      Exit the loop when the data are equal

void Down(HPDataType* a,size_t parent,size_t size)
{
	size_t lchild = parent*2 + 1;
	size_t rchild = parent*2 + 2;
	while (rchild<size)
	{
		if (a[lchild]<a[rchild])
		{
			if (a[parent] > a[lchild])
			{
				swap(&a[parent], &a[lchild]);
				parent = lchild;
				lchild = parent*2 + 1;
				rchild = parent*2 + 2;
			}
		}
		else if (a[lchild]>a[rchild])
		{
			if (a[parent] > a[rchild])
			{
				swap(&a[parent], &a[rchild]);
				parent = rchild;
				lchild = parent*2 + 1;
				rchild = parent*2+ 2;
			}
		}
		else
		{
			break;
		}
	}
}

Downward adjustment function optimization

For the optimization of the above code, a child child is directly determined, and it is the left child by default. At the first if, it must be judged that child+1 is less than size to prevent out of bounds.

If the right child is smaller than the left child, the left child ++ is directly equal to the right child, otherwise unchanged

Then directly judge the size of the parent node and the child to complete the exchange or exit

//down优化
void Down(HPDataType* a, size_t parent, size_t size)
{
	size_t child = parent * 2 + 1;
	while (child < size)
	{
		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;
		}
	}
}
//删除堆顶数据
//互换堆顶和末尾数据,向下调整
void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	size_t parent = 0;
	swap(&php->a[0],&php->a[php->size-1]);
	php->size--;
	Down(php->a,parent,php->size);
}

 Heap empty judgment, heap length, heap top element

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}
size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}
HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size>0);
	return php->a[0];
}

Heap element print 

void HeapPrint(HP* php)
{
	assert(php);
	for (size_t i=0;i<php->size;i++)
	{
		printf("%d ",php->a[i]);
	}
	printf("\n");
}

Third, heap sort

Give a set of data to make it orderly

Create a heap, put data into the heap, and determine whether the heap is empty

Then update the top element of the heap to the array, pay attention to the top element of the heap, and the top element of the heap is always the largest or smallest

Printing the updated data completes the sorting of a set of data

//堆排序
void HeapSort(int* a,int size)
{
	HP hp;
	HeapInit(&hp);
	for (int i = 0;i<size;i++)
	{
		HeapPush(&hp,a[i]);
	}
    HeapPrint(&hp);
	int j = 0;
	while (!HeapEmpty(&hp))
	{
		a[j] = HeapTop(&hp);
		j++;
		HeapPop(&hp);
	}
	HeapDestroy(&hp);
}

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


                 Come and like and comment, iron guys~~~~~~~~~~~~

 

Guess you like

Origin blog.csdn.net/weixin_53316121/article/details/123977909