最小-最大堆的实现

最小-最大堆的实现:
/*
最小最大堆的性质:
1. 对于在偶数深度上的任意节点X,存储在X上的关键字小于它的父亲但是大于它的祖父
2. 对于在奇数深度上的任意节点X,存储在X上的关键字大于它的父亲但是小于它的祖父

从其中可以推理出:
1.任意节点X,其关键字的值必定在它的父亲和其祖父之间,也就是说X所在的层上所有关键字
  的值必定处于它的父亲层和它的祖父层之间
2.所有偶数层从根向下关键字的值递增,所有奇数层从根向下关键字的值递减
3.所有奇数层的关键字值大于偶数层的关键字值
4.如何判定一个节点X是在奇数层还是偶数层:就是判定X节点的祖父节点在奇数层还是偶数层,
  递归的方法就可以实现,{ while(i>1) i/=4; if(i==1) 偶数层 ; if(i==0) 奇数层 ; } 其中
  i是节点X的位置。时间复杂度是O(logN)
  另外一种方法,根据3.如果X的节点值小于其父亲的节点值,则X在偶数层上,前提是X的值满足最大最小
  堆的性质,同时X的值和其父亲的值不相等
5.一个最大最小堆的例子

                        1
             /                    \
            19                    15
        /        \            /        \
       2          4          3          6
    /     \    /     \    /     \    /     \
   16     18  9      10  7      12  13     14
  /  \   /  \
 5   11 8   17

*/

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


typedef struct MinMaxStruct* MinMaxHeap;
typedef int Position;
typedef int ElementType;
#define MinElement 0
#define MaxElement 0x00ffffff
struct MinMaxStruct
{
	int Capacity;
	int Size;
	ElementType* Elements;
};

static int
IsEmpty(MinMaxHeap H)
{
	return H->Size ? 0 : 1;
}
static int
IsFull(MinMaxHeap H)
{
	return H->Size == H->Capacity;
}

static MinMaxHeap
Initalize(int MaxElements)
{
	MinMaxHeap H;
	int Size;
	Size = sizeof(struct MinMaxStruct) + (MaxElements + 1) * sizeof(ElementType);
	H = malloc(Size);
	if(H == NULL) return NULL;
	H->Capacity = MaxElements;
	H->Size = 0;
	H->Elements = (ElementType*)(H + 1);
	H->Elements[0] = MinElement;
	return H;
}
static void
Destroy(MinMaxHeap H)
{
	H->Capacity = 0;
	H->Size = 0;
	free(H);
}


/*
 * 上滤:节点值从大变小的过程叫做上滤
 * 上滤的过程包括从根开始向下的所有奇数层,转换到偶数层后
 * 再从底部向上经历所有的偶数层
 * 插入:在树的底端进行,要么经过上滤到偶数层上,要么
 * 下滤到奇数层上
 * 删除最大值:从堆的2或3的位置求出最大值,把对最后一个
 * 数据放到最大值的位置,然后经过一个完整的上滤过程
 * DecreaseKey:减小关键字的值,是将关键字位置减少后,对
 * 其经历一个完整的上滤过程
 */
static Position
PercolateUp(Position i, MinMaxHeap H)
{
	Position j = i;
	ElementType X;

	H->Elements[0] = MinElement;
	X = H->Elements[i];

	while(j>1) j = j >> 2;

	/* 奇数层,先下滤,再上滤,偶数层直接上滤 */
	if(j==0)
	{
		/* 下滤到一个奇数层上 */
		for( ; i*4 < H->Size; i = j)
		{
			int k;
			j = k = 4*i;
			if(H->Size>=k+1 && H->Elements[j] < H->Elements[k+1]) j = k+1;
			if(H->Size>=k+2 && H->Elements[j] < H->Elements[k+2]) j = k+2;
			if(H->Size>=k+3 && H->Elements[j] < H->Elements[k+3]) j = k+3;
			if(H->Elements[j] > X)
				H->Elements[i] = H->Elements[j];
			else
				break;
		}
		H->Elements[i] = X;
		/* 进行奇偶层互换,把偶数层上的一个最大值替换到奇数层上 */
		j = i*2;
		if(j < H->Size)  //j的值最大可以是H->Size-1为偶数,H->Size是奇数值
		{
			if(H->Elements[j] < H->Elements[j+1]) j++;
		}
		else if(j > H->Size) j = i/2;

		if(H->Elements[j] > X)
		{
			H->Elements[i] = H->Elements[j];
			i = j;
		}
		else
			return i;
	}
	/* 上滤 */
	for( ; H->Elements[i/4] > X ; i /= 4)
		H->Elements[i] = H->Elements[i/4];
	H->Elements[i] = X;
	return i;
}
/*
 * 下滤:节点值从小变大的过程叫做下滤
 * 下滤的过程包括从根开始向下的所有偶数层,转换到奇数层后
 * 再从底部向上经历所有的奇数层
 * 插入:在树的底端进行,要么经过上滤到偶数层上,要么
 * 下滤到奇数层上
 * 删除最小值:从堆的1位置求出最小值,把对最后一个
 * 数据放到1位置上,然后经过一个完整的下滤过程
 * IncreaseKey:增大关键字的值,是将关键字位置增加后,对
 * 其经历一个完整的下滤过程
 */
