数据结构与算法分析--c语言描述(原书第二版)练习自答(第六章)

6.1

待完善

6.2

在这里插入图片描述

在这里插入图片描述

static void PercolateDown(int index,ElementType Data[],int Length)
{
        ElementType Temp;
        int i,Child;
        for(i=index;i*2<=Length;i=Child)
        {
                Child=i*2;
                if(Child!=Length&&Data[Child]>Data[Child+1])
                        Child++;
                if(Data[i]>Data[Child])
                {
                        Temp=Data[i];
                        Data[i]=Data[Child];
                        Data[Child]=Temp;
                }
                else
                        break;
        }
}
void BuildHeap(ElementType Data[],int Length,PriorityQueue H)
{
        if(!IsEmpty(H))
        {
                Error("Make PriorityQueue be initialized!");
                return;
        }
        for(int index=1;index<=Length;index++)
                H->Elements[index]=Data[index-1];
        H->Size=Length;
        for(int index=Length/2;index>0;index--)
                PercolateDown(index,H->Elements,Length);
}

6.3

  • 继承6.2a

在这里插入图片描述

  • 继承6.2b

在这里插入图片描述

6.4

void PercolateUp(int index,ElementType Data[],int Length)//假设在数组下标为零的位置设置了值为INT_MIN的sentinel
{
        int i,parent;
        ElementType Temp;
        for(i=index;i>0;i=parent)
        {
                parent=i/2;
                if(Data[i]<Data[parent])
                {
                        Temp=Data[i];
                        Data[i]=Data[parent];
                        Data[parent]=Temp;
                }
        }
}
static void PercolateDown(int index,ElementType Data[],int Length)
{
        ElementType Temp;
        int i,Child;
        for(i=index;i*2<=Length;i=Child)
        {
                Child=i*2;
                if(Child!=Length&&Data[Child]>Data[Child+1])
                        Child++;
                if(Data[i]>Data[Child])
                {
                        Temp=Data[i];
                        Data[i]=Data[Child];
                        Data[Child]=Temp;
                }
                else
                        break;
        }
}

6.5

BinaryHeap.H

#ifndef _BinaryHeap_H
#define _BinaryHeap_H
typedef int ElementType;
struct HeapStruct;
typedef struct HeapStruct *PriorityQueue;

PriorityQueue Initialize(int MaxElements);
void Destroy(PriorityQueue H);
void MakeEmpty(PriorityQueue H);
void Insert(ElementType X,PriorityQueue H);
ElementType DeleteMin(PriorityQueue H);
ElementType FindMin(PriorityQueue H);
int IsEmpty(PriorityQueue H);
int IsFull(PriorityQueue H);

void BuildHeap(ElementType Data[],int Length,PriorityQueue H);
void DecreaseKey(int index,int delta,PriorityQueue H);
void IncreaseKey(int index,int delta,PriorityQueue H);
void Delete(int index,PriorityQueue H);
#endif

BinaryHeap.c

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "BinaryHeap.h"
#define MinPQSize 1

struct HeapStruct
{
        int Capacity;
        int Size;
        ElementType *Elements;
};
static void FatalError(char *string);
static void Error(char *string);
static void PercolateUp(int index,ElementType Data[],int Length);
static void PercolateDown(int index,ElementType Data[],int Length);

static void FatalError(char *string)
{
        fputs(string,stderr);
        putc('\n',stderr);
        exit(EXIT_FAILURE);
}
static void Error(char *string)
{
        fputs(string,stderr);
        putc('\n',stderr);
}
static void PercolateUp(int index,ElementType Data[],int Length)//假设在数组下标为零的位置设置了值为INT_MIN的sentinel
{
        int i,parent;
        ElementType Temp;
        for(i=index;i>0;i=parent)
        {
                parent=i/2;
                if(Data[i]<Data[parent])
                {
                        Temp=Data[i];
                        Data[i]=Data[parent];
                        Data[parent]=Temp;
                }
        }
}
static void PercolateDown(int index,ElementType Data[],int Length)
{
        ElementType Temp;
        int i,Child;
        for(i=index;i*2<=Length;i=Child)
        {
                Child=i*2;
                if(Child!=Length&&Data[Child]>Data[Child+1])
                        Child++;
                if(Data[i]>Data[Child])
                {
                        Temp=Data[i];
                        Data[i]=Data[Child];
                        Data[Child]=Temp;
                }
                else
                        break;
        }
}

