课程作业:
-
堆中的路径 将在“小白专场”中介绍C语言的实现方法,是建立最小堆的基本操作训练,一定要做;
-
File Transfer 关于并查集,2005、2007年浙江大学计算机学院免试研究生上机考试题即由此题改编而来。“小白专场”中介绍了原始并查集算法的优化,听完课以后自己尝试一下;
-
Huffman Codes 考察对Huffman编码的理解,程序可能略繁,量力而为。
1.堆中的路径
/*题意理解:将一系列数字插入一个初始为空的小顶堆H[]中,并打印从H[i]到根结点的路径*/
/*思路:1.创建最小空堆,最小堆的插入*/
/*2.打印路径时,注意父结点与子节点的序号关系*/
#include <stdio.h>
#include <stdlib.h>
#define ElementType int
#define MinData -10001
typedef struct HeapNode *HeapTree;
struct HeapNode
{
ElementType *Elements; /*存储堆元素的数组指针*/
int Size; /*堆当前的元素个数*/
int Capacity; /*堆的最大容量*/
};
HeapTree CreateHeapMin(int Maxsize); //创建最小堆
void InsertMin(HeapTree H, ElementType item); //最小堆的插入
int IsFull(HeapTree H); //判断堆是否满,满堆返回1
int IsEmpty(HeapTree H); //判断堆是否空,空堆返回1
int main(void)
{
int N, M, item, i, j; /*N为插入堆中的元素个数,M为需要进行查找的元素个数*/
HeapTree H;
H = CreateHeapMin(1000); //创建一个空堆
scanf("%d %d", &N, &M);
// int R[M],Path[M]; /*存放被查找的元素,和查找路径上的元素*/
for (i = 0; i < N; i++) /*输入N个元素,并插入到最小堆中*/
{
scanf("%d", &item);
InsertMin(H, item);
}
for (i = 0; i < M; i++)
{
scanf("%d", &j);
printf("%d", H->Elements[j]);
while (j > 1)
{
j /= 2;
printf(" %d", H->Elements[j]);
}
printf("\n");
}
return 0;
}
// 创建最小堆
HeapTree CreateHeapMin(int Maxsize) //创建容量为Maxsize的空堆
{
HeapTree H = (HeapTree)malloc(sizeof(struct HeapNode));
H->Elements = (ElementType *)malloc(sizeof(ElementType) * (Maxsize + 1));
H->Size = 0;
H->Capacity = Maxsize;
H->Elements[0] = MinData; //定义哨兵
return H;
}
void InsertMin(HeapTree H, ElementType item) //将元素item插入到最大堆H中,其中哨兵为H->ElementType[0]
{
int i;
if (IsFull(H))
{
printf("堆已满\n");
return;
}
i = ++H->Size;
for (; H->Elements[i / 2] > item; i = i / 2)
{
H->Elements[i] = H->Elements[i / 2]; //向下过滤比插入值小的结点
}
H->Elements[i] = item; // item的插入位置
}
int IsFull(HeapTree H) //判断堆是否满,满堆返回1
{
return (H->Size == H->Capacity);
}
int IsEmpty(HeapTree H) //判断堆是否空,空堆返回1
{
return (H->Size == 0);
}
/*期待输入*/
// 5 3
// 46 23 26 24 10
// 5 4 3
/*期待输出*/
// 24 23 10
// 46 23 10
// 26 10
2.File Transfer
/*题目介绍:输入计算机数目N,C i j表示查询第i台和第j台计算机是否连接;I i j表示连接第i台和第j台计算机;
S表示输入结束,若计算机以全部连接,打印“The network is connected.”,否则打印“There are m components.”,其中m表示计算机集合个数*/
/*思路:1.使用集合的简化表示(使用数组来存储集合,数组下标对应元素值,数组值对应根结点元素下标)
2.集合查找时选用路径压缩的方法(将每一个元素都调整为指向根结点)注意:将N台计算机映射到集合0-(N-1)范围
3.集合并操作选用按秩归并的方法(层数,节点个数)*/
/*具体实现见下文代码*/
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 10001
/*集合的简化表示:将有限集合的N个元素映射到整数0-(N-1),集合元素用下标来表示,其存储的内容为对应的父结点下标*/
typedef int ElementType; /*默认元素可以用非负整数表示*/
typedef int SetName; /*默认用根结点的下标作为集合名称*/
typedef ElementType SetType[MaxSize];
void Input_connection(SetType S); /*连接两台计算机*/
void Check_connection(SetType S); /*检查两台计算机是否连接*/
void Check_network(SetType S, int N); /*检查整个计算机网络*/
SetName Find(SetType S, ElementType X);
void Union(SetType S, SetName Root1, SetName Root2);
// Initialization(SetType S, int N);
int main(void)
{
SetType S;
int N, i;
char Comd;
/*初始化集合*/
scanf("%d", &N);
getchar();
for (i = 0; i < N; i++)
S[i] = -1;
do
{
Comd = getchar();
switch (Comd)
{
case 'I': /*连接两台计算机*/
Input_connection(S);
break;
case 'C': /*检查两台计算机是否连接*/
Check_connection(S);
break;
case 'S': /*检查整个计算机网络*/
Check_network(S, N);
break;
}
} while (Comd != 'S');
return 0;
}
void Input_connection(SetType S)
{ /*连接两台计算机*/
ElementType m1, m2;
SetName Root1, Root2;
scanf("%d%d", &m1, &m2);
getchar();
Root1 = Find(S, m1 - 1);
Root2 = Find(S, m2 - 1);
if (Root1 != Root2) /*将两台计算机的根结点连接起来*/
Union(S, Root1, Root2);
}
void Check_connection(SetType S)
{ /*检查两台计算机是否连接*/
ElementType m1, m2;
SetName Root1, Root2;
scanf("%d%d", &m1, &m2);
getchar();
Root1 = Find(S, m1 - 1);
Root2 = Find(S, m2 - 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.", counter);
}
SetName Find(SetType S, ElementType X)
{ /*默认集合元素全部初始化为-1*/
/*路径压缩*/
if (S[X] < 0)
return X;
else
return S[X] = Find(S, S[X]); /*递归:遇到根结点时,返回根结点下标X2,将X2赋值给上一个结点S[X1]=X2,并继续返回X1*/
}
void Union(SetType S, SetName Root1, SetName Root2)
{ /* 这里默认Root1和Root2是不同集合的根结点 */
/*按秩归并:元素个数*/
if (S[Root1] < S[Root2])
{ /*树1元素更多一些,将集合2指向集合1*/
S[Root1] += S[Root2];
S[Root2] = Root1;
}
else
{ /*树2元素更多一些,将集合1指向集合2*/
S[Root2] += S[Root1];
S[Root1] = Root2;
}
// /*按秩归并:树高*/
// if (S[Root1] < S[Root2])
// S[Root2] = Root1;
// else
// {
// if (S[Root1 == Root2])
// S[Root2]--; /*树高相同时,将集合1指向集合2*/
// S[Root1] = Root2;
// }
}
3.Huffman Codes
没做出来,暂时没思路,后面有时间继续看一下
结束
课程来源:浙江大学数据结构慕课MOOC