1. 程式人生 > >資料結構之堆的簡單實現

資料結構之堆的簡單實現

堆的主要介面包括,堆的初始化,堆的銷燬,堆的插入,堆的刪除,獲取堆頂的資料,判斷堆是否為空,求堆的大小,以及堆的氣泡排序。在這裡還有堆的簡單的資料結構的實現。因為堆是動態增長的,所以實現堆的資料結構裡包含一個存放資料的堆的陣列data,堆的大小sz,以及堆的容量capacity。

​#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* data;//存放資料的陣列
	int sz;//堆的陣列元素個數
	int capacity;//堆的容量
}Heap;


void HeapInit(Heap* hp);//堆的初始化
void HeapDestory(Heap* hp);//堆的銷燬
void HeapPush(Heap* hp, HPDataType x);//堆的插入
void HeapPop(Heap* hp);//堆的刪除
HPDataType* HeapTop(Heap*hp);//獲取堆頂的資料
int HeapSize(Heap* hp);//求堆的大小
int HeapEmpty(Heap* hp);//判斷堆是否為空
void HeapSort(Heap*hp);//堆的氣泡排序​

在這一部分是各個函式的相對實現,值得一提的是堆在刪除時,先交換了堆頂和堆尾的資料,當hp->sz--後,再把堆尾的資料向上調整。同時還有向上調整法(把大資料調上去)和向下調整法(把小資料調下來),同時在獲取堆頂資料和堆的大小時可以用一些簡單的操作就可以得到的相應的結果。如下程式碼所示:

#include"Heap.h"
void Swap(HPDataType* x1, HPDataType* x2)
{
	HPDataType x = *x1;
	*x1 = *x2;
	*x2 = x;
}
void AdjustDown(HPDataType*data, int n, int root)//向下調整方法
{
	int parent = root;
	int child = parent * 2 + 1;


	while (child < n)
	{
		//選取左右孩子中較大的那個,預設為左孩子
		if ((data[child]<data[child + 1])
			&&(child+1<n))    //child+1<n防止出界
		{
			child++;
		}
		if (data[child] > data[parent])//比較孩子和父親的大小,
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapInit(Heap* hp,HPDataType*data,int n)//堆的初始化
{
	assert(hp);
	int i = 0;
	hp->data = (HPDataType*)malloc(sizeof(HPDataType)*n);//開闢陣列大小的位元組
	hp->sz = n;
	hp->capacity = n;
	for ( i = 0; i < n; i++)//給堆的陣列賦值
	{
		hp->data[i] = data[i];
	}
	for (i = (n - 2) / 2; i >= 0; i--)//找到非葉子的最後一個節點,把大的向上調,小的向下
	{
		AdjustDown(hp->data, hp->sz, i);//
	}

}
void HeapDestory(Heap* hp)//堆的銷燬
{
	assert(hp);
	free(hp->data);
	hp->data = NULL; 
	hp->sz = hp->capacity = 0;
}
void AdjustUp(HPDataType*data, int n, int child)//向上調整法,在HeapPop()中讓孩子和父親比較大小,把小的向上調整
{
	assert(data);
	int parent = (child-1)/2;
	while (child > 0)
	{
		if (data[parent]<data[child])//當父親小於孩子時,進行交換
		{
			Swap(&data[parent], &data[child]);
			child = parent;//改變孩子的大小
			parent = (child - 2) / 2;//改變父親的大小

		}
		else
		{
			break;
		}
	}
}
void HeapPush(Heap* hp, HPDataType x)//堆的插入
{
	assert(hp);
	if (hp->sz == hp->capacity)//當堆的大小等於容量的大小,就要擴容
	{
		hp->capacity *= 2;
		hp->data = (HPDataType*)realloc(hp->data,sizeof(HPDataType)*hp->capacity);//開闢空間
	}
	hp->data[hp->sz] = x;
	hp->sz++;//個數加1
	AdjustUp(hp->data, hp->sz,hp->sz-1);//向上調整法,把大的調上去,小的放下邊
}
void HeapPop(Heap* hp)//堆的刪除,把堆頂資料和最後一個數據交換,再把對頂資料向下調整
{
	assert(hp);
	Swap(&hp->data[0], &hp->data[hp->sz - 1]);
	HPDataType* cur = &hp->data[hp->sz - 1];
	hp->sz--;
	AdjustDown(hp->data, hp->sz, 0);
	return *cur;
}
HPDataType* HeapTop(Heap*hp)//獲取堆頂的資料,
{
	assert(hp);
	return hp->data[0];
}
int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->sz;
}
int HeapEmpty(Heap* hp)//空為0,非空1
{
	return hp->sz == 0 ? 0 : 1;//三字元運算
}
void PrintHeap(Heap* hp)//列印函式
{
	assert(hp);
	for (int i = 0; i < hp->sz; i++)
	{
		printf("%d ", hp->data[i]);
	}
	printf("\n");
}
void HeapSort(Heap*hp)//冒泡泡排序
{
	int i = 0;
	int j = 0;
	for (i = 0; i < hp->sz - 1; i++)
	{
		int flag = 0;//優化標記
		for (j = 0; j < hp->sz - i - 1; j++)//迴圈趟數
		{
			if (hp->data[j] < hp->data[j + 1])//比較次數
			{
				HPDataType tmp = hp->data[j];
				hp->data[j] = hp->data[j + 1];
				hp->data[j + 1] = tmp;
				flag = 1;
			}
		}
		if (flag == 0)//當裡面沒有交換時,說明交換完成
			return;
	}
}

簡單的測試函式就不再這裡提了,以上就時堆的簡單介面的實現。