【数据结构】(C语言):堆(二叉树的应用)

堆:

  • 此处堆为二叉树的应用,不是计算机中用于管理动态内存的堆。
  • 形状是完全二叉树。
  • 堆分两种:最大堆,最小堆。
  • 最大堆:每个节点比子树所有节点的数值都大,根节点为最大值。
  • 最小堆:每个节点比子树所有节点的数值都小,根节点为最小值。
  • 左右节点的数值没有顺序要求,但有左子节点才能有右子节点。
  • 一般用数组实现堆。最小堆可以实现优先队列。

注:完全二叉树:每个节点最多2个节点,倒数第二层级(含)之前层级的所有节点都有元素,最后一层级从左到右依次有元素(中间不能断)。

子树:节点及其所有子节点形成子树。(即节点,左右子节点,左右子节点的左右子节点,。。。)

根节点:没有父节点。

兄弟节点:其父节点是同一个节点。

父子节点在数组中的索引号
节点索引号(根节点为0)
节点x
父节点(x-1)// 2
左兄弟节点(右节点才有)x - 1
右兄弟节点(左节点才有)x + 1
左子节点2x + 1
右子节点2x + 2


C语言实现:(使用数组实现最小堆)

创建堆(结构体数据类型):记录数组地址和元素个数

// 堆(结构体数据类型)
typedef struct Heap
{
	int *p;			// 记录数组地址
	int n;			// 记录元素个数
} Heap;             // 别名

 (函数)堆初始化:

// 堆初始化
void init(Heap *heap, int length)
{
	heap->p = (int *)malloc(length * sizeof(int));    // 分配内存空间
	if(heap->p == NULL)
	{
		perror("Memory allocation failed");
		exit(-1);
	}
	heap->n = 0;            // 元素个数,初始化为0
}

 创建堆变量,并初始化

Heap heap;         // 创建堆变量
init(&heap, 8);    // 设置数组最大元素个数为8

添加元素:

1、先在末尾添加元素。

2、(向上调整)与父节点比较大小,若小于父节点,与父节点交换位置,直到开头位置(根节点,数组第一个元素)。

(注:子节点索引号为x,父节点索引号为(x-1)//2)

void add(Heap *heap, int data)		// add a element to the heap
{
	// 往末尾添加元素
	heap->p[heap->n] = data;
	// (向上调整) 与父节点比较,小于父节点的值,与父节点交换位置
	int cur = heap->n;
	while(cur > 0)
	{
		int parent = ceil((cur - 1) / 2);
		if(heap->p[parent] > data)
		{
			heap->p[cur] = heap->p[parent];
			heap->p[parent] = data;
			cur = parent;
		}
		else break;
	}
    // 每添加一个元素,元素个数+1
	heap->n++;
}

删除(根节点):

1、记录根节点(数组第一个元素)和末尾节点(数组最后一个元素)。

2、末尾节点的值换到根节点位置,元素个数-1。

3、(向下调整)从根节点开始,依次与左右子节点比较大小,数值小的是父节点,直到比对到末尾。

(注:父节点索引号为x,左子节点索引号为2x+1,右子节点索引号为2x+2)

int delete(Heap *heap)			// delete root from the heap
{
	if(heap->n == 0) return -1;    // 空树
	heap->n--;                     // 每删除一次根节点,元素个数-1
	int root = heap->p[0], enddata = heap->p[heap->n];
	heap->p[0] = enddata;	       // 末尾元素换到第一个位置
	// (向下调整) 与左右子节点比较,若子节点小,与较小子节点交换位置
	int cur = 0;
	while(cur <= heap->n)
	{
		int left = cur * 2 + 1, right = cur * 2 + 2, minchild;
		if(left > heap->n) break;				// 没有左子节点
		if(right > heap->n) minchild = left;	// 没有右子节点,有左子节点
		else									// 左右子节点都有的情况
		{
			// 左右子节点比较,找到较小子节点
			if(heap->p[right] < heap->p[left]) minchild = right;
			else minchild = left;
			// 父节点与较小子节点比较,若子节点小,与子节点交换位置
			if(heap->p[minchild] < enddata)
			{
				heap->p[cur] = heap->p[minchild];
				heap->p[minchild] = enddata;
				cur = minchild;
			}
			else break;
		}
	}
	return root;
}

获取根节点:(数组第一个元素)

int getroot(Heap *heap)			// get the root from the heap
{
	if(heap->n == 0)
	{
		printf("Empty heap\n");
		exit(-1);
	}
	return heap->p[0];
}

遍历堆:(类似广度遍历二叉树)

每个节点比子树的所有节点都小,但左右节点没有顺序要求。

void traverse(Heap *heap)		// show element one by one (like breadth traverse the tree)
{
	if(heap->n == 0) return ;

	printf("elements(%d): ", heap->n);
	for(int k = 0; k < heap->n; k++)
	{
		printf("%d  ", heap->p[k]);
	}
	printf("\n");
}

清空堆:

释放数组内存空间,指向数组的指针指向NULL,元素个数为0。

void clear(Heap *heap)		// clear the heap (free memory space of the array)
{
	free(heap->p);          // 释放数组内存空间
	heap->p = NULL;         // 指针指向NULL,避免野指针
	heap->n = 0;            // 元素个数为0
}


完整代码:(heap.c)

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/* structure */
typedef struct Heap
{
	int *p;			// memory address of the heap (array)
	int n;			// the number of the heap
} Heap;

/* function prototype */
void init(Heap *, int);		// heap initialization
void add(Heap *, int);		// add a element to the heap
int delete(Heap *);			// delete root from the heap
int getroot(Heap *);		// get the root from the heap
void traverse(Heap *);		// show element one by one (likely breadth traverse the tree)
void clear(Heap *);			// clear the heap (free memory space of the array)

/* main function */
int main(void)
{
	Heap heap;
	init(&heap, 8);
	printf("length: %d\n", heap.n);

	add(&heap, 5);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	add(&heap, 8);	
	add(&heap, 3);	
	add(&heap, 9);	
	add(&heap, 2);
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);

	delete(&heap);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	delete(&heap);	
	printf("root(the minimum): %d\n", getroot(&heap));
	traverse(&heap);
	
	clear(&heap);
	printf("length: %d\n", heap.n);
	printf("root(the minimum): %d\n", getroot(&heap));
	return 0;
}