PriorityQueue Initialize(int MaxElements)
{
        PriorityQueue H;
        if(MaxElements<MinPQSize)
                Error("Priority queue is too small!");
        H=malloc(sizeof(struct HeapStruct));
        if(H==NULL)
                FatalError("Out of space to create Priority queue!");
        H->Elements=malloc(sizeof(ElementType)*(MaxElements+1));
        if(H->Elements==NULL)
                FatalError("Out of space for elements!");
        H->Capacity=MaxElements;
        H->Size=0;
        H->Elements[0]=INT_MIN;
        return H;
}
void BuildHeap(ElementType Data[],int Length,PriorityQueue H)
{
        if(!IsEmpty(H))
        {
                Error("Make PriorityQueue be initialized!");
                return;
        }
        for(int index=1;index<=Length;index++)
                H->Elements[index]=Data[index-1];
        H->Size=Length;
        for(int index=Length/2;index>0;index--)
                PercolateDown(index,H->Elements,Length);
}
void Destroy(PriorityQueue H)
{
        if(H==NULL)
                Error("Priority queue isn't exist!");
        else
        {
                free(H->Elements);
                free(H);
        }
}
void MakeEmpty(PriorityQueue H)
{
        if(H==NULL)
                Error("Initiate first!");
        else
        {
                H->Size=0;
        }
}
void Insert(ElementType X,PriorityQueue H)
{
        int i;
        if(IsFull(H))
        {
                Error("Priority queue is full!");
                return;
        }
        for(i=++H->Size;X<H->Elements[i/2];i/=2)
                H->Elements[i]=H->Elements[i/2];
        H->Elements[i]=X;
}
ElementType DeleteMin(PriorityQueue H)
{
        int i,child;
        ElementType MinElement,LastElement;
        if(IsEmpty(H))
        {
                Error("Priority queue is empty!");
                return H->Elements[0];
        }
        MinElement=H->Elements[1];
        LastElement=H->Elements[H->Size--];
        for(i=1;i*2<=H->Size;i=child)
        {
                child=i*2;
                if(child!=H->Size&&H->Elements[child]>H->Elements[child+1])
                        child++;
                if(LastElement>H->Elements[child])
                        H->Elements[i]=H->Elements[child];
                else
                        break;
        }
        H->Elements[i]=LastElement;
        return MinElement;
}
ElementType FindMin(PriorityQueue H)
{
        if(IsEmpty(H))
        {
                Error("Priority queue is empty!");
                return INT_MIN;
        }
        return H->Elements[1];
}
int IsEmpty(PriorityQueue H)
{
        return H->Size==0;
}
int IsFull(PriorityQueue H)
{
        return H->Size==H->Capacity;
}
void DecreaseKey(int index,int delta,PriorityQueue H)
{
        H->Elements[index]-=delta;
        PercolateUp(index,H->Elements,H->Size);
}
void IncreaseKey(int index,int delta,PriorityQueue H)
{
        H->Elements[index]+=delta;
        PercolateDown(index,H->Elements,H->Size);
}
void Delete(int index,PriorityQueue H)
{
        ElementType min=FindMin(H);
        DecreaseKey(index,H->Elements[index]-min+1,H);
        DeleteMin(H);
}

test.c

