IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆的实现(C语言) -> 正文阅读

[数据结构与算法]堆的实现(C语言)

什么是堆?

可以简单理解为:1.堆中某个节点的值总是不大于或不小于其父节点的值2.堆总是一棵完全二叉树3.将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。 理解了堆的概念后那么下面就来创建一个堆。

假设有这样一个数组:int array[]={8,2,3,4,5,6},存储的是完全二叉树,那么:

?从上图中可以发现,除了根节点外,其余部分满足小堆的基本性质。因为:2<4,? ? 2<5;? ? 3<6。那么如何将上面的完全二叉树调整为一个小堆呢?

首先,用根节点的值和它的两个孩子节点值进行比较,如果根节点的值比孩子节点的值大,那么就和两个孩子节点中值较小的进行交换,一直重复上述过程,就将其变成了堆(小堆)。图解如下:

下面来写代码:

void Swap(int* a, int* b){//交换两个数的值
	*a ^= *b;
	*b ^= *a;
	*a ^= *b;
}
void BuildHeap(int *array, int parent, int size){//向下调整
	int child = parent * 2 + 1;//找到左孩子
	while (child<size){
		if (child + 1 < size&&array[child]>array[child+1]){//右孩子更小,就更换
			child += 1;
		}
		if (array[parent]>array[child]){
			Swap(&array[parent], &array[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else{
			return;
		}
	}
}

?在堆的这种结构中,在这里给定第一个元素的下标是0。任意一个节点的下标为i,那么它的左孩子节点的下标就是2*i+1。

程序中要注意:1.孩子节点的下标不超过数组长度。2.每次进行交换时是交换根节点和孩子节点中值较小的,交换完毕后更新child和parent的值。

上述代码中对于堆的构建是建立在除了根节点外其余节点都满足堆的性质的条件下,那么如果给定一组乱序的值,该如何来构建堆(小堆)?

根据上述代码,可以发现只要根节点下面的元素满足堆的性质,那么就可以用上述代码来构建堆。所以当给定乱序的值后,首先找到倒数第一个非叶子节点,调整其与它的孩子节点构成堆,然后依次找到之前的非叶子节点,在调整为堆,直到找到最后一个非叶子节点(根节点),进行最后一次调整。简单图示如下:

那么代码很简单了,写一个循环,然后在调用上述代码就可以了:

for (int i = (size - 2) / 2; i>=0; i--){//size是数组长度
		BuildHeap(hp->array,i, size);
	}

?那么堆的构建就基本完成了,接下来就是对堆的 插入、删除等一系列操作了。

1.插入:将元素插在堆尾,然后在进行向上调整,且向上调整时只需要比较当前位置的值与双亲节点的值就可以了,要注意,此时这个堆是大堆还是小堆。代码如下:

void Heapjust(int *array, int size){//向上调整
	int child = size - 1;
	int parent = (child-1) / 2;
	while (child>0){//child等于零说明到了堆顶,不用调整了
		if (array[parent]>array[child){
			Swap(&array[child], &array[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else{
			return;
		}
	}
}

这里注意,child变成0的时候就找到了数组的第一个元素,此时向上调整已经完成。

2.删除:删除时要求要删除的是堆顶元素,但是不能直接删除,因为这样就直接破坏了堆的结构。那么删除时应该首先把堆顶元素和堆尾元素进行交换,然后忽略堆尾元素,在对其余元素进行一次堆的构建就可以了。

这些操作完成后,其余对堆的操作就很简单,这里就不赘述了。下面来看完整代码,利用顺序表进行存储。且在堆的构建中函数中加入了函数指针,进行回调。回调函数由我们自己提供,用以来决定创建大堆还是小堆。代码如下:

1.Heap.h

#pragma once 
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <assert.h>
typedef int DataType;
typedef int(*Callback)(int, int);//这里Callback是函数指针类型
typedef struct Heap{
	DataType * array;
	int size;
	int capacity;
	Callback Call;
}Heap;
extern void HeapCreat(Heap *hp, DataType *a, int n, Callback Call);
extern void HeapPop(Heap *hp);
extern int HeapEmpty(Heap *hp);
extern void HeapPush(Heap *hp, DataType x);
extern DataType HeapTop(Heap *hp);
extern void HeapDestory(Heap *hp);
extern int Heapsize(Heap *hp);

2.Heap.c

#include "Heap.h"
void Swap(DataType* a, DataType* b){//交换两个数的值
	*a ^= *b;
	*b ^= *a;
	*a ^= *b;
}
void BuildHeap(DataType *array, int parent, int size, Callback Call){//向下调整
	DataType child = parent * 2 + 1;//找到左孩子
	while (child<size){
		if (child + 1 < size&&Call(array[child],array[child+1])){//右孩子更小,就更换
			child += 1;
		}
		if (Call(array[parent], array[child])){
			Swap(&array[parent], &array[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else{
			return;
		}
	}
}
void HeapCreat(Heap *hp, DataType *a, int n, Callback Call){//创建堆
	assert(a);
	assert(hp);
	hp->array = (DataType *)malloc(sizeof(DataType)*n);
	if (hp == NULL){
		perror("malloc");
		exit(0);
	}
	memcpy(hp->array, a, sizeof(DataType)*n);
	hp->size = n;
	hp->capacity = n;
	hp->Call = Call;
	for (int i = (hp->size - 2) / 2; i>=0; i--){
		BuildHeap(hp->array,i, hp->size,hp->Call);
	}
}
void Expansion(Heap *hp){//扩容空间
	hp->array = (DataType *)realloc(hp->array, sizeof(DataType)*(hp->capacity + 5));
	if (hp->array == NULL){
		perror("malloc");
		return;
	}
	hp->capacity += 5;
}
void Heapjust(DataType *array, int size, Callback Call){//向上调整
	int child = size - 1;
	int parent = (child-1) / 2;
	while (child>0){//child等于零说明到了堆顶,不用调整了
		if (Call(array[parent], array[child])){
			Swap(&array[child], &array[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else{
			return;
		}
	}
}
void HeapPush(Heap *hp, DataType x){//插入元素
	assert(hp);
	if (hp->size == hp->capacity){
		Expansion(hp);
	}
	hp->array[hp->size] = x;
	hp->size++;
	Heapjust(hp->array, hp->size,hp->Call);//调用向上调整函数
}
void HeapPop(Heap *hp){//删除堆顶元素
	if (!HeapEmpty(hp)){
		Swap(&hp->array[0],&hp->array[hp->size-1]);
		hp->size--;
		BuildHeap(hp->array,0 , hp->size,hp->Call);
	}
}
DataType HeapTop(Heap *hp){//获取堆顶元素
	assert(hp);
	if (!HeapEmpty(hp)){
		return hp->array[0];
	}
}
int Heapsize(Heap *hp){//获取元素个数
	assert(hp);
	return hp->size;
}
int HeapEmpty(Heap *hp){//判空
	assert(hp);
	return hp->size == 0;
}
void HeapDestory(Heap *hp){//销毁堆
	assert(hp);
	free(hp->array);
	hp->array = NULL;
	hp->size = 0;
	hp->capacity = 0;
}

3.main.c

#include "Heap.h"
int ComInt(DataType x,DataType y){//回调函数
	if (x > y){
		return 1;
	}
	return 0;
}
int main(){
	Heap  s;
	Heap *hp = &s;
	DataType array[] = {45,21,36,98,74};
	int lengh = sizeof(array) / sizeof(array[0]);
	HeapCreat(hp, array, lengh, ComInt);
	HeapPush(hp, 35);
	HeapPush(hp, 26);
	HeapPush(hp, 18);
	HeapPush(hp, 64);
	HeapPop(hp);
	HeapDestory(hp);
	system("pause");
	return 0;
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 12:17:52  更:2021-12-07 12:20:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 7:46:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码