第1关:基于哈夫曼树的数据压缩算法
任务描述
输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。
编程要求
输入
多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。
输出
每组数据输出2n+4行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+2行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+3行为编码后的字符串,第2n+4行为解码后的字符串(与输入的字符串相同)。
#include<iostream>
#include<string.h>
#define MAXSIZE 100
using namespace std;
typedef struct
{//哈夫曼树结点的形式
int weight; //结点的权值
int parent,lchild,rchild; //结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树
typedef char **HuffmanCode; //定义编码表类型
int Search(char a[],char ch)
{//查找数组中字符ch所在的位置,返回数组下标,否则返回-1
for(int i=0;a[i]!='\0';i++)
{
if(a[i]==ch) return i;
}
return -1;
}
void Sort(char a[],int b[],int len)
{//按ASCII码冒泡排序
/**************begin************/
int i ,j,t2;
char t1;
for(i = 0; i < len - 1; i++){
for(j = 0; j < len - 1 - i; j++){
if(a[j] > a[j+1]){
t1=a[j];
a[j]=a[j+1];
a[j+1]=t1;
t2=b[j];
b[j]=b[j+1];
b[j+1]=t2;
}
}
}
/**************end************/
}
void Select_min(HuffmanTree HT,int n,int &s1,int &s2)
{// 在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
/**************begin************/
int min1=MAXSIZE,min2=MAXSIZE,i,min1_j,min2_j;
for(i=1;i<=n;i++)
{
if(HT[i].parent==0) //选择双亲域为0的结点
{
if(HT[i].weight<min1)
{
min1=HT[i].weight; //更新min1为当前最小值
min1_j=i; //记录相应下标i
}
}
}
s1=min1_j; //记录它在HT中的序号s1
for(i=1;i<=n;i++)
{
if(HT[i].parent==0&&i!=min1_j) //选择双亲域为0且不是刚才已选择的结点
{
if(HT[i].weight<min2)
{
min2=HT[i].weight;
min2_j=i;
}
}
}
s2=min2_j; //记录它在HT中的序号s2
/**************end************/
}
int m;
void CreateHuffmanTree(HuffmanTree &HT,int n,int b[])
{//构造哈夫曼树HT
/**************begin************/
if(n<=1) return;
int s1,s2;
m=2*n-1; //共有2n-1个结点
HT=new HTNode[m+1]; //0号单元未用,所以需要动态分配m+1单元,HT[m]表示根结点
int i;
for(i=1;i<=m;i++) //将1~m号单元中的双亲、左孩子、右孩子的下标都初始化为0
{
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(i=1;i<=n;i++) //读入前n个单元中叶子结点的权值
HT[i].weight=b[i-1];
/*-------------------初始化工作结束,下面开始创建哈夫曼树------------------*/
for(i=n+1;i<=m;i++)
{//通过n-1次的选择、删除和合并来创建哈夫曼树
Select_min(HT,i-1,s1,s2);
// 在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
HT[s1].parent=i;
HT[s2].parent=i;
//得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域有0改为1
HT[i].lchild=s1; //s1,s2分别作为i的左右孩子
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight; //i的权值为左右孩子权值之和
}//for
/**************end************/
}
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
/**************begin************/
HC=new char*[n+1]; //分配存储n个字符编码的编码表空间
char* cd;
int i,c,f,start;
cd=new char[n]; //分配临时存放每个字符编码的动态分配空间
cd[n-1]='\0'; //编码结束符
for(i=1;i<=n;i++) //逐个字符求哈夫曼编码
{
start=n-1; //start开始时指向最后,即编码结束符位置
c=i;
f=HT[i].parent; //f指向结点c的双亲结点
while(f!=0) //从叶子结点开始向上回溯,直到根结点
{
--start;
if(HT[f].lchild==i) //结点c是f的左孩子,则生成代码0
cd[start]='0';
else //结点c是f的右孩子,则生成代码1
cd[start]='1';
c=f;
f=HT[c].parent; //继续向上回溯
} //求出第i个字符的编码
HC[i]=new char[n-start]; //为第i个字符编码分配空间
strcpy(HC[i],&cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}//for
delete cd; //释放临时空间
/**************end************/
}
void CharFrequency(char ch[],char a[],int b[],int &j)
{//统计词频
/**************begin************/
int i,pos;
for(i=0;ch[i]!='\0';i++)
{
pos=Search(a,ch[i]); //在数组a中查找字符ch[i]的位置
if(pos==-1) //如果在a中没有找到
{
a[j]=ch[i]; //将字符ch[i]加入数组a中
a[j+1]='\0'; //数组a的元素末位置为'\0'
b[j]++; //词频数组元素b[j]加1
j++; //后移指针j
}
else
{
b[pos]++; //如果在a中找到了字符ch[i]的位置,对应词频元素数值加1
}
}
/**************end************/
}
void PrintHT(HuffmanTree HT)
{//输出哈夫曼树的存储结构的终态
/**************begin************/
for(int i=1;i<=m;i++)
{
cout<<i<<" "<<HT[i].weight<<" "<<HT[i].parent<<" "<<HT[i].lchild<<" "<<HT[i].rchild<<endl;
}
/**************end************/
}
void PrintHC(HuffmanCode HC,char a[],int j)
{//输出每个字符的哈夫曼编码
/**************begin************/
for(int i=1;i<=j;i++)
{
if(i!=j)
cout<<a[i-1]<<":"<<HC[i]<<" ";
else
cout<<a[i-1]<<":"<<HC[i]<<endl;
}
/**************end************/
}
int main()
{
char ch[MAXSIZE];
int i,j;
while(cin>>ch)
{
if(ch[0]=='0') break;
HuffmanTree HT;
char a[MAXSIZE]={'\0'};
int b[MAXSIZE]={0};
j=0; //j统计不同字符的数量
CharFrequency(ch,a,b,j); //统计词频
Sort(a,b,j); //按ASCII码冒泡排序
for(i=0;a[i]!='\0';i++) //输出统计出来的字符和出现频率
{
if(a[i+1]!='\0')
cout<<a[i]<<":"<<b[i]<<" ";
else
cout<<a[i]<<":"<<b[i]<<endl;
}
//构造哈夫曼树
CreateHuffmanTree(HT,i,b); //构造哈夫曼树HT
PrintHT(HT); //输出哈夫曼树的存储结构的终态
//哈夫曼编码
HuffmanCode HC; //编码表HC
CreateHuffmanCode(HT,HC,j);
PrintHC(HC,a,j); //输出每个字符的哈夫曼编码
int k;
for(i=0;ch[i]!='\0';i++) //输出编码后的字符串
{
for(k=0;k<j;k++)
{
if(ch[i]==a[k])
cout<<HC[k+1];
}
}
cout<<endl;
cout<<ch<<endl;//输出解码后的字符串(与输入的字符串相同)
}
return 0;
}
第2关:基于二叉链表的树结构相等的判断
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,按此方法创建两棵二叉树,然后编写递归算法判断这两棵树是否相等。
编程要求
输入
多组数据,每组数据有两行。每行为一个二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行。若两个二叉树相等输出“YES”,否则输出“NO”。
#include<iostream>
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{先序建立二叉树
/**************begin************/
if(S[i]=='0') T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
/**************end************/
}
int Compare(BiTree T1,BiTree T2)
{//判断两棵二叉树是否相等,不相等返回0,相等返回1
/**************begin************/
if(T1==NULL&&T2==NULL) return 1; //都是NULL,相等
else if(T1==NULL||T2==NULL) return 0; //只有一个为NULL,不等
if(T1->data!=T2->data) return 0; //根结点相等,直接返回不等,否则递归
int left=0,right=0;
left=Compare(T1->lchild,T2->lchild);
right=Compare(T1->rchild,T2->rchild);
return left&&right;
/**************end************/
}
int main()
{
char S1[100],S2[100];
while(cin>>S1&&S1[0]!='0')
{
cin>>S2;
int i=-1,j=-1;
BiTree T1,T2;
CreateBiTree(T1,S1,++i);
CreateBiTree(T2,S2,++j);
if(!Compare(T1,T2))
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
return 0;
}
第3关:基于二叉链表的二叉树左右孩子的交换
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法交换该二叉树的左右孩子。
编程要求
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行。为交换左右孩子后的二叉树的先序序列。
#include<iostream>
#include<cstring>
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void ChangeRL(BiTree &T)
{//二叉树左右孩子的交换
/**************begin************/
if(T)
{
BiTree temp = T->lchild;//直接用BitTree类型,因为它是指针类型。不然就是 BiTNode *tem;
T->lchild = T->rchild;
T->rchild = temp;
ChangeRL(T->lchild);
ChangeRL(T->rchild);
}
/**************end************/
}
void PreOrderTraverse(BiTree T)
{//先序遍历
if(T)
{
cout<<T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
int main()
{
char S[100];
while(cin>>S)
{
if(strcmp(S,"0")==0) break;
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
ChangeRL(T);
PreOrderTraverse(T);
cout<<endl;
}
return 0;
}
第4关:基于二叉链表的二叉树的双序遍历
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写递归算法实现该二叉树的双序遍历(双序遍历是指对于二叉树的每一个结点来说,先访问这个结点,再按双序遍历它的左子树,然后再一次访问这个结点,接下来按双序遍历它的右子树)。
编程要求
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行,为双序遍历法得到的二叉树序列。
#include<iostream>
#include <string.h>
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void DoubleTraverse(BiTree T)
{//双序遍历二叉树T的递归算法
/**************begin************/
if(T){
cout<<T->data;
DoubleTraverse(T->lchild);
cout<<T->data;
DoubleTraverse(T->rchild);
}
/**************end************/
}
int main()
{
char S[100];
while(cin>>S)
{
if(strcmp(S,"0")==0) break;
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
DoubleTraverse(T);
cout<<endl;
}
return 0;
}
第5关:基于二叉链表的二叉树最大宽度的计算
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法计算该二叉树的最大宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。
编程要求
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行。为二叉树的最大宽度。
#include <iostream>
#include <string.h>
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
BiTree CreateBiTree(int &pos, char *str)
{// 先序建立二叉树
char c=str[pos++];
if(c=='0') return NULL;
BiTree root=new BiTNode();
root->data=c;
root->lchild=CreateBiTree(pos,str);
root->rchild=CreateBiTree(pos,str);
return root;
}
int Width(BiTree T)
{// 求二叉树T最大宽度
/**************begin************/
if(T==NULL) return 0; // 空二叉树宽度为0
else
{
BiTree Q[100]; // Q是二叉树结点指针的队列,容量尽量大,本题设为100
int qfront=1,qrear=1,qlast=1,Local_w=0,Max_w=0;
// 依次为:队头指针、队尾指针、同层最右结点在队列中的位置、局部宽度、最大宽度
Q[qrear]=T; // 根节点入队
while(qfront<=qlast)
{// 当队头指针不大于同层最右结点位置时
BiTree p=Q[qfront++];//将根节点入队;
Local_w++; // 同层结点数加1
if(p->lchild!=NULL) Q[++qrear]=p->lchild; // 如果有左孩子,则左孩子入队
if(p->rchild!=NULL) Q[++qrear]=p->rchild; // 如果有右孩子,则右孩子入队
if(qfront>qlast)
{//如果队头指针大于同层最右结点位置
qlast=qrear; // 更新最右结点位置,指向下层最右元素
if(Local_w>Max_w) Max_w=Local_w; // 更新当前最大宽度
Local_w=0; // 将局部最大宽度置为0
}
}
return Max_w;
}
/**************end************/
}
int main()
{
char str[1000];
while(cin>>str)
{
if(strcmp(str,"0")==0) break;
int pos=0; // 标记字符串处理位置
BiTree root=CreateBiTree(pos,str);
cout<<Width(root)<<endl;
}
return 0;
}
第6关:基于二叉链表的二叉树最长路径的求解
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法求出该二叉树中第一条最长的路径。
编程要求
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行,第一行为二叉树的最长路径长度,第二行为此路径上从根到叶结点的各结点的值。
#include<iostream>
#define MAXSIZE 100
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//程序生成器
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void LongestPath(BiTree T)
{//双击以监控参考的最大数量B
/**************begin************/
BiTree p=T,l[MAXSIZE],s[MAXSIZE];
//1.秒是堆栈中两个点的指示器,当前库存中的结果保持在1级中间
int top=0,tag[MAXSIZE],longest=0;
//Tag是标记标记的数量,元素是?第一排当前站点的试用费已经支付,第二排已经收取了很长时间
while(p||top>0)
{
while(p)//当p大于0
{
s[++top]=p;
tag[top]=0;
p=p->lchild;
}
if(tag[top]==1)//测试值是否已降低
{
if(!s[top]->lchild&&!s[top]->rchild)//只有当存在数据块时,前视图路径的长度才会更长
{
if(top>longest) //最大长度
{
for(int j=1;j<=top;j++) l[j]=s[j];//将当前的最高值保留
longest=top;
}
}
top--;
}
else if(top>0)
{
tag[top]=1;
p=s[top]->rchild;
}
}
cout<<longest<<endl;
for(int k=1;k<=longest;k++)
cout<<l[k]->data;
cout<<endl;
/**************end************/
}
int main()
{
char S[100];
while(cin>>S&&S[0]!='0')
{
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
LongestPath(T);
}
return 0;
}
第7关:基于二叉链表的二叉树叶子结点到根结点的路径的求解
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写算法求出每个叶子结点到根结点的路径。
编程要求
输入
多组数据。每组数据一行,为二叉树的先序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出n行(n为叶子结点的个数),每行为一个叶子结点到根节点的路径(按照叶子结点从左到右的顺序)。
#include<iostream>
using namespace std;
char path[100]; //路径数组,存储路径上每个结点的值
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void AllPath(BiTree T,char path[],int pathlen)
{//二叉树叶子结点到根结点的路径的求解
/**************begin************/
int i;
if(T!=NULL)
{
if(T->lchild==NULL && T->rchild==NULL)
{
//cout<<" "<<T->data<<"到根结点路径:";
cout<<T->data;
for(i=pathlen-1;i>=0;i--)
cout<<path[i];
cout<<endl;
}
else
{
path[pathlen]=T->data;
pathlen++;
AllPath(T->lchild,path,pathlen);
AllPath(T->rchild,path,pathlen);
pathlen--;
}
}
/**************end************/
}
int main()
{
char S[100];
while(cin>>S&&S[0]!='0')
{
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
int pathlen=0; //初始化路径到根结点的长度为0
AllPath(T,path,pathlen);
}
return 0;
}
第8关:基于二叉链表的二叉树的遍历
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法分别实现二叉树的先序、中序和后序遍历。
编程要求
输入
多组数据。每组数据一行,为二叉树的前序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出三行,为二叉树的先序、中序和后序序列。
#include<iostream>
#include<string.h>
using namespace std;
int flag;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void PreOrderTraverse(BiTree T)
{//二叉树的先序遍历
/**************begin************/
if(T)
{
cout<<T->data;
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
/**************end************/
}
void InOrderTraverse(BiTree T)
{//二叉树的中序遍历
/**************begin************/
if(T)
{
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
/**************end************/
}
void PostOrderTraverse(BiTree T)
{//二叉树的后序遍历
/**************begin************/
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout<<T->data;
}
/**************end************/
}
int main()
{
char S[100];
while(cin>>S)
{
if(strcmp(S,"0")==0) break;
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
PreOrderTraverse(T);
cout<<endl;
InOrderTraverse(T);
cout<<endl;
PostOrderTraverse(T);
cout<<endl;
}
return 0;
}
第9关:基于二叉链表的二叉树结点个数的统计
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,编写三个递归算法对二叉树的结点(度为0、1、2)个数进行统计。
编程要求
输入
多组数据。每组数据一行,为二叉树的前序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据输出一行,每行三个数分别为二叉树的度为0、1、2的结点个数。每两个数用空格分隔。
#include<iostream>
#include<string.h>
using namespace std;
int a,b,c;//a、b、c分别表示度为0、1、2的结点个数
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
void Count(BiTree T)
{//二叉树结点个数的统计
/**************begin************/
if(T!=NULL)
{
if(T->lchild&&T->rchild) //度为2的结点
c++;
else if(T->lchild||T->rchild) //度为1的结点
b++;
else //度为0的结点
a++;
Count(T->lchild);
Count(T->rchild);
}
/**************end************/
}
int main()
{
char S[100];
while(cin>>S)
{
if(strcmp(S,"0")==0) break;
a=b=c=0;
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
Count(T);
cout<<a<<" "<<b<<" "<<c<<endl;
}
return 0;
}
第10关:基于二叉链表的二叉树高度的计算
任务描述
设二叉树中每个结点的元素均为一个字符,按先序遍历的顺序建立二叉链表,,编写递归算法计算二叉树的高度。
编程要求
输入
多组数据。每组数据一行,为二叉树的前序序列(序列中元素为‘0’时,表示该结点为空)。当输入只有一个“0”时,输入结束。
输出
每组数据分别输出一行,为二叉树的高度。
#include<iostream>
#include <string.h>
using namespace std;
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T,char S[],int &i)
{//先序建立二叉树
if(S[i]=='0')
T=NULL;
else
{
T=new BiTNode;
T->data=S[i];
CreateBiTree(T->lchild,S,++i);
CreateBiTree(T->rchild,S,++i);
}
}
int Depth(BiTree T)
{//二叉树高度的计算
/**************begin************/
int m,n;
if(!T) return 0;
else
{
m=Depth(T->lchild);
n=Depth(T->rchild);
if(m>n) return (m+1);
else return (n+1);
}
/**************end************/
}
int main()
{
char S[100];
while(cin>>S)
{
if(strcmp(S,"0")==0) break;
int i=-1;
BiTree T;
CreateBiTree(T,S,++i);
cout<<Depth(T)<<endl;
}
return 0;
}
第11关:基于二叉树的表达式求值
任务描述
输入一个表达式(表达式中的数均为小于10的正整数),利用二叉树来表示该表达式,创建表达式树,然后利用二叉树的遍历操作求表达式的值。
编程要求
输入
多组数据。每组数据一行,为一个表达式,表达式以‘=’结尾。当输入只有一个“=”时,输入结束。
输出
每组数据输出一行,为表达式的值。
#include<iostream>
#define MAXSIZE 100
using namespace std;
typedef struct BiTNode
{//二叉树的双链表存储表示
double data; //结点数据域
bool ischaracter; //判断结点是否为字符
struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTNode,*BiTree;
typedef struct
{//字符栈的存储结构
char *base; //栈底指针
char *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack1;
typedef struct
{//结点栈的存储结构
BiTree *base;
BiTree *top;
int stacksize;
}SqStack2;
void InitStack1(SqStack1 &s)
{//字符栈的初始化
s.base=new char[MAXSIZE]; //为顺序栈动态分配一个最大容量为MAXSIZE的数组空间
s.top=s.base; //初始为空栈
s.stacksize=MAXSIZE; //置栈的最大容量为MAXSIZE
}
void InitStack2(SqStack2 &s)
{//结点栈的初始化
s.base=new BiTree[MAXSIZE];
s.top=s.base;
s.stacksize=MAXSIZE;
}
void Push1(SqStack1 &s,char ch)
{//字符入栈操作
if(s.top-s.base==s.stacksize) //栈满
return;
*s.top=ch; //元素ch压入栈顶
s.top++; //栈顶指针加1
}
void Push2(SqStack2 &s,BiTree t)
{//结点入栈操作
if(s.top-s.base==s.stacksize)
return;
*s.top=t;
s.top++;
}
void Pop1(SqStack1 &s,char &ch)
{//字符出栈操作
if(s.top==s.base) //栈空
return;
else
{
s.top--; //栈顶指针减1
ch=*s.top; //将栈顶元素赋给ch
}
}
void Pop2(SqStack2 &s,BiTree &t)
{//结点出栈操作
if(s.top==s.base)
return;
else
{
s.top--;
t=*s.top;
}
}
char GetTop(SqStack1 s)
{//取字符栈的栈顶元素
if(s.base==s.top) //栈空
return -1;
else
return *(s.top-1); //返回栈顶元素的值,栈顶指针不变
}
bool EmptyStack(SqStack1 s)
{//栈的判空操作
if(s.base==s.top) //栈空返回true
return true;
else
return false; //栈非空返回false
}
char Precede(char a,char b)
{//判断符号的优先级
if(a=='+'||a=='-')
{
if(b=='+'||b=='-'||b==')'||b=='=')
return '>'; //>代表a的优先级高于b
else
return '<';
}
else if(a=='*'||a=='/')
{
if(b=='+'||b=='-'||b=='*'||b=='/'||b==')'||b=='=')
return '>';
else
return '<';
}
else if(a=='(')
{
if(b==')')
return '=';
else
return '<';
}
else if(a==')')
return '>';
else
{
if(b=='=')
return '=';
else
return '<';
}
}
double Operate(double a,char ch,double b)
{//运算操作,返回相应的数值结果
if(ch=='+')
return a+b;
else if(ch=='-')
return a-b;
else if(ch=='*')
return a*b;
else
return a/b;
}
bool IsCharacter(char ch)
{//判断ch是否为+、-、*、/、(、)、= 这类的字符,是则返回true
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='=')
return true;
else
return false;
}
double InOrder(BiTree T)
{//中序遍历二叉树并求表达式的值
/**************begin************/
double m,n;
char opr;
if(T!=NULL)
{
if(T->ischaracter==false)
return T->data; //不是字符时,直接返回结点数值
else
{
m=InOrder(T->lchild); //递归遍历左子树并返回相应数值
opr=(char)(T->data); //将结点字符转为字符型赋给opr
n=InOrder(T->rchild); //递归遍历右子树并返回相应数值
return Operate(m,opr,n); //返回运算结果
}
}
else
return 0; //树空时,函数默认返回0
/**************end************/
}
void CreateBT(char ch[],BiTree &t,SqStack1 optr,SqStack2 expt)
{//创建二叉树
int i=0;
char opr,c[2]; //辅助数组c
BiTree t1,t2;
double num;
while(ch[i]!='\0'||!EmptyStack(optr))
{
if(!IsCharacter(ch[i])) //当前遍历的不是运算符元素
{
c[0]=ch[i];
c[1]='\0';
BiTree q=new BiTNode; //生成一个新结点*q
num=strtod(c,NULL); //将字符数组c转换成浮点数,赋给num
q->ischaracter=false; //结点*q不为运算符
q->data=num; //结点数据域置为num
q->lchild=NULL; //左右孩子置为NULL
q->rchild=NULL;
Push2(expt,q); //将结点q压入数字栈
i++; //指针i加1
}//if
else //当前遍历的是运算符元素
{
switch(Precede(GetTop(optr),ch[i])) //比较栈顶元素和当前遍历字符的优先级
{
case '<': //栈顶元素优先级小于当前运算符
Push1(optr,ch[i]); //将当前运算符入栈
i++; //指针i加1
break;
case '>': //栈顶元素优先级大于当前运算符
Pop1(optr,opr); //运算符栈的元素出栈
Pop2(expt,t2); //数字栈的栈顶元素出栈
Pop2(expt,t1);
t=new BiTNode; //生成新结点*t
t->ischaracter=true; //结点*t为运算符
t->data=opr; //结点数据域置为opr
t->lchild=t1; //左孩子指向t1
t->rchild=t2; //右孩子指向t2
Push2(expt,t); //将结点t压入数字栈
break;
case '=': //栈顶元素优先级等于当前运算符
Pop1(optr,opr); //运算符栈的元素出栈
i++; //指针i加1
break;
}//switch
}//else
}//while
}
int main()
{
char ch[MAXSIZE];
while(cin>>ch)
{
if(ch[0]=='=') break;
BiTree t;
SqStack1 optr; //运算符栈optr
SqStack2 expt; //数字栈expt
InitStack1(optr); //初始化栈
InitStack2(expt); //初始化栈
Push1(optr,'='); //先在运算符栈底放入一个'='
CreateBT(ch,t,optr,expt); //创建二叉树
double answer=InOrder(t);
cout<<answer<<endl;
}
return 0;
}
第12关:二叉树的WPL计算
任务描述
二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树T, 采用二叉链表存储,结点结构为:left weight right,其中叶结点的weight域保存该结点的非负权值。设root为指向T的根结点的指针,请设计求T的WPL的算法。
编程要求
输入
多组数据,每组数据一行,为一个二叉树的先序序列(序列中元素为0时,表示该结点为空,每两个元素之间用空格隔开)。当输入只有一个0时,输入结束。
输出
每组数据输出一行,为该二叉树的WPL。
#include<iostream>
using namespace std;
typedef struct BiTNode
{
int weight;
struct BiTNode *left,*right;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T)
{//先序建立二叉树
int x;
cin>>x;
if(x==0) T=NULL;
else
{
T=new BiTNode;
T->weight=x;
CreateBiTree(T->left);
CreateBiTree(T->right);
}
}
int WPL(BiTree &T,int d)
{//求二叉树T的带权路径长度
/**************begin************/
int wpl = 0;
if (T != NULL)
{
if (T->left == NULL && T->right == NULL)
wpl += d * T->weight;
wpl += WPL(T->left, d + 1);
wpl += WPL(T->right, d + 1);
}
return wpl;
/**************end************/
}
int main()
{
while(1)
{
BiTree T;
CreateBiTree(T);
if(!T) break;
int d=0; //调用时T指向二叉树的根结点,d为0
cout<<WPL(T,d)<<endl;
}
return 0;
}