static Position
PercolateDown(Position i, MinMaxHeap H)
{
	int j = i;
	ElementType X;

	H->Elements[0] = MaxElement;
	X = H->Elements[i];

	while(j>1) j = j >> 2;

	/* 偶数层,先下滤,再上滤,奇数层直接上滤 */
	if(j==1)
	{
		/* 下滤到一个偶数层上 */
		for( ; i*4 < H->Size; i = j)
		{
			int k;
			j = k = 4*i;
			if(H->Size>=k+1 && H->Elements[j] > H->Elements[k+1]) j = k+1;
			if(H->Size>=k+2 && H->Elements[j] > H->Elements[k+2]) j = k+2;
			if(H->Size>=k+3 && H->Elements[j] > H->Elements[k+3]) j = k+3;
			if(H->Elements[j] < X)
				H->Elements[i] = H->Elements[j];
			else
				break;
		}
		H->Elements[i] = X;
		/* 进行奇偶层互换,把奇数层上的一个最小值替换到偶数层上 */
		j = i*2;
		if(j < H->Size)  //j的值最大可以是H->Size-1为偶数,H->Size是奇数值
		{
			if(H->Elements[j] > H->Elements[j+1]) j++;
		}
		else if(j > H->Size) j = i/2;

		if(H->Elements[j] < X)
		{
			H->Elements[i] = H->Elements[j];
			i = j;
		}
		else
			return i;
	}
	/* 上滤 */
	for( ; H->Elements[i/4] < X ; i /= 4)
		H->Elements[i] = H->Elements[i/4];
	H->Elements[i] = X;
	return i;
}

/*
 * 插入:
 * 在堆的最后的位置插入关键字,要么经历上滤过程
 * 要么经历下滤过程
 */
static void
Insert(ElementType X, MinMaxHeap H)
{
	Position i;
	if(IsFull(H)) return ;

	i = ++H->Size;
	H->Elements[i] = X;
	i=PercolateUp(i, H);
	if(i==H->Size)
		PercolateDown(i, H);
}

/*
 * 删除最小值:
 * 将1号位置的值取下来,把最后一个元素放到此处
 * 然后经历一个完整的下滤过程
 */
static ElementType
DeleteMin(MinMaxHeap H)
{
	ElementType Min;
	if(IsEmpty(H)) return MinElement;

	Min = H->Elements[1];
	H->Elements[1] = H->Elements[H->Size--];
	PercolateDown(1, H);
	return Min;
}

/*
 * 查找最小值
 */
static ElementType
FindMin(MinMaxHeap H)
{
	return H->Elements[1];
}

/*
 * 删除最大值:
 * 对2和3号位置比较大小后,把最后一个元素放到此处
 * 然后经历一个完整的上滤过程
 */
static ElementType
DeleteMax(MinMaxHeap H)
{
	int i;
	ElementType Max;
	if(IsEmpty(H)) return MaxElement;

	if(H->Elements[2] < H->Elements[3])
	{
		Max = H->Elements[3];
		i = 3;
	}
	else
	{
		Max = H->Elements[2];
		i = 2;
	}
	H->Elements[i] = H->Elements[H->Size--];
	PercolateUp(i, H);
	return Max;
}

/*
 * 查找最大值
 */
static ElementType
FindMax(MinMaxHeap H)
{
	return H->Elements[2] < H->Elements[3] ?
		H->Elements[3] : H->Elements[2];
}


/*
 * 减小关键字的值
 * 对i位置的值减小后执行上滤过程
 */
static void
DecreaseKey(Position i, ElementType Delta, MinMaxHeap H)
{
	if(i <= H->Size)
	{
		H->Elements[i] -= Delta;
		PercolateUp(i, H);
	}
}

/*
 * 增加关键字的值
 * 对i位置的值增加后执行下滤过程
 */
static void
IncreaseKey(Position i, ElementType Delta, MinMaxHeap H)
{
	if(i <= H->Size)
	{
		H->Elements[i] += Delta;
		PercolateDown(i, H);
	}
}

/*
 * 删除关键字
 * 把最后一个位置的值放到i位置
 * 如果删除值比最后一个值小,相当于增加了i位置的值,
 * 执行下滤过程
 * 如果删除值比最后一个值大,相当于减小了i位置的值,
 * 执行上滤过程
 */
static void
Delete(Position i, MinMaxHeap H)
{
	ElementType Del;
	if(i <= H->Size)
	{
		Del = H->Elements[i];
		H->Elements[i] = H->Elements[H->Size--];
		if(Del < H->Elements[i])
			PercolateDown(i, H);
		else if(Del > H->Elements[i])
			PercolateUp(i, H);
	}
}





/*
 * 测试例程 
 */
void MinMaxHeapTest(void)
{
	int i;
	MinMaxHeap H;

	H = Initalize(1000);
	if(H==NULL) return;

	for(i=1; i<1000; i++)
		Insert(i,H);
	
	IncreaseKey(1,1000,H);

	for(i=0; i<400; i++)
	{
		printf("% 3d--% 3d\n",DeleteMin(H), DeleteMax(H));
	}
	Destroy(H);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值