数据结构与算法 (最大)堆

数据结构与算法 (最大)堆

堆是一个二叉树结构,如下图:
在这里插入图片描述

堆又分为两种:1.最大堆 2.最小堆

堆的表示:使用数组

堆(最大堆)的特点:

1.每个节点最多可以有两个节点(如上图,一个⚪代表一个节点)。
2.根节点的值是所有堆节点的值中最大的,且每个节点的值都比其孩子(子节点)的值大。
3.除了根节点没有兄弟节点外,最后一个左子节点可以没有兄弟节点,其他节点必须有兄弟节点。

最小堆的特点与最大堆基本一样,只是特点2稍作修改:
2.根节点的值是所有堆节点的值中最小的,且每个节点的值都比其孩子(子节点)的值小。

《注意》:如果不满足上述三个条件,那么就不是堆。

左子节点:
在这里插入图片描述
兄弟节点:
在这里插入图片描述
因为堆由数组实现,所以堆的子节点和父节点寻找方式如下:
i 为数组下标:
i 的左子节点:2i+1
i 的右子节点:2
i+2
i 的父节点: (i-1)/2

数组存储与堆的关系图如下:

在这里插入图片描述

最大堆实现:

初始化时,通过(heap.size / 2 - 1)找出最小(最下层)父节点。找出后判断子节点是否比父节点大,若比父节点大,则交换位置,否则不动。大小位置调整好后,i值减1,从下一个父节点开始判断,依次循环。

完整代码:

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

#define DEFAULT_CAPCITY 128  //数组默认大小

typedef struct _Heap {
    
    
	int* arr;		  //表示存储堆元素的数组
	int size;		  //当前已存储的元素个数
	int capacity;	  //当前的存储容量
}Heap;

//将当前节点和子节点调整成最大堆
void adjustDown(Heap& heap, int index) {
    
    
	int cur = heap.arr[index]; //当前待调整的节点
	int parent, child;

	/*
		*判断是否存在大于当前节点的字节点,若不存在,则堆本身是平衡的,不需要调整;
		*若存在,则将最大的子节点与之交换,交换后,如果这个子节点下还有子节点
		*则要继续按照同样的步骤对这个子节点进行调整
	*/
	for (parent = index; (parent * 2 + 1) < heap.size; parent = child) {
    
    
		child = parent * 2 + 1;

		//取两个子节点中的最大的节点
		if (((child + 1) < heap.size) && (heap.arr[child] < heap.arr[child + 1])) {
    
    
			child++;
		}

		//判断最大的节点是否大于当前的父节点
		if (cur >= heap.arr[child]) {
    
     //不大于,则不需要调整,跳出循环
			break;
		}
		else {
    
     //大于当前的父节点,进行交换,然后从子节点位置继续向下调整
			heap.arr[parent] = heap.arr[child];
			heap.arr[child] = cur;
		}
	}
}

//从最后一个父节点(size/2 - 1的位置)逐个往前调整所有父节点(直到根节点),
//确保每一个父节点都是一个最大堆,最后整体上形成一个最大堆
void buildHeap(Heap& heap) {
    
    
	int i;
	for (i = heap.size / 2 - 1; i >= 0; i--) {
    
    
		adjustDown(heap, i);
	}
}

//初始化数组
bool initHeap(Heap& heap, int* orginal, int size) {
    
    //orginal为数组,size为数组大小
	//如果size比默认值小,则取默认值
	int capacity = DEFAULT_CAPCITY > size ? DEFAULT_CAPCITY : size;

	heap.arr = new int[capacity];//分配内存空间
	if (!heap.arr) return false; //内存分配失败

	heap.capacity = capacity;    //数组存储容量
	heap.size = 0;

	//如果存在原始数据则构建堆
	if (size > 0) {
    
    
		//将原有数组中的数据复制到堆数组中
		memcpy(heap.arr,orginal,size*sizeof(int));
		heap.size = size;		 //原始数组元素个数
		//建堆
		buildHeap(heap);
	}
	return true;
}

int main(void) {
    
    
	Heap hp;
	int i;
	int origVals[] = {
    
    3,8,54,68,72,88,97,42,30};

	if (!initHeap(hp, origVals, sizeof(origVals) / sizeof(origVals[0]))) {
    
    
		fprintf(stderr,"初始化堆失败!\n");
		exit(-1);
	}

	for (i = 0; i < hp.size; i++) {
    
    
		printf("第%d个元素为:%d\n", i, hp.arr[i]);
	}

	system("pause");
	return 0;
}

在这里插入图片描述

おすすめ

転載: blog.csdn.net/qq_45337964/article/details/103211762