c语言删除最小的j个元素,数据结构——最小最大堆(C语言)

这里以删除最小元素为例。最小-最大堆的根节点元素为最小,则把根节点删除,并调整好堆,使其成为新的最小-最大堆。

一般情况下,把最后一个节点关键值为item重新插入到根节点为空的最小-最大堆中,分以下两种情况讨论:

根节点没有儿子。此时,可把item直接插入根节点。

根节点至少有一个儿子节点。此时,最小-最大堆的关键字值最小节点(不包括item)一定位于根节点的儿子节点或后代节点。设最小关键字值节点的下标为k,则需讨论以下几种情况:

a)item<=heap[k]时,此时由于堆中不存在比item更小的关键字值,则可把item直接插入到根节点。

b)item>heap[k]且k是根节点的儿子节点,此时,由于k是最大节点,所以其后代节点中不可能存在关键字值大于heap[k]的节点,从而也没有关键字值大于item的节点,所以把关键字值heap[k]移到根节点,并将item插入k节点中。

c)item>heap[k]且k是根节点的后代节点,此时,可以把关键字值heap[k]移到根节点,并将item插入k节点中,然后考察k节点的父亲节点parent:如果item>heap[parent],则将item与heap[parent]交换,此时,问题转化为将item插入到以k为根节点的子堆中,而且此子堆的根节点heap[k]已经腾空,这时将item插入到以1为根节点的最小-最大堆而根节点1为空的情况相似。

例子:在此最小-最大堆中item=12,且根节点的所有儿子和后代节点的最小关键字值为9,设关键字值为9节点的下标为k,其父节点下标为parent。因为9<12;且k节点是根节点的后代节点,则属于情况2(c),此时把heap[k]=9移到根节点,由于item=12

0818b9ca8b590ca3270a3433284dd417.png

/*最小最大堆删除操作,并返回最小元素*/

int delete_min_heap(int *heap,int *n)

{

if(!(*n))

{

printf("The heap is empty.\n");

exit(1);

}

int item,temp;

int k,parent;

int i,last;

int x;

x=heap[1];//根节点关键字值赋给x

item=heap[(*n)--];//最后节点的值赋给item

i=1;

last=(*n)/2;//为重新插入item初始化

/*寻找插入item的位置*/

while(i<=last)//有儿子或后代节点,情况2

{

k=min_child_grandchild(i,*n);//返回最小元素的节点下标

if(item<=heap[k])break;//如情况2(a),直接插入到根节点

else

{

heap[i]=heap[k];//把关键字值移到根节点

if(k<=2*i+1)//k是i的直接儿子,情况2(b)

{

i=k;//把item插入到heap[k]

break;

}

else//k是i的后代节点,情况2(c)

{

parent=k/2;

if(item>heap[parent])

SWAP(item,heap[parent],temp);

i=k;

}

}

}

heap[i]=item;

return x;

}

五、程序

函数声明:

#ifndef FUNCTION_H_INCLUDED

#define FUNCTION_H_INCLUDED

#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))

#define MAX_SIZE 10

int heap[MAX_SIZE];

void verify_max(int *heap,int i,int item);

void verify_min(int *heap,int i,int item);

int level(int node);//判断结点属于最大层还是最小层

void min_max_insert(int *heap,int *n,int item);

int delete_min_heap(int *heap,int *n);

int min_child_grandchild(int i,int n);

#endif // FUNCTION_H_INCLUDED

函数定义:

#include

#include

#include

#include "function.h"

/**从最大结点i开始,沿着从i到根结点路径,依次检查最大结点**/

/**查找插入数据item的正确结点,这个结点应有以下性质:从该结点

向上到根的路径上所有最大结点的关键字值都不小于item,而且从结点

i向下到该结点的路径上所有最大关键字值都小于item.**/

/**查找过程中,关键字值小于item的最大结点被下移到下一个最大层**/

void verify_max(int *heap,int i,int item)

{

int grandparent=i/4;//第一个非叶子结点

while(grandparent)

{

if(item<=heap[grandparent])

break;

else

{

heap[i]=heap[grandparent];

i=grandparent;

grandparent/=4;

}

}

heap[i]=item;

}

