数据结构堆的实现和使用(C实现)

创建堆

typedef int HPDataType;
typedef struct Heap
{
	HPDataType*  _a;
	int  _size;
	int _capacity;
}Heap;

初始化

对传入的数据进行建堆,假设要查找前几个小的数据。

应该建大堆,然后依次把堆顶数据和最后一个数据交换,

//交换
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向下调整
void ADjustDown(HPDataType* a, int n,int root)
{
	int parent = root;  //把堆顶的位置下标给父亲
	int child = parent * 2 + 1; //找到孩子的位置
	while (child < n) //孩子的下标小于堆里的数据个数就继续
	{
		//找出左右孩子小的哪一个
		if ((child +1) < n &&a[child + 1] < a[child])//防治下标越界
		{
			++child;
		}
		//孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;    //继续迭代
			child = parent * 2 + 1;
		}
		else
		{
			break;//不满足就退出
		}
	}
}
//初始化
void HeapInit(Heap* php, HPDataType* a, int n)
{
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);//开辟一块空间
	memcpy(php->_a, a, sizeof(HPDataType) * n);//拷贝原空间的数据到开辟空间里
	php->_size = n;//更新数据个数
	php->_capacity = n;//可用的数组数据

	//构建堆
	for (int i = (n - 1 - 1) / 2; i > 0; --i)//往叶子节点开始调整
	{
		ADjustDown(php->_a, php->_size, i);
	}
}

往堆入数据

入了数据后要使堆满足之前的条件,使其还是小堆。(这里我创建的是小堆)

//交换
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向上调整;
void AdjustUP(HPDataType* a, int n, int child)
{
	int parent = (child - 1) / 2;   //找到父亲的位置下标
	while (child > 0) //孩子的下标大于0就循环,到0了就是堆顶的数据,就不用调整了
	{
		if (a[child] < a[parent]) //孩子小于父亲就向上调整
		{
			Swap(&a[child], &a[parent]);
			child = parent;//更新child的位置下标
			parent = (child - 1) / 2;//继续查找父亲的位置下标
		}
		else
		{
			break;    //不满足条件就退出
		}
	}
}
//往推入数据
void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	//空间不够就扩容
	if (php->_size == php->_capacity)
	{
		php->_capacity *= 2;//扩容2倍
		//动态开辟
		HPDataType* tmp = (HPDataType *)realloc(php->_a, sizeof(HPDataType)*php->_capacity);
		php->_a = tmp;//把开辟的空间更新
	}
	php->_a[php->_size++] = x;//把数据给到最后一个叶子节点
	AdjustUP(php->_a, php->_size, php->_size - 1);//向上调整,使堆满足小堆
}

删除堆数据

//弹数据
void HeapPop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);//数据个数必须为有效个数
	//从堆顶删除数据,把堆顶数据和最后一个数据交换位置,然后删除最后一个节点
	Swap(&php[0], &php->_a[php->_size - 1]);
	php->_size--;//下标--
	ADjustDown(php->_a, php->_size, 0);//向下调整使数据,满足小堆条件
}

查看堆顶数据

//堆顶数据
HPDataType HeapTop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);//数据个数为有效个
	return php->_a[0];//堆顶的数据就是第一个数据
}

销毁

//销毁
void HeapDestory(Heap* php)
{
	assert(php);
	free(php->_a);//释放创建的空间
	php->_a = NULL;
	php->_size = php->_capacity = 0;
}

下面是全部代码

Heap.h

#pragma once
#include
#include
#include
#include
typedef int HPDataType;
typedef struct Heap 
{
	HPDataType*  _a;
	int  _size;
	int _capacity;
}Heap;

//向下调整
void ADjustDown(HPDataType* a, int n, int root);
//初始化
void HeapInit( Heap* php,HPDataType *a,int n);
//销毁
void HeapDestory( Heap* php);
//往推入数据
void HeapPush(Heap* php, HPDataType x);
//删除堆数据
void HeapPop(Heap* php);
//堆顶数据
HPDataType HeapTop(Heap* php);

