1. 程式人生 > >C語言_堆的基本操作

C語言_堆的基本操作

本片部落格主要包含一下幾個內容:

堆的基本操作

1、建立堆

2、調整堆(向下調整)

3、插入

4、移除堆頂元素

5、返回堆元素個數

6、判斷是不是空堆

7、返回堆頂元素

8、向上調整堆

9、交換兩個數

10、判斷堆是否已滿,如果滿了,就增容;如果沒有滿,就返回

11、銷燬堆

12、小於比較

13、大於比較

14、標頭檔案程式碼

15、測試程式碼


 


1、建立堆


void CreateHeap(Heap *hp, HPDataType* arr, int size, Compare Com)
{
	int cur = 0;
	assert (hp != NULL);
	hp->_hp = (HPDataType*)malloc (size * sizeof (HPDataType));
	if (hp->_hp == NULL)
	{
		assert (0);
		return ;
	}
	//拷貝元素
	memcpy (hp->_hp, arr, size*sizeof (HPDataType));
	hp->size = size;
	hp->capacity = size;
	hp->_com = Com;
	//調整成堆
	cur = ((size-1-1)>>1);	//size-1為最大下標,再減一除二為最後一個節點的雙親節點
	for (; cur>=0; cur--)
	{
		AdjustDown (hp, cur);//向下調整堆
	}
}


2、調整堆(向下調整)


void AdjustDown (Heap* hp, int parent)//parent 為開始調整的節點
{
	int child = 0;
	assert (hp != NULL);
	child = (parent<<1) + 1;  //孩子節點等於雙親節點乘二加一
	while (child < hp->size)
	{
		if (child+1 < hp->size)//如果右孩子存在,找左右孩子中最小的孩子
		{
			if (hp->_com (hp->_hp[child], hp->_hp[child+1]))
			{
				child += 1;
			}
		}

		if (hp->_com(hp->_hp[parent], hp->_hp[child]))
		{
			Swap (&hp->_hp[parent], &hp->_hp[child]);
		}
		else
		{
			return;
		}
		parent = child;
		child = (parent<<1) + 1;
	}

}


3、插入

 

void InsertHeap (Heap* hp, HPDataType data)	//插入元素
{
	assert (hp != NULL);
	//判斷還有沒有空間,有的話就插入元素,沒有就增容再插入元素
	CheakHeap (hp);
	hp->_hp[hp->size] = data;
	hp->size++;
	//向上調整堆
	AdjustUp (hp, (hp->size)-1);

}



4、移除堆頂元素

//移除元素,(把堆頂元素和最後一個元素交換,size--就把堆頂元素刪除了,最後在調整一下堆頂元素)

void RemoveHeap (Heap* hp)
{
	assert (hp != NULL);
	Swap (&hp->_hp[0], &hp->_hp[hp->size-1]);
	hp->size--;
	AdjustDown (hp, 0, hp->_com);
}


5、返回堆元素個數


int SizeHeap (Heap* hp)	//返回堆元素個數
{
	assert (hp != NULL);
	return hp->size;
}


6、判斷是不是空堆


int IsHeapEmpty (Heap* hp)	//判斷是不是空堆,空堆返回1,非空返回0
{
	assert (hp != NULL);
	return (hp->size == 0);
}


7、返回堆頂元素


HPDataType HeapTop (Heap* hp)	//返回堆頂元素
{
	assert (hp != NULL);
	return hp->_hp[0];
}


8、向上調整堆


void AdjustUp (Heap* hp, int child)
{
	int parent = 0;
	assert (hp != NULL);
	parent = (child - 1)/2;
	while (child)
	{
		if (!(hp->_com(hp->_hp[child], hp->_hp[parent])))
		{
			Swap (&hp->_hp[child], &hp->_hp[parent]);
		}
		child = parent;
		parent = (child - 1)/2;
	}

}


9、交換兩個數


void Swap (HPDataType*p, HPDataType* q)
{
	HPDataType tmp;
	assert (p != NULL && q != NULL);
	tmp = *p;
	*p = *q;
	*q = tmp;
}

 


10、判斷堆是否已滿,如果滿了,就增容;如果沒有滿,就返回


