05-树8 堆中的路径

/*=====================================================================================
#       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).明显第二种方法优于第一种方法。
==============================================================================================*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值