#include <stdio.h>
#include "BinaryHeap.h"
int main(void)
{
        int arr[]={8,3,4,2,5};
        PriorityQueue H=Initialize(13);
        BuildHeap(arr,5,H);
        Insert(11,H);
        printf("The minimum is %d\n",FindMin(H));
        IncreaseKey(1,8,H);
        printf("The minimum is %d\n",FindMin(H));
        DecreaseKey(4,7,H);
        printf("The minimum is %d\n",FindMin(H));
        Delete(2,H);
        while(!IsEmpty(H))
                printf("Now,the minimum is %d\n",DeleteMin(H));
        Destroy(H);
        return 0;
}

6.6

一颗高度为h的完全平衡二叉树有 2 h + 1 − 1 2^{h+1}-1 2h+11个节点,图中有15个节点在最深层没有儿子,所以再减去30个节点,一共225个。

6.7

待完善

6.8

待完善

6.9

  • 对二叉堆使用先序遍历
ElementType PreOrder(PriorityQueue H)
{
        if(Element小于X)
        {
                返回Element
                PreOrder(H的左儿子)
                PreOrder(H的右儿子)
        }
}
  • 左势堆和斜堆可行,d-堆时间界将是O(kd),二项队列不可行。

6.10

待完善

6.11

详细代码
a.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "BinaryHeap.h"
int main(void)
{
        srand((unsigned int)time(0));
        fputs("指定一个整数M,随机生成M个元素作为输入:",stdout);
        int M,index;
        fscanf(stdin,"%d",&M);
//      ElementType arr[M];这么写的话,M过大栈会溢出,分配到堆上好些
        ElementType *arr;
        arr=malloc(sizeof(ElementType)*M);
        for(index=0;index<M;index++)
                arr[index]=rand()%10000+1;
        PriorityQueue H=Initialize(2*M);

        clock_t start,end;
        start=clock();
        for(index=0;index<M;index++)
                Insert(arr[index],H);
        end=clock();
        printf("时间%ld",(end-start));//毫秒

        Destroy(H);
        return 0;
}

b.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "BinaryHeap.h"
int main(void)
{
        srand((unsigned int)time(0));
        fputs("指定一个整数M,随机生成M个元素作为输入:",stdout);
        int M,index;
        fscanf(stdin,"%d",&M);
        ElementType *arr;
        arr=malloc(sizeof(ElementType)*M);
        for(index=0;index<M;index++)
                arr[index]=rand()%10000+1;
        PriorityQueue H=Initialize(2*M);

        clock_t start,end;
        start=clock();
        BuildHeap(arr,M,H);
        end=clock();
        printf("时间%ld",(end-start));

        Destroy(H);
        return 0;
}

6.12

待完善

6.13

父亲位于 ( i + d − 2 ) d \frac {(i+d-2)} d d(i+d2),儿子位于 ( i − 1 ) ∗ d + 2 (i-1)*d+2 (i1)d+2 i d + 1 id+1 id+1

6.14

  1. O ( ( M + d N ) l o g d N ) O((M+dN)log_dN) O((M+dN)logdN)
  2. O ( ( M + N ) l o g N ) O((M+N)logN) O((M+N)logN)
  3. O ( M + N 2 ) O(M+N^2) O(M+N2)
  4. d = m a x ( 2 , M N ) d=max(2,{\frac M N}) d=max(2,NM)

6.15

待完善

6.16

在这里插入图片描述

6.17

在这里插入图片描述

6.18

 根据上一题的答案,当 1 ≤ k ≤ 15 1 \leq k\leq 15 1k15时都是成立的,假设 k = n k=n k=n时推论也成立,这时候将1,2,3…… 2 n − 1 2^n-1 2n1依次插入树中,恰好第i层有 2 i 2^i 2i个节点(根节点在第0层,i=0,1,2……n-1)。这时候当 k = ( n + 1 ) k=(n+1) k=(n+1)时,插入的关键字序列是1,2,3…… 2 n − 1 2^n-1 2n1 2 n 2^n 2n…… 2 n + 1 − 1 2^{n+1}-1 2n+11。新增的节点数为 ( 2 n + 1 − 1 ) − ( 2 n − 1 ) = 2 n (2^{n+1}-1)-(2^n-1)=2^n (2n+11)(2n1)=2n,正好填满第n层,满足完全平衡的要求,所以推论成立。

