浙大数据结构慕课课后题(05-树7 堆中的路径)

题目要求

将一系列给定数字插入一个初始为空的最小堆 h。随后对任意给定的下标 i,打印从第 i 个结点到根结点的路径。 

输入格式  

每组测试第 1 行包含 2 个正整数 n 和 m (≤103),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间 [−104,104] 内的 n 个要被插入一个初始为空的小顶堆的整数。最后一行给出 m 个下标。 

输出格式 

对输入中给出的每个下标 i,在一行中输出从第 i 个结点到根结点的路径上的数据。数字间以 1 个空格分隔,行末不得有多余空格。 

输入样例 

5 3
46 23 26 24 10
5 4 3 

输出样例 

24 23 10
46 23 10
26 10 

题解  

        思路如注释所示,可通过所有测试点

#include<bits/stdc++.h>
using namespace std;           
typedef struct HeapStruct *MinHeap;
#define ElementType int
#define MinData -10005
struct HeapStruct{
	ElementType *Elements;//元素类型的数组 
	int Size;             //堆的当前元素个数 
	int Capacity;	      //堆的最大容量 
};

MinHeap creat(int MaxSize){
	MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
	H->Elements =(int *)malloc((MaxSize+1)*sizeof(ElementType));
	H->Size = 0;
	H->Capacity = MaxSize;
	H->Elements[0] = MinData;
	return H;
}
 
bool IsFull(MinHeap H){
	return (H->Size==H->Capacity);
}

void Insert(MinHeap H,ElementType item){
	int i;
	if(IsFull(H)){
		cout<<"最小堆已满";
		return; 
	}
	i = ++H->Size;    //先对元素个数加一,在把待插入元素的位序改为队尾 
	for(;H->Elements[i/2]>item&&i>1;i=i/2){
		H->Elements[i] = H->Elements[i/2];   //依次与父节点比较,若父节点较小则把父节拉下来 
	}
	H->Elements[i] = item;   //把合适插入位置上的元素值改为item 
} 

bool IsEmpty(MinHeap H){
	return (H->Size==0);
}

void Print(MinHeap H,int i){
	if(IsEmpty(H)){
		cout<<"堆为空";
		return; 
	}
	else{
		int flag=1;      //用flag记录是否为第一个元素,第一个元素前不加空格
		for(;i>0;i=i/2){   //因为该函数是值传递,所以循环中直接用i就行,便于理解, (根据堆排序的特点父节点的下标为子节点下标的1/2)
			if(flag==1){
				cout<<H->Elements[i];
				flag = 0;
			}
			else cout<<' '<<H->Elements[i];
		}	
	}
} 

int main(){
	int N,T;
	MinHeap H;
	cin>>N>>T;
	H = creat(N);
	
	while(N--){
		int n;
		cin>>n;
		Insert(H,n);
	}	
	while(T--){
		int i;
		cin>>i;
		Print(H,i);
		cout<<'\n';		
	}	
} 

        这道题可以看作是堆的操作集的阉割版,没有对堆中的元素进行删除(对堆的操作中删除操作最为复杂),直接对指定下标的元素寻找路线(也就是父节点) 。该题有以下几个要点。

        1.堆的下标特性:堆排序的特点,父节点的下标为子节点下标的1/2(这点很重要,为整个题的基石),左子树下标为父节点下标的2倍,右子树为2倍加1。

        2.每次插入时要注意整个堆的有序性,初始插入位置为叶子节点,然后依次和已排序的父节点进行比较。

         此系列为作者记录数据结构学习文章,由于能力所限,难免有细节处理不当之处,恳请读者谅解并指正。

  • 31
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值