数据结构实验二 树和二叉树的实现

广州大学学生实验报告

 

开课实验室:计算机科学与工程实验(电子楼418A)     2019年5月13日

学院

计算机科学与教育软件学院

年级、专业、班

计算机科学与技术172班

姓名

 

学号

17061

实验课程名称

数据结构实验

成绩

 

实验项目名称

实验二 树和二叉树的实现

指导老师

 

一、实验目的

理解并运用树的操作方法

二、使用仪器、器材

微机一台

操作系统:Win10

编程软件:C++

三、实验内容及原理

自己选择存储方法、自己设计输入输出方式,在实验报告中清晰说明。

  1. 输入一棵多元树,进行多种遍历

树的高度(设空树高度为-1)不小于3,包含儿子数为0、1、2、3的结点。

  1. 输入一棵二叉树进行多种遍历。

树的高度(设空树高度为-1)不小于4,包含了儿子数为0、1、2的结点。选做:二叉树的总结点(或叶片)数目的统计。

3.补充下列程序,使该程序能正确运行。

题目要求:由先序遍历序列建立二叉树的515二叉链表,中序线索化二叉树并找出结点的前驱和后继。

 

  • 实验过程原始数据记录

1、输入一棵多元树,进行多种遍历

树的高度(设空树高度为-1)不小于3,包含儿子数为0、1、2、3的结点。

Tree.h

#pragma once

#include <stdio.h>

#include <malloc.h>

#define MaxSize 100

typedef struct tnode

{

    char data;                         //节点的值

    struct tnode *hp;              //指向兄弟

    struct tnode *vp;              //指向孩子节点

} TSBNode;                             //孩子兄弟链存储结构类型

 

TSBNode *CreateTree(char *str);         //由str建立孩子兄弟链存储结构

void DispTree(TSBNode *t);     //输出孩子兄弟链存储结构

void DestroryTree(TSBNode *&t);    //销毁树t

int TreeHeight2(TSBNode *t);

 

void PreOrder(TSBNode *b);     //先序遍历的递归算法

void PostOrder(TSBNode *b);        //后序遍历的递归算法

void LevelOrderTraverse(TSBNode *b);//层次遍历

 

tree.cpp

#include"pch.h"

#include "tree.h"

 

TSBNode * CreateTree(char * str)

{

    struct

    {

         TSBNode *nodep;                //节点指针

         int num;                  //孩子个数

    } St[MaxSize];                     //顺序栈

    int top = -1;                      //栈顶指针

    int i = 0, j; char ch = str[i];

    TSBNode *t = NULL, *p=NULL, *q;

    while (ch != '\0')

    {

         switch (ch)

         {

         case '(': top++; St[top].nodep = p;

             St[top].num = 0;               //当前节点p进栈

             break;

         case ')':top--;   break;            //退栈

         case ',':St[top].num++; break; //栈顶节点增加一个孩子

         default:

             p = (TSBNode *)malloc(sizeof(TSBNode));

             p->data = ch;                  //建立一个节点p存放ch

             p->hp = p->vp = NULL;

             if (t == NULL)                 //原为空树

                  t = p;

             else                      //将其作为栈顶节点的一个孩子

             {

                  if (St[top].num == 0)      //第一个孩子用vp指向它

                      St[top].nodep->vp = p;

                  else                  //其他孩子用栈顶节点的孩子节点的hp指向它

                  {

                      q = St[top].nodep->vp;

                      for (j = 1; j < St[top].num; j++)

                          q = q->hp;

                      q->hp = p;

                  }

             }

             break;

         }

         i++;

         ch = str[i];

    }

    return t;

}

 

void DispTree(TSBNode * t)

{

    TSBNode *p;

    if (t != NULL)

    {

         printf("%c", t->data);

         if (t->vp != NULL)        //有孩子时输出一个'('

         {

             printf("(");

             p = t->vp;            //p指向节点t的第一个孩子

             while (p != NULL)

             {

                  DispTree(p);

                  p = p->hp;

                  if (p != NULL)

                      printf(",");

             }

             printf(")");      //输出一个')'

         }

    }

}

 

void DestroryTree(TSBNode *& t)

