当前位置:   article > 正文

按之字顺序打印二叉树_按之字形顺序打印二叉树

按之字形顺序打印二叉树

一、前言

前文《上往下打印二叉树》是从上往下,从左往右打印,扩展一下这个问题,按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推,该怎样打印呢?

 

二、题目

按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推

 

三、思路

先回顾一下前文《上往下打印二叉树》,用一个队列来实现的,队列是先进先出,正好满足从左往右打印树。队列我们可以看着是一组数据正着进去,正着出来。现在我们要求是按之字顺序打印,也就是类似一组数据先正着读,再反着读,双向链表不是正好可以满足?。哈哈哈!我本来是想说用两个栈可以实现,栈1将栈2中的树子节点添加到栈1中,先添加左子节点再添加右子节点,栈2将栈1中的树子节点添加到栈2中,先添加右子节点再添加左子节点。算是意外收获了一种解法。

解法一:用两个栈实现

解法二:用连表实现

直接看图:

奇数行从左往右打印,偶数行从右往左打印。

当我们从左往右打印当前行的时候,可以获得下一行的数据,获得数据顺序是从左往右。

当我们从右往左打印当前行的时候,可以获得下一行的数据,获得数据顺序是从右往左。

发现不管我们是从左往右还是从右往左,获得下一行数据顺序和上一行是同方向,但是我们现在需要下一行读取顺序和上一行顺序是相反的。入栈和出栈顺序相反,可以满足,此时为解法一。读当前行数据的时候将下一行数据从头加到大连表中,读完当前行数据的时候,从头开始读取连表的数据,读取数据顺序和添加顺序相反,此时为解法二。

 

四、闲谈

当对一个问题反复思考的时候,可能会有意想不到的收获。本质上栈底层可以用连表实现。

