二叉树的一些基本知识:
二叉树与树有许多相似之处,但二叉树不是树的特殊情形。
定义
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(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 }
来源:https://www.cnblogs.com/HuHu-Plus-Ice/p/5475613.html