1.以二叉链表为存储结构,实现二叉树的创建、遍历
1)问题描述:在主程序中设计一个简单的菜单,分别调用相应的函数功能:
1…建立树
2…前序遍历树
3…中序(非递归)遍历树
4…后序遍历树
0…结束
2)实验要求:在程序中定义下述函数,并实现要求的函数功能:
CreateTree():按从键盘输入的前序序列,创建树
PreOrderTree():前序遍历树(递归)
InOrderTree():中序(非递归)遍历树
LaOrderTree(): 后序遍历树(递归)
3)注意问题:
注意理解递归算法的执行步骤。
注意字符类型数据在输入时的处理。
重点理解如何利用栈结构实现非递归算法
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
BiTNode* lchild,*rchild;
};
typedef BiTNode* BiTree;
int STree(BiTree r,int a,int b){
int flag;
if(r == NULL) return 0;
if(r->data == a){
if(r->lchild == NULL){
r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
r->lchild->data = b;
r->lchild->lchild = NULL;
r->lchild->rchild = NULL;
return 1;
}
else if(r->rchild == NULL){
r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
r->rchild->data = b;
r->rchild->lchild = NULL;
r->rchild->rchild = NULL;
return 1;
}
}
else{
flag = STree(r->lchild,a,b);
if(flag != 1){
flag = STree(r->rchild,a,b);
}
}
return flag;
}
int count = 1;
void PreOrderTree(BiTree root,int m){
if(root == NULL) return;
if(m != count){
printf("%d ",root->data);
count++;
}
else{
printf("%d\n",root->data);
}
PreOrderTree(root->lchild,m);
PreOrderTree(root->rchild,m);
}
int count1 = 1;
void InOrderTree(BiTree root,int m){
BiTree p,stack[100];
int top = 0;
if(root == NULL) return;
p = root;
while(!(p == NULL && top == 0)){
while(p != NULL){
if(top<99){
stack[top] = p;
top++;
}
else{
printf("栈溢出");
return;
}
p = p->lchild;
}
if(top<=0) return;
else{
top--;
p = stack[top];
if(m != count1){
printf("%d ",p->data);
count1++;
}
else{
printf("%d\n",p->data);
}
p = p->rchild;
}
}
}
int count2 = 1;
void LaOrderTree(BiTree root,int m){
if(root == NULL) return;
LaOrderTree(root->lchild,m);
LaOrderTree(root->rchild,m);
if(m != count2){
printf("%d ",root->data);
count2++;
}
else{
printf("%d\n",root->data);
}
}
int main(){
int n,count=0,k,m;
BiTree t;
t = (BiTNode*)malloc(sizeof(BiTNode));
cout<<"1...建立树"<<endl;
cout<<"2...前序遍历树"<<endl;
cout<<"3...中序(非递归)遍历树"<<endl;
cout<<"4...后序遍历树"<<endl;
cout<<"0...结束"<<endl;
while(1){
scanf("%d",&k);
if(k==1){
printf("请建立树:\n");
scanf("%d",&n); //输入节点个数
m=n;
if(n!=0){
while(n-1){
int a,b;
scanf("%d%d",&a,&b);
if(count == 0){
t->data = a;
t->lchild = NULL;
t->rchild = NULL;
count++;
}
STree(t,a,b);
n--;
}
}
}
else if(k==2){
printf("前序遍历树\n");
PreOrderTree(t,m);
cout<<endl;
}
else if(k==3){
printf("中序遍历树\n");
InOrderTree(t,m);
cout<<endl;
}
else if(k==4){
printf("后序遍历树\n");
LaOrderTree(t,m);
cout<<endl;
}
else if(k==0){
break;
}
}
return 0;
}
2.在二叉树中,P所指结点为二叉树中任一给定的结点,编写算法求从根结点到P所指结点之间的路径。
实验要求:以二叉链表作为存储结构
实验提示:采用非递归后序遍历二叉树,当后序遍历访问到P所指结点时,此时栈中所有结点均为P所指结点的祖先,由这些祖先便构成了一条从根结点到P所指结点之间的路径。
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
BiTNode *lchild,*rchild;
};
typedef BiTNode *BiTree;
typedef struct{
BiTree link;
int flag;
}StackType;
void LaOrderTree(BiTree root,int p){ //后序遍历非递归实现
StackType stack[100];
BiTree q;
int top,sign;
if(root == NULL) return;
top = -1;
q = root;
while(!(q==NULL && top==-1)){
if(q!=NULL){
top++;
stack[top].link = q;
stack[top].flag = 1;
q = q->lchild;
}
else{
q = stack[top].link;
sign = stack[top].flag;
top--;
if(sign==1){
top++;
stack[top].link = q;
stack[top].flag = 2;
q = q->rchild;
}
else{
char tmp[100];
int i=0,length;
if(q->data == p){
length = top+1;
tmp[i] = p;
while(top != -1){
q = stack[top].link;
tmp[++i] = q->data;
top--;
}
cout<<endl;
cout<<"路径为:"<<endl;
while(length>0){
printf("%d ",tmp[length]);
length--;
}
printf("%d",tmp[0]);
break;
}
q = NULL;
}
}
}
}
int STree(BiTree r,int a,int b){
int flag;
if(r == NULL) return 0;
if(r->data == a){
if(r->lchild == NULL){
r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
r->lchild->data = b;
r->lchild->lchild = NULL;
r->lchild->rchild = NULL;
return 1;
}
else if(r->rchild == NULL){
r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
r->rchild->data = b;
r->rchild->lchild = NULL;
r->rchild->rchild = NULL;
return 1;
}
}
else{
flag = STree(r->lchild,a,b);
if(flag != 1){
flag = STree(r->rchild,a,b);
}
}
return flag;
}
int main(){
int n,count=0;
BiTree t;
t = (BiTNode*)malloc(sizeof(BiTNode));
cout<<"请建立树:"<<endl;
scanf("%d",&n);
int m=n;
if(n!=0){
while(n-1){
int a,b;
scanf("%d%d",&a,&b);
if(count == 0){
t->data = a;
t->lchild = NULL;
t->rchild = NULL;
count++;
}
STree(t,a,b);
n--;
}
}
int p;
scanf("%d",&p);
LaOrderTree(t,p);
return 0;
}
3.试编写按层次顺序遍历二叉树的算法
问题描述:编写按层次顺序遍历二叉树的算法
实验要求:以二叉链表作为存储结构
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
int data;
BiTNode *lchild,*rchild;
};
typedef BiTNode* BiTree;
int STree(BiTree r,int a,int b){
int flag;
if(r == NULL) return 0;
if(r->data == a){
if(r->lchild == NULL){
r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
r->lchild->data = b;
r->lchild->lchild = NULL;
r->lchild->rchild = NULL;
return 1;
}
else if(r->rchild == NULL){
r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
r->rchild->data = b;
r->rchild->lchild = NULL;
r->rchild->rchild = NULL;
return 1;
}
}
else{
flag = STree(r->lchild,a,b);
if(flag != 1){
flag = STree(r->rchild,a,b);
}
}
return flag;
}
int count=1;
int print_level(BiTree T,int level,int k){
if(!T || level < 0) return 0;
if(level == 0){
if(count!=k){
cout<<T->data<<" ";
count++;
}
else{
cout<<T->data;
}
return 1;
}
return print_level(T->lchild,level-1,k)+print_level(T->rchild,level-1,k);
}
void print_for_level(BiTree T,int m){
int i=0;
for(i=0; ;i++){
if(!print_level(T,i,m)) break;
}
}
int main(){
int n,count=0;
BiTree t;
t = (BiTNode*)malloc(sizeof(BiTNode));
cout<<"请建立树:"<<endl;
scanf("%d",&n);
int m=n;
if(n!=0){
while(n-1){
int a,b;
scanf("%d%d",&a,&b);
if(count == 0){
t->data = a;
t->lchild = NULL;
t->rchild = NULL;
count++;
}
STree(t,a,b);
n--;
}
}
cout<<endl;
cout<<"按层次遍历结果为"<<endl;
print_for_level(t,m);
return 0;
}
4.编写算法求二叉树高度及宽度。
1) 问题描述:二叉树高度是指树中所有节点的最大层数,二叉树宽度是指在二叉树的各层上,具有节点数最多的那一层上的节点总数。
2) 实验要求:以二叉链表作为存储结构
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct BiTNode{
char data;
BiTNode *lchild,*rchild;
};
typedef BiTNode *BiTree;
int STree(BiTree r,int a,int b){
int flag;
if(r == NULL) return 0;
if(r->data == a){
if(r->lchild == NULL){
r->lchild = (BiTNode*)malloc(sizeof(BiTNode));
r->lchild->data = b;
r->lchild->lchild = NULL;
r->lchild->rchild = NULL;
return 1;
}
else if(r->rchild == NULL){
r->rchild = (BiTNode*)malloc(sizeof(BiTNode));
r->rchild->data = b;
r->rchild->lchild = NULL;
r->rchild->rchild = NULL;
return 1;
}
}
else{
flag = STree(r->lchild,a,b);
if(flag != 1){
flag = STree(r->rchild,a,b);
}
}
return flag;
}
int Depth(BiTree T){
int dep1,dep2;
if(T == NULL) return 0;
else{
dep1 = Depth(T->lchild);
dep2 = Depth(T->rchild);
if(dep1>dep2) return(dep1 + 1);
else return(dep2+1);
}
}
int Width(BiTree T){
BiTree q[100];
int front = -1, rear = -1;
int flag = 0,count = 0,p;
if(T!=NULL){
rear++;
q[rear] = T; //入栈
flag=1;
p=rear;
}
while(front<p){
front++;
T=q[front];
if(T->lchild!=NULL){
rear++;
q[rear]=T->lchild;
count++;
}
if(T->rchild!=NULL){
rear++;
q[rear]=T->rchild;
count++;
}
if(front==p){
if(flag<count) flag=count;
count=0;
p=rear;
}
}
return flag;
}
int main(){
int n,count=0;
BiTree t;
t = (BiTNode*)malloc(sizeof(BiTNode));
cout<<"请建立树:"<<endl;
scanf("%d",&n);
int m=n;
if(n!=0){
while(n-1){
int a,b;
scanf("%d%d",&a,&b);
if(count == 0){
t->data = a;
t->lchild = NULL;
t->rchild = NULL;
count++;
}
STree(t,a,b);
n--;
}
}
printf("深度为:%d 宽度为:%d",Depth(t),Width(t));
return 0;
}
5.实现一个哈夫曼编/译码系统
1)问题描述:利用哈夫曼编码进行信息通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。但是,这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码。对于双工信道,每端都需要一个完整的编码/译码系统。试为这样的信息收发站写一个哈夫曼的编/译码系统。
2)实验要求:一个完整的系统应具有以下功能:
(1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
(2) E:编码(Encoding)。利用已建好的哈夫曼树对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
(3) D:译码(Decoding)。利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
(4) P:打印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。
(5) T:打印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
3) 实现提示:
(1) 文件CodeFile的基类型可以设为字节型。
(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。请用户键入一个选择功能符。此功能执行完毕后再显示此菜单,直至某次用户选择了“E”为止。
(3) 在程序的一次执行过程中,第一次执行I、D或C命令之后,哈夫曼树已经在内存了,不必再读入。每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。
#include<iostream>
using namespace std;
#include<cstdlib>
#include<cstring>
#include<cmath>
#define MaxWeight 1000
#define MaxLeaf 300
#define MaxNode MaxLeaf*2-1
#define MaxBit 100
typedef struct HNodeType{
int weight;
int parent;
int lchild;
int rchild;
char ch;
};
typedef struct HCodeType{
int bit[MaxBit];
int start;
};
typedef struct{
HNodeType link;
int flag;
}StackType;
int N;
void HuffmanTree(HNodeType HuTree[],int n){ //哈弗曼树的构造
FILE *fp;
int i,j,m1,m2,x1,x2;
// scanf("%d",&n); //输入字符集大小
for(i=0;i<2*n-1;i++){
HuTree[i].weight = 0;
HuTree[i].parent = -1;
HuTree[i].lchild = -1;
HuTree[i].rchild = -1;
HuTree[i].ch = '$';
}
getchar();
for(i=0;i<n;i++){
scanf("%c",&HuTree[i].ch);
getchar();
}
for(i=0;i<n;i++){
scanf("%d",&HuTree[i].weight);
}
for(i=0;i<n-1;i++){
m1 = m2 = MaxWeight;
x1 = x2 = 0;
for(j=0;j<n+i;j++){
if(HuTree[j].weight<m1 && HuTree[j].parent == -1){
m2 = m1;
x2 = x1;
m1 = HuTree[j].weight;
x1 = j;
}
else if(HuTree[j].weight<m2 && HuTree[j].parent == -1){
m2 = HuTree[j].weight;
x2 = j;
}
}
HuTree[x1].parent = n+i;
HuTree[x2].parent = n+i;
HuTree[n+i].weight = HuTree[x1].weight + HuTree[x2].weight;
HuTree[n+i].lchild = x1;
HuTree[n+i].rchild = x2;
}
fp=fopen("hfmTree.dat","wb");
for(i=0;i<2*n-1;++i)
fwrite(&HuTree[i],sizeof(HuTree),1,fp);
//在hfmTree中存入树的各节点数据域信息
fclose(fp);
}
//编码
void HaffmanCode(HNodeType HuTree[],int n){
HCodeType HuffCode[MaxNode],cd;
int i,j,c,p;
// HuffmanTree(HuTree,n);
for(i=0;i<n;i++){
cd.start = n-1;
c = i;
p = HuTree[c].parent;
while(p!=-1){
if(HuTree[p].lchild==c) cd.bit[cd.start]=0;
else cd.bit[cd.start]=1;
cd.start--;
c = p;
p = HuTree[c].parent;
}
for(j=cd.start+1;j<n;j++){
HuffCode[i].bit[j] = cd.bit[j];
}
HuffCode[i].start = cd.start;
}
//输出编码
FILE *fp1;
fp1 = fopen("ToBeTran.txt","r");
FILE *fp2;
fp2=fopen("CodeFile.txt","w");
char b[100];
int f=0;
while(fscanf(fp1,"%c",&b[f]) && !feof(fp1)){
i=0;
while(i<n){
if(b[f] == HuTree[i].ch){
for(j=HuffCode[i].start+1;j<n;j++){
fprintf(fp2,"%ld",HuffCode[i].bit[j]);
}
break;
}
else{
i++;
}
}
f++;
}
fclose(fp1);
fclose(fp2);
}
int main(){
HNodeType HuTree[100];
int Q,n;
char T;
int p=0,c;
char b;
cout<<"I:初始化"<<endl;
cout<<"E:编码"<<endl;
cout<<"D:译码"<<endl;
cout<<"P:打印代码文件"<<endl;
cout<<"T:打印哈弗曼树"<<endl;
cout<<"Q:退出"<<endl;
cout<<endl;
cout<<"请首先建立树:"<<endl;
scanf("%c",&T);
while(T != 'Q'){
if(T=='I'){
cout<<"格式为:节点个数 各节点名称 各节点权值"<<endl;
scanf("%d",&n);
HuffmanTree(HuTree,n);
cout<<"建立哈弗曼树成功!"<<endl;
cout<<endl;
}
else if(T=='E'){
HaffmanCode(HuTree,n);
cout<<"编码成功!"<<endl;
cout<<endl;
}
else if(T=='D'){
FILE *fp4;
fp4 = fopen("CodeFile.txt","r");
FILE *fp5;
fp5 = fopen("TextFile.txt","w");
getchar();
while(p != -1){
c=p;
p = HuTree[c].parent;
}
int q=c;
int count=0;
int d=0;
string str;
while(fscanf(fp4,"%c",&str[d]) && !feof(fp4)){
if(str[d] == '0'){
q = HuTree[q].lchild;
if(HuTree[q].ch != '$'){
fprintf(fp5,"%c",HuTree[q].ch);
q = c;
}
}
else if(str[d] == '1'){
q = HuTree[q].rchild;
if(HuTree[q].ch != '$'){
fprintf(fp5,"%c",HuTree[q].ch);
q = c;
}
}
d++;
}
cout<<"译码成功!"<<endl;
cout<<endl;
}
else if(T == 'P'){
FILE *fp8,*fp6;
int num=100;
char a[num];
fp8=fopen("CodeFile.txt","r");
fp6=fopen("CodePrin.txt","w");
fgets(a,num,fp8);
cout<<"打印CodeFile文件:"<<endl;
int l= strlen(a);
for(int j=0;j<l;j++)
{
cout<<a[j];
fprintf(fp6,"%c",a[j]);
if((j+1)%50==0) //每行输出50个
cout<<endl;
}
cout<<endl;
fclose(fp8);
cout<<"输出成功!"<<endl;
cout<<endl;
}
else if(T == 'T'){
FILE *fp7;
fp7 = fopen("TreePrint.txt","w");
int i=2*n-2,j=i+2,count=0,sum=0;
int k=1;sum = pow(2,0);
cout<<"哈弗曼树为:"<<endl;
while(j--){
cout<<" ";
fprintf(fp7,"%c",' ');
}
while(i>=0){
j=i;
count++;
cout<<HuTree[i].weight<<" ";
fprintf(fp7,"%d",HuTree[i].weight);
fprintf(fp7,"%c",' ');
if(count == sum){
sum += pow(2,k);
k++;
cout<<endl;
cout<<endl;
while(j--){
cout<<" ";
fprintf(fp7,"%c",' ');
}
}
i--;
}
cout<<endl;
cout<<endl;
cout<<endl;
}
scanf("%c",&T);
}
cout<<"结束"<<endl;
return 0;
}