实验目的:
1、熟练掌握二叉树的二叉链表表示方法及二叉树遍历算法
2、根据哈夫曼算法创建哈夫曼树
涉及的知识点:
二叉树的表示法、二叉树遍历算法的设计
实验内容:
1、设计一个程序,根据二叉树的先根序列和中根序列创建一棵用左右指针表示的二叉树
例如:先根序列为 ABDGCEF#, 中根序列为 DGBAECF# (#表示结束)。然后用程序构造一棵二叉树。注意程序的通用性(也就是说上述只是一个例子,你的程序要接受两个序列(先根和中根序列),然后构造相应的二叉树)。
2. 设计一个程序,把中缀表达式转换成一棵二叉树,然后通过后序遍历计算表达式的值
例如:中缀表达式为(a+b)*(c+d)# (#表示结束),将之转换成一棵二叉树,然后通过后序遍历计算表达式的值,其中abcd都是确定的值。注意程序的通用性(也就是说上述只是一个例子,你的程序要接受一个序列,然后构造相应的二叉树,最后通过后序遍历计算出值(注意不是根据中缀表达式计算出值,而是通过后序遍历所构造出的二叉树计算出值))。
main.cpp
#include"st.h"
void main()
{
string preNode;
string inNode;
BiTNode* root = NULL;
printf("连续输入先序序列如ABDGCEF\n");
cin >> preNode;
printf("连续输入中序序列如DGBAECF\n");
cin >> inNode;
root = createBiTree(preNode, inNode);
printf("已创建二叉树\n");
printf("先序序列\n");
preshow(root);
printf("\n");
printf("连续输入如(500+600)*(400+300)#\n");
BiTree e = InitExpTree();
printf("已创建表达式二叉树\n");
printf("先序序列\n");
preshow(e);
printf("\n");
printf("结果是");
cout<<EvaluateExpTree(e);
system("pause");
}
st.h
#pragma once
#include<iostream>
#include<string>
using namespace std;
typedef string BTElemType;
typedef struct BiTNode
{
BTElemType BTdata;
struct BiTNode *lchild, *rchild;
}*BiTree;
typedef BiTree SElemType;
typedef struct Node
{
SElemType Sdata;
struct Node *next;
}*Stack;
bool InitStack(Stack &S);
bool StackEmpty(Stack S);
int StackLength(Stack S);
bool Push(Stack &S, SElemType e);
bool Pop(Stack &S, SElemType &e);
bool GetTop(Stack S, SElemType &e);
void preshow(BiTree &T);
BiTNode* createBiTree(string pre, string in);
bool In(char ch);
BiTree CreateExpTree( BTElemType a, BiTree L, BiTree R);
char Precede(char OPTRtop, char ch);
BiTree InitExpTree();
int GetValue(char ch, int a, int b);
int EvaluateExpTree(BiTree T);
st.cpp
#include"st.h"
bool InitStack(Stack &S)
{
S = NULL;
return true;
}
bool StackEmpty(Stack S)
{
if (S == NULL) return true;
else return false;
}
int StackLength(Stack S)
{
Stack p;
int i = 0;
for (p = S; p != NULL; p = p->next, i++);
return i;
}
bool Push(Stack &S, SElemType e)
{
Stack p = new Node;
if (!p) return false;
p->Sdata = e;
p->next = S;
S = p;
return true;
}
bool Pop(Stack &S, SElemType &e)
{
Stack p;
if (S == NULL) return false;
e = S->Sdata;
p = S; S = S->next;
delete p;
return true;
}
bool GetTop(Stack S, SElemType &e)
{
if (S == NULL) return false;
e = S->Sdata;
return true;
}
//先序遍历打印二叉树T
void preshow(BiTree &T)
{
if (T)
{
cout << T->BTdata << " ";
preshow(T->lchild);
preshow(T->rchild);
}
}
//根据先序pre和中序in序列生成二叉树BiTNode*
BiTNode* createBiTree(string pre, string in)
{
int i = 0, P = 0;
BiTNode*node = NULL;
string lpre, rpre;
string lin, rin;
int n = pre.length();
if (n == 0) return NULL;
node = new BiTNode;
if (node == NULL)return NULL;
//先序序列的第一个元素必为根结点
node->BTdata = pre[0];
//根据根结点将中序序列分为左子树和右子数
for (i = 0; i < n; i++)
{
if ((i == P) && (in[i] != pre[0]))
{
P++;
lin.push_back(in[i]);
}
else if (in[i] != pre[0])
{
rin.push_back(in[i]);
}
}
//根据左子树的长度将先序序列分为左子树和右子数
//主意 从i=1开始 因为先序遍历的第一个是根
for (i = 1; i < n; i++)
{
if (i < (P + 1))//P代表了左子树的长度
{
lpre.push_back(pre[i]);
}
else
{
rpre.push_back(pre[i]);
}
}
node->lchild = createBiTree(lpre, lin);//递归创建
node->rchild = createBiTree(rpre, rin);
return node;
}
//判断ch是否是运算符
bool In(char ch)
{
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '#')
return 1;
else return 0;
}
//以根节点元素a,指向左子树的指针L,指向右子树的指针R,创建二叉树
BiTree CreateExpTree( BTElemType a, BiTree L, BiTree R)
{
BiTree T = new BiTNode;
if (!T) return NULL;
T->BTdata = a;
T->lchild = L;
T->rchild = R;
return T;
}
//比较栈顶运算符OPTRtop与输入运算符符ch优先级
char Precede(char OPTRtop, char ch)
{
{
if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
{
if (OPTRtop == '(')
return '<';
else if (OPTRtop == '*' || OPTRtop == '/')
return '>';
else if (OPTRtop == '+' || OPTRtop == '-')
{
if (ch == '*' || ch == '/')return '<';
else if (ch == '+' || ch == '-') return '>';
}
}
else if (ch == '(')
return '<';
else if (ch == ')')
{
if (OPTRtop == '(')return '=';
else return '>';
}
else if (ch == '#')
return '>';
}
}
//表达式树BiTree创建
BiTree InitExpTree()
{
BiTree op, lt, rt, t, x;
Stack EXPT, OPTR;
InitStack(EXPT);
InitStack(OPTR);
string S;
cin >> S;//输入中缀表达式S
int e = S.length();//求表达式字符串长度
string s1,s2;//暂存数字和运算符在字符串中
for (int i = 0; i < e; i++)
{
if (!In(S[i]))//S[i]是数值
{
s1.push_back(S[i]);//字符串s1末添加S[i]
}
if (In(S[i]))//S[i]是运算符
{
s2.push_back(S[i]);//运算符暂存于字符串s2
if (s1.length() != 0)//s1非空
{
Push(EXPT, CreateExpTree(s1, NULL, NULL));//s1入栈
s1.clear();//清空s1
}
if (StackEmpty(OPTR))//S[i]是运算符,运算符栈空
{
Push(OPTR, CreateExpTree(s2, NULL, NULL));
}
else//运算符栈非空
{
GetTop(OPTR, t);
switch (Precede((t->BTdata)[0], S[i]))
{
case'<':
Push(OPTR, CreateExpTree(s2, NULL, NULL));
break;
case'>':
Pop(OPTR, op);
Pop(EXPT, rt);
Pop(EXPT, lt);
Push(EXPT, CreateExpTree(op->BTdata, lt, rt));
i--;
break;
case'=':
Pop(OPTR, x);
break;
}
}
s2.clear();//清空s2
}
}
BiTree T;
Pop(EXPT, T);
return T;
}
//根据运算符ch,左操作数a,右操作数b进行运算
int GetValue(char ch, int A, int B)
{
if (ch == '+')
return A + B;
else if (ch == '-')
return A - B;
else if (ch == '*')
return A * B;
else if (ch == '/')
return A/ B;
}
//后序遍历表达式树T求值
int EvaluateExpTree(BiTree T)
{
int lvavlue = 0, rvalue = 0;
if (T->lchild == NULL && T->rchild == NULL)
{
int c = atoi((T->BTdata).c_str());//string转int
return c;
}
else
{
lvavlue = EvaluateExpTree(T->lchild);
rvalue = EvaluateExpTree(T->rchild);
return GetValue((T->BTdata)[0], lvavlue, rvalue);
}
}