《数据结构》实验二报告
日期: 2020-11-23 程序名: shiyan2.c
实验内容: 二叉树的遍历
一、目的和要求(需求分析):
1、掌握二叉树的存储结构以及二叉树的建立和操作。
2、输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。
(输入表达式如此形式:a+b*c-d-e/f….;以#号结束。)
3、递归实现表达式运算。
二、程序设计的基本思想,原理和算法描述:
程序的结构:首先定义二叉树,随后创建二叉树,此时利用flag判断记录表达式中是否有括号,基于此对输入的表达式中的数字、运算符进行分别处理,生成二叉树的节点。然后分别实现二叉树的前、中、后序遍历,有括号的要去括号处理。如果当前节点是运算符,就要判断它的左右孩子节点。然后是实现输出结果的函数。最后是main函数,输入时要考虑以#结束。
二叉树前、中、后序遍历的数据结构:
*
void preorder(BiTree T)
{//先序遍历
if (T->leftChild != NULL || T->rightChild != NULL)
{
printf("%c", T->op);
if (T->leftChild)
{
preorder(T->leftChild);
}
if (T->rightChild)
{
preorder(T->rightChild);
}
}
else
{
printf("%d", T->data);
}
}
void inorder(BiTree T)
{//中序遍历
if (T->leftChild != NULL)
inorder(T->leftChild);
else
{
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
return;
}
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
if (T->rightChild != NULL)
inorder(T->rightChild);
}
void postorder(BiTree T)
{//后序遍历
if (T->leftChild != NULL)
postorder(T->leftChild);
else
{
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
return;
}
if (T->rightChild != NULL)
postorder(T->rightChild);
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
}*
输入/输出设计:略
三、调试和运行程序过程中产生的问题及采取的措施:
问题1:对于表达式传化为二叉树的过程难以理解。
措施:看课本相关内容然后自己动手画二叉树就能明白了。
问题2:难以将表达式直接转化成二叉树。
措施:中序表达式是不可能直接转化为二叉树的,所以可以先转换为后缀表达式,然后通过后缀构造。
问题3:在创建链表时,提示了“取消对NULL指针“root” 的引用“的错误。
措施:这是因为在写代码时,没有加判断内存分配是否分配成功的语句造成的,加if条件判断即可。
四、源程序及注释:
[ 源程序 ] 程序名: shiyan2.c
*#include<stdio.h>
#include<stdlib.h>
#include <string.h>
typedef struct node {
struct node* leftChild;
struct node* rightChild;
char op;
int data;
int fg;//判断存储的是数字还是字符
}BiTreeNode, * BiTree;
struct node* InitTree(char s[], int start, int end)
{//创建二叉树
struct node* root = (struct node*)malloc(sizeof(struct node));
int number = 0;
int flag = 0;//判断是否有括号
int k1 = 0;int n1 = 0;int k2 = 0;int n2 = 0;int k3 = 0;int n3 = 0;int k4 = 0;int n4 = 0;
int point;
if (start > end) return NULL;
for (int i = start; i <= end; i++){
//进入括号
if (s[i] == '(')
{
flag = 1;
}
//退出括号
else if (s[i] == ')')
{
flag = 0;
}
//括号外有运算符
else if (flag == 0)
{
if (s[i] == '+' || s[i] == '-')
{
k1 = i;
n1 = 1;
}
else if (s[i] == '*' || s[i] == '/')
{
k2 = i;
n2 = 1;
}
}
//括号中有运算符
else
{
if (s[i] == '+' || s[i] == '-')
{
k3 = i;
n3 = 1;
}
else if (s[i] == '*' || s[i] == '/')
{
k4 = i;
n4 = 1;
}
}
}
if (n1 == 1)
{
point = k1;
root->op = s[point];
root->fg = 0;
root->leftChild = InitTree(s, start, point - 1);
root->rightChild = InitTree(s, point + 1, end);
}
else if (n2 == 1)
{
point = k2;
root->fg = 0;
root->op = s[point];
root->leftChild = InitTree(s, start, point - 1);
root->rightChild = InitTree(s, point + 1, end);
}
else if (n3 == 1)
{
point = k3;
root->fg = 0;
root->op = s[point];
root->leftChild = InitTree(s, start, point - 1);
root->rightChild = InitTree(s, point + 1, end);
}
else if (n4 == 1)
{
point = k4;
root->fg = 0;
root->op = s[point];
root->leftChild = InitTree(s, start, point - 1);
root->rightChild = InitTree(s, point + 1, end);
}
else
{//只剩数字
for (int i = start; i <= end; i++)
{
if (s[i] >= '0' && s[i] <= '9')
{
number = number * 10 + (s[i] - '0');
}
}
root->fg = 1;
root->data = number;
root->leftChild = NULL;
root->rightChild = NULL;
}
return root;
}
void preorder(BiTree T)
{//先序遍历
if (T->leftChild != NULL || T->rightChild != NULL)
{
printf("%c", T->op);
if (T->leftChild)
{
preorder(T->leftChild);
}
if (T->rightChild)
{
preorder(T->rightChild);
}
}
else
{
printf("%d", T->data);
}
}
void inorder(BiTree T)
{//中序遍历
if (T->leftChild != NULL)
inorder(T->leftChild);
else
{
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
return;
}
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
if (T->rightChild != NULL)
inorder(T->rightChild);
}
void postorder(BiTree T)
{//后序遍历
if (T->leftChild != NULL)
postorder(T->leftChild);
else
{
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
return;
}
if (T->rightChild != NULL)
postorder(T->rightChild);
if (T->fg == 0)
printf("%c", T->op);
else
printf("%d", T->data);
}
double printend(BiTree T)
{//输出计算结果
double num;
if (T->fg == 0)
{
if (T->op == '+')
num = printend(T->leftChild) + printend(T->rightChild);
if (T->op == '-')
num = printend(T->leftChild) - printend(T->rightChild);
if (T->op == '*')
num = printend(T->leftChild) * printend(T->rightChild);
if (T->op == '/')
num = printend(T->leftChild) * 1.0 / printend(T->rightChild);
}
else
num = T->data;
return num;
}
int main()
{
BiTree S;
char k;
char s[200];
int num = 0;
double sum;
printf("请输入要计算的表达式(#表示输入结束):\n");
scanf_s("%c", &k);
while (k != '#')
{//以#结束
s[num] = k;
num++;
scanf_s("%c", &k);
}
S = InitTree(s, 0, num - 1);
printf("先序遍历:\n");
preorder(S);
printf("\n");
printf("中序遍历:\n");
inorder(S);
printf("\n");
printf("后序遍历:\n");
postorder(S);
printf("\n");
sum = printend(S);
printf("表达式结果为:\n");
printf("%.2f\n", sum);
return 0;
}*
五、运行输出结果:
六、心得与体会:
掌握了二叉树的存储结构以及二叉树的建立和操作。明白了如何输入一串表达式后,建立二叉树,并对其进行先序、中序和后序的遍历。还理解了为什么表达式能转化为二叉树,这是由于运算符的优先级关系, 建立二叉树要把所有的操作数都放在叶子节点上, 所有的操作符都放在根节点上, 这就与二叉树对应起来了。