Visual C++ 6.0调试功能 图解教程(3)--实例二

树和二叉树

  1. 实验目的

1.熟悉二叉树的二叉链表存储结构;

2.掌握构造二叉树的方法;

3.加深对二叉树的遍历的理解。

二.需求分析

    本程序演示用C++编写,完成按先序遍历生成二叉树,先序遍历打印输出二叉树后序遍历打印输出二叉树中序遍历打印输出二叉树层序遍历打印输出二叉树先序遍历方法交换左右子树,求树的高度,求树的叶子结点个数.

输入值的范围:建立一棵二叉时,要求结点的的左右孩子为空时输入0代替.所有输入值必须为整形.输入的结点个数:若为单边二叉树(全只有左结点或全只有右结点)则为任意个数;若非单边二叉则要求结点最多的层个数不得超过MAXSIZE的值.

输出形式:输出时如果结点的左右指针这空则以" #"代替输出.

程序所能完成的功能:程序能完成按先序遍历生成二叉树,先序遍历打印输出二叉树后序遍历打印输出二叉树中序遍历打印输出二叉树层序遍历打印输出二叉树先序遍历方法交换左右子树,求树的高度,求树的叶子结点个数.操作.

测试数据

A建立二叉树中输入1230000 生成一棵树123####

B交换左右子树得到一棵二叉树1#2#3##

C按层序遍历树得到一棵二叉树1#2#3##

D求二叉树的高度得到高度3

E求叶子结点个数得到个数1

.设计概要

(1)为了实现上述程序的功能,需要定义二叉树的抽象数据类型:

ADT BiTree is{

数据对象:D={ai|aiIntegerSet,i=0,1,2,…,n,n≥0} 
数据关系:R={<ai,ai+1>|ai,ai+1 D}

基本操作:

creat()

操作结果:建立一棵二叉树

preorder()

初始条件:二叉树已经存在

操作结果:先序遍历显示二叉树

preordertswap()

初始条件二叉树已经存在

操作结果:交换二叉树的左右子树

theight()

初始条件二叉树已经存在

操作结果:输出二叉树的高度

tleaves()

初始条件:

操作结果:输出二叉树的叶子结点个数

levelorder()

初始条件二叉树已经存在

操作结果:层序遍历显示二叉树

}ADT BiTree

(2) 本程序包含两个类和一个结构体类型

A基类:队列类SeQueue5个函数

    1.构造函数                            SeQueue()

    2.析构函数                            ~SeQueue()

    3.进队函数                            AddQ(NodeType x)

    4.出队函数                            DelQ()

    5.判断非空函数                            IsEmpty()

B派生类:二叉树类BiTree20个函数

    1主函数                                main()

2. 构造函数                            BiTree()

    3. 析构函数                            ~BiTree()

    4. 建立树函数                            creat0()

    5. 先序遍历函数                        void preorder()

    6. 中序遍历函数                        inorder()

    7. 后序遍历函数                        postorder()

    8.层序遍历函数                            levelorder()

    9. 交换左右子树函数                    preordertswap()

    10. 求二叉树高度函数                    theight()

    11. 求二叉树叶子结点个数函数                tleaves()

    12. 建立二叉树递归算法函数                *creat()

    13. 先序遍历递归算法函数                preorder(NodeType *p)

    14. 中序遍历递归算法函数                inorder(NodeType *p)

    15. 后序遍历递归算法函数                postorder(NodeType *p)

    16. 按层遍历算法函数                    levelorder(NodeType *p)

    17. 先序遍历方法交换左右子树函数            preorderswap(NodeType *p)

    18. 求二叉树高度递归算法函数                height(NodeType *p)

    19. 求二叉树叶子结点个数的递归算法函数    leaves(NodeType *p)

    20. 删除二叉树所有结点函数                destroy(NodeType* &p)

C结构体类型NodeType

(3)本程序的三个文件

1.头文件BiTree.h

2.源文件     Queue.cpp

        BiTree.cpp

(4)函数之间的关系

 

 

.详细设计

 

  1 // BiTree.h
  2 // #include <iostream.h>
  3 #include  < iostream >      //  Visual Studio 2008中要求的
  4 #include  " stdlib.h "
  5 #define  MAXSIZE 2    
  6 typedef  int  ElemType;
  7 using   namespace  std;     //  Visual Studio 2008中要求的
  8
  9 struct  NodeType                            // 定义结点结构体
 10 {       
 11    ElemType   data;                    
 12    NodeType  *lch,*rch;
 13}