6.19

 当输入关键字为逆序输入时,这时候左式堆将形成一个只有一连串左儿子的长链,这时候的右路径最短。

6.20

 在很深的节点执行PercolateUp的操作将会非常昂贵,更有效的做法是对x为根的子树执行delete,然后再对其左右子树执行merge以形成新的子树代替原来的子树(之后原x的父节点到根节点都需要重新调整结构特性,最多有 l o g N logN logN个节点会受到影响),而对于想要进行DecreaseKey的x节点则可以执行Insert操作。

6.21

待完善

6.22

 分步完成,当首元素重新出现在一个出队操作的堆中时,意味着下一步开始。第一次合并,将有 N / 2 N/2 N/2次merge发生在右路径不超过1个节点的heap间,而且因为合并的时间与右路径的长的和成正比,所以将有 2 ∗ 1 ∗ ( N / 2 ) 2*1*(N/2) 21(N/2)个时间单位。第二次合并,将有 N / 4 N/4 N/4次merge发生在右路径不超过2个节点的heap间,所以将有 2 ∗ 2 ∗ ( N / 4 ) 2*2*(N/4) 22(N/4)个时间单位,以此类推, 2 ∗ 3 ∗ ( N / 4 ) 2*3*(N/4) 23(N/4)……
 和为4N,于是 O ( N ) O(N) O(N).
该算法的右路径更短。

6.23

在这里插入图片描述

6.24

在这里插入图片描述

6.25

 推论成立,证明方法同6.18

6.26

可以,时间界依旧是 O ( N ) O(N) O(N)

6.27

 推论成立。显然当k=1时成立,假设i=1,2,……k时都成立。这时候 B k + 1 B_{k+1} Bk+1由一个 B k B_k Bk附加到另一个 B k B_k Bk的根上形成,由假设得到其中一个 B k B_k Bk包含二项树 B 0 B_0 B0 B 1 B_1 B1…… B k − 1 B_{k-1} Bk1,再加上另一个 B k B_k Bk,得到 B k + 1 B_{k+1} Bk+1含有二项树 B 0 B_0 B0 B 1 B_1 B1…… B k − 1 B_{k-1} Bk1 B k B_k Bk。故推论成立。

6.28

 归纳法,当k=1时,显然成立。假设i=1,2,3……k时都成立。这时 B k + 1 B_{k+1} Bk+1是由一个 B k B_k Bk附加到另一个 B k B_k Bk的根上形成的。那么初始的 B k B_k Bk在深度d的有 ( d k ) (^k_d) (dk)个节点,附加的 B k B_k Bk在深度d-1处(也就是新形成的树的深度d处)有 ( d − 1 k ) (^k_{d-1}) (d1k)个节点。相加得知推论成立。

6.29

在这里插入图片描述

6.30

待完善

6.31

BinQueue Insert(ElementType X,BinQueue H)
{
        BinTree Temp;
        Temp=MakeSingleNodeTree(X);
        H->CurrentSize+=1;
        for(int index=0,j=1;j<=H->CurrentSize;index++,j=j<<1)
        {
                if(H->TheTrees[index]==NULL)
                {
                        H->TheTrees[index]=Temp;
                        break;
                }
                else
                {
                        Temp=CombineTrees(Temp,H->TheTrees[index]);
                        H->TheTrees[index]=NULL;
                }
        }
        return H;
}

6.32

