/*=====================================================================================
# COPYRIGHT NOTICE
# Copyright (c) 2016
#
# @Author :Zehao Wang
# @Email :zehaowang@163.com
# @from :https://pta.patest.cn/pta/test/1342/exam/4/question/21731
# @Last modified :2016-12-05
# @Description :05-树8 堆中的路径
========================================================================================*/
#include <stdio.h>
#include<stdlib.h>
#define MAX 50
#define MinData -1//最小元素哨兵
typedef struct HeapStruct* MinHeap;
struct HeapStruct {
int *Elements;
int size;//堆的当前元素个数
int capacity;//堆的最大容量
};
MinHeap CreatMinHeap(int MaxSize)
{
MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
H->Elements = (int*)malloc((MaxSize + 1) * sizeof(int));
H->size = 0;
H->capacity = MaxSize;
H->Elements[0] = MinData;
return H;
}
int IsFull(MinHeap H)
{
if (H->size == H->capacity)
return 1;
else
return 0;
}
void Insert(int X, MinHeap H)//第一种构建方式:这种构建堆的方式时间复杂度为O(NlogN)
{
if (IsFull(H)) {
printf("最小堆已满。");
return;
}
else {
int i = ++H->size;
for (; X < H->Elements[i / 2];i=i/2) {
H->Elements[i] = H->Elements[i / 2];
}
H->Elements[i] = X;
}
}
int main(void)
{
int tag = 0;//调整格式
MinHeap H;
H = CreatMinHeap(MAX);//构建一个最多可容纳50个元素的小顶堆
int N, M,X,K; //N:插入元素的个数。M:需要打印的路径条数。X:输入的节点数字.K:起始节点编号
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++)//在堆中连续插入N个节点
{
scanf("%d", &X);
Insert(X, H);
}
for (int i = 0; i < M; i++)
{
int j;
scanf("%d", &K);
while (1)
{
if (K < 1)
{
printf("\n");
tag = 0;
break;
}
if (K % 2 == 0 || K == 1)
{
j = K;
if (tag == 0)
{
printf("%d", H->Elements[j]);
tag++;
}
else
{
printf(" %d", H->Elements[j]);
tag++;
}
K = K / 2;
}
else
{
j = K;
if (tag == 0)
{
printf("%d", H->Elements[j]);
tag++;
}
else
{
printf(" %d", H->Elements[j]);
tag++;
}
K = (K - 1) / 2;
}
}
}
}
MinHeap BuildMinHeap(MinHeap H)//第二种构建方式:这种构建方式的时间复杂度为O(N)
{
int N;
int X;
scanf("%d", &N);
H->Elements[0] = MinData;
for (int i = 1; i <= N; i++)//将N个数依次填入数组,不考虑堆的有序性
{
scanf("%d", &X);
H->Elements[i] = X;
H->size++;
}
int parent, child, i;
for (i = H->size / 2; i > 0; i--)
{
int temp = H->Elements[i];
for (parent = i; parent * 2 <= H->size; parent = child)
{
child = parent * 2;
if (child != H->size&&H->Elements[child++] < H->Elements[child])
child++;//取左右儿子中较小的那一个
if (temp < H->Elements[child])
break;
else
H->Elements[parent] = H->Elements[child];
}
H->Elements[parent] = temp;
}
}
/*============================================================================================
注:此题较基础,考察的是堆的一些基本操作。如创建一个堆,在堆中插入元素等。堆具有两种重要的特性,
第一点 是它的结构特性,即用数组表示完全二叉树。第二点是堆的有序性,即父节点和两个子节点之间是有
关系的。(小顶堆和大顶堆)。
堆也被称作是“优先队列”,它的本质是队列。只不过在往队列中插入元素时,要不断的调整元素的位置。
关于堆的创建,课本中讲解了两种方法,第一种是创建一个空数组然后一个一个往里面插入元素。它的复杂度
是O(NlogN),第二种是先把所有元素按照顺序先插进去,然后再从第N/2个元素以此往前进行调整,复杂度
是O(N).明显第二种方法优于第一种方法。
==============================================================================================*/