;
 14
 15 // 队列
 16 class  SeQueue                                 // 定义队列类SeQueue
 17 {  
 18private:
 19       NodeType elem[MAXSIZE];        //存储队列的数组个数
 20        int front,rear;                //队头,队尾
 21public:
 22        SeQueue();
 23        ~SeQueue();
 24        void AddQ(NodeType x);        //入队函数
 25        NodeType DelQ();            //出队函数
 26        int IsEmpty()                //判断队列非空函数
 27        {
 28            return front == rear;
 29        }

 30}
;
 31
 32 // 二叉树
 33 class  BiTree: public  SeQueue               // 定义二叉树类BiTree 作为队列类SeQueue的派生类
 34 {
 35 public:
 36     BiTree(){    root = NULL;    }                //构造函数
 37     ~BiTree(){    destroy(root);    }        //析构函数
 38     void preorder()                    //先序遍历
 39     {        preorder(root);        }
 40     void inorder()                          //中序遍历
 41      {     inorder(root);  }                
 42     void postorder()                     //后序遍历
 43     {        postorder(root);    }
 44
 45     void preordertswap()                   //交换左右子树
 46      {     preorderswap(root);  }
 47     int  theight()                          //求二叉树高度
 48      {     return height(root);  }
 49     int tleaves()                         //求二叉树叶子结点个数
 50     {        return leaves( root );    }
 51     void levelorder()                       //按层遍历
 52     {        levelorder(root);    }    
 53      void creat0();                        //建立树函数
 54  private:
 55     NodeType *root;                    //数据成员,根结点
 56     NodeType *creat();                    //建立二叉树递归算法
 57    void    preorder(NodeType *p);            //先序遍历递归算法
 58     void    inorder(NodeType *p);            //中序遍历递归算法
 59    void    postorder(NodeType *p);            //后序遍历递归算法
 60    void    levelorder(NodeType *p);            //按层遍历算法
 61     void    preorderswap(NodeType *p);       //利用先序遍历方法交换左右子树
 62     int    height(NodeType *p);            //求二叉树高度递归算法
 63    int    leaves(NodeType *p);            //求二叉树叶子结点个数的递归算法
 64     void destroy(NodeType* &p);            //删除二叉树所有结点
 65}
;
 66
 67 // BiTree.cpp
 68 #include  " BiTree.h "
 69
 70 void   BiTree::creat0()                          // 建立树函数,
 71     {  
 72    cout << "请按照树的先序遍历顺序组织数据" << endl;
 73     cout << "若结点信息是int,把每个结点的空孩子以输入;" << endl;
 74     cout << "一个结点的二叉树,输入:0 0;" << endl;
 75     root = creat();          //调用私有creat()(工具函数);
 76     }

 77 NodeType  *  BiTree::creat()       // 递归建立二叉树算法
 78
 79    NodeType *p;   
 80    ElemType x;
 81    cout << "\n 输入数据:"
 82    cin >> x;
 83    if( x == 0 )        //若左或右孩子为空,置当前指针这空.
 84        p = NULL;
 85    else {
 86            p = new NodeType; 
 87            p->data = x;
 88            p->lch = creat();                  //递归调用自身
 89            p->rch = creat();
 90          }

 91   return p;
 92}

 93
 94 // 先序遍历递归算法
 95 void  BiTree::preorder(NodeType  * p)               // 先序遍历显示
 96 {
 97    if( p != NULL)
 98    {
 99        cout << p->data;
100        preorder( p->lch );        //递归调用自身
101        preorder( p->rch );        //递归调用自身
102    }

103    else
104        cout <<"#";
105}

106 // 中序遍历递归算法
107 void  BiTree::inorder(NodeType  * p)      // 中序遍历显示
108 {  
109 
110    if( p != NULL )
111    {
112        inorder( p->lch );        //递归调用自身
113        cout << p->data;
114        inorder( p->rch );        //递归调用自身
115    }

116    else
117        cout << "#";    
118
119}

120 // 后序遍历递归算法
121 void  BiTree::postorder(NodeType  * p)
122 {
123    if( p != NULL )
124    {
125        
126        postorder( p-> lch );        //递归调用自身
127        postorder( p-> rch );        //递归调用自身
128        cout << p->data;
129    }

130    else
131        cout <<"#";
132}

133 void  BiTree::preorderswap(NodeType  * p)          // 利用先序遍历方法交换左右子树
134 {      
135    if( p != NULL )
136    {       
137        NodeType *r; 
138        r = p->lch;
139        p->lch = p->rch; 
140        p->rch = r;
141//上面几条语句可以认为对结点的访问(交换左右孩子)
142//替换了原来的:cout<<p->data<<" ";  语句
143        preorderswap( p->lch );        //递归调用自身
144        preorderswap( p->rch );
145    }

146}

