当前位置:   article > 正文

数据结构之二叉树(类模板实现)(C++)_objarraylist.h

objarraylist.h


注:代码中使用的“ObjArrayList.h”、"SqStack.h"、"CQueue.h" 头文件代码在上三篇博文中已给出,分别为数据结构之顺序列表、栈、队列。

  1. //文件名:"BiTree.h"
  2. #pragma once
  3. #ifndef BITREE_H_
  4. #define BITREE_H_
  5. #include <string>
  6. #include "ObjArrayList.h" //顺序表(对象元素)
  7. #include "SqStack.h" //顺序栈(对象元素),也可用链栈
  8. #include "CQueue.h" //循环队列(对象元素),也可用链队列
  9. using namespace std;
  10. /*
  11. . 二叉树 类模板实现 BiTree (Binary Tree)
  12. . 存储结构:二叉链表
  13. . 遍历方式:先序遍历(Preoder Traversal)、中序遍历(InOrder Traversal)、后序遍历(PostOrder Traversal)
  14. . 注:元素对象需实现 输出操作符 的重载,否则无法打印树结点!
  15. */
  16. //二叉树结点类型
  17. template <typename ElemType>
  18. struct Node
  19. {
  20. ElemType * data; //数据域
  21. int seq; //完全二叉树序号
  22. int level; //层次
  23. int num; //层次上的坐标序号(考虑空结点)
  24. Node<ElemType> * lchild; //左子树指针域
  25. Node<ElemType> * rchild; //右子树指针域
  26. };
  27. //非递归后序遍历结点类型(含标志位)
  28. template <typename ElemType>
  29. struct NodeTag
  30. {
  31. Node<ElemType> *p; //二叉树结点域
  32. int tag; //结点访问次数标志域:1|访问一次 2|访问二次 -1|可销毁
  33. };
  34. template <typename ElemType>
  35. class BiTree
  36. {
  37. private:
  38. Node<ElemType> *bt; //树根指针
  39. /*
  40. . 注:深度高度值虽相同,但算法上有不同
  41. . 1.高度:自下而上求解
  42. . 2.深度:自上而下求解
  43. */
  44. int height; //二叉树高度(自下而上定义)
  45. int depth; //二叉树深度(自上而下定义)
  46. Node<ElemType> * _PreOrderCreate_R(ObjArrayList<ElemType> *list, int &index, int seq); //先序遍历递归构造树(对象型结点)
  47. void _PostOrderDestory_R(Node<ElemType> *p); //后序遍历递归 销毁二叉树
  48. void _CreateCoordinate(Node<ElemType> *p, int seq); //创建结点坐标
  49. int _PostOrderHelght_R(Node<ElemType> *p); //后序遍历递归 求二叉树高度(自下而上求解)
  50. void _PostOrderDepth_R(Node<ElemType> *p, int level, int &depth); //后序遍历递归 求二叉树深度(自上而下求解)
  51. int _PostOrderNodeCount_R(Node<ElemType> *p); //后序遍历递归 求结点个数
  52. int _PostOrderLeafCount_R(Node<ElemType> *p); //后序遍历递归 求叶子结点个数
  53. bool _PreOrderCompare_R(Node<ElemType> *p, Node<ElemType> *q); //比较二叉树是否相同
  54. Node<ElemType> * _PreOrderCopy_R(Node<ElemType> *p); //复制二叉树
  55. void _PreOrderDisplay_R(Node<ElemType> *p); //先序遍历递归 解析二叉树
  56. void _InOrderDisplay_R(Node<ElemType> *p); //中序遍历递归 解析二叉树
  57. void _PostOrderDisplay_R(Node<ElemType> *p); //后序遍历递归 解析二叉树
  58. public:
  59. BiTree() { this->bt = NULL; this->height = 0; this->depth = 0; };
  60. BiTree(ObjArrayList<ElemType> *list); //有参构造
  61. ~BiTree(); //析构函数:销毁二叉树
  62. int Helght(); //获取二叉树高度
  63. int Depth(); //获取二叉树深度
  64. int NodeCount(); //获取二叉树结点个数
  65. int LeafCount(); //获取二叉树叶子结点个数
  66. bool Compare(BiTree<ElemType> *t); //比较二叉树是否相同
  67. BiTree<ElemType> *Copy(); //复制二叉树对象
  68. void PreOrderDisplay_R(); //先序遍历递归 解析二叉树
  69. void PreOrderDisplay(); //先序遍历非递归 解析二叉树
  70. void InOrderDisplay_R(); //中序遍历递归 解析二叉树
  71. void InOrderDisplay(); //中序遍历非递归 解析二叉树
  72. void PostOrderDisplay_R(); //后序遍历递归 解析二叉树
  73. void PostOrderDisplay(); //后序遍历非递归 解析二叉树
  74. void LevelOrderDisplay(); //层次遍历非递归 解析二叉树
  75. void LevelOrderDisplayStruct(); //层次遍历非递归 打印二叉树结构
  76. };
  77. template <typename ElemType>
  78. BiTree<ElemType>::BiTree(ObjArrayList<ElemType> *list)
  79. {
  80. //默认采用先序遍历顺序表构造二叉树
  81. int index = 0;
  82. int seq = 1;
  83. this->bt = _PreOrderCreate_R(list, index, seq);
  84. //利用后序遍历,从下而上求树高
  85. this->height = _PostOrderHelght_R(this->bt);
  86. //利用后序遍历,从上而下求树深
  87. int level = 1, depth = 0;
  88. _PostOrderDepth_R(this->bt, level, depth);
  89. this->depth = depth;
  90. }
  91. template <typename ElemType>
  92. BiTree<ElemType>::~BiTree()
  93. {
  94. /*
  95. . 销毁二叉树
  96. */
  97. _PostOrderDestory_R(this->bt);
  98. cout << "二叉树已销毁!" << endl;
  99. }
  100. template <typename ElemType>
  101. int BiTree<ElemType>::Helght()
  102. {
  103. /*
  104. . 获取二叉树高度
  105. */
  106. return this->height;
  107. }
  108. template <typename ElemType>
  109. int BiTree<ElemType>::Depth()
  110. {
  111. /*
  112. . 获取二叉树高度
  113. */
  114. return this->depth;
  115. }
  116. template <typename ElemType>
  117. int BiTree<ElemType>::NodeCount()
  118. {
  119. /*
  120. . 获取二叉树结点个数
  121. */
  122. return _PostOrderNodeCount_R(this->bt);
  123. }
  124. template <typename ElemType>
  125. int BiTree<ElemType>::LeafCount()
  126. {
  127. /*
  128. . 获取二叉树叶子结点个数
  129. */
  130. return _PostOrderLeafCount_R(this->bt);
  131. }
  132. template <typename ElemType>
  133. bool BiTree<ElemType>::Compare(BiTree<ElemType> *t)
  134. {
  135. /*
  136. . 比较两棵树是否相同
  137. */
  138. return _PreOrderCompare_R(this->bt, t->bt);
  139. }
  140. template <typename ElemType>
  141. BiTree<ElemType> *BiTree<ElemType>::Copy()
  142. {
  143. /*
  144. . 比较两棵树是否相同
  145. */
  146. //初始化二叉树对象
  147. BiTree<ElemType> *t = new BiTree<ElemType>();
  148. //复制二叉树(对象数据,非对象地址)
  149. t->bt = _PreOrderCopy_R(this->bt);
  150. t->height = this->height;
  151. t->depth = this->depth;
  152. return t;
  153. }
  154. template <typename ElemType>
  155. Node<ElemType> *BiTree<ElemType>::_PreOrderCreate_R(ObjArrayList<ElemType> *list, int &index, int seq)
  156. {
  157. /*
  158. . 先序遍历递归创建二叉树
  159. . 入参:
  160. . ObjArrayList<ElemType> *list : 先序遍历组合的对象结点顺序表
  161. . int &index: 顺序表遍历索引
  162. . int seq: 以完全二叉树,对每个结点排序
  163. . 出参:
  164. . Node<ElemType> * : 树根结点指针
  165. . 注:以顺序表(对象元素结点)创建
  166. */
  167. Node<ElemType> *p = NULL;
  168. //1.超出顺序表时返回,结束
  169. if (index >= list->Length())
  170. {
  171. return p;
  172. }
  173. //2.元素为 NULL 时,意为空结点
  174. else if (list->Get(index) == NULL)
  175. {
  176. return p;
  177. }
  178. //3.创建根结点,并递归创建其左右子树
  179. else
  180. {
  181. p = new Node<ElemType>;
  182. p->data = list->Get(index);
  183. _CreateCoordinate(p, seq); //创建结点坐标
  184. p->lchild = _PreOrderCreate_R(list, ++index, 2 * seq);
  185. p->rchild = _PreOrderCreate_R(list, ++index, 2 * seq + 1);
  186. }
  187. return p;
  188. }
  189. template <typename ElemType>
  190. void BiTree<ElemType>::_PostOrderDestory_R(Node<ElemType> *p)
  191. {
  192. /*
  193. . 后序遍历 递归 销毁二叉树
  194. . 注:需先销毁子节点,再根结点
  195. */
  196. if (p != NULL)
  197. {
  198. _PostOrderDestory_R(p->lchild);
  199. _PostOrderDestory_R(p->rchild);
  200. delete p;
  201. }
  202. }
  203. template <typename ElemType>
  204. void BiTree<ElemType>::_CreateCoordinate(Node<ElemType> *p, int seq)
  205. {
  206. /*
  207. . 创建结点坐标
  208. . 入参:
  209. . Node<ElemType> *p: 树结点
  210. . int seq: 完全二叉树的形式的结点序号
  211. */
  212. p->seq = seq; //结点序号(完全二叉树形式)
  213. p->level = (int)floor(log(seq) / log(2)) + 1; //结点所在层次深度:floor( log2(seq) ) + 1;log2() 利用换底公式:log2(x) = log(x)/log(2)
  214. p->num = seq - (int)pow(2, p->level - 1) + 1; //结点所在层次的结点位置序号:seq - 上层末尾结点序号(完全二叉树形式)
  215. }
  216. template <typename ElemType>
  217. int BiTree<ElemType>::_PostOrderHelght_R(Node<ElemType> *p)
  218. {
  219. /*
  220. . 后序遍历 递归求二叉树高度(自下而上)
  221. . 入参:
  222. . 1.Node<ElemType> *p: 树结点
  223. . 出参:
  224. . 1.int : 子树高度
  225. . 算法解析:
  226. . 1.求每颗子树的高度(左右子树高度取最大)
  227. . 2.叶子结点高度为 1
  228. */
  229. int lheight = 0, rheight = 0;
  230. if (p != NULL)
  231. {
  232. lheight = _PostOrderHelght_R(p->lchild);
  233. rheight = _PostOrderHelght_R(p->rchild);
  234. return (lheight > rheight ? lheight : rheight) + 1; //返回较大的一个树深 + 1 (根结点)
  235. }
  236. return 0; //空结点返回 0
  237. }
  238. template <typename ElemType>
  239. void BiTree<ElemType>::_PostOrderDepth_R(Node<ElemType> *p, int level, int &depth)
  240. {
  241. /*
  242. . 后序遍历递归 求树深度(自上而下)
  243. . 入参:
  244. . 1.Node<ElemType> *p: 树结点
  245. . 2.int level: 树层次
  246. . 3.int &depth: 树深度
  247. . 算法解析:
  248. . 1.depth = max[ level(i) ] , 其中i 为每一个根到叶的路径
  249. . 2.自上而下体现在:level 的逐层往下增加
  250. */
  251. if (p != NULL)
  252. {
  253. _PostOrderDepth_R(p->lchild, level + 1, depth);
  254. _PostOrderDepth_R(p->rchild, level + 1, depth);
  255. //若为叶子节点,则一条根叶路径走完,比较深度
  256. //if (p->lchild == NULL && p->rchild == NULL) //此判断多此一举,上层深度不可能比下层大
  257. if (level > depth)
  258. depth = level;
  259. }
  260. }
  261. template <typename ElemType>
  262. int BiTree<ElemType>::_PostOrderNodeCount_R(Node<ElemType> *p)
  263. {
  264. /*
  265. . 后序遍历递归 求树结点数
  266. */
  267. if (p != NULL)
  268. return _PostOrderNodeCount_R(p->lchild) + _PostOrderNodeCount_R(p->rchild) + 1; //先左,后右,再返回相加结果,即为后序
  269. return 0;
  270. }
  271. template <typename ElemType>
  272. int BiTree<ElemType>::_PostOrderLeafCount_R(Node<ElemType> *p)
  273. {
  274. /*
  275. . 后序遍历递归 求树叶子结点数
  276. */
  277. if (p != NULL)
  278. {
  279. if (p->lchild == NULL && p->rchild == NULL)
  280. return 1;
  281. else
  282. return _PostOrderLeafCount_R(p->lchild) + _PostOrderLeafCount_R(p->rchild); //先左,后右,再返回相加结果,即为后序
  283. }
  284. return 0;
  285. }
  286. template <typename ElemType>
  287. bool BiTree<ElemType>::_PreOrderCompare_R(Node<ElemType> *p, Node<ElemType> *q)
  288. {
  289. /*
  290. . 先序遍历递归 比较两颗二叉树是否相同
  291. */
  292. if (p != NULL && q != NULL)
  293. {
  294. //先比较根结点元素(结点元素类需实现 Compare() 接口),后比较左右子树
  295. return (p->data->Compare(q->data))
  296. && _PreOrderCompare_R(p->lchild, q->lchild)
  297. && _PreOrderCompare_R(p->rchild, q->rchild);
  298. }
  299. else if (p == NULL && q == NULL)
  300. return true;
  301. else
  302. return false;
  303. }
  304. template <typename ElemType>
  305. Node<ElemType> * BiTree<ElemType>::_PreOrderCopy_R(Node<ElemType> *p)
  306. {
  307. /*
  308. . 先序遍历递归 复制二叉树(实现复制对象数据,并非对象地址!!)
  309. */
  310. Node<ElemType> *q = NULL;
  311. if (p != NULL)
  312. {
  313. q = new Node<ElemType>;
  314. q->data = p->data->Copy(); //结点元素类需实现 Copy() 接口!!
  315. q->lchild = _PreOrderCopy_R(p->lchild);
  316. q->rchild = _PreOrderCopy_R(p->rchild);
  317. }
  318. return q;
  319. }
  320. template <typename ElemType>
  321. void BiTree<ElemType>::PreOrderDisplay_R()
  322. {
  323. /*
  324. . 先序遍历递归显示二叉树
  325. */
  326. cout << "The BiTree is: ";
  327. _PreOrderDisplay_R(this->bt);
  328. cout << endl;
  329. }
  330. template <typename ElemType>
  331. void BiTree<ElemType>::_PreOrderDisplay_R(Node<ElemType> *p)
  332. {
  333. /*
  334. . 先序遍历递归显示二叉树
  335. */
  336. if (p != NULL)
  337. {
  338. cout << p->data << " ";
  339. _PreOrderDisplay_R(p->lchild);
  340. _PreOrderDisplay_R(p->rchild);
  341. }
  342. else
  343. {
  344. cout << "# "; //空结点以 '#' 代替
  345. }
  346. }
  347. template <typename ElemType>
  348. void BiTree<ElemType>::PreOrderDisplay()
  349. {
  350. /*
  351. . 先序遍历 非递归 解析二叉树
  352. . 算法:(栈)
  353. . 1.先访问子树根结点,根结点入栈,然后访问左子树;
  354. . 2.等到子树根结点为空,出栈根结点,访问其右子树;
  355. . 3.如此循环...
  356. */
  357. //树根结点
  358. Node<ElemType> *p = this->bt;
  359. //初始化栈,存放压栈结点
  360. SqStack<Node<ElemType>> *st = new SqStack<Node<ElemType>>(20); //栈容量 需满足 二叉树深度减一
  361. /* 按照一般思路写出的代码,其中两个 while 可以合并,如下结果
  362. //子树根结点不为空,遍历整棵树
  363. while (p != NULL)
  364. {
  365. //1.输出子树根结点
  366. cout << p->data << " ";
  367. //2.入栈根结点(含NULL)(也可入栈右子树结点,但这样就不可输出 NULL 结点)
  368. st->Push(p);
  369. //3.指针 p 移到左子树结点
  370. p = p->lchild;
  371. //输出 左子树(NULL)结点
  372. if (p == NULL)
  373. cout << "# ";
  374. //4.若子树结点为空,且栈不为空
  375. while (p == NULL && !st->Empty())
  376. {
  377. //则出栈,且指针 p 移到出栈结点右子树上
  378. p = st->Pop();
  379. p = p->rchild;
  380. //输出 右子树(NULL)结点
  381. if (p == NULL)
  382. cout << "# ";
  383. }
  384. }
  385. */
  386. cout << "The BiTree is: ";
  387. //子树根结点不为空,且栈不为空,遍历整棵树
  388. while (p != NULL || !st->Empty())
  389. {
  390. //1.子树根结点不为空
  391. if (p != NULL)
  392. {
  393. //1.输出子树根结点
  394. cout << p->data << " ";
  395. //2.入栈根结点(含NULL)(也可入栈右子树结点,但这样就不可输出 NULL 结点)
  396. st->Push(p);
  397. //3.指针 p 移到左子树结点
  398. p = p->lchild;
  399. }
  400. //2.子树结点为空
  401. else
  402. {
  403. //则出栈,且指针 p 移到出栈结点右子树根上
  404. p = st->Pop();
  405. p = p->rchild;
  406. }
  407. //输出 子树(NULL)结点(左右)
  408. if (p == NULL)
  409. cout << "# ";
  410. }
  411. cout << endl;
  412. //释放栈
  413. delete st;
  414. }
  415. template <typename ElemType>
  416. void BiTree<ElemType>::InOrderDisplay_R()
  417. {
  418. /*
  419. . 中序遍历递归显示二叉树
  420. */
  421. cout << "The BiTree is: ";
  422. _InOrderDisplay_R(this->bt);
  423. cout << endl;
  424. }
  425. template <typename ElemType>
  426. void BiTree<ElemType>::_InOrderDisplay_R(Node<ElemType> *p)
  427. {
  428. /*
  429. . 中序遍历递归显示二叉树
  430. */
  431. if (p != NULL)
  432. {
  433. _InOrderDisplay_R(p->lchild);
  434. cout << p->data << " ";
  435. _InOrderDisplay_R(p->rchild);
  436. }
  437. else
  438. {
  439. cout << "# "; //空结点以 '#' 代替
  440. }
  441. }
  442. template <typename ElemType>
  443. void BiTree<ElemType>::InOrderDisplay()
  444. {
  445. /*
  446. . 中序遍历 非递归 显示二叉树
  447. . 算法:(栈)
  448. . 1.先根结点入栈,然后访问左子树;
  449. . 2.等到子树根结点为空,出栈根结点,访问根结点,访问右子树;
  450. . 3.如此循环...
  451. */
  452. //初始化根结点
  453. Node<ElemType> *p = this->bt;
  454. //初始化栈,存放压栈结点
  455. SqStack<Node<ElemType>> *st = new SqStack<Node<ElemType>>(20); //栈容量 需满足 二叉树深度减一
  456. cout << "The BiTree is: ";
  457. //子树根结点不为空,且栈不为空,遍历整棵树
  458. while (p != NULL || !st->Empty())
  459. {
  460. //1.子树根结点不为空
  461. if (p != NULL)
  462. {
  463. //1.入栈根结点(含NULL)(也可入栈右子树结点,但这样就不可输出 NULL 结点)
  464. st->Push(p);
  465. //2.指针 p 移到左子树结点
  466. p = p->lchild;
  467. }
  468. //2.子树结点为空
  469. else
  470. {
  471. //1.则出栈
  472. p = st->Pop();
  473. //2.输出子树根结点
  474. cout << p->data << " ";
  475. //3.指针 p 移到出栈结点右子树根上
  476. p = p->rchild;
  477. }
  478. //输出 子树(NULL)结点(左右)
  479. if (p == NULL)
  480. cout << "# ";
  481. }
  482. cout << endl;
  483. //释放栈
  484. delete st;
  485. }
  486. template <typename ElemType>
  487. void BiTree<ElemType>::PostOrderDisplay_R()
  488. {
  489. /*
  490. . 后序遍历递归显示二叉树
  491. */
  492. cout << "The BiTree is: ";
  493. _PostOrderDisplay_R(this->bt);
  494. cout << endl;
  495. }
  496. template <typename ElemType>
  497. void BiTree<ElemType>::_PostOrderDisplay_R(Node<ElemType> *p)
  498. {
  499. /*
  500. . 后序遍历递归显示二叉树
  501. */
  502. if (p != NULL)
  503. {
  504. _PostOrderDisplay_R(p->lchild);
  505. _PostOrderDisplay_R(p->rchild);
  506. cout << p->data << " ";
  507. }
  508. else
  509. {
  510. cout << "# "; //空结点以 '#' 代替
  511. }
  512. }
  513. template <typename ElemType>
  514. void BiTree<ElemType>::PostOrderDisplay()
  515. {
  516. /*
  517. . 后序遍历 非递归 显示二叉树
  518. . 算法:(栈)
  519. . 1.先入栈子树根结点(访问次数默认1),访问左子树结点;
  520. . 2.直到子树根结点为空,出栈根结点:
  521. . 2.1.若其访问次数为1,则标记其为2,并将其再入栈,访问其右子树;
  522. . 2.2.若其访问次数为2,则访问根结点;
  523. . 3.如此循环...
  524. . 注:也可每次入栈根结点、右子树结点,这样会比只入栈根结点多一倍的栈容量,但可不用区分栈中根结点第几次被访问
  525. */
  526. //初始化根结点
  527. Node<ElemType> *p = this->bt;
  528. //初始化带标识位结点
  529. NodeTag<ElemType> *nt = NULL;
  530. //初始化栈,存放压栈结点
  531. SqStack<NodeTag<ElemType>> *st = new SqStack<NodeTag<ElemType>>(20); //栈容量 需满足 二叉树深度减一
  532. cout << "The BiTree is: ";
  533. //子树根结点不为空,且栈不为空,遍历整棵树
  534. while (p != NULL || !st->Empty())
  535. {
  536. //1.子树根结点不为空
  537. if (p != NULL)
  538. {
  539. //0.创建带标识位的结点
  540. nt = new NodeTag<ElemType>;
  541. nt->p = p; //赋值根结点
  542. nt->tag = 1; //标识位初始默认 1
  543. //1.入栈根结点(带标识位)
  544. st->Push(nt);
  545. //2.指针 p 移到左子树根结点
  546. p = p->lchild;
  547. }
  548. //2.子树根结点为空
  549. else
  550. {
  551. //1.出栈根结点
  552. nt = st->Pop();
  553. //2.若第一次访问
  554. if (nt->tag == 1)
  555. {
  556. //1.置标识位 2 ,根结点再次入栈
  557. nt->tag = 2;
  558. st->Push(nt);
  559. //2.指针 p 移到右子树根结点
  560. p = nt->p->rchild;
  561. }
  562. //3.若第二次访问
  563. else
  564. {
  565. //输出根结点
  566. cout << nt->p->data << " ";
  567. //标记结点为可销毁 -1 状态
  568. nt->tag = -1;
  569. }
  570. }
  571. //输出 子树(NULL)结点(左右),且出栈根结点为可销毁(-1)状态
  572. if (p == NULL && nt->tag != -1)
  573. cout << "# ";
  574. //销毁 nt 指向的标志结点内存
  575. if (nt->tag == -1)
  576. delete nt;
  577. //置空 nt
  578. nt = NULL; //置空
  579. }
  580. cout << endl;
  581. delete st;
  582. }
  583. template <typename ElemType>
  584. void BiTree<ElemType>::LevelOrderDisplay()
  585. {
  586. /*
  587. . 层次遍历 非递归 显示二叉树
  588. . 算法:(队列)
  589. . 1.将树根结点入队;
  590. . 2.出队结点,访问子树根结点,为空时输出"#",非空时输出结点,入队左、右子树;
  591. . 3.如此循环 2 ...
  592. . 注:两种结点访问时机:
  593. . 1.结点入队前:需分左右子树输出,代码不统一。
  594. . 2.结点出队后:统一由出队子树根结点输出,代码更统一。(此处采用)
  595. */
  596. //初始化队列
  597. CQueue<Node<ElemType>> *cq = new CQueue<Node<ElemType>>(20); //入队容量 需满足 结点数最多的一层( <= 取最深层叶子节点数 (2^n - 1) )
  598. //初始化结点指针
  599. Node<ElemType> *p = NULL;
  600. cout << "The BiTree is: ";
  601. if (this->bt == NULL)
  602. return;
  603. //1.入队根结点
  604. cq->EnQueue(this->bt);
  605. //2.循环出队,访问子树
  606. while (!cq->isEmpty())
  607. {
  608. //1.出队 子树根结点
  609. p = cq->DeQueue();
  610. //1.1.为空:输出 "#"
  611. if (p == NULL)
  612. cout << "# ";
  613. //1.2.非空:访问子树
  614. else
  615. {
  616. //1.访问根结点
  617. cout << p->data << " ";
  618. //2.入队 左子树
  619. cq->EnQueue(p->lchild);
  620. //3.入队 右子树
  621. cq->EnQueue(p->rchild);
  622. }
  623. }
  624. cout << endl;
  625. delete cq;
  626. }
  627. template <typename ElemType>
  628. void BiTree<ElemType>::LevelOrderDisplayStruct()
  629. {
  630. /*
  631. . 层次遍历 非递归 打印二叉树结构(含结点坐标信息)
  632. . 结点坐标信息:
  633. . 1.seq : 完全二叉树序号
  634. . 2.level : 层次
  635. . 3.num : 层次上的坐标序号(考虑空结点)
  636. . 算法:(队列)
  637. . 1.访问根结点,将其入队;
  638. . 2.出队结点,先访问左子树(非空时输出、入队,空时输出 "#"),后访问右子树(非空时输出、入队,空时输出 "#");
  639. . 3.如此循环 2 ...
  640. . 注:两种结点访问时机:
  641. . 1.结点入队前:需分左右子树输出,代码不统一,但是可以由出队结点确定其下子树 NUlL 的层次。(此处采用)
  642. . 2.结点出队后:统一由出队子树根结点输出,代码更统一。
  643. .
  644. . 注:目前还是实现不了结点位置的准确输出---!!!
  645. . (想法:再实现一个坐标类,可将结点坐标输进去,就能显示了)
  646. */
  647. //初始化队列
  648. CQueue<Node<ElemType>> *cq = new CQueue<Node<ElemType>>(20); //入队容量 需满足 结点数最多的一层( <= 取最深层叶子节点数 (2^n - 1) )
  649. //初始化结点指针
  650. Node<ElemType> *p = NULL, *q = NULL;
  651. //初始化树层次
  652. int level = 1;
  653. //初始化标记
  654. int tag = -1; // -1|队列出队 0|访问右子树 1|访问左子树
  655. cout << "The BiTree Struct is: " << endl;
  656. if (this->bt == NULL)
  657. return;
  658. //1.访问根结点,将其入队
  659. cout << this->bt->data << " ";
  660. cq->EnQueue(this->bt);
  661. //2.循环出队,访问子树
  662. while (!cq->isEmpty() || tag != -1)
  663. {
  664. //标记:出队
  665. if (tag == -1)
  666. {
  667. //1.出队 子树根结点
  668. p = cq->DeQueue();
  669. //如果 p->level + 1 > level ,则转为下一层
  670. if (p->level + 1 > level)
  671. {
  672. level = p->level + 1; //出队元素层次 + 1,即为当前层次
  673. cout << endl;
  674. }
  675. tag = 0; //将标记置为 0
  676. continue; //进入下一次循环
  677. }
  678. //标记:访问左子树
  679. else if (tag == 0)
  680. {
  681. q = p->lchild;
  682. tag = 1; //将标记置为 1
  683. }
  684. //标记:访问右子树
  685. else
  686. {
  687. q = p->rchild;
  688. tag = -1; //将标记置为 -1
  689. }
  690. //访问子树结点
  691. if (q == NULL)
  692. cout << "# ";
  693. else
  694. {
  695. //1.1.访问子树结点
  696. cout << q->data << "_(" << q->seq << "," << q->level << "," << q->num << ") ";
  697. //1.2.入队 子树
  698. cq->EnQueue(q);
  699. }
  700. }
  701. cout << endl;
  702. delete cq;
  703. }
  704. #endif // !BITREE_H_
  1. //文件名:"BiTree_Test.cpp"
  2. #include "stdafx.h"
  3. #include <iostream>
  4. #include "BiTree.h"
  5. #include "ObjArrayList.h"
  6. using namespace std;
  7. //树结点元素
  8. struct Element
  9. {
  10. char a;
  11. int b;
  12. public:
  13. bool Compare(Element *p)
  14. {
  15. /*
  16. . 实现元素对象比较接口
  17. */
  18. return a == p->a;
  19. }
  20. Element *Copy()
  21. {
  22. /*
  23. . 实现元素对象复制接口
  24. */
  25. Element *p = new Element;
  26. p->a = a;
  27. p->b = b;
  28. return p;
  29. }
  30. friend ostream & operator <<(ostream& out, Element *p)
  31. {
  32. /*
  33. . 友元函数重载输出操作符,实现对象输出
  34. */
  35. out << "(" << p->a << "," << p->b << ")";
  36. return out;
  37. }
  38. };
  39. int mian()
  40. {
  41. cout << endl << "----------------------测试1.1.-------------------------" << endl;
  42. //1.1.测试 元素对象 输出
  43. Element *e = new Element{ 'A',1 };
  44. cout << "对象:" << e << endl;
  45. cout << endl << "----------------------测试1.2.-------------------------" << endl;
  46. //1.2.以 先序遍历的结点顺序 存放元素结点于 顺序列表 中
  47. //.................012345678901234
  48. //先序遍历字符串:"ABC##DE#G##F###"; //15个字符
  49. ObjArrayList<Element> *list = new ObjArrayList<Element>(15);
  50. list->Add(0, new Element{ 'A',1 });
  51. list->Add(1, new Element{ 'B',2 });
  52. list->Add(2, new Element{ 'C',3 });
  53. list->Add(3, NULL);
  54. list->Add(4, NULL);
  55. list->Add(5, new Element{ 'D',4 });
  56. list->Add(6, new Element{ 'E',5 });
  57. list->Add(7, NULL);
  58. list->Add(8, new Element{ 'G',7 });
  59. list->Add(9, NULL);
  60. list->Add(10, NULL);
  61. list->Add(11, new Element{ 'F',6 });
  62. list->Add(12, NULL);
  63. list->Add(13, NULL);
  64. list->Add(14, NULL);
  65. cout << endl << "----------------------测试1.3.-------------------------" << endl;
  66. //1.3.测试 顺序列表 输出
  67. cout << "顺序表长度:" << endl << list->Length() << " ;顺序表大小:" << list->Size() << endl;
  68. cout << "顺序表输出:" << endl << list << endl;
  69. cout << endl << "----------------------测试2.1.-------------------------" << endl;
  70. //2.1.测试 创建二叉树(先序遍历)
  71. BiTree<Element> *t = new BiTree<Element>(list);
  72. cout << endl << "----------------------测试2.2.-------------------------" << endl;
  73. //2.2.测试 显示二叉树(先序、中序、后续遍历)
  74. cout << "二叉树 先序遍历 递归 输出:" << endl;
  75. t->PreOrderDisplay_R();
  76. cout << "二叉树 先序遍历 非递归 输出:" << endl;
  77. t->PreOrderDisplay();
  78. cout << "二叉树 中序遍历 递归 输出:" << endl;
  79. t->InOrderDisplay_R();
  80. cout << "二叉树 中序遍历 非递归 输出:" << endl;
  81. t->InOrderDisplay();
  82. cout << "二叉树 后序遍历 递归 输出:" << endl;
  83. t->PostOrderDisplay_R();
  84. cout << "二叉树 后序遍历 非递归 输出:" << endl;
  85. t->PostOrderDisplay();
  86. cout << "二叉树 层次遍历 非递归 输出:" << endl;
  87. t->LevelOrderDisplay();
  88. cout << endl << "----------------------测试2.3.-------------------------" << endl;
  89. //2.3.测试 树属性
  90. cout << "二叉树高度:" << t->Helght() << ";二叉树深度:" << t->Depth() << endl;
  91. cout << "二叉树结点数:" << t->NodeCount() << ";二叉树叶子结点数:" << t->LeafCount() << endl;
  92. cout << endl << "----------------------测试2.4.-------------------------" << endl;
  93. //2.4.测试 二叉树两两比较
  94. ObjArrayList<Element> *list1 = new ObjArrayList<Element>(15);
  95. list1->Add(0, new Element{ 'A',1 });
  96. list1->Add(1, new Element{ 'B',2 });
  97. list1->Add(2, new Element{ 'C',3 });
  98. list1->Add(3, NULL);
  99. list1->Add(4, NULL);
  100. list1->Add(5, new Element{ 'D',4 });
  101. list1->Add(6, new Element{ 'E',5 });
  102. list1->Add(7, NULL);
  103. list1->Add(8, new Element{ 'G',7 });
  104. list1->Add(9, NULL);
  105. list1->Add(10, NULL);
  106. list1->Add(11, new Element{ 'F',6 });
  107. list1->Add(12, NULL);
  108. list1->Add(13, NULL);
  109. list1->Add(14, NULL);
  110. BiTree<Element> *t1 = new BiTree<Element>(list1);
  111. cout << "t 与 t1 两颗二叉树是否相同:" << (t->Compare(t1) ? "是" : "否") << endl;
  112. //更改二叉树 t1 结点 后再比较
  113. list1->Get(11)->a = 'H';
  114. cout << "修改 t1 节点后,两颗二叉树是否相同:" << (t->Compare(t1) ? "是" : "否") << endl;
  115. cout << endl << "----------------------测试2.5.-------------------------" << endl;
  116. //2.5.测试 二叉树复制
  117. BiTree<Element> *t2 = t->Copy();
  118. cout << "复制的二叉树 t2 与原二叉树 t 比较是否相同:" << (t->Compare(t2) ? "是" : "否") << endl;
  119. cout << endl << "----------------------测试2.6.-------------------------" << endl;
  120. //2.6.测试 以二叉树结构输出
  121. t->LevelOrderDisplayStruct();
  122. cout << endl << "----------------------测试2.7.-------------------------" << endl;
  123. //2.7.测试 二叉树销毁
  124. delete t;
  125. delete t1;
  126. delete t2;
  127. return 0;
  128. }