{

    if (t != NULL)

    {

         DestroryTree(t->vp);

         DestroryTree(t->hp);

         free(t);              //释放根节点

    }

}

 

int TreeHeight2(TSBNode * t)

{

    TSBNode *p;

    int h, maxh = 0;

    if (t == NULL) return 0;       //空树返回0

    else

    {

         p = t->vp;                //指向第1个孩子节点

         while (p != NULL)         //扫描t的所有子树

         {

             h = TreeHeight2(p);   //求出p子树的高度

             if (maxh < h) maxh = h;    //求所有子树的最大高度

             p = p->hp;            //继续处理t的其他子树

         }

         return(maxh + 1);         //返回maxh+1

    }

}

 

void PreOrder(TSBNode * b)

{

    //st1为处理整个树的栈,st2为处理其兄弟节点的栈

    TSBNode *st1[100], *st2[100], *p = NULL;

    int top1 = -1, top2 = -1;

    if (b != NULL)

    {

         p = b;

         top1++;

         st1[top1] = p;                     //先将根节点进栈

         while (top1 >= 0)              //栈不空时循环

         {

             p = st1[top1];

             top1--;                        //退栈

             printf("%c ", p->data);        //打印输出

             if (p->vp)                //若该节点存在兄弟节点

             {

                  p = p->vp;

                  while (p != NULL)     //将兄弟节点依次进栈

                  {

                      top2++;

                      st2[top2] = p;

                      p = p->hp;

                  }

                  while (top2 >= 0)     //将兄弟节点依次退栈st2并将退栈的元素放到st1中

                  {

                      top1++;

                      st1[top1] = st2[top2];

                      top2--;

                  }

             }

         }

    }

}

 

 

void PostOrder(TSBNode * b)

{

    if (b == NULL)

         return;

    TSBNode *p = b->vp;

    PostOrder(p);                               //递归打印孩子节点

 

    if (p != NULL)

         p = p->hp;

    while (p)                                       //该节点不空则递归打印兄弟节点

    {

         PostOrder(p);

         p = p->hp;

    }

    printf("%c ", b->data);                     //打印输出

}

}

 

void LevelOrderTraverse(TSBNode * b)

{

}

 

Main.cpp

#include "pch.h"

#include <iostream>

#include"tree.h"

int main()

{

 

    TSBNode *t;

    t = CreateTree("A(B(E,F),C(G(J)),D(H,I(K,L,M)))");

    printf("t:"); DispTree(t);

    printf("\n树t的高度:%d\n", TreeHeight2(t));

    printf("\n树t的先根遍历结果为:"); PreOrder(t);

    printf("\n");

    printf("\n树t的后根遍历结果为:"); PostOrder(t);

    DestroryTree(t);

    return 1;

}

2、输入一棵二叉树进行多种遍历。

树的高度(设空树高度为-1)不小于4,包含了儿子数为0、1、2的结点。选做:二叉树的总结点(或叶片)数目的统计。

Btree.h

#pragma once

#include"pch.h"

#include <stdio.h>

#include <malloc.h>

#define MaxSize 100

typedef char ElemType;

typedef struct node

{

    ElemType data;            //数据元素

    struct node *lchild;  //指向左孩子节点

    struct node *rchild;  //指向右孩子节点

} BTNode;

void CreateBTree(BTNode * &b, char *str);   //创建二叉树

void DestroyBTree(BTNode *&b);

BTNode *FindNode(BTNode *b, ElemType x);

BTNode *LchildNode(BTNode *p);

BTNode *RchildNode(BTNode *p);

int BTHeight(BTNode *b);

void DispBTree(BTNode *b);//输出二叉树

 

//二叉树的遍历算法

void PreOrder1(BTNode *b);//先序遍历非递归算法1

void PreOrder2(BTNode *b);//先序遍历非递归算法2

void InOrder1(BTNode *b);//中序遍历非递归算法1

void PostOrder1(BTNode *b);//后序遍历非递归算法1

 

//有关栈的操作

typedef struct

{

    BTNode *data[MaxSize];         //存放栈中的数据元素

    int top;                       //存放栈顶指针,即栈顶元素在data数组中的下标

} SqStack;                             //顺序栈类型

 

void InitStack(SqStack *&s);            //初始化栈