147 void   BiTree::destroy(NodeType *   & p)             // 删除二叉树所有结点
148 {
149    if(p != NULL)
150    {    destroy( p->lch );
151        destroy( p->rch );
152        delete p;
153        p = NULL;
154    }

155}

156 int  BiTree::height(NodeType  * p)                 // 求二叉树高度递归算法
157 {       
158    int hl,hr;
159    if( p != NULL )
160    {
161        hl = height( p->lch );
162        hr = height( p->rch );
163        return ( hl > hr ? hl : hr ) + 1;        //当前结点高度是以最大的(左右)子树的高度加得到
164        
165    }

166    else
167        return 0;
168
169}

170 // 求二叉树叶子结点个数的递归算法
171 int  BiTree::leaves(NodeType  * p)
172 {
173    if( p == NULL )            //当前结点是否为空,当为空时就没有左右孩子
174        return 0;
175    if( ( p-> lch == NULL ) && ( p-> rch == NULL ))    //当前结点是否有左右孩子
176    {
177        return 1;
178    }

179    return leaves( p-> lch ) + leaves( p-> rch );    //递归调用自身累加叶子结点个数
180}

181
182 // 按层遍历算法
183 void  BiTree::levelorder(NodeType  * p)
184 {
185    SeQueue q;            //初始化一个队列
186    NodeType *= p;
187    if (p)
188    {
189        q.AddQ(*p);        //根结点非空则入队
190    }

191    while (!q.IsEmpty())
192    {
193        t = &(q.DelQ());    //队非空则将结点指针出队
194        cout << t->data;    //并打印输出结点的数据值
195        if (t->lch)
196        {
197            q.AddQ(*(t->lch));    //存在左孩子则将其进队
198        }

199        else
200            cout << "#";
201
202        if (t->rch)
203        {
204            q.AddQ(*(t->rch));    //存在右孩子则将其进队
205        }

206        else
207            cout << "#";
208    }

209}

210
211 // ---------------------------------------------------------------------------
212 int  main()
213
214  int k;    
215  BiTree root0;                     //声明创建二叉树对象,调用构造函数
216  do{ cout<<"\n\n";
217      cout<<"\n\n     1. 建立二叉树";
218      cout<<"\n\n     2. 交换左右子树";
219      cout<<"\n\n     3. 按层序遍历树";  
220      cout<<"\n\n     4. 求二叉树深度 ";
221      cout<<"\n\n     5. 求叶子结点个数";  
222      cout<<"\n\n     6. 结束程序运行";
223      cout<<"\n======================================";
224      cout<<"\n     请输入您的选择(0,1,2,3,4,5,6):"
225      cin>>k;
226      switch(k)
227         {  
228          case 1:{  
229                    cout << "\n\t 输入(0)结束:";
230                    root0.creat0();
231                     cout << "\n\t 先序遍历结果:";
232                    root0.preorder();
233                    cout << "\n\t 中序遍历结果:"
234                    root0.inorder();
235                    cout << "\n\t 后序遍历结果:"
236                    root0.postorder();                    
237                   }
 break;
238           case 2:{  
239                    cout <<"\n\t 交换左右子树结果:";
240                    root0.preordertswap();
241                    cout << "\n\t 先序遍历结果:";
242                    root0.preorder();             
243                    cout << "\n\t 中序遍历结果:";
244                    root0.inorder();
245                    cout << "\n\t 后序遍历结果:"
246                    root0.postorder();    
247                   }
 break;
248           case 3:{  
249                    cout << "\n\t 按层序遍历结果:";
250                    root0.levelorder();    
251                   }
 break;   
252           case 4:{  
253                   int deep;
254                   deep = root0.theight();
255                   cout << "\n\t 树的深度是:" << deep;
256                  }
 break;
257           case 5:{
258                    int leaf;
259                    leaf = root0.tleaves();
260                    cout << "\n\t 树的叶子结点个数是:" << leaf;
261                  }
 break;
262           case 6: exit(0);
263          }
 //  switch
264cout<<"\n ----------------";
265      }
 while(k>=0 && k<6); 
266   return 0;
267}
// -----  
268
269 // Queue.cpp
270 #include  " BiTree.h "
271 SeQueue::SeQueue()         // 初始化队列
272 {  
273    front=0;
274    rear=0;
275}