/* subfunction */
void init(Heap *heap, int length)		// heap initialization
{
	heap->p = (int *)malloc(length * sizeof(int));
	if(heap->p == NULL)
	{
		perror("Memory allocation failed");
		exit(-1);
	}
	heap->n = 0;
}

void add(Heap *heap, int data)		// add a element to the heap
{
	// add a element to the end of the heap
	heap->p[heap->n] = data;
	// (adjust up) compare with parent,if smaller than parent, change the position
	int cur = heap->n;
	while(cur > 0)
	{
		int parent = ceil((cur - 1) / 2);
		if(heap->p[parent] > data)
		{
			heap->p[cur] = heap->p[parent];
			heap->p[parent] = data;
			cur = parent;
		}
		else break;
	}
	heap->n++;
}

int delete(Heap *heap)			// delete root from the heap
{
	if(heap->n == 0) return -1;
	heap->n--;
	int root = heap->p[0], enddata = heap->p[heap->n];
	heap->p[0] = enddata;	// put the last element to the first position
	// (adjust down) compare with left and right child, minimun is parent
	int cur = 0;
	while(cur <= heap->n)
	{
		int left = cur * 2 + 1, right = cur * 2 + 2, minchild;
		if(left > heap->n) break;				// no left child
		if(right > heap->n) minchild = left;	// have left child, no right child
		else									// have left child and right child
		{
			// left child compare with right child, find smaller one
			if(heap->p[right] < heap->p[left]) minchild = right;
			else minchild = left;
			// smaller child compare with parent,if child is the smallest, change
			if(heap->p[minchild] < enddata)
			{
				heap->p[cur] = heap->p[minchild];
				heap->p[minchild] = enddata;
				cur = minchild;
			}
			else break;
		}
	}
	return root;
}

int getroot(Heap *heap)			// get the root from the heap
{
	if(heap->n == 0)
	{
		printf("Empty heap\n");
		exit(-1);
	}
	return heap->p[0];
}

void traverse(Heap *heap)		// show element one by one (like breadth traverse the tree)
{
	if(heap->n == 0) return ;

	printf("elements(%d): ", heap->n);
	for(int k = 0; k < heap->n; k++)
	{
		printf("%d  ", heap->p[k]);
	}
	printf("\n");
}

void clear(Heap *heap)		// clear the heap (free memory space of the array)
{
	free(heap->p);
	heap->p = NULL;
	heap->n = 0;
}

编译链接: gcc -o heap heap.c

执行可执行文件: ./heap

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值