算法 树7 堆中的路径

全部每周作业和视频思考题答案和解析 见 浙江大学 数据结构 思考题+每周练习答案汇总

题目:将一系列给定数字插入一个初始为空的小顶堆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;
}

测试结果如下:

发布了174 篇原创文章 · 获赞 394 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/tiao_god/article/details/105137737