二叉堆介绍 Introduction to Heap (C implementation)

本文介绍了二叉堆的基本概念,包括其结构属性和顺序属性,并详细阐述了如何通过数组实现二叉堆。此外,还深入探讨了二叉堆的关键操作,如插入、删除最大元素、获取最大元素以及堆的构建等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Preface

This article belongs to the Data Structure series, which give some brief introduction to Tree,Heap,and Hash. Binary Heap is an important basic structure and has great efficiency in Sorting problems (Heap Sort). If there is any error in the article, please feel free to point it out and I will be really aprreciated with it.
We will start from the properties of Binary Heap, which tells you what can be regarded as a binary heap. Then, we introduce the basic operations of it, like insertion, deletion, and build. Enjoy!


一、What is binary Heap?

Binary heap is one of the most common used heaps. It can also be used as a priority Queue (A Queue with order so that any element with higher priority will be pop first, and the elements with the same order will be pop following FIFO principle)
It’s a binary tree with 2 key properties:

Structure Property:

It must be a complete tree, which means all levels except possibly the last are full( Full means each node is either a leaf or has 2 children). And all nodes in the last level have to be as left as possible.
Binary Heap
This property makes it extremely easy to implement the binary heap with array.

Order Property:

There are 2 kinds of Binary Heap: Min Heap and Max Heap. Let’s take Max Heap as an example. In Max Heap, the element in root must be the maximum element in the whole heap, and element in the parent nodes must be bigger or equal to that of the children nodes. Note: There is no sorting information in the heap, no comparison between nodes in the same level.
Example of a max heap

二、Operations of Binary Heap (Max Heap)

1.Basic Struct

How can we represent a binary heap?

Since heap is a complete binary tree, we usually represent it as an array:
Root Node: Array[0]
For the i-th Node:
Its parent node: Array[(i-1)/2]
Left child: Array [2 * i+1]
Right child: Array [2 * i+2]

Last Element: Array[HeapSize-1]
There won’be any gap in the array since the tree is complete.

Array representation

typedef int Element 
struct HeapStruct{
    int Size;//Current number of Elements
    int Capacity;//Maximum element
    Element* Array;
    }
typedef struct HeapStruct* Heap;
//2 common boolean function
int isEmpty(Heap H){
return H->size==0;
}

int isFull(Heap H){
return H->size==H->capacity;
}

2.Insert

There are 2 Steps of Insertion.
Step1:
We insert the new input to the end, update the size information.
在这里插入图片描述
Step2:
Since the insertion breaks the Order Principle of heap, we need to keep comparing the new input and the element (Let’s say, A) in its parent node. We switch the postion of the new input and A until: new input is smaller or equal to A or new input is at the root.
在这里插入图片描述
Here’s the code in details:

//int has been type redefined as Element
//This helps a lot when you want to change the input type
void insert(Heap H,Element input){
if(isFull(H)){
   printf("Heap is Full!\n");
   return;
}
//Step1:
H->size++;
int childIndex=H->size-1, parentIndex=(childIndex-1)/2; 
//Step2:
while(parentIndex>=0&& input>H->Array[parentIndex]){
  H->Array[childIndex]=H->Array[parentIndex];
  childIndex=parentIndex;
  parentIndex=(childIndex-1)/2;
}
H->Array[childIndex]=input;
return;

Speed: O(logn)

3.Pop_Max

To Pop the max value, there are also 2 steps.
Step1:
We first create a variable to store the max value, which is at the root node. Then, we delete the root value, and use the last element to fill the blank. Remember to update the heap size.
EG
Step2:
After Step1, the order property of the heap might be broken. Then, we first find the bigger value of the new root’s children, and switch the new root’s position with the bigger child. Keep this process until the new root value is bigger than both of its children or it reaches the leaf level.
EG
Remember to return the variable you used to store the old root value. Below is the code in detail:

Element Pop_Max(Heap H){
//Step1:
Element Temp=H->Array[0];//Use the Temp to store the return value
Element lastElement=H->Array[H->size-1];//Get the value of the last
                                       //  element. 
H->size--;//Update the size
int parentIndex=0,childIndex=parentIndex*2+1;//Suppose the last element has been put at the root
                   
//Step2:
while(childIndex<=H->size-1){//Not reaches the leaf level
     if(childIndex<H->size-1){//If the node has 2 children
      if(H->Array[childIndex]]<H->Array[childIndex+1])
          childIndex++;//Find the bigger child
     }
     if(lastElement>=H->Array[childIndex])
         break;//Bigger than both, end.
     H->Array[parentIndex]=H->Array[childIndex];
     parentIndex=childIndex;
     childIndex=parentIndex*2+1;
}
H->Array[parentIndex]=lastElemen;
return Temp;

Speed: O(logn)

4.get_Max

Root is the maximum value due to the order principle

Element get_Max(Heap H){
 if(isEmpty(H)){
 printf("Heap is Empty!\n");
 exit(1);
 }
 return H->Array[0];
 }

Speed: O(1)

5.Build_Heap

Simple Approach

It’s very easy to build heap, you just need to allocate some space for the heap structure and insert all the elements into the heap:

Heap Build_Heap(int MaxSize){
Heap H=malloc(sizeof(struct HeapStruct));
H->size=0;
H->capacity=MaxSize;
H->Array=malloc(sizeof(Element)*(MaxSize+1));
}
//And just use the function insert to do the insertion of all elements

Better Approach:

The time complexity of the previous approach is O(n*logn). Can we do better? The answer is yes, we just need to insert all the elements in the heap without considering the Order Property, which means, do not care which one is bigger and just follow the input flow. Then, we start adjusting the order property of the last non-leaf node in reverse level order.
EG
Codes are below:

Heap buildHeap(int size, Element* list) {
	Heap H = malloc(sizeof(struct HeapStruct));
	H->size = size;
	H->capacity = size + 1;
	H->Array = malloc(sizeof(Element) * (size + 1));
	for (int i = 0;i < size;i++)
		H->Array[i] = list[i];
	int parent = (size-1 - 1) / 2;
	int children, Temp;
	while (parent >= 0) {//Reverse Order
		Temp = H->Array[parent];
		children = parent * 2 + 1;
		int localchildren = children, localparent = parent;
		if (children == size - 1) {
			if (Temp < H->Array[children])
			{
				H->Array[parent] = H->Array[children];
				H->Array[children] = Temp;
			}
		}
		else {
			do {
				if (H->Array[localchildren] < H->Array[localchildren + 1])
					localchildren++;
				if (Temp < H->Array[localchildren]) {
					H->Array[localparent] = H->Array[localchildren];
					H->Array[localchildren] = Temp;
				}
				localparent = localchildren;
				localchildren = localparent * 2 + 1;
			} while (localchildren<=size-1&&Temp < H->Array[localchildren]);

		}
		parent--;
	}

6. Delete Heap

void Delete_Heap(Heap H){
  free(H->Array);
  free(H);
  }

Conlusion:

This article is aiming at helping you to better understand the inside thoughts of binary heap. So some codes here might not be that clean, to help you better understand. If there is more time, I will introduce the 2 applications of heap: Heap Sort and K-th Smallest Element later. Anyway, if there is any question, feel free to comment.
(By the way, if you have better idea of the second Algorithm of Build_Heap, please let me know. I think it could be more clean with a little adjustment)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值