Data structure: heap implementation (C implementation)

insert image description here

Personal homepage: Personal homepage
Personal column: "Data Structure" "C Language"


pile

When a complete binary tree is stored as a sequential list, it is called a heap.

  • The heap is always a complete binary tree
  • The value of a node of the heap is always not greater than (large heap) or not less than (small heap) the value of its parent node

It can be used to solve top k problems or heap sort
insert image description here

The following is the function of the heap to be implemented. The focus is on the insertion and deletion of the heap.


//堆的构建
void HeapInit(Heap* hp);

//堆的销毁
void HeapDestroy(Heap* hp);

//堆的插入
void HeapPush(Heap* hp, HPDataType x);

//堆的删除
void HeapPop(Heap* hp);

//取堆顶的数据
HPDataType HeapTop(Heap* hp);

//堆的数据个数
int HeapSize(Heap* hp);

//堆的判空
bool HeapEmpty(Heap* hp);

2. Implementation ideas

The diagrams in the next part are all based on logical structure! ! !
What is built here is a small heap.

1. Definition of structure

A heap uses a sequence table to store a complete binary tree, so the structure of the heap is the same as that of the sequence table.
A pointer to the dynamically opened space (data), a variable to record the size of the space (capacity), and a variable to record the effective data in the space (size).

typedef int HPDataType;

typedef struct Heap
{
    
    
	HPDataType* data;
	int capacity;
	int size;
}Heap;

2. Heap construction (HeapInit)

Malloc a piece of space, use data to record its address, capacity to record the size of the space at this time, and set size to 0 (there is no valid data in the space at this time).

//堆的构建
#define SIZE 4

void HeapInit(Heap* hp)
{
    
    
	assert(hp);

	hp->data = (HPDataType*)malloc(sizeof(HPDataType) * SIZE);
	if (hp == NULL) 
	{
    
    
		perror("mallo: ");
		exit(-1);
	}

	hp->capacity = SIZE;
	hp->size = 0;
}

3. Heap destruction (HeapDestroy)

Free the dynamically opened space, and set the capacity and size to 0 (at this time, the space size is 0)

//堆的销毁
void HeapDestroy(Heap* hp)
{
    
    
	assert(hp);

	free(hp->data);
	hp->data = NULL;

	hp->capacity = hp->size = 0;
}

4. Heap insertion (HeapPush)

Insert the data at the end of the heap (after the last child node), and then compare it with its parent node. If the node is smaller than its parent node (here is a small heap), exchange the values ​​​​of the two nodes until the node is the top of the heap or Its parent node is smaller than this node.

  • Suppose the subscript of the node is i, then the subscript of its parent node is ( i - 1 ) / 2

insert image description here

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向上调整 假设该节点是 i,父节点是 (i - 1) / 2
void AdjustUp(HPDataType* data, int child)
{
    
    
	int parent = (child - 1) / 2;

	while (child > 0)
	{
    
    
		if (data[child] < data[parent])
		{
    
    
			swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else 
		{
    
    
			break;
		}
	}
}


//堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
    
    
	assert(hp);

	//检查容量
	if (hp->capacity == hp->size)
	{
    
    
		HPDataType* tmp = (HPDataType*)realloc(hp->data ,sizeof(HPDataType) * (hp->capacity * 2));
		if (tmp == NULL)
		{
    
    
			perror("realloc:");
			exit(-1);
		}

		hp->data = tmp;
		hp->capacity *= 2;
	}

	hp->data[hp->size] = x;
	hp->size++;

	//向上调整   传入数组和出入数据的下标
	//此处是小堆
	AdjustUp(hp->data, hp->size - 1);
}

5. Heap deletion (HeapPop)

Heap deletion is to delete the top data of the heap.
The data at the top of the heap is exchanged with the data at the end of the heap, the size is reduced by one, and then the new top data is compared with the minimum value of the left and right child nodes. If the new top data is greater than the minimum value of the left and right child nodes, the data is exchanged, and the new The minimum value of the left and right child nodes
is compared. Until the data is less than the minimum value of the left and right children, or the data exceeds the valid data range.

  • Suppose the subscript of a node is i, the subscript of its left child node: i * 2 + 1, the subscript of its right child: i * 2 + 2
  • Delete the data at the top of the heap, and cannot move to the data to overwrite the data at the top of the heap. If the data is moved, the sibling nodes may become parent-child nodes, and the size relationship between sibling nodes is not guaranteed, which may destroy the heap structure (here, the small heap structure will be destroyed).

insert image description here

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}


//向下调整,假设该节点是 i, 右孩子节点是 2 * i + 1,左孩子节点是 2 * i + 2
void AdjustDown(HPDataType* data, int parent, int size)
{
    
    
	int child = parent * 2 + 1;

	while (parent < size)
	{
    
    
		//防止越界                    找左右孩子中最小的
		if (child + 1 < size && data[child] > data[child + 1])
		{
    
    
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
    
    
			swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
    
    
			break;
		}
	}
}