void DestroyStack(SqStack *&s);         //销毁栈

bool StackEmpty(SqStack *s);            //判断栈是否为空

bool Push(SqStack *&s, BTNode *e); //进栈

bool Pop(SqStack *&s, BTNode *&e); //出栈

bool GetTop(SqStack *s, BTNode *&e);    //取栈顶元素

Btree.cpp

#include"pch.h"

#include "btree.h"

 

void CreateBTree(BTNode *& b, char * str) //创建二叉树

{  

    BTNode *St[MaxSize], *p = NULL;

    int top = -1, k, j = 0;

    char ch;

    b = NULL;                 //建立的二叉树初始时为空

    ch = str[j];

    while (ch != '\0')    //str未扫描完时循环

    {

         switch (ch)

         {

         case '(':top++; St[top] = p; k = 1; break;       //为左孩子节点

         case ')':top--; break;

         case ',':k = 2; break;                           //为孩子节点右节点

         default:p = (BTNode *)malloc(sizeof(BTNode));

             p->data = ch; p->lchild = p->rchild = NULL;

             if (b == NULL)                        //*p为二叉树的根节点

                  b = p;

             else                                   //已建立二叉树根节点

             {

                  switch (k)

                  {

                  case 1:St[top]->lchild = p; break;

                  case 2:St[top]->rchild = p; break;

                  }

             }

         }

         j++;

         ch = str[j];

    }

}

 

void DestroyBTree(BTNode *& b)

{  

    if (b != NULL)

    {

         DestroyBTree(b->lchild);

         DestroyBTree(b->rchild);

         free(b);

    }

}

 

BTNode * FindNode(BTNode * b, ElemType x)

{  

    BTNode *p;

    if (b == NULL)

         return NULL;

    else if (b->data == x)

         return b;

    else

    {

         p = FindNode(b->lchild, x);

         if (p != NULL)

             return p;

         else

             return FindNode(b->rchild, x);

    }

}

 

BTNode * LchildNode(BTNode * p)

{

    return p->lchild;

}

 

BTNode * RchildNode(BTNode * p)

{

    return p->rchild;

}

 

int BTHeight(BTNode * b)

{  

    int lchildh, rchildh;

    if (b == NULL) return(0);               //空树的高度为0

    else

    {

         lchildh = BTHeight(b->lchild); //求左子树的高度为lchildh

         rchildh = BTHeight(b->rchild); //求右子树的高度为rchildh

         return (lchildh > rchildh) ? (lchildh + 1) : (rchildh + 1);

    }

}

 

void DispBTree(BTNode * b)

{

    if (b != NULL)

    {

         printf("%c", b->data);

         if (b->lchild != NULL || b->rchild != NULL)

         {

             printf("(");                       //有孩子节点时才输出(

             DispBTree(b->lchild);              //递归处理左子树

             if (b->rchild != NULL) printf(","); //有右孩子节点时才输出,

             DispBTree(b->rchild);              //递归处理右子树

             printf(")");                       //有孩子节点时才输出)

         }

    }

}

 

void PreOrder1(BTNode * b)

{

    BTNode *p;

    SqStack *st;                   //定义一个顺序栈指针st

    InitStack(st);                     //初始化栈st

    Push(st, b);                   //根节点进栈

    while (!StackEmpty(st))        //栈不为空时循环

    {

         Pop(st, p);               //退栈节点p并访问它

         printf("%c ", p->data);   //访问节点p

         if (p->rchild != NULL) //有右孩子时将其进栈

             Push(st, p->rchild);

         if (p->lchild != NULL) //有左孩子时将其进栈

             Push(st, p->lchild);

    }

    printf("\n");

    DestroyStack(st);              //销毁栈

}

 

void PreOrder2(BTNode * b)

{

    BTNode *p;

    SqStack *st;                   //定义一个顺序栈指针st

    InitStack(st);                     //初始化栈st

    p = b;

    while (!StackEmpty(st) || p != NULL)

    {

         while (p != NULL)              //访问节点p及其所有左下节点并进栈

         {

             printf("%c ", p->data);   //访问节点p

             Push(st, p);              //节点p进栈

             p = p->lchild;            //移动到左孩子

         }

         if (!StackEmpty(st))      //若栈不空

         {

             Pop(st, p);               //出栈节点p

             p = p->rchild;            //转向处理其右子树

         }

    }

    printf("\n");

    DestroyStack(st);              //销毁栈

}

 

