**
一:实验要求
**
实验 1 二叉树的建立及其基本运算算法
目的:理解二叉树左右指针存储结构,并基于该数据结构,掌握二叉
树各种基本运算算法的设计
内容:编写一个程序 btree_op.c 实现二叉树的基本运算,完成如下
1 有图 5.1 所示的二叉树创建对应的左右指针存储结构 t,
该二叉树的括号表示串为“A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”
2 输出二叉树 t
3 输出‘H’结点的左右孩子结点值
4 输出二叉树 t 的高度
5 释放二叉树 t
二:代码实现
1.结构体的定义
struct tree{ //树节点
char val;
struct tree* l;
struct tree* r;
};
typedef struct tree Node;
typedef struct tree* Pnode;
typedef struct tree Tree;
typedef struct tree* Ptree;
代码分析:
1.树节点中一个数据域用来储存值,两个指针域用来分别指向左右孩子节点
2.树的创建
void creat_tree(Ptree &root,char c[]){
int maxnum = strlen(c);//获取字符串的长度
Ptree st[1000]; //使用字符数组模拟栈
int top = -1;//控制栈顶元素下标
int j = 0;//用来遍历字符串数组c
int k = 0;//k=1:表示将处理的节点作为左节点
Ptree node; //用来储存新的节点
root = NULL;
char ch = c[j];
while(ch != '\0'){
switch(ch){
case '(':{
top++;
st[top] = node;
k = 1;
break;
}
case ')':{
top--;
break;
}
case ',':{
k = 2;
break;
}
default:{
node = (Ptree)malloc(sizeof(Tree));
if(node != NULL){
node->val = ch;
node->l = NULL;
node->r = NULL;
}
if (root == NULL) {
root = node;
}
else {
switch (k) {
case 1: {
st[top]->l = node;
break;
}
case 2: {
st[top]->r = node;
break;
}
}
}
}
}
j++;
ch = c[j];
}
}
代码分析:
1.接受两个参数,分别是根节点和字符串数组
2.接受到字符串数组后需要对字符串数组进行遍历,以此来确定每个字符在树中的具体位置。
3.使用变量j来控制对字符数组的遍历
4.node节点为当前处理的节点
5char ch 为字符串中正在处理的字符
6.使用变量k来确定当前处理的节点是左子树还是右子树,k=1代表将node节点作为根节点的左子树,n=2 代表将node节点作为根节点右子树。
7.Ptree st[1000]用来模拟栈,以此来使得所有的节点建立联系
8.top 可以理解为栈的栈顶元素的下标
9.栈顶元素为一棵树的根节点,node节点是用来储存新的节点的
10.因为树的定义是递归的,想要建立节点之间的关系,必须要抽象出问题的本质,在分析中,可以简单的理解为处理只有三个节点的二叉树,比较容易理解。
11.在构建树的过程中st[top]节点就可以理解为根节点,node节点为将要添加的节点,将node节点赋值之后,要判断该节点放在左子树上还是右子树上。
12.在遍历字符串的时候,c[j]只存在四种可能,(1)左括号(2)右括号(3)逗号(4)字符
14.遇见左括号时,说明根节点存在左子树,但是不一定。例如(,A)
15.遇见逗号时,说明根节点存在右子树
16.遇见右括号,说明这颗树已经处理结束,需要将栈顶元素弹出。再次强调递归!!!
17.举例说明A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))构建一颗树,
<1>c[j] = ‘A’ 扫描到这里,执行default语句,为节点node开辟空间,并将其左右子节点全部置空
<2>一开始的时候root节点为空,此时扫描到’A’,将’A‘节点作为整棵树的根节点。
<3>第一次遍历结束,j自增,ch = c[j],进入第二次遍历。
<4>此时 c[j] = ‘(‘ 说明上一次遍历的节点存在左子树,那么,将上一次的节点压入栈中,即st[++top] = node;k=1;
<5>循环结束,ch = c[++j]
<6>第三次遍历ch = ‘B’,执行default语句,开辟空间node,因为在上次循环中已经是k=1,此时需要执行第二个switch语句,st[top]->l = node,break;就把’B‘节点连接在了栈顶元素即根节点的左子树上。
<7>以此类推,就可以实现整棵树的链接。
3.显示树中的所有节点
void Disptree(Ptree root){
if (root != NULL) {
cout << root->val;
if (root->l || root->r) {
cout << "(";
Disptree(root->l);
if (root->r) {
cout << ",";
}
Disptree(root->r);
cout << ")";
}
}
}
代码分析
- 将根节点作为参数传进来
- 首先判断根节点是否为空,只有根节点不为空,才能显示树的内容
- 先将根节点的值输出,之后判断根节点是否存在左右子树,如果存在,先输出左括号,再次递归的遍历左子树
- 如果根节点存在右子树,需要先输出逗号,再递归的处理根节点的右子树,最后处理完所有的节点输出右括号。
5求某个节点的左子树和右子树
Ptree leftChild_link(Ptree p){
if(p ==NULL){
return NULL;
}
else{
return p->l;
}
}
Ptree rightChild_link(Ptree p) {
if (p == NULL) {
return NULL;
} else {
return p->r;
}
}
代码分析:
1. 如果该节点为空,就返回空
2. 否则直接返回该节点的左子树或右子树
求某棵树的高度
int PtreeHight(Ptree t){
int lchild;
int rchild;
if(t == NULL){
return 0;
}
else{
lchild = PtreeHight(t->l) ;
rchild = PtreeHight(t->r) ;
return (lchild > rchild) ? (lchild + 1) : (rchild + 1);
}
}
代码分析:
- 将树根作为参数传递进来
- 定义两个变量lchild,rchild分别递归的统计左右子树的高度
返回节点值为x的节点的指针
Ptree FindNode(Ptree t,char x){
if(t == NULL){
return NULL;
}
else if(t->val == x){
return t;
}
else{
Ptree p = FindNode(t->l, x);
if(p!=NULL){
return p;
}
else
return FindNode(t->r, x);
}
}
释放整棵树
void DestroyBTree(Ptree root){
if(root != NULL){
DestroyBTree(root->l);
DestroyBTree(root->r);
free(root);
}
}
三:效果展示
***