void  CheakHeap (Heap* hp)	//判斷堆是否已滿,如果滿了,就增容;如果沒有滿,就返回
{
	int newCapacity = 0;
	int i = 0;
	HPDataType* temp;
	assert (hp != NULL);
	if (hp->capacity > hp->size)
	{
		return ;
	}
	//如果堆已滿,增容
	newCapacity = 2 * (hp->capacity)+3;
	temp = (HPDataType*)malloc (newCapacity * sizeof (HPDataType));	//開闢新空間
	if (temp == NULL)
	{
		perror ("CheakHeap::malloc>>");
		return ;
	}
	//拷貝元素
	for (; i<hp->size; ++i)	
	{
		temp[i] = hp->_hp[i];
	}
	//釋放原空間
	free (hp->_hp);
	hp->_hp = NULL;
	
	//讓原空間指向新開闢的空間
	hp->_hp = temp;
	hp->capacity = newCapacity;
}

11、銷燬堆


void DestroyHeap (Heap* hp)
{
	assert (hp != NULL);
	free (hp->_hp);
	hp->_hp = NULL;
	hp->capacity = 0;
	hp->size = 0;
	printf ("銷燬成功\n");
}


12、小於比較


//Less 和 Greater兩個函式用來比較兩個數的大小,在建堆時用函式指標的形式呼叫,用來分別建大堆小堆
int Less (HPDataType pLeft, HPDataType pRight)	//小於比較
{
	assert (pLeft != NULL && pRight != NULL);
	if (pLeft > pRight)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}


13、大於比較


int Greater (HPDataType pLeft, HPDataType pRight)	//大於比較
{
	if (pLeft > pRight)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

14、標頭檔案程式碼


#ifndef __HEAP_H__
#define __HEAP_H__

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

//堆:是一個數組,其中的元素是按照二叉樹的順序在陣列中存放的

	//任意一個節點的資料都比其左右孩子都小---小堆
	//任意一個節點的資料都比它的左右孩子大---大堆
typedef int HPDataType;
typedef int (*Compare) (HPDataType pLeft, HPDataType pRight);

typedef struct Heap
{
	HPDataType* _hp;
	int capacity;
	int size;
	Compare _com;
}Heap;


void CreateHeap(Heap *hp, HPDataType* arr, int size, Compare Com);	//建立堆
void AdjustDown (Heap* hp, int parent);	//調整堆(向下調整)
void InsertHeap (Heap* hp, HPDataType data);	//插入
void RemoveHeap (Heap* hp);	//移除元素,(把堆頂元素和最後一個元素交換,size--就把堆頂元素刪除了,最後在調整一下堆頂元素)
int SizeHeap (Heap* hp);	//返回堆元素個數
int IsHeapEmpty (Heap* hp);	//判斷是不是空堆
HPDataType HeapTop (Heap* hp);	//返回堆頂元素
void AdjustUp (Heap* hp, int child);	//向上調整堆
void Swap (HPDataType* p, HPDataType*q);	//交換兩個數
void  CheakHeap (Heap* hp);	//判斷堆是否已滿,如果滿了,就增容;如果沒有滿,就返回
void DestroyHeap (Heap* hp);	//銷燬堆
int Less (HPDataType pLeft, HPDataType pRight);	//小於比較
int Greater (HPDataType pLeft, HPDataType pRight);	//大於比較


#endif 

15、測試程式碼


#include "Heap.h"

void test_Heap()
{
	//test_CreateHeap
	int ret = 0;
	HPDataType top = 0;
	int arr[] = {53, 17, 78, 9, 45, 65, 87, 23, 31};
	Heap hp;
	CreateHeap (&hp, arr, sizeof(arr)/sizeof(arr[0]), Less);
	//test_SizeEmptyTopHeap
	ret = SizeHeap(&hp);
	printf ("堆的大小為:%d\n", ret);
	ret = IsHeapEmpty(&hp);
	if (ret == 1)
	{
		printf ("這是空堆!\n");
	}
	else
	{
		printf ("不是空堆!\n");
	}
	top = HeapTop(&hp);
	printf ("堆頂元素是:%d\n", top);
	//test_InsertHeap
	InsertHeap(&hp, 5);
	//test_RemoveHeap
	RemoveHeap(&hp);
	DestroyHeap (&hp);
}

int main ()
{
	test_Heap();
	return 0;
}