void InOrder1(BTNode * b)

{

    BTNode *p;

    SqStack *st;                       //定义一个顺序栈指针st

    InitStack(st);                         //初始化栈st

    if (b != NULL)

    {

         p = b;

         while (!StackEmpty(st) || p != NULL)

         {

             while (p != NULL)              //扫描节点p的所有左下节点并进栈

             {

                  Push(st, p);              //节点p进栈

                  p = p->lchild;            //移动到左孩子

             }

             if (!StackEmpty(st))      //若栈不空

             {

                  Pop(st, p);               //出栈节点p

                  printf("%c ", p->data);   //访问节点p

                  p = p->rchild;            //转向处理其右子树

             }

         }

         printf("\n");

    }

    DestroyStack(st);              //销毁栈

}

 

void PostOrder1(BTNode * b)

{

    BTNode *p, *r;

    bool flag;

    SqStack *st;                       //定义一个顺序栈指针st

    InitStack(st);                         //初始化栈st

    p = b;

    do

    {

         while (p != NULL)                  //扫描节点p的所有左下节点并进栈

         {

             Push(st, p);                   //节点p进栈

             p = p->lchild;                 //移动到左孩子

         }

         r = NULL;                              //r指向刚刚访问的节点,初始时为空

         flag = true;                       //flag为真表示正在处理栈顶节点

         while (!StackEmpty(st) && flag)

         {

             GetTop(st, p);                 //取出当前的栈顶节点p

             if (p->rchild == r)            //若节点p的右孩子为空或者为刚刚访问过的节点

             {

                  printf("%c ", p->data);   //访问节点p

                  Pop(st, p);

                  r = p;                    //r指向刚访问过的节点

             }

             else

             {

                  p = p->rchild;            //转向处理其右子树

                  flag = false;             //表示当前不是处理栈顶节点

             }

         }

    } while (!StackEmpty(st));         //栈不空循环

    printf("\n");

    DestroyStack(st);              //销毁栈

}

 

void InitStack(SqStack *& s)

{

    s = (SqStack *)malloc(sizeof(SqStack));//分配一个是顺序栈空间,首地址存放在s中

    s->top = -1;                       //栈顶指针置为-1

}

 

void DestroyStack(SqStack *&s)     //销毁栈

{

    free(s);

}

 

bool StackEmpty(SqStack * s)

{

    return(s->top == -1);

}

 

bool Push(SqStack *& s, BTNode * e)

{

    if (s->top == MaxSize - 1)         //栈满的情况,即栈上溢出

         return false;

    s->top++;                          //栈顶指针增1

    s->data[s->top] = e;               //元素e放在栈顶指针处

    return true;

}

 

bool Pop(SqStack *& s, BTNode *& e)

{

    if (s->top == -1)                  //栈为空的情况,即栈下溢出

         return false;

    e = s->data[s->top];               //取栈顶指针元素的元素

    s->top--;                          //栈顶指针减1

    return true;

}

 

bool GetTop(SqStack * s, BTNode *& e)

{

    if (s->top == -1)                  //栈为空的情况,即栈下溢出

         return false;

    e = s->data[s->top];               //取栈顶元素

    return true;

}

 

Main.cpp

int main()

{

    BTNode *b;

    CreateBTree(b, "A(B(D(G,H(,J)),E(,I)),C(,F))");

    DispBTree(b);

    printf("\n");

    printf("先序遍历序列1:"); PreOrder1(b);

    printf("先序遍历序列2:"); PreOrder2(b);

    printf("中序遍历序列:"); InOrder1(b);

    printf("后序遍历序列:"); PostOrder1(b);

    DestroyBTree(b);

    printf("\n");

}

 

3补充下列程序,使该程序能正确运行。

步骤一:新建工程,新建一个头文件,命名为 thread.h,一个源文件命名为thread.cpp

 

步骤二

在thread.h中编辑代码,代码如下:

#include <iostream>

using namespace std;

typedef char DataType;

 

typedef struct Node

