全部每周作业和视频思考题答案和解析 见 浙江大学 数据结构 思考题+每周练习答案汇总
题目:将一系列给定数字插入一个初始为空的小顶堆H[]
。随后对任意给定的下标i
,打印从H[i]
到根结点的路径。
输入格式:
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输出格式:
对输入中给出的每个下标i
,在一行中输出从H[i]
到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。
输入样例:
5 3
46 23 26 24 10
5 4 3
输出样例:
24 23 10
46 23 10
26 10
解答:
视频讲的特别详细了,这里就不再叙述了。
注意前面的MINDATA最小数一定要设置的足够小。我当时就是忽略了题目中给的数据范围,设置的不够小,结果运行超时(可能运行出的结果也是错的)。
还需要注意这里不能用先输入到数组再进行调整的办法,即视频中的第二个算法。这样输出的顺序和直接插入是不一致的。
下面给出的代码中,有几个函数用不到,但是为了功能完整性还是给放进去了。
直接给出代码:
#include <iostream>
using namespace std;
typedef int ElementType;
typedef struct HNode *Heap; // 堆的类型定义
struct HNode {
ElementType *Data; // 存储元素的数组
int Size; // 堆中当前元素个数
int Capacity; // 堆的最大容量
};
typedef Heap MaxHeap; // 最大堆
typedef Heap MinHeap; // 最小堆
#define MINDATA -1000000 // 该值应根据具体情况定义为大于堆中所有可能元素的值
MinHeap CreateHeap(int MaxSize)
{ // 创建容量为MaxSize的空的最大堆
MinHeap H = (MinHeap )malloc(sizeof(struct HNode));
H->Data = (ElementType *)malloc((MaxSize + 1) * sizeof(ElementType));
H->Size = 0;
H->Capacity = MaxSize;
H->Data[0] = MINDATA; // 定义"哨兵"为大于堆中所有可能元素的值
return H;
}
bool IsFull(MaxHeap H)
{
return (H->Size == H->Capacity);
}
void Insert(MinHeap H, ElementType X)
{ // 将元素X插入最大堆H,其中H->Data[0]已经定义为哨兵
int i = ++H->Size; // i指向插入后堆中的最后一个元素的位置
for (; H->Data[i / 2] > X; i /= 2)
H->Data[i] = H->Data[i / 2]; // 上滤X
H->Data[i] = X; // 将X插入
}
#define ERROR -1 // 错误标识应根据具体情况定义为堆中不可能出现的元素值
bool IsEmpty(MinHeap H)
{
return (H->Size == 0);
}
ElementType DeleteMin(MinHeap H)
{ // 从最大堆H中取出键值为最大的元素,并删除一个结点
int Parent, Child;
ElementType MinItem, X;
if (IsEmpty(H)) {
printf("最大堆已为空");
return ERROR;
}
MinItem = H->Data[1]; // 取出根结点存放的最大值
// 用最大堆中最后一个元素从根结点开始向上过滤下层结点
X = H->Data[H->Size--]; //注意当前堆的规模要减小
for (Parent = 1; Parent * 2 <= H->Size; Parent = Child) {
Child = Parent * 2;
//
if ((Child != H->Size) && (H->Data[Child]>H->Data[Child + 1]))
Child++; // Child指向左右子结点的较小者
if (X <= H->Data[Child]) break; // 找到了合适位置
else // 下滤X
H->Data[Parent] = H->Data[Child];
}
H->Data[Parent] = X;
return MinItem;
}
//----------- 建造最小堆 -----------
void PercDown(MinHeap H, int p)
{ // 下滤:将H中以H->Data[p]为根的子堆调整为最小堆
int Parent, Child;
ElementType X;
X = H->Data[p]; // 取出根结点存放的值
for (Parent = p; Parent * 2 <= H->Size; Parent = Child) {
Child = Parent * 2;
if ((Child != H->Size) && (H->Data[Child]>H->Data[Child + 1]))
Child++; // Child指向左右子结点的较小者
if (X <= H->Data[Child]) break; // 找到了合适位置
else // 下滤X
H->Data[Parent] = H->Data[Child];
}
H->Data[Parent] = X;
}
void BuildHeap(MaxHeap H)
{ // 调整H->Data[]中的元素,使满足最大堆的有序性
// 这里假设所有H->Size个元素已经存在H->Data[]中
int i;
// 从最后一个结点的父节点开始,到根结点1
for (i = H->Size / 2; i>0; i--)
PercDown(H, i);
}
int main(void) {
int N, M;
cin >> N >> M;
MinHeap H = CreateHeap(N);
for (int i = 1;i <= N;i++) {
int temp;
cin >> temp;
Insert(H, temp);
}
//不能使用如下建堆的方法,因为输出不一致。
/*for(int i = 1;i<=N;i++)
cin >> H->Data[i];
H->Size = N;
BuildHeap(H);*/
for (int i = 0;i < M;i++) {
int Addr;
cin >> Addr;
for (int j = Addr;j;j /= 2)
{
cout << H->Data[j];
if (j != 1) {
cout << " ";
}
}
cout << endl;
}
system("pause");
return 0;
}
测试结果如下: