树和二叉树的综合应用

第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;
}

  • 19
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值