增加函数:int BiTree<ElemType>::_CalSpaceNum_Coordinate(int level, int num)
修改函数:void BiTree<ElemType>::LevelOrderDisplayStruct()
实现二叉树树形打印:
  1. template <typename ElemType>
  2. void BiTree<ElemType>::LevelOrderDisplayStruct()
  3. {
  4. /*
  5. . 层次遍历 非递归 打印二叉树结构(含结点坐标信息)
  6. . 结点坐标信息:
  7. . 1.seq : 完全二叉树序号
  8. . 2.level : 层次
  9. . 3.num : 层次上的坐标序号(考虑空结点)
  10. . 算法:(队列)
  11. . 1.访问根结点,将其入队;
  12. . 2.出队结点,先访问左子树(非空时输出、入队,空时输出 "#"),后访问右子树(非空时输出、入队,空时输出 "#");
  13. . 3.如此循环 2 ...
  14. . 注:两种结点访问时机:
  15. . 1.结点入队前:需分左右子树输出,代码不统一,但是可以由出队结点确定其下子树 NUlL 的层次。(此处采用)
  16. . 2.结点出队后:统一由出队子树根结点输出,代码更统一。
  17. .
  18. . 二叉树形打印示例图及相关公式:
  19. . 1.公式:
  20. . 1.1.计算每层第一个结点左侧空格数
  21. . space_i_first = pow(2, tol_level - level) - 1;
  22. . 1.2.计算各层结点间的空格数(间距)
  23. . space_i = 2 * space_i_first + 1;
  24. . 1.3.计算第 n 层 第 num 个结点前的空格数
  25. . space_num = (num - 1) * (space_i + 1) + space_i_first; //其中 space_i + 1 意为 空格数加上结点本身占的位置
  26. . 1.4.计算当前层上当前结点前实际需要打印的空格数
  27. . 1.4.1.当前层上 第一次 打印结点:直接打印当前结点前空格数 cur_space_num
  28. . 1.4.1.当前层上 第二次及以上 打印结点:打印 当前结点空格 - 之前结点空格(需加上本身)
  29. . cur_space_num - (last_space_num + 1)
  30. . 2.图例:
  31. . (注:图中以 '.' 代表空格,因为 数个'_'连在一起,分不清个数)
  32. . space_i_first space_i
  33. . 1 ...............A................ 15 = 2^(5-1)-1 31 = 15*2+1
  34. . 2 .......A...............A........ 7 = 2^(5-2)-1 15 = 7*2+1
  35. . 3 ...A.......A.......A.......A.... 3 = 2^(5-3)-1 7 = 3*2+1
  36. . 4 .A...A...A...A...A...A...A...A.. 1 = 2^(5-4)-1 3 = 1*2+1
  37. . 5 A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A. 0 = 2^(5-5)-1 1 = 0*2+1
  38. .
  39. */
  40. //初始化队列
  41. CQueue<Node<ElemType>> *cq = new CQueue<Node<ElemType>>(20); //入队容量 需满足 结点数最多的一层( <= 取最深层叶子节点数 (2^n - 1) )
  42. //初始化结点指针
  43. Node<ElemType> *p = NULL, *q = NULL;
  44. //初始化树层次
  45. int level = 1;
  46. //初始化当前层上结点的序号
  47. int num = 1;
  48. //初始化当前层上的空格打印信息
  49. int last_space_num = 0; //当前层的上一个结点前的空格数
  50. int cur_space_num = 0; //当前层的当前结点前的空格数
  51. //初始化标记
  52. int tag = -1; // -1|队列出队 0|访问右子树 1|访问左子树
  53. cout << "The BiTree Struct is: " << endl;
  54. if (this->bt == NULL)
  55. return;
  56. q = this->bt;
  57. //2.循环出队,访问子树
  58. while (q == this->bt || !cq->isEmpty() || tag != -1)
  59. {
  60. //计算当前层的当前结点前的空格数
  61. cur_space_num = _CalSpaceNum_Coordinate(level, num);
  62. /*
  63. . 打印空格:(两种情况)
  64. . 1.当前结点是本层上打印的第一个结点(序号不一定为 1 ),即:last_space_num == 0 时,直接打印空格数
  65. . 2.当前结点不是本层上打印的第一个结点,即:last_space_num != 0时,需减掉之前结点及空格数
  66. */
  67. for (int i = 0; i < cur_space_num - (last_space_num == 0 ? 0 : last_space_num + 1); i++)
  68. cout << ".";
  69. //上一结点前空格数 赋值上 当前结点前空格数,并置当前结点空格数为 0
  70. last_space_num = cur_space_num;
  71. cur_space_num = 0;
  72. //访问子树结点
  73. if (q == NULL)
  74. cout << "#"; //空结点输出
  75. else
  76. {
  77. //1.访问子树结点
  78. cout << q->data;
  79. //2.入队 子树
  80. cq->EnQueue(q);
  81. q = NULL; //指针 q 置空
  82. }
  83. //标记:出队
  84. if (tag == -1)
  85. {
  86. //1.出队 子树根结点
  87. p = cq->DeQueue();
  88. //如果 p->level + 1 > level ,则转为下一层
  89. if (p->level + 1 > level)
  90. {
  91. level = p->level + 1; //出队元素层次 + 1,即为当前层次
  92. last_space_num = 0; //置为下一层时,空格数置 0
  93. cout << endl;
  94. }
  95. tag = 0; //将标记置为 0
  96. }
  97. //标记:访问左子树
  98. if (tag == 0)
  99. {
  100. q = p->lchild;
  101. if (q == NULL)
  102. num = 2 * p->seq - (int)pow(2, level - 1) + 1; //根据双亲结点,计算其左子树结点层上序号(含空结点)
  103. else
  104. num = q->num;
  105. tag = 1; //将标记置为 1
  106. }
  107. //标记:访问右子树
  108. else if (tag == 1)
  109. {
  110. q = p->rchild;
  111. num = num + 1; //根据 左子树结点 + 1, 即为右子树结点层上序号(含空结点)
  112. tag = -1; //将标记置为 -1
  113. }
  114. }
  115. cout << endl;
  116. delete cq;
  117. }
  118. template <typename ElemType>
  119. int BiTree<ElemType>::_CalSpaceNum_Coordinate(int level, int num)
  120. {
  121. /*
  122. . 计算结点需打印空格数(坐标计算)
  123. . 入参:
  124. . 1.int level: 当前结点所在层数
  125. . 2.int num: 当前层的第几个结点(含空结点,按完全二叉树形式)
  126. . 出参:
  127. . 1.int : 需打印坐标空格数
  128. */
  129. int tol_level = this->height + 1; //树的总层数 + 1 (希望将最后一层之下的空层也打印)
  130. int space_i_first = (int)pow(2, tol_level - level) - 1; //各层首个结点前空格数
  131. int space_i = 2 * space_i_first + 1; //各层结点间空格数
  132. int space_num = (num - 1) * (space_i + 1) + space_i_first; //返回结点前空个数
  133. return space_num;
  134. }

打印结果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/233093
推荐阅读
相关标签
  

闽ICP备14008679号