/**从最小结点i开始,沿着从i到根结点路径,依次检查最小结点**/

/**查找插入数据item的正确结点,这个结点应有以下性质:从该结点

向上到根的路径上所有最小结点的关键字值都不大于item,而且从结点

i向下到该结点的路径上所有最小关键字值都大于item.**/

/**查找过程中,关键字值大于item的最小结点被下移到下一个最小层**/

void verify_min(int *heap,int i,int item)

{

int grandparent=i/4;

while(grandparent)

{

if(item>=heap[grandparent])

break;

else

{

heap[i]=heap[grandparent];

i=grandparent;

grandparent/=4;

}

}

heap[i]=item;

}

int level(int node)//判断结点属于最大层还是最小层

{

double k=log(node)/log(2);

if((int)k%2==0)return 0;//最小层返回0

else return 1;//最大层返回1

}

/**最小-最大堆插入操作**/

void min_max_insert(int *heap,int *n,int item)

{

int parent;

int i;

i=(*n);

i++;

if(MAX_SIZE==i)//判断是否为满堆

{

printf("it is full.\n");

exit(1);

}

parent=(i)/2;//第一个非叶子结点,即结点i的父结点

if(!parent)//判断是否为空堆

heap[1]=item;//序号从1开始,而不是0

else

{

int k;

k=level(parent);//判断parent结点在最大层还是最小层

switch(k)//k=0为最小层,1为最大层

{

case 0:

if(item

{

heap[i]=heap[parent];//交换

verify_min(heap,parent,item);//插入在parent结点向上到根

//的最小层中

}

else

verify_max(heap,i,item);

break;

case 1:

if(item>heap[parent])

{

heap[i]=heap[parent];

verify_max(heap,parent,item);

}

else

verify_min(heap,i,item);

break;

}

}

*n=i;

}

/*确定节点i所有儿子和后代节点的最小关键字值*/

int min_child_grandchild(int i,int n)

{

int child,temp,t;

int j;

child=2*i;//i的儿子节点

temp=heap[child];//保存当前值

while(child<=n)//节点下标小于节点数

{

for(j=child;j<=n;j++)//遍历所有儿子节点和后代节点

{

if(temp>heap[j+1])

{

temp=heap[j+1];//若当前节点的儿子节点或后代节点存在小于当前关键字值,把该节点赋给当前节点

t=j+1;//保存最小节点的下标

}

}

child=j;

}

return t;

}

/*最小最大堆删除操作,并返回最小元素*/

int delete_min_heap(int *heap,int *n)

{

if(!(*n))

{

printf("The heap is empty.\n");

exit(1);

}

int item,temp;

int k,parent;

int i,last;

int x;

x=heap[1];//根节点关键字值赋给x

item=heap[(*n)--];//最后节点的值赋给item

i=1;

last=(*n)/2;//为重新插入item初始化

/*寻找插入item的位置*/

while(i<=last)//有儿子或后代节点,情况2

{

k=min_child_grandchild(i,*n);//返回最小元素的节点下标

if(item<=heap[k])break;//如情况2(a),直接插入到根节点

else

{

heap[i]=heap[k];//把关键字值移到根节点

if(k<=2*i+1)//k是i的直接儿子,情况2(b)

{

i=k;//把item插入到heap[k]

break;

}

else//k是i的后代节点,情况2(c)

{

parent=k/2;

if(item>heap[parent])

SWAP(item,heap[parent],temp);

i=k;

}

}

}

heap[i]=item;

return x;

}

测试程序:

#include

#include

#include"function.h"

int main()

{

int i,item;

int n=0;

for(item=1;item<10;item++)

min_max_insert(heap,&n,item);//插入节点

for(i=1;i<10;i++)

printf("%d ",heap[i]);

printf("\n");

item=delete_min_heap(heap,&n);//删除节点,并返回最小元素

printf("The deleted data is %d\n",item);

for(i=1;i<=n;i++)

printf("%d ",heap[i]);

return 0;

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值