1、使学生熟练掌握二叉树的逻辑结构和存储结构。
2、熟练掌握二叉树的各种遍历算法。
3、使学生熟练掌握哈夫曼树的生成算法。
4、熟练掌握哈夫曼编码的方法。
本次实验提供4个题目,难度不等,学生可以根据自己的情况选做,其中题目一是必做题,其它选作!
题目一:二叉树的基本操作实现 (* 必做题)
题目二:哈夫曼树和哈夫曼编码(**)
题目三:寻求最佳判断(***)
题目四:果子合并(***)
1、掌握树的逻辑结构。
2、掌握二叉树的存储及遍历算法。
3、掌握哈夫曼树的定义及生成算法。
4、掌握哈夫曼编码的方法。
[问题描述]
建立一棵二叉树,试编程实现二叉树的如下基本操作:
1. 按先序序列构造一棵二叉链表表示的二叉树T;
2. 对这棵二叉树进行遍历:先序、中序、后序以及层次遍历,分别输出结点的遍历序列;
3. 求二叉树的深度/结点数目/叶结点数目;(选做)
4. 将二叉树每个结点的左右子树交换位置。(选做)
[基本要求]
从键盘接受输入(先序),以二叉链表作为存储结构,建立二叉树(以先序来建立)
[输入]
ABCффDEфGффFффф
[输出]
先序:ABCDEGF
中序:CBEGDFA
后序:CGEFDBA
层序:ABCDEFG
[源代码及注释]
#include
#include
using namespace std;
typedef struct tree{
char data;
struct tree *lchild;
struct tree *rchild;
}BiTNode,*BiTree; //二叉树的结构组成
void CreateBiTree(BiTree &T); //先序序列构造一棵二叉树
void DLR(BiTree &T); //先序遍历
void LDR(BiTree &T); //中序遍历
void LRD(BiTree &T); //后序遍历
void floor(BiTree &T); //层次遍历
int Depth(BiTree &T); //二叉树的深度
int NodeCount(BiTree &T); //二叉树的结点个数
void Exchange(BiTree &T); //二叉树每个结点的左右子树交换位置
int main()
{
BiTree T;
CreateBiTree(T);
cout<<"先序遍历,即DLR:";
DLR(T);
cout<data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
} //递归创建二叉树的结点
void DLR(BiTree &T)
{
if(T)
{
cout<data;
DLR(T->lchild);
DLR(T->rchild);
}
} //递归先序遍历
void LDR(BiTree &T)
{
if(T)
{
LDR(T->lchild);
cout<data;
LDR(T->rchild);
}
} //递归中序遍历
void LRD(BiTree &T)
{
if(T)
{
LRD(T->lchild);
LRD(T->rchild);
cout<data;
}
} //递归后序遍历
void floor(BiTree &T)
{
queue Q;
Q.push(T);
while(!Q.empty()){
BiTree t=Q.front();
Q.pop();
if(t)cout<data;
if(t->lchild)Q.push(t->lchild);
if(t->rchild)Q.push(t->rchild);
}
} //队列层次遍历
int Depth(BiTree &T)
{
if(T==NULL)
return 0;
int m=Depth(T->lchild);
int n=Depth(T->rchild);
return m>n?m+1:n+1;
} //求二叉树的深度
int NodeCount(BiTree &T)
{
if(!T)
return 0;
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
} //统计二叉树的结点数量
void Exchange(BiTree &T)
{
if(!T)
return;
BiTree temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
Exchange(T->lchild);
Exchange(T->rchild);
} //二叉树每个结点的左右子树交换位置
[运行结果]
[问题描述]
n堆果子, 每堆果子数量任意,试设计一种最佳方案,将这n堆果子合并为一堆,使得合并工作量最小。
注:规定合并两堆果子的工作量是这两堆果子的数量之和。
[标准输入]
M,N
M表示M组测试数据,N表示每组测试数据数量不超过N个,每堆果子数量不超过10000。随后的M行是测试数据。
[标准输出]
M行数据表示对应果子的合并工作量
[输入样例]
2 6
7,5,2,4
5,6,2,9,7
[输出样例]
35
65
[源代码及注释]
#include
using namespace std;
typedef struct{
int weight; //结点的权值
int parent,lchild,rchild; //结点的双亲、左孩子、右孩子的下表
}HTNode,*HuffmanTree; //动态分配数组储存哈夫曼树
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2);//选择两个权值最小结点
void CreatHuffmanTree(HuffmanTree &HT,int n,int w[]); //哈夫曼树的创建
int CombineWorkload(HuffmanTree &HT); //合并工作量
void SelectMinNode(HuffmanTree &HT,int k,int &s1,int &s2)
{
int Min=1e9; //初始化当前最小权值
for(int i=1;i<=k;++i)
if(!HT[i].parent)
{
if(HT[i].weight<=Min)
{
Min=HT[i].weight;
s1=i;
}
} //不断更新Min
//从前k个结点找出最小结点
Min=1e9; //重置权值
for(int i=1;i<=k;++i)
if(!HT[i].parent&&i!=s1)
{
if(HT[i].weight<=Min)
{
Min=HT[i].weight;
s2=i;
}
} //不断更新Min
//从前k个结点除s1外找出最小结点
}
void CreatHuffmanTree(HuffmanTree &HT,int n,int w[])
{
if(n<=1)
return;
int m=2*n-1;
HT=new HTNode[m+1]; //0号单元未使用
for(int i=1;i<=n;++i)
{
HT[i].weight=w[i]; //初始化前n个结点
HT[i].lchild=HT[i].rchild=HT[i].parent=0;
}
for(int i=n+1;i<=m;++i)
HT[i].weight=HT[i].parent=HT[i].rchild=HT[i].lchild=0;
//初始化从n+1到m的结点
for(int i=n+1;i<=m;++i) //n-次的选择删除合并来创建哈夫曼树
{
int s1,s2;
SelectMinNode(HT,i-1,s1,s2); //将最小两个结点的下标赋予s1,s2;
HT[s1].parent=i; //s1双亲亲赋予i第i编号
HT[s2].parent=i; //s2双亲亲赋予i第i编号
HT[i].lchild=s1; //s1成为编号为i的左孩子
HT[i].rchild=s2; //s2成为编号为i的右孩子
HT[i].weight=HT[s1].weight+HT[s2].weight; //合并左右孩子权值
}
}
int CombineWorkload(HuffmanTree &HT,int n)
{
int ans=0;
for(int i=n+1;i<=2*n-1;++i)
ans+=HT[i].weight; //合并从n+1到2*n-1结点的
//所有权值之和
return ans; //返回最终的权值和
}
int main()
{
int M,N;
cin>>M>>N; //M表示M组测试数据
//N表示每组测试数据数量不超过N个
while(M--)
{
int n=1,w[10001]; //真实输入的n堆果子
//w数组储存每堆果实的数量
while(n<=N)
{
cin>>w[n];
char ch=getchar();
if(ch=='\n')
break;
++n;
} //控制输入的格式,得到有效果子数量n
HuffmanTree HT;
CreatHuffmanTree(HT,n,w);
cout<
[运行结果]