五、编码实现

  1. #pragma once
  2. #include <cstdio>
  3. #include <queue>
  4. #include <vector>
  5. #include <map>
  6. #include <stack>
  7. #include <list>
  8. #include "Common.h"
  9. using namespace std;
  10. #define NAMESPACE_GETTREELINES namespace GETTREELINES {
  11. #define NAMESPACE_GETTREELINESEND }
  12. // 从上往下,从左往右,按行输出节点,不包含空节点
  13. //【队列实现】
  14. template<class T>
  15. void GetTreesInLines(BinaryTreeNode<T>* pRoot, map<int, vector<T>>& data)
  16. {
  17. if (pRoot == nullptr)
  18. return;
  19. std::queue<BinaryTreeNode<T>*> nodes;
  20. nodes.push(pRoot);
  21. int nextLevel = 0;
  22. int toBePrinted = 1;
  23. vector<T> vt;
  24. int line = 1;
  25. while (!nodes.empty())
  26. {
  27. BinaryTreeNode<T>* pNode = nodes.front();
  28. //printf("%d ", pNode->m_nValue);
  29. vt.push_back(pNode->m_nValue);
  30. if (pNode->m_pLeft != nullptr)
  31. {
  32. nodes.push(pNode->m_pLeft);
  33. ++nextLevel;
  34. }
  35. if (pNode->m_pRight != nullptr)
  36. {
  37. nodes.push(pNode->m_pRight);
  38. ++nextLevel;
  39. }
  40. nodes.pop();
  41. --toBePrinted;
  42. if (toBePrinted == 0)
  43. {
  44. //printf("\n");
  45. data[line++] = vt;
  46. vt.clear();
  47. toBePrinted = nextLevel;
  48. nextLevel = 0;
  49. }
  50. }
  51. }
  52. // 从上往下,从左往右,包含空节点
  53. //【队列实现】
  54. template<class T>
  55. void GetTreesInLines(BinaryTreeNode<T>* pRoot, map<int, vector<T>>& data, T empty)
  56. {
  57. if (pRoot == nullptr)
  58. return;
  59. std::queue<BinaryTreeNode<T>*> nodes;
  60. nodes.push(pRoot);
  61. int nextLevel = 0;
  62. int toBePrinted = 1;
  63. vector<T> vt;
  64. int line = 1;
  65. bool ret = false;
  66. while (!nodes.empty())
  67. {
  68. BinaryTreeNode<T>* pNode = nodes.front();
  69. if (pNode == nullptr)
  70. {
  71. vt.push_back(empty);
  72. //左节点
  73. nodes.push(nullptr);
  74. ++nextLevel;
  75. //又节点
  76. nodes.push(nullptr);
  77. ++nextLevel;
  78. }
  79. else
  80. {
  81. vt.push_back(pNode->m_nValue);
  82. nodes.push(pNode->m_pLeft);
  83. ++nextLevel;
  84. nodes.push(pNode->m_pRight);
  85. ++nextLevel;
  86. if (pNode->m_pLeft != nullptr || pNode->m_pRight != nullptr)
  87. {
  88. ret = true;
  89. }
  90. }
  91. nodes.pop();
  92. --toBePrinted;
  93. if (toBePrinted == 0)
  94. {
  95. data[line++] = vt;
  96. vt.clear();
  97. toBePrinted = nextLevel;
  98. nextLevel = 0;
  99. if (ret == false)
  100. {
  101. break;
  102. }
  103. ret = false;
  104. }
  105. }
  106. }
  107. //按行输出节点,不包含空节点
  108. //按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
  109. //【双栈实现】
  110. template<class T>
  111. void GetTreesInLines_Zigzag_Stack(BinaryTreeNode<T>* pRoot, map<int, vector<T>>& data)
  112. {
  113. data.clear();
  114. if (pRoot == nullptr)
  115. {
  116. return;
  117. }
  118. stack<BinaryTreeNode<T>*> stkR; // 向右打印, 左 -> 右
  119. stack<BinaryTreeNode<T>*> stkL; // 向左打印, 右 -> 左
  120. int line = 1;
  121. stkR.push(pRoot);
  122. vector<T> vect;
  123. while (true)
  124. {
  125. vect.clear();
  126. if ((line & 1) == 1) // 奇数列,左 -> 右
  127. {
  128. if (stkR.empty())
  129. {
  130. break;
  131. }
  132. while (!stkR.empty())
  133. {
  134. vect.push_back(stkR.top()->m_nValue);
  135. // 先左
  136. if (stkR.top()->m_pLeft != nullptr)
  137. {
  138. stkL.push(stkR.top()->m_pLeft);
  139. }
  140. // 再右
  141. if (stkR.top()->m_pRight != nullptr)
  142. {
  143. stkL.push(stkR.top()->m_pRight);
  144. }
  145. stkR.pop();
  146. }
  147. }
  148. else // 偶数列,右 -> 左
  149. {
  150. if (stkL.empty())
  151. {
  152. break;
  153. }
  154. while (!stkL.empty())
  155. {
  156. vect.push_back(stkL.top()->m_nValue);
  157. // 先右
  158. if (stkL.top()->m_pRight != nullptr)
  159. {
  160. stkR.push(stkL.top()->m_pRight);
  161. }
  162. // 再左
  163. if (stkL.top()->m_pLeft != nullptr)
  164. {
  165. stkR.push(stkL.top()->m_pLeft);
  166. }
  167. stkL.pop();
  168. }
  169. }
  170. data[line++] = vect;
  171. }
  172. }
  173. //按行输出节点,不包含空节点
  174. //按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
  175. //【一个连表实现】
  176. template<class T>
  177. void GetTreesInLines_Zigzag_List(BinaryTreeNode<T>* pRoot, map<int, vector<T>>& data)
  178. {
  179. data.clear();
  180. if (pRoot == nullptr)
  181. {
  182. return;
  183. }
  184. list<BinaryTreeNode<T>*> lt;
  185. lt.push_back(pRoot);
  186. auto itt = lt.begin();
  187. auto ih = *itt;
  188. ih->m_nValue;
  189. T n = (*(lt.begin()))->m_nValue;
  190. int line = 1;
  191. int toBePrinted = 1;
  192. int nextCount = 0;
  193. vector<T> vect;
  194. auto itBegin = lt.begin();
  195. auto itEnd = lt.end();
  196. auto it = itBegin;
  197. while (true)
  198. {
  199. if (it == itEnd)
  200. {
  201. return;
  202. }
  203. vect.push_back((*it)->m_nValue);
  204. if ((line & 1) == 1) // 奇数列,左 -> 右
  205. {
  206. // 先左
  207. if ((*it)->m_pLeft != nullptr)
  208. {
  209. lt.push_front((*it)->m_pLeft);
  210. ++nextCount;
  211. }
  212. // 再右
  213. if ((*it)->m_pRight != nullptr)
  214. {
  215. lt.push_front((*it)->m_pRight);
  216. ++nextCount;
  217. }
  218. }
  219. else // 偶数列,右 -> 左
  220. {
  221. // 先右
  222. if ((*it)->m_pRight != nullptr)
  223. {
  224. lt.push_front((*it)->m_pRight);
  225. ++nextCount;
  226. }
  227. // 再左
  228. if ((*it)->m_pLeft != nullptr)
  229. {
  230. lt.push_front((*it)->m_pLeft);
  231. ++nextCount;
  232. }
  233. }
  234. ++it;
  235. if (--toBePrinted <= 0)
  236. {
  237. itEnd = itBegin;
  238. itBegin = lt.begin();
  239. it = itBegin;
  240. toBePrinted = nextCount;
  241. nextCount = 0;
  242. data[line++] = vect;
  243. vect.clear();
  244. }
  245. }
  246. }
  247. NAMESPACE_GETTREELINES
  248. //
  249. // 测试
  250. template<class T>
  251. void Test(const char* testName, T* preorder, T* inorder, int length, T empty=0)
  252. {
  253. map<int, vector<T>> data;
  254. auto Print = [&]()
  255. {
  256. for (auto it = data.begin(); it != data.end(); ++it)
  257. {
  258. for (auto itv = it->second.begin(); itv != it->second.end(); ++itv)
  259. {
  260. cout << *itv << " ";
  261. }
  262. cout << endl;
  263. }
  264. cout << endl;
  265. };
  266. cout << testName << "从左往右,不含空节点打印,用【队列】实现" << endl;
  267. BinaryTreeNode<T>* pRoot = Construct(preorder, inorder, length);
  268. GetTreesInLines(pRoot, data);
  269. Print();
  270. cout << testName << "从左往右,含空节点打印,用【队列】实现" << endl;
  271. GetTreesInLines(pRoot, data, empty);
  272. Print();
  273. cout << testName << "之字形打印,用两个【栈】实现" << endl;
  274. GetTreesInLines_Zigzag_Stack(pRoot, data);
  275. Print();
  276. cout << testName << "之字形打印,用一个【连表】实现" << endl;
  277. GetTreesInLines_Zigzag_List(pRoot, data); (pRoot, data);
  278. Print();
  279. }
  280. // 普通二叉树
  281. // 1
  282. // / \
  283. // 2 3
  284. // / / \
  285. // 4 5 6
  286. // \ /
  287. // 7 8
  288. void Test1()
  289. {
  290. const int length = 8;
  291. char preorder[length + 1] = "12473568";
  292. char inorder[length + 1] = "47215386";
  293. char empty = 'X';
  294. Test("Test1", preorder, inorder, length, empty);
  295. }
  296. // 完全二叉树
  297. // 1
  298. // / \
  299. // 2 3
  300. // / \ / \
  301. // 4 5 6 7
  302. void Test2()
  303. {
  304. const int length = 7;
  305. char preorder[length + 1] = "1245367";
  306. char inorder[length + 1] = "4251637";
  307. char empty = 'X';
  308. Test("Test2", preorder, inorder, length, empty);
  309. }
  310. // 1
  311. // / \
  312. // 2 3
  313. // / \ / \
  314. // 4 5 6 7
  315. // / \ / \ / \ / \
  316. // 8 9 10 11 12 13 14 15
  317. void Test3()
  318. {
  319. const int length = 15;
  320. int preorder[length] = { 1, 2, 4, 8, 9, 5, 10, 11, 3, 6, 12, 13, 7, 14, 15 };
  321. int inorder[length] = { 8, 4, 9, 2, 10, 5, 11, 1, 12, 6, 13, 3, 14, 7, 15 };
  322. int empty = -1;
  323. Test("Test3", preorder, inorder, length, empty);
  324. }
  325. NAMESPACE_GETTREELINESEND
  326. void GetTreesInLines_Test()
  327. {
  328. GETTREELINES::Test1();
  329. GETTREELINES::Test2();
  330. GETTREELINES::Test3();
  331. }

执行结果:

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号