数据结构--优先列队(堆)的实现与相关操作

    实现优先列队的最普遍的工具是二叉堆,有时也只叫做堆。

    二叉堆有两个性质:结构性和堆序性。

   结构性:堆是一颗被完全填满的二叉树,底层除外,底层元素从左到右依次填入,对于一个完全二叉树,用一个数组来表示一棵树,发现对于数组的任意位置i的元素,他的左儿子在2i处,右儿子在2i+1出,父亲在i/2向下取整处。

   堆序性:如果想要快速找出最小元素,那么任意节点就应该小于它所有的后裔,如果想要快速找到最大的元素,则相反。

   二叉堆在概念上抽象为一颗二叉树,满足上面的两个性质,在程序中则实际上为一个数组,同样满足上面的两个性质。

   下面给出最小堆(即可以以常数时间找出最小元素)的一个代码实现:

   

#include<iostream>

using namespace std;
#define MinPQSize 10
#define MinData -1

struct Heapstruct;
typedef struct Heapstruct* PriorityQueue;

struct Heapstruct
{
   int Capacity;
   int Size;
   int *Elements;
};


PriorityQueue Init_priorityqueue(int MaxElements)   //创建并初始化一个优先列队
{
   PriorityQueue H;
   if(MaxElements < MinPQSize) cout << "Priority queue size is too small" << endl;

   H = (PriorityQueue)malloc(sizeof(Heapstruct));
   if(H == NULL) cout << "out of space" << endl;

   H->Elements = (int*)malloc(sizeof(int) * MaxElements + 1);
   if(H->Elements == NULL) cout << "out of space" << endl;

   H->Capacity = MaxElements;
   H->Size = 0;
   H->Elements[0] = MinData;

   for(int i = 1; i <= H->Capacity; ++i)
   {
      H->Elements [i] = 0;  //全部幅值为0
   }

   return H;
}

void Destroy(PriorityQueue H)   //释放一个优先列队
{
   free(H->Elements);
   free(H);
}

void MakeEmpty (PriorityQueue H)
{
   for(int i = 1; i <= H->Capacity; ++i)
   {
      H->Elements[i] = 0;
   }
   H->Size = 0;
}

bool IsEmpty (PriorityQueue H)
{
    if(H->Size == 0)
		return true;
	else 
		return false;
}

bool IsFull (PriorityQueue H)
{
   if(H->Size == H->Capacity )
       return true;
	else 
	   return false;
}

void Insert(int Key,PriorityQueue H)
{
	int i;
	
	if(IsFull(H))
	{
	   cout << "Priority queue is full" << endl;
	   return;
	}
	//优先列队的队首元素一定为最下元素,插入时先在最后创建一个空穴,在把这个空穴上滤
	//对于优先列队的任意位置i的元素,他的左儿子在2i处,右儿子在2i+1出,父亲在i/2向下取整处
	for (i = ++H->Size; H->Elements[i/2] > Key; i /= 2)
		H->Elements[i] = H->Elements[i/2];
	H->Elements[i] = Key;
}

int DeleteMin(PriorityQueue H)
{
   int i, Child;
   int MinElement, LastElement;
   
   if(IsEmpty(H))
   {
      cout << "Priority queue if Empty" << endl;
	  return H->Elements[0];
   }

   MinElement = H->Elements[1];
   LastElement = H->Elements[H->Size--];

   //思想很巧妙,空穴从最低一个位子一直下滤
   for(i = 1; i * 2 <= H->Size; i = Child)
   {
	   //寻找小的儿子
      Child = i * 2;
	  if(Child != H->Size && H->Elements[Child + 1] < H->Elements[Child])
		  Child ++;

	  if(LastElement > H->Elements[Child])
		  H->Elements[i] = H->Elements[Child];
	  else
		  break;
   }
   H->Elements[i] = LastElement;
   return MinElement;
}

int main ()
{
	PriorityQueue H = Init_priorityqueue(11);
	
	Insert(16, H);
	Insert(26, H);
	Insert(13, H);
	Insert(14, H);
	Insert(19, H);
	Insert(69, H);
	Insert(32, H);
	Insert(21, H);
	Insert(31, H);

	for (int i = 0; i <= 9; ++i)
	{
	   cout << DeleteMin(H) << endl;
	}
   return 0;
}

    因为二叉堆的堆序性,所以可以用来排序,即堆排序,以后会具体论述。

       夜深了,,,

      从未提起,从未忘记。

原文地址:https://www.cnblogs.com/1242118789lr/p/6817830.html