BinQueue Merge(BinQueue H1,BinQueue H2)
{
        if(H1==H2)
        {
                Error("Can't merge the same Binomial queue!");
                return H1;
        }
        else
        {
                if(H1->CurrentSize<H2->CurrentSize)
                {
                        BinQueue Temp;
                        Temp=H1;
                        H1=H2;
                        H2=Temp;
                }
                BinTree T1,T2,Carry=NULL;
                int i,j;
                if(H1->CurrentSize+H2->CurrentSize>Capacity)
                {
                        Error("Merge would exceed capacity!");
                }
                H1->CurrentSize+=H2->CurrentSize;
                for(i=0,j=1;j<=H1->CurrentSize;i++,j=j<<1)
                {
                        T1=H1->TheTrees[i];
                        T2=H2->TheTrees[i];
                        switch(!!T1+2*!!T2+4*!!Carry)
                        {
                                case 0:/*这个高度上没有树*/
                                case 1:/*这个高度上只有H1的树存在,保持不变*/
                                     break;
                                case 2:/*这个高度上只有H2的树存在,交换到H1*/
                                     H1->TheTrees[i]=T2;
                                     H2->TheTrees[i]=NULL;
                                     break;
                                case 3:/*这个高度上H1和H2的树都存在*/
                                     Carry=CombineTrees(T1,T2);
                                     H1->TheTrees[i]=H2->TheTrees[i]=NULL;
                                     break;
                                case 4:/*这个高度只有Carry存在,放到H1*/
                                     H1->TheTrees[i]=Carry;
                                     Carry=NULL;
                                     break;
                                case 5:/*这个高度H1的树和Carry存在*/
                                     Carry=CombineTrees(Carry,T1);
                                     H1->TheTrees[i]=NULL;
                                     break;
                                case 6:/*这个高度H2的树和Carry存在*/
                                     Carry=CombineTrees(Carry,T2);
                                     H2->TheTrees[i]=NULL;
                                     break;
                                case 7:/*这个高度上三个都存在,将Carry放到H1*/
                                     H1->TheTrees[i]=Carry;
                                     Carry=CombineTrees(T1,T2);
                                     H2->TheTrees[i]=NULL;
                                     break;
                        }
                        if(j>H2->CurrentSize&&(!!T2+!!Carry==0))
                                return H1;
                }
                return H1;
        }
}
ElementType DeleteMin(BinQueue *H)//因为修改了Merge使得较小的二项队列总是被合并的较大的队列中,所以返回的二项队列会改变,因为懒得修改DeleteMin,所以就把参数简单变成二项队列的指针算了
{
        ElementType MinItem=INT_MAX;
        int MinTree;
        int i,j;
        BinQueue DeletedQueue;
        Position DeletedTree,OldRoot;
        if(IsEmpty(*H))
        {
                Error("Empty binomial queue!");
                return INT_MIN;
        }
        for(i=0;i<MaxTrees;i++)
        {
                if((*H)->TheTrees[i]&&(*H)->TheTrees[i]->Element<MinItem)
                {
                        MinItem=(*H)->TheTrees[i]->Element;
                        MinTree=i;
                }
        }
        OldRoot=DeletedTree=(*H)->TheTrees[MinTree];
        DeletedTree=DeletedTree->LeftChild;
        free(OldRoot);
        DeletedQueue=Initialize();
        DeletedQueue->CurrentSize=(1<<MinTree)-1;
        for(j=MinTree-1;j>=0;j--)
        {
                DeletedQueue->TheTrees[j]=DeletedTree;
                DeletedTree=DeletedTree->NextSibling;
                DeletedQueue->TheTrees[j]->NextSibling=NULL;
        }
        (*H)->TheTrees[MinTree]=NULL;
        (*H)->CurrentSize-=DeletedQueue->CurrentSize+1;
        (*H)=Merge(*H,DeletedQueue);
        return MinItem;
}

6.33

待完善

6.34

待完善

6.35

 额外保存一个值作为基准值,而在节点中只保存该节点和其父节点的值的差,这样一来,只需要修改基准值就可以实现 O ( 1 ) O(1) O(1)时间界的DecreaseAllKeys。

6.36

待完善

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值