276
277 SeQueue:: ~ SeQueue() {} ;
278 // 进队
279 void  SeQueue::AddQ(NodeType x)    
280 {   
281    if((rear+1% MAXSIZE==front)
282         cout<<"QUEUE IS FULL\n";
283    else
284    {
285           rear=(rear+1% MAXSIZE;
286           elem[rear]=x;        //将结点指针入队
287    }

288}

289
290 // 出队
291 NodeType SeQueue::DelQ()
292 {        
293    NodeType q;
294    NodeType *= NULL;
295    if(front==rear)
296    {
297        return *t;    //返回空指针
298    }

299
300    else
301    {
302        front = (front+1% MAXSIZE;
303        q = elem[front];
304        return q;        //返回出栈的指针结点
305    }

306

 

.心得:

    这次实验不仅能巩固理解递归的方法,另一方面很能考验运用指针的能力,还有就是数据类型要使用得当.levelorder(NodeType *p)函数来看,首先, DelQ()的返回类型要与BiTree二叉树结点指针的类型一至.其次,在递归过程中,传入AddQ(NodeType x)是整个结点的内容而不是一个指针.值得讨论的是,在定义存储队列的数组时如何节省存储空间?因为输入的结点个数:若为单边二叉树(全只有左结点或全只有右结点)则为任意个数(实验上这时只需要两个存储空间);若非单边二叉则要求结点最多的层个数不得超过MAXSIZE的值.后者时MAXSIZE的值(由性质2)应该为2(h-1) (h为树的高度).这一点如何实现呢?BiTree类是SeQueue类的子类,height()函数是BiTree类的函数,如果能把高度传入SeQueue类的构造函数就可以通过一个for()语句来求得一个合适的值用以初始化MAXSIZE.那么就大大的节省了内存空间,并且还能实现输入节点的个数为任意的.但把高度传入SeQueue类的构造函数如何实现?还有其他要考虑的问题,我在今后的学习中深入了解.

.使用说明

    程序名为No4.exe运行环境为DOS,执行后显示:

请输入您的选择(0,1,2,3,4,5,6):"后输入数字选择执行的功能.

测试结果:

1)选择1.后输入1240003500600.(如右图的一棵二叉树)

2)选择4

3)选择5

4)选择2

5)选择3

6)选择6或输入非"0,1,2,3,4,5,6"的数字

.调试过程

    本程序主要对按层序遍历操作功能进行调试.Visual Studio 2008演示.首先把BiTree.h中的" #define MAXSIZE 30"改成" #define MAXSIZE 4",目的是从Visual Studio 2008的监视(Watch)窗口中得到更好的观察效果.

  1. 将光标移置BiTree.cpp文件的void BiTree::levelorder(NodeType *p)和第一条语句处Ctrl+F10开始调试
  2. 选择1.后输入1240003500600.(如右图的一棵二叉树)再选择3.
  3. 这时Debugger仍停留在void BiTree::levelorder(NodeType *p)的第一条语句上.可以从自动监视窗口中看到已经建立了一棵二叉树,指针P指向二叉树的根结点.

  4. 在监视窗口1中输入变量名:q,t进行观察,F10单步调试,这时Debugger停留在    SeQueue q;    语句处

    可以在监视1窗口中看到对象q的指针t都未合法初始化.

  5. 断续F10单步调试两步,这时Debugger停留在if(p)语句处,如图:

    在监视1窗口输入!p进行观察,这时!p值为0,if(p)判断语句值为真.

    可以进入f(p)执行,F10断续,Debugger停留在q.AddQ(*p)语句时可以从调用堆栈窗口中看到现在调用的函数为F11步入SeQueue类的AddQ(*p)函数.

  6. 这进Debugger停留在AddQ(*p)函数的第一条语句上.同可以从调用堆栈窗口中看到现在调用的函数为AddQ(*p)

    在监视2窗口中输入rear, elem[rear]进行观察.同时在自动窗口中可以看到变量X已经指向二叉树的根结点.

     

  7. 断续F10真到AddQ(NodeType x)结束语句处,可以从监视2窗口看到根结点已经入队

  8. F10后可以看到调用堆栈窗口中当前调用的是levelorder(NodeType *p)函数,同时在监视1窗口中输入!q.IsEmpty()观察到值为true,即可以进入while()控制语句执行.

    F10单步至    t = &(q.DelQ()),F11步入q.DelQ(),这时Debugger停留在DelQ()的第一条语句上,可以从调用堆栈窗口中看到当前调用的是DelQ()函数.

  9. 在监视3窗口中输入q进行观察.断续F10Debugger停留在DelQ()函数的return q语句时可以从监视窗口3中看到根结点已经出队

    同时在自动窗口中可以看到从DelQ()函数返回了出队结点并赋给了指针t

  10. F10单步调试直到Debugger停留在levelorder(NodeType *p)函数的cout << t->data语句上,这时可以在调用堆栈窗口中看到当前调用的是levelorder(NodeType *p)函数,在监视窗口1中输入t->date进行观察,已经取得根结点数据域的值

  11. F10单步调试一步可以在DOS窗口中看到已经输出根结点

  12. Shift+F5退出调试,完成调试演示.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值