浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第五讲)
编程题目
编程说明
编程环境:平台运行
编程语言:C
第一题代码
#include <stdio.h>
#include <stdlib.h>
#define MAXN 1001
#define MINH -10001
void Create(void);
void Insert(int);
int H[MAXN],size;
int main()
{
int N,M,x,y,j;
scanf("%d %d",&N,&M);
//堆初始化
Create();
//把元素逐个插入堆
for(int i=0;i<N;i++)
{
scanf("%d",&x);
Insert(x);
}
//打印路径
for(int i=0;i<M;i++)
{
scanf("%d",&y);
printf("%d",H[y]);
while(y>1)//沿根方向输出节点
{
y=y/2;
printf(" %d",H[y]);
}
printf("\n");
}
return 0;
}
void Create(void)
{
size=0;
H[0]=MINH;
//设置岗哨
}
void Insert(int x)
{
int i;
for(i=++size;H[i/2]>x;i/=2)
{
H[i]=H[i/2];
}
H[i]=x;
}
第二题代码
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 10001
typedef int SetName;/*默认用根结点的下标作为集合名称*/
typedef int ElementType;/*默认元素可以用非负整数表示*/
typedef ElementType SetType[Maxsize];
void Initialization(SetType S,int n);
SetName Find(SetType S, ElementType X);
void Input_connection(SetType S);
void Check_connection(SetType S);
void Check_network(SetType S, int n);
int main()
{
SetType S;
int n;
char in;
scanf("%d\n",&n);
Initialization(S, n);
do{
scanf("%c",&in);
switch(in)
{
case 'I': Input_connection(S); break;
case 'C': Check_connection(S); break;
case 'S': Check_network(S, n); break;
}
}while(in != 'S');
return 0;
}
void Input_connection(SetType S)
{
ElementType u,v;
SetName Root1,Root2;
scanf("%d %d\n",&u,&v);
Root1=Find(S,u-1);
Root2=Find(S,v-1);
if(Root1!=Root2)
Union(S,Root1,Root2);
}
void Check_connection(SetType S)
{
ElementType u, v;
SetName Root1, Root2;
scanf("%d %d\n", &u, &v);
Root1 = Find(S, u-1);
Root2 = Find(S, v-1);
if ( Root1 == Root2 )
printf("yes\n");
else
printf("no\n");
}
void Check_network(SetType S, int n)
{
int i, counter = 0;
for (i=0; i<n; i++)
{
if ( S[i] < 0 )
counter++;
}
if ( counter == 1 )
printf("The network is connected.\n");
else
printf("There are %d components.\n", counter);
}
void Initialization(SetType S,int n)
{
for(int i=0;i<n;i++)
S[i]=-1;
}
SetName Find(SetType S, ElementType X)
{
/* 默认集合元素全部初始化为-1 */
for(;S[X]>=0;X=S[X]);
return X;
}
//按秩归并,小树成为大树的子树
void Union( SetType S, SetName Root1, SetName Root2 )
{
if (S[Root2] < S[Root1])
S[Root1] = Root2;
else
{
if (S[Root1]==S[Root2])
S[Root1]--;
S[Root2] = Root1;
}
}
第三题代码
这里参考https://www.cnblogs.com/Jie-Fei/p/10158522.html
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
typedef struct HFTNode{
char Data;
int Parent;
int Lchild;
int Rchild;
int Weight;
}HFTNode ,*HFTree;
typedef struct CNode{
char Data;
char Code[100];
}CNode;
HFTree T;
void AddNode(int N);
int JuChild(int m1, int m2, CNode *Code);
int main()
{
int N, M, Weight=0;
scanf("%d", &N);//获取叶子节点数目
getchar();
//N+N-1个节点
T=(HFTNode*)malloc(sizeof(HFTNode)*(2*N));
//读入节点数据和频率
for(int i=1; i<=N; i++)
{
scanf("%c %d", &T[i].Data, &T[i].Weight);
getchar();
T[i].Parent=0;
T[i].Lchild=0;
T[i].Rchild=0;
}
//霍夫曼节点合并并累加计算WPL
for(int i=N+1; i<2*N; i++)//WPL带权路径为非叶子节点权值之和
{
AddNode(i);
Weight+=T[i].Weight;
}
//读取同学数量
scanf("%d",&M);
for(int i=0; i<M; i++)
{
CNode Code[100];
int weight=0;
//依次读取每一个同学A-G的编码
for(int j=1; j<=N; j++)
{
scanf("%c%*c%s", &Code[j].Data, &Code[j].Code);
weight += T[j].Weight * strlen(Code[j].Code);//WPL
}
//首先检查带权路径是否一致
if(Weight!=weight)
{
printf("No\n");
}
else//其次检查是否存在前缀码的关系
{
int flag=1;
for(int k=N; k>=1 && flag; k--)//每次将相对最短编码作为比较对象
{
for(int l=1; l<k; l++)//前面的编码依次与相对最短编码进行比较
{
int is=JuChild(k, l, Code);
if(is)
{
printf("No\n");
flag=0;
break;
}
}
}
if(flag)
printf("Yes\n");
}
}
return 0;
}
void AddNode(int N)
{
int min1=0, min2=0;
for(int i=1; i<N; i++)//寻找没有父母节点的两个节点
{
if(T[i].Parent==0 && min1==0)
{
min1=i;
}
else if(T[i].Parent==0 && min1!=0)
{
min2=i;
}
}
//保证min1所在下标是权重最小的
if(T[min1].Weight > T[min2].Weight)
{
int temp=min1;
min1=min2;
min2=temp;
}
//寻找两个没有父母节点的最小节点
for(int i=1;i<N;i++)
{
if(T[i].Parent==0 && T[i].Weight<T[min1].Weight)
{
min2=min1;
min1=i;
}
else if(T[i].Parent==0 && T[i].Weight<T[min2].Weight && min1!=i)
{
min2=i;
}
}
//更新非叶子节点的信息
T[N].Weight=T[min1].Weight+T[min2].Weight;
T[N].Lchild=min1;
T[N].Rchild=min2;
T[N].Parent=0;
T[min1].Parent=N;
T[min2].Parent=N;
}
int JuChild(int m1, int m2, CNode *Code)
{
int len=strlen(Code[m1].Code);//m1是较短的那个编码
int flag=0;
for(int i=0; i<len; i++)
{
if(Code[m1].Code[i] != Code[m2].Code[i])//不相等则说明不是前缀码
flag=1;
}
if(!flag)//说明是子序列
return 1;
else
return 0;
}