//堆的删除  首元素 与 尾元素交换,新的堆顶在向下调整
void HeapPop(Heap* hp)
{
    
    
	assert(hp);
	assert(!HeapEmpty(hp));
	
	hp->data[0] = hp->data[hp->size - 1];
	hp->size--;

	//向下调整
	AdjustDown(hp->data, 0, hp->size);
}

6. Get the data at the top of the heap (HeapTop)

Just read the subscript of the array space as 0.

//取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
    
    
	assert(hp);

	return hp->data[0];
}

7. The number of data in the heap (HeapSize)

The size in the heap structure indicates the number of valid data in the heap at this time, just access the size.

//堆的数据个数
int HeapSize(Heap* hp)
{
    
    
	assert(hp);

	return hp->size;
}

8. Heap empty judgment (HeapEmpty)

size indicates the number of valid data in the heap, if size == 0, it means the heap is empty.

//堆的判空
bool HeapEmpty(Heap* hp)
{
    
    
	assert(hp);

	return hp->size == 0;
}

3. Code implementation

//Heap.c   文件


#include "Heap.h"


//堆的构建
void HeapInit(Heap* hp)
{
    
    
	assert(hp);

	hp->data = (HPDataType*)malloc(sizeof(HPDataType) * SIZE);
	if (hp == NULL) 
	{
    
    
		perror("mallo: ");
		exit(-1);
	}

	hp->capacity = SIZE;
	hp->size = 0;
}


//堆的销毁
void HeapDestroy(Heap* hp)
{
    
    
	assert(hp);

	free(hp->data);
	hp->data = NULL;

	hp->capacity = hp->size = 0;
}

//交换
void swap(HPDataType* a, HPDataType* b)
{
    
    
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向上调整 假设该节点是 i,父节点是 (i - 1) / 2
void AdjustUp(HPDataType* data, int child)
{
    
    
	int parent = (child - 1) / 2;

	while (child > 0)
	{
    
    
		if (data[child] < data[parent])
		{
    
    
			swap(&data[child], &data[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
    
    
			break;
		}
	}
}


//堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
    
    
	assert(hp);

	//检查容量
	if (hp->capacity == hp->size)
	{
    
    
		HPDataType* tmp = (HPDataType*)realloc(hp->data ,sizeof(HPDataType) * (hp->capacity * 2));
		if (tmp == NULL)
		{
    
    
			perror("realloc:");
			exit(-1);
		}

		hp->data = tmp;
		hp->capacity *= 2;
	}

	hp->data[hp->size] = x;
	hp->size++;

	//向上调整   传入数组和出入数据的下标
	//此处是小堆
	AdjustUp(hp->data, hp->size - 1);
}



//向下调整,假设该节点是 i, 右孩子节点是 2 * i + 1,左孩子节点是 2 * i + 2
void AdjustDown(HPDataType* data, int parent, int size)
{
    
    
	int child = parent * 2 + 1;

	while (parent < size)
	{
    
    
		//防止越界                    找左右孩子中最小的
		if (child + 1 < size && data[child] > data[child + 1])
		{
    
    
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
    
    
			swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
    
    
			break;
		}
	}
}



//堆的删除  首元素 与 尾元素交换,新的堆顶在向下调整
void HeapPop(Heap* hp)
{
    
    
	assert(hp);
	assert(!HeapEmpty(hp));
	
	hp->data[0] = hp->data[hp->size - 1];
	hp->size--;

	//向下调整
	AdjustDown(hp->data, 0, hp->size);
}



//取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
    
    
	assert(hp);

	return hp->data[0];
}




//堆的数据个数
int HeapSize(Heap* hp)
{
    
    
	assert(hp);

	return hp->size;
}



//堆的判空
bool HeapEmpty(Heap* hp)
{
    
    
	assert(hp);

	return hp->size == 0;
}
//Heap.h  文件

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

#define SIZE 4

typedef int HPDataType;

typedef struct Heap
{
    
    
	HPDataType* data;
	int capacity;
	int size;
}Heap;


//堆的构建
void HeapInit(Heap* hp);

//堆的销毁
void HeapDestroy(Heap* hp);

//堆的插入
void HeapPush(Heap* hp, HPDataType x);

//堆的删除
void HeapPop(Heap* hp);

//取堆顶的数据
HPDataType HeapTop(Heap* hp);

//堆的数据个数
int HeapSize(Heap* hp);

//堆的判空
bool HeapEmpty(Heap* hp);


Summarize

The above is my implementation of the heap! ! !
insert image description here

Guess you like

Origin blog.csdn.net/li209779/article/details/132227139