【封装】二叉树相关算法的实验验证

天大地大妈咪最大 提交于 2020-04-01 08:34:40

 二叉树的一些基本知识:

二叉树与树有许多相似之处,但二叉树不是树的特殊情形。

定义

在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
二 叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;
深度为k 的二叉树至多有2^k-1个结点;
对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。

相关术语

树的结点:包含一个数据元素及若干指向子树的分支;
孩子结点:结点的子树的根称为该结点的孩子;
双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;
兄弟结点:同一双亲的孩子结点; 堂兄结点:同一层上结点;
祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙
结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;
树的深度:树中最大的结点层
结点的度:结点子树的个数
树的度: 树中最大的结点度。
叶子结点:也叫终端结点,是度为 0 的结点;
分枝结点:度不为0的结点;

二叉树性质

(1) 在非空二叉树中,第i层的结点总数不超过

, i>=1;
(2) 深度为h的二叉树最多有

个结点(h>=1),最少有h个结点;
(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
(4) 具有n个结点的完全二叉树的深度为

(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
若I为结点编号则 如果I>1,则其父结点的编号为[I/2](取下);
如果2*I<=N,则其左儿子(即左子树的根结点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。

 

二叉树的顺序存储

对于完全二叉树,结点的层次顺序反映了其结构,可按层次顺序给出一棵完全二叉树结点的编号。

可以利用一维数组A来存储一棵含有n个结点的完全二叉树。

A[1]存储二叉树的根结点,

A[i]存储二叉树编号为i的结点,

A[i]的左孩子(若存在)存放在A[2i]处,

A[i]的右孩子(若存在)存放在A[2i+1]处。

 

 

 

 

二叉树相关算法的实验验证代码:

  1 #include <iostream>
  2 #include "stdio.h"
  3 #include <stack>
  4 #include <queue>
  5 #include <math.h>
  6 using namespace std;
  7 
  8 typedef struct Node
  9 {
 10         char data;//数据域
 11         struct Node *left,*right;//左孩子,右孩子指针域
 12 }node;
 13 
 14 /*void C(char a)
 15 {
 16         cout<<"OK"<<a<<endl;
 17 }*/
 18 
 19 class BinaryTree
 20 {
 21 public:
 22         BinaryTree(){root=NULL;}
 23         node* InputByExtend(node *p);//输入拓展先根序列创建二叉树
 24         void FirstRoot1(node *t);//先根遍历(递归)
 25         void FirstRoot2(node *t);//先根遍历(非递归)
 26         void MiddleRoot1(node *t);//中根遍历(递归)
 27         void MiddleRoot2(node *t);//中根遍历(非递归)
 28         void LastRoot1(node *t);//后根遍历(递归)
 29         void LastRoot2(node *t);//后根遍历(非递归)
 30         void Layer(node *t);//层次遍历
 31         node* Father(node *t,node *p);//寻找父节点
 32         node* Find(node *t,char item);//寻找符合数据域的点
 33         void DelTwo(node* t);//删除某个节点及其左右子树
 34         node* Del(node *p);//递归删除释放
 35         node *root;//根节点
 36         void TreeShow(node* t);//输出当前树形
 37 
 38 };
 39 //先根遍历(递归)
 40 void BinaryTree::FirstRoot1(node *t)
 41 {
 42 
 43         if(t!=NULL)
 44         {
 45                 cout<<t->data<<endl;
 46                 FirstRoot1(t->left);
 47                 FirstRoot1(t->right);
 48         }
 49         /*else
 50                 cout<<"#"<<endl;*/
 51         //拓展序列
 52 }
 53 //先根遍历(非递归)
 54 void BinaryTree::FirstRoot2(node *t)
 55 {
 56         stack<node*> S;
 57         node* p=t;
 58        loop: while(p!=NULL)
 59         {
 60                 S.push(p);
 61                 cout<<p->data<<endl;//压栈的同时输出数据,即先输出根数据,再压左孩子,再压右孩子
 62                 p=p->left;
 63         }
 64         /*if(p==NULL)
 65                 cout<<"#"<<endl;*/
 66         if(S.empty())
 67                 return;
 68         else
 69         {p=S.top();
 70         S.pop();//弹栈不输出数据
 71         }
 72         p=p->right;
 73         goto loop;
 74 
 75 }
 76 //中根遍历(递归)
 77 void BinaryTree::MiddleRoot1(node *t)
 78 {
 79         /*if(t==NULL)
 80         cout<<"#"<<endl;
 81         else*/
 82         if(t!=NULL)
 83         {MiddleRoot1(t->left);
 84         cout<<t->data<<endl;
 85         MiddleRoot1(t->right);}
 86 }
 87 //中根遍历(非递归)
 88 void BinaryTree::MiddleRoot2(node *t)
 89 {
 90          stack<node*> S;
 91         node* p=t;
 92        loop: while(p!=NULL)
 93         {
 94                 S.push(p);
 95                 p=p->left;//压栈不输出数据,弹栈输出数据,先压根节点,再压左孩子结点,弹栈输出后,再压右孩子结点
 96         }
 97         /*if(p==NULL)
 98                 cout<<"#"<<endl;*/
 99         if(S.empty())
100                 return;
101         else
102         {p=S.top();
103         S.pop();
104         }
105         cout<<p->data<<endl;//弹栈输出数据,先弹左孩子
106         p=p->right;
107         goto loop;
108 }
109 //后根遍历(递归)
110 void BinaryTree::LastRoot1(node *t)
111 {
112           /*if(t==NULL)
113               cout<<"#"<<endl;
114         else*/
115         if(t!=NULL)
116         {
117         LastRoot1(t->left);
118         LastRoot1(t->right);
119         cout<<t->data<<endl;
120         }
121 }
122 //后根遍历(非递归)
123 /*树中任一结点q都需进栈三次,出栈三次,第一次出栈为遍历结点q的左子树,第二次出栈是为遍历结点q的右子树,第三次出栈是为访问结点q
124 (1)将根结点压入栈,同时将i=0压入栈。
125 (2)弹栈,对出栈元素p同时对应的i进行判断
126 1.如果i=0,则将p压入栈,同时将i=1压入栈;如果p的左孩子不为空,则将p->left压入栈,同时将0压入栈,准备遍历其左子树。
127 2.如果i=1,此时表明已经遍历完p的左子树,将p压入栈,同时将i=2压入栈;若p的右孩子不为空,则将p->right压入栈,同时将0压入栈,准备遍历其右子树。
128 3.如果i=2,此时已经遍历完p的右子树,访问结点p
129 
130 本段代码采用两个辅助堆栈来实现
131 */
132 void BinaryTree::LastRoot2(node *t)
133 {
134         node* p;
135         int i;
136         if(t==NULL)
137         {
138                 /*cout<<"#"<<endl;*/return;
139         }
140         stack<node*> Sa;//二叉树的结点栈
141         stack<int> Sb;//辅助判断参数i的栈
142         Sa.push(t);
143         Sb.push(0);//先把根节点和0入栈
144         while((!Sa.empty())&&(!Sb.empty()))
145         {
146                 //先弹栈,然后对判断系数i进行判断
147                 p=Sa.top();Sa.pop();
148                 i=Sb.top();Sb.pop();
149                 if(i==0)
150                 {
151                         Sa.push(p);
152                         Sb.push(1);
153                         if(p->left!=NULL)
154                         {
155                                 Sa.push(p->left);
156                                 Sb.push(0);
157                         }
158                         /*else
159                                 cout<<"#"<<endl;*/
160                 }
161                 if(i==1)
162                 {
163                         Sa.push(p);
164                         Sb.push(2);
165                         if(p->right!=NULL)
166                         {
167                                 Sa.push(p->right);
168                                 Sb.push(0);
169                         }
170                         /*else
171                                 cout<<"#"<<endl;*/
172                 }
173                 if(i==2)
174                         cout<<p->data<<endl;
175         }
176 
177 }
178 //层次遍历
179 /*
180 (1)根节点入队
181 (2)重复本步骤直至队空。
182 如果队不空,取头结点并访问;
183 如果他的左指针不空,将其左孩子入队。
184 如果他的右指针不空,将其右孩子入队。
185 */
186 void BinaryTree::Layer(node *t)
187 {
188         queue<node*> Q;
189         node* p=t;
190         if(p!=NULL)
191                 Q.push(p);
192         while(!Q.empty())
193         {
194                 p=Q.front();
195                 Q.pop();
196                 cout<<p->data<<endl;
197                 if(p->left!=NULL)
198                         Q.push(p->left);
199                 if(p->right!=NULL)
200                         Q.push(p->right);
201         }
202 
203 }
204 //寻找父节点
205 node* BinaryTree::Father(node *t,node *p)
206 {
207         node* q,*qL,*qR;
208        if(t==NULL)
209        {
210                q=NULL;
211                return q;
212        }
213        if(t->left==p||t->right==p)
214        {
215                q=t;
216                return q;
217        }
218        qL=Father(t->left,p);//递归判断,t的左子树是否是所给结点的父节点
219        if(qL!=NULL)
220        {
221                q=qL;
222                return q;
223        }
224        else
225        {
226                qR=Father(t->right,p);//递归判断,t的右子树是否是所给结点的父节点
227                q=qR;
228                return q;
229 
230        }
231 
232 }
233 //寻找符合数据域的点
234 node* BinaryTree::Find(node *t,char item)
235 {
236         node* q,*p;
237         if(t==NULL)
238         {
239                 q=NULL;
240                 return q;
241         }
242         if(t->data==item)
243         {
244                 q=t;
245                 return q;
246         }
247         p=Find(t->left,item);
248         if(p!=NULL){q=p;return q;}//如果不空,即为所求解,如果空,则向右搜索
249         q=Find(t->right,item);
250         return q;
251 }
252 //输入拓展先根序列创建二叉树
253 node* BinaryTree::InputByExtend(node *p)
254 {
255 
256         char a;
257 
258         cin>>a;
259         if(a=='#')
260         {
261                 p=NULL;
262                 return p;
263         }
264         else
265         {
266                 p=new node;
267                 p->data=a;
268         }
269         //构建左子树
270         p->left=InputByExtend(p->left);
271         //构建右子树
272         p->right=InputByExtend(p->right);
273         return p;
274 
275 
276 }
277 //删除某个节点及其左右子树
278 void BinaryTree::DelTwo(node *t)
279 {
280         node *p,*q;
281         if(t==NULL)
282                 return;
283         if(t==root)
284         {
285                 Del(t);root=NULL;return;
286         }
287         p=t;
288         //寻找t的父节点q
289         q=Father(root,p);
290         //修改q的指针域
291         if(q->left==p)
292                 q->left=NULL;
293         if(q->right==p)
294                 q->right=NULL;
295         //删除p及其子树
296         Del(p);
297 
298 }
299 //递归删除释放
300 node* BinaryTree::Del(node *p)
301 {
302         if(p==NULL) return p;
303         //递归删除
304         Del(p->left);
305         Del(p->right);
306         delete [] p;
307 }
308 //输出当前树形
309 //暴力手工输出,只能输出前三行,象征性表示
310 void BinaryTree::TreeShow(node* t)
311 {
312 
313         if(t==NULL){cout<<"该二叉树不存在,无树形可言"<<endl;return;}
314         node *p=t->left,*q=t->right;
315         cout<<"*****"<<t->data<<"*****"<<endl;
316         cout<<"**";
317         if(p==NULL)
318                 cout<<"*";
319         else
320                 cout<<p->data;
321         cout<<"*****";
322         if(q==NULL)
323                 cout<<"*";
324         else
325                 cout<<q->data;
326         cout<<"**"<<endl;
327 
328         cout<<"*";
329         if(p!=NULL)
330         {
331                 node* p1=p->left,*p2=p->right;
332                 if(p1!=NULL)
333                         cout<<p1->data<<"*";
334                 else
335                         cout<<"**";
336                 if(p2!=NULL)
337                         cout<<p2->data<<"*";
338                 else
339                         cout<<"**";
340         }
341         else
342                 cout<<"****";
343         cout<<"**";
344         if(q!=NULL)
345         {
346         if(q->left!=NULL)
347                 cout<<q->left->data<<"*";
348         if(q->left==NULL)
349                 cout<<"**";
350         if(q->right!=NULL)
351                 cout<<q->right->data<<"*"<<endl;
352         if(q->right==NULL)
353                 cout<<"**"<<endl;
354         }
355         else
356                 cout<<"****"<<endl;
357 }
358 
359 int main()
360 {
361         //freopen("input.txt","r",stdin);//文件输入
362         //freopen("output.txt","w",stdout);//文件输出
363         BinaryTree tree;
364         //菜单
365         cout<<"请选择你要进行的操作:"<<endl<<"1.创建"<<endl<<"2.遍历"<<endl<<"3.搜索父结点"<<endl
366         <<"4.搜索符合数据域结点"<<endl<<"5.删除给定结点及其左右子树"<<endl<<"6.查看当前树形"
367         <<endl<<"7.释放树"<<endl<<"0.退出"<<endl;
368 
369         int a;
370         cin>>a;
371         while(a!=0)
372         {
373                 cout<<endl;
374         if(a==1)
375         {
376         cout<<"请输入拓展先根序列:"<<endl;
377         tree.root=tree.InputByExtend(tree.root);
378         tree.TreeShow(tree.root);
379         cout<<endl;
380         }
381         else if(a==2)
382         {
383                 cout<<"请选择遍历的方法:"<<endl<<"1.先根遍历(递归)"<<endl<<"2.先根遍历(非递归)"<<endl<<"3.中根遍历(递归)"<<endl<<"4.中根遍历(非递归)"<<endl;
384                 cout<<"5.后根遍历(递归)"<<endl<<"6.后根遍历(非递归)"<<endl<<"7.层次遍历"<<endl;
385                 int b;
386                 cin>>b;
387                 if(b==1)
388                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"先根遍历(递归)的序列为:"<<endl;tree.FirstRoot1(tree.root);cout<<endl;}
389                 else if(b==2)
390                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"先根遍历(非递归)的序列为:"<<endl;tree.FirstRoot2(tree.root);cout<<endl;}
391                  else if(b==3)
392                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"中根遍历(递归)的序列为:"<<endl;tree.MiddleRoot1(tree.root);cout<<endl;}
393                 else if(b==4)
394                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"中根遍历(非递归)的序列为:"<<endl;tree.MiddleRoot2(tree.root);cout<<endl;}
395                 else if(b==5)
396                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"后根遍历(递归)的序列为:"<<endl;tree.LastRoot1(tree.root);cout<<endl;}
397                 else if(b==6)
398                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"后根遍历(非递归)的序列为:"<<endl;tree.LastRoot2(tree.root);cout<<endl;}
399                 else if(b==7)
400                         {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;cout<<"层次遍历的序列为:"<<endl;tree.Layer(tree.root);cout<<endl;}
401                 else;
402 
403         }
404         else if(a==3)
405         {
406                char a;
407                 cout<<"请输入查询子节点的数据:"<<endl;
408                 cin>>a;
409                 node *p,*q;
410                 p=tree.Find(tree.root,a);
411                 if(p==tree.root)
412                 {cout<<"所查询的结点为根节点,无父结点"<<endl<<endl;}
413                 else
414                 {q=tree.Father(tree.root,p);
415                 cout<<"所要寻找父节点的数据为:"<<q->data<<endl;
416                 cout<<endl;}
417         }
418         else if(a==4)
419         {
420                 char a;
421                 cout<<"请输入查询的数据:"<<endl;
422                 cin>>a;
423                 node *p,*q;
424                 p=tree.Find(tree.root,a);
425                 if(p!=NULL)
426                 {
427                       cout<<"查询成功!"<<endl;
428                 if(p==tree.root)
429                         cout<<"该结点为二叉树的根节点"<<endl;
430                 else
431                 {
432                         q=tree.Father(tree.root,p);
433                         cout<<"所查询结点的父结点的数据为:"<<q->data<<endl;
434                         if(p->left!=NULL)
435                                 cout<<"所查询结点的左孩子结点的数据为:"<<p->left->data<<endl;
436                         else
437                                 cout<<"所查询的结点没有左孩子结点"<<endl;
438                         if(p->right!=NULL)
439                                 cout<<"所查询结点的右孩子结点的数据为:"<<p->right->data<<endl;
440                         else
441                                 cout<<"所查询的结点没有右孩子结点"<<endl;
442                 }
443                 }
444                 else
445                         cout<<"该二叉树中没有该数据的结点"<<endl;
446 
447                 cout<<endl;
448 
449 
450         }
451         else if(a==5)
452         {
453                 cout<<"当前树形如下:"<<endl;
454                 tree.TreeShow(tree.root);
455                 cout<<"请输入删除的结点的数据:";
456                 char b;
457                 cin>>b;
458                 node*p;
459 
460                 p=tree.Find(tree.root,b);
461 
462                 tree.DelTwo(p);
463 
464                 cout<<"删除成功,删除后的树形为:"<<endl;
465                 tree.TreeShow(tree.root);
466                 cout<<endl;
467 
468         }
469         else if(a==6)
470                 {cout<<"当前二叉树的树形为:"<<endl;tree.TreeShow(tree.root);cout<<endl;}
471         else if(a==7)
472         {
473                 tree.DelTwo(tree.root);
474                 cout<<"释放成功"<<endl;
475         }
476         else;
477        cout<<"请选择你要进行的操作:"<<endl<<"1.创建"<<endl<<"2.遍历"<<endl<<"3.搜索父结点"<<endl
478        <<"4.搜索符合数据域结点"<<endl<<"5.删除给定结点及其左右子树"<<endl<<"6.查看当前树形"<<endl<<"7.释放树"<<endl<<"0.退出"<<endl;
479         cin>>a;
480         cout<<endl;
481         }
482 }
View Code

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!