{

       DataType data;

       int      Ltag;

       int      Rtag;

__struct Node__ *LChild;   /*填空1、指针域的数据类型*/

       __struct Node__ *RChild;

}BTNode;

 

BTNode *pre;

void CreateBiTree(BTNode  *&root, DataType Array[]) ; //创建初始化二叉树

void  Inthread(BTNode *root); //实现中序线索二叉树

BTNode * InPre(BTNode *p);  //求中序线索二叉树结点的前驱

BTNode * InNext(BTNode * p) ; //求中序线索二叉树结点的后驱

 

在Thread.cpp中编辑代码,代码如下:

#include "thread.h"            /*11、填空:请填空:包含头文件*/

 

void CreateBiTree(BTNode  *&root, DataType Array[])

{

       static int count=0;      //静态变量count

   char item=Array[count];//读取Array[]数组中的第count个元素

       count++;

       if(item == '#') //如果读入#字符,创建空树

          { root = NULL; return ;}

   else

       {

              root = __ (BTNode *)malloc(sizeof(BTNode))__;/*填空3:生成一个新结点*/

        ___ root->data___ = item; /*填空4:将ch做为新结点的数据域的值*/

              root->Ltag=0;

              root->Rtag=0;

              __ CreateBiTree(root->LChild, Array)_; /*填空5: 递归的方法,生成左子树,注意实参的表示方法*/

       __ CreateBiTree(root->RChild, Array)_; /*填空6: 递归的方法,生成右子树,注意实参的表示方法*/

 

       }

}

 

void  Inthread(BTNode *root)

/* root所指的二叉树进行中序线索化,其中pre始终指向刚访问过的结点,其初值为NULL */

{

       if (root!=NULL)

       {

              Inthread(root->LChild);  /* 线索化左子树 */

              if (root->LChild==NULL)

              {

                     root->Ltag=___ 1__;

                     __ root->LChild_=pre;  /*填空7-8:置前驱线索 */

              }

              if (pre!=NULL&& pre->RChild==NULL)  /* 填空9-10:置后继线索 */

{

                     pre->Rtag=__ 1___;

                     __ root->RChild __=root;

              }

          pre=root;

          Inthread(root->RChild);  /*线索化右子树*/

       }

}

 

/* 在中序线索二叉树中查找p的中序前驱, 并用pre指针返回结果 */

BTNode * InPre(BTNode *p)

       BTNode *q;

       if(p->Ltag==1)

              pre = __p->LChild__;  /*填空13:直接利用线索找前驱*/

       else

       { /* 填空14-15:在p的左子树中查找"最右下端"结点 */

              for(q = p->LChild;q->Rtag==__0__;q=q->_ RChild __);

              pre=q;

       }

       return(pre);

}

 

/*在中序线索二叉树中查找p的中序后继结点,并用next指针返回结果*/

BTNode * InNext(BTNode * p)

{

       BTNode *Next;

       BTNode *q;

       if (p->Rtag==1) 

              Next = p->RChild;  /*填空16:直接利用线索*/

       else

       { /*填空17-18 p的右子树中查找"最左下端"结点*/

              for(q=p->RChild; q->Ltag==___0___ ;q=q->__ LChild ___);

              Next=q;

       }

       return(Next);

}

 

void main()

{

       BTNode *root,*q;

       DataType A[]="AB#CD##E##F#G##";//"#"补充空分支后的某个遍历序列

 

       CreateBiTree(root,A);//以先序遍历序列建立二叉树

pre = NULL;

       Inthread(root);

       q =InPre(root); /*找根结点的前驱,大家试找其它结点的前驱*/

       cout<<root->data<<"的前驱为"<<q->data<<endl;

       q =InNext(root); /*找根结点的后驱,大家试找其它结点的后驱*/

       cout<<root->data<<"的后继为"<<q->data<<endl;

};

  

  • 实验结果及分析

1.输入一棵多元树,进行多种遍历

多元树存储结构为孩子兄弟存储结构,遍历算法:先跟遍历采用非递归算法,后根遍历采用递归算法。

2.输入一棵二叉树进行多种遍历。

 

遍历算法均为非递归算法

3.补充下列程序,使该程序能正确运行。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值