Heap.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
//交换
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向上调整;
void AdjustUP(HPDataType* a, int n, int child)
{
	int parent = (child - 1) / 2;   //找到父亲的位置下标
	while (child > 0) //孩子的下标大于0就循环,到0了就是堆顶的数据,就不用调整了
	{
		if (a[child] < a[parent]) //孩子小于父亲就向上调整
		{
			Swap(&a[child], &a[parent]);
			child = parent;//更新child的位置下标
			parent = (child - 1) / 2;//继续查找父亲的位置下标
		}
		else
		{
			break;    //不满足条件就退出
		}
	}
}

//向下调整
void ADjustDown(HPDataType* a, int n,int root)
{
	int parent = root;  //把堆顶的位置下标给父亲
	int child = parent * 2 + 1; //找到孩子的位置
	while (child < n) //孩子的下标小于堆里的数据个数就继续
	{
		//找出左右孩子小的哪一个
		if ((child +1) < n &&a[child + 1] < a[child])//防治下标越界
		{
			++child;
		}
		//孩子小于父亲就交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;    //继续迭代
			child = parent * 2 + 1;
		}
		else
		{
			break;//不满足就退出
		}
	}
}
//初始化
void HeapInit(Heap* php, HPDataType* a, int n)
{
	php->_a = (HPDataType*)malloc(sizeof(HPDataType) * n);//开辟一块空间
	memcpy(php->_a, a, sizeof(HPDataType) * n);//拷贝原空间的数据到开辟空间里
	php->_size = n;//更新数据个数
	php->_capacity = n;//可用的数组数据

	//构建堆
	for (int i = (n - 1 - 1) / 2; i > 0; --i)//往叶子节点开始调整
	{
		ADjustDown(php->_a, php->_size, i);
	}
}
//销毁
void HeapDestory(Heap* php)
{
	assert(php);
	free(php->_a);//释放创建的空间
	php->_a = NULL;
	php->_size = php->_capacity = 0;
}
//往推入数据
void HeapPush(Heap* php, HPDataType x)
{
	assert(php);
	//空间不够就扩容
	if (php->_size == php->_capacity)
	{
		php->_capacity *= 2;//扩容2倍
		//动态开辟
		HPDataType* tmp = (HPDataType *)realloc(php->_a, sizeof(HPDataType)*php->_capacity);
		php->_a = tmp;//把开辟的空间更新
	}
	php->_a[php->_size++] = x;//把数据给到最后一个叶子节点
	AdjustUP(php->_a, php->_size, php->_size - 1);//向上调整,使堆满足小堆
}
//弹数据
void HeapPop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);//数据个数必须为有效个数
	//从堆顶删除数据,把堆顶数据和最后一个数据交换位置,然后删除最后一个节点
	Swap(&php[0], &php->_a[php->_size - 1]);
	php->_size--;//下标--
	ADjustDown(php->_a, php->_size, 0);//向下调整使数据,满足小堆条件
}
//堆顶数据
HPDataType HeapTop(Heap* php)
{
	assert(php);
	assert(php->_size > 0);//数据个数为有效个
	return php->_a[0];//堆顶的数据就是第一个数据
}


test.c

#include"Heap.h"

void  HeapSort(int* a, int n)
{
	//建堆
	//for(int i = n - 1; i >= 0; --i)   从最后一个下标开始找
	//时间复杂度
	//假设有N个节点,树高度LogN
	for (int i = (n - 1-1)/2 ; i >= 0; --i)//最后一个叶子节点的位置
	{
		ADjustDown(a, n, i);//向下调整
	}
	int end = n - 1;//最后一个叶子节点位置
	while (end)//到顶了就停止
	{
		Swap(&a[0], &a[end]);//把堆顶和最后一个数据交换
		ADjustDown(a, end, 0);//继续调整堆中数据,直到满足小堆
		--end;//下标--
	}
}


int main()
{
	int arr[] = {27,15,19,18,28,34,65,49,25,37};//创建数组
	Heap hp;//创建一个堆
	HeapInit(&hp, arr, sizeof(arr) / sizeof(HPDataType));//拷贝原数据
	HeapPush(&hp, 14);//往堆插入数据
	HeapPush(&hp, 9);
	HeapPush(&hp, 5);


	HeapDestory(&hp);//销毁
	return 0;
}

你可能感兴趣的:(数据结构,算法)