当前位置:   article > 正文

C++数据结构---二叉树_c++二叉树

c++二叉树


树的概念
树是一种能分层存储数据的数据结构,树中的每个元素被称为树的节点,每个节点有若干个指针指向子节点
从节点的角度来看,树是由唯一的起始结点引出的节点集合,这个起始结点被称为根(root),
树中节点的子树数目称为节点的度
树的度指其中节点的度最大值。比如1号节点的孩子是2、3、4,则1号节点的度数是3,且1号节点的度是最大的,故该树的度为3。


二叉树
二叉树是指对于树中的每个节点而言,最多由两个子节点,即任意节点的度小于等于2
层数:从根节点到某个节点的路径长度,根节点为0层
高度:最大层数+1
叶子节点数:没有子树的结点是叶子结点


满二叉树
要不没有子节点,要不有两个子节点
完全二叉树(顺序结构更好)
一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号。
只有最下面的节点的字节点可以小于2,并且最后一层的分叉全在最左边


二叉树的遍历
前序遍历(pre—order)
访问根节点,按前序遍历左子树,按前序遍历右子树
中序遍历(in—order)
按中序遍历左子树,访问根节点,按中序遍历右子树。特别的 ,对于二叉树搜索树,中序遍历可以获得一个由大到小或由小到大的有序序列
后序遍历(post—order)
按后序遍历左子树,按后序遍历右子树,访问根节点 
都属于深度优先算法
层次遍历
首先访问第0层,当第i层访问结束后,再从左到右依次访问第i+1层
层次遍历属于广度优先算法

本文实现的二叉树的功能有

1.创建一个二叉树

本文添加了一个不太成熟的创建二叉树的功能,用来根据已有的二叉树图像,基于层序遍历的方法创建二叉树。

2.二叉树的前序遍历打印

有采用非递归方式和递归方式两种,本文使用后者。

前序遍历是:先访问根节点,按前序遍历左子树,再按前序遍历右子树。

3.二叉树的中序遍历打印

按中序遍历左子树,访问根节点,按中序遍历右子树。特别的 ,对于二叉树搜索树,中序遍历可以获得一个由大到小或由小到大的有序序列。

4.二叉树的后序遍历打印

按后序遍历左子树,按后序遍历右子树,最后再访问根节点 。

5.层序遍历打印

6.返回二叉树节点的数量

7.返回二叉树第k层节点的个数

8.返回二叉树的深度

9.返回节点存储值为val的第一个节点
这里有四种方式返回(即四种遍历的方式返回四种情况),这里以前序遍历为例。

10.判断二叉树是否为完全二叉树

11.销毁二叉树,防止内存泄漏

下面是代码实现,就不在上面展示了!

  1. #pragma once
  2. #include<iostream>
  3. #include<string>
  4. #include<queue>
  5. #include<vector>
  6. #include<math.h>
  7. using namespace std;
  8. //二叉树的节点
  9. class Linknode
  10. {
  11. public:
  12. Linknode();
  13. int data;
  14. Linknode* left;//左子节点
  15. Linknode* right;//右子节点
  16. };
  17. Linknode::Linknode()
  18. {
  19. left = NULL;
  20. right = NULL;
  21. }
  22. //二叉树
  23. class Tree
  24. {
  25. public:
  26. Tree();
  27. Linknode* root;//记录二叉树的根
  28. int nodenum;//记录二叉树节点的数量
  29. //创建一个二叉树
  30. void Gettree(Linknode* root);
  31. //二叉树的前序遍历打印
  32. void pre_order(Linknode* root);
  33. //二叉树的中序遍历打印
  34. void in_order(Linknode* root);
  35. //二叉树的后序遍历打印
  36. void post_order(Linknode* root);
  37. //二叉树的层序遍历打印
  38. void level_order(Linknode* root);
  39. //返回二叉树节点的数量
  40. int LNnum(Linknode* root);
  41. //返回二叉树第k层节点的个数(这里采用函数的重载)
  42. int Lnnum(Linknode* root,int k);
  43. //返回二叉树的深度
  44. int depth(Linknode* root);
  45. //返回节点存储值为val的第一个节点
  46. Linknode* Find(Linknode* root, int val);
  47. //判断二叉树是否为完全二叉树
  48. bool Iscomplete(Linknode* root);
  49. //销毁二叉树
  50. void clear(Linknode* root);
  51. };
  52. Tree::Tree()
  53. {
  54. root = NULL;
  55. nodenum = 1;
  56. }
  57. //创建一个二叉树
  58. //根据层序遍历的原理创建一个二叉树,一层一层创建节点
  59. //当没有左子节点,或者右子节点时,输入-1即可
  60. //输入的时候记得小心!!!
  61. void Tree::Gettree(Linknode* root)
  62. {
  63. queue<Linknode*> q;
  64. if (root == NULL)
  65. return;
  66. q.push(root);
  67. while (!q.empty())
  68. {
  69. cout << "请输入此节点的左字节点的值" << endl;
  70. q.front()->left = new Linknode;
  71. cin >> q.front()->left->data;
  72. if (q.front()->left->data == -1)
  73. {
  74. delete q.front()->left;
  75. q.front()->left = NULL;
  76. }
  77. else
  78. {
  79. q.push(q.front()->left);
  80. this->nodenum++;
  81. }
  82. cout << "请输入此节点的右字节点的值" << endl;
  83. q.front()->right = new Linknode;
  84. cin >> q.front()->right->data;
  85. if (q.front()->right->data == -1)
  86. {
  87. delete q.front()->right;
  88. q.front()->right = NULL;
  89. }
  90. else
  91. {
  92. q.push(q.front()->right);
  93. this->nodenum++;
  94. }
  95. q.pop();
  96. }
  97. }
  98. //二叉树的前序遍历打印(方法一:采用递归方式)
  99. //访问根节点,按前序遍历左子树,按前序遍历右子树
  100. void Tree::pre_order(Linknode* root)
  101. {
  102. if (root == NULL)//空节点,不打印(也可以打印空)
  103. return;//递归返回
  104. cout << root->data;//打印本节点
  105. pre_order(root->left);//遍历左子树,左节点作为左子树的根
  106. pre_order(root->right);//遍历右子树,右节点作为右子树的根
  107. }
  108. //二叉树的中序遍历打印
  109. //按中序遍历左子树,访问根节点,按中序遍历右子树。特别的 ,对于二叉树搜索树,中序遍历可以获得一个由大到小或由小到大的有序序列
  110. void Tree::in_order(Linknode* root)
  111. {
  112. if (root != NULL)
  113. in_order(root->left);
  114. else
  115. return;
  116. cout << root->data;//打印本节点
  117. in_order(root->right);
  118. }
  119. //二叉树的后序遍历打印
  120. //按后序遍历左子树,按后序遍历右子树,访问根节点
  121. void Tree::post_order(Linknode* root)
  122. {
  123. if (root != NULL)
  124. post_order(root->left);
  125. else
  126. return;
  127. post_order(root->right);
  128. cout << root->data;
  129. }
  130. //二叉树的层序遍历打印
  131. void Tree::level_order(Linknode* root)
  132. {
  133. //先将根结点入队,根据队列先进先出的性质。当上一层的结点出队的时候,把下一层的结点入队......
  134. queue<Linknode*> q;//创建队列
  135. if (root == NULL)//空树不打印
  136. return;
  137. q.push(root);//将根入队
  138. cout << root->data;//打印本节点
  139. while (!q.empty())
  140. {
  141. if (q.front()->left)//左子节点是否为空
  142. {
  143. q.push(q.front()->left);//不为空入队
  144. cout << q.front()->left->data;//打印节点
  145. }
  146. if (q.front()->right)//右子节点是否为空
  147. {
  148. q.push(q.front()->right);//不为空入队
  149. cout << q.front()->right->data;//打印节点
  150. }
  151. q.pop();//将父节点删除
  152. }//循环直到没有节点
  153. }
  154. //返回二叉树节点的数量
  155. int Tree::LNnum(Linknode* root)
  156. {
  157. return this->nodenum;
  158. }
  159. //返回二叉树第k层节点的个数(这里采用函数的重载)
  160. int Tree::Lnnum(Linknode* root, int k)
  161. {
  162. queue<Linknode*> q;//同层序遍历相似
  163. if (root == NULL)
  164. return 0;
  165. if (k == 0)
  166. return 1;
  167. q.push(root);
  168. int floor = 1;//层数
  169. int fnum = 1;//上一层的节点数
  170. int arr[100] = { 0 };//创建一个数组,存储k层的节点数
  171. while (!q.empty()&&floor<=k)
  172. {
  173. if (q.front()->left != NULL)
  174. {
  175. q.push(q.front()->left);
  176. arr[floor]++;//+1
  177. }
  178. if (q.front()->right != NULL)
  179. {
  180. q.push(q.front()->right);
  181. arr[floor]++;
  182. }
  183. q.pop();
  184. fnum--;
  185. if (fnum == 0)
  186. {
  187. floor++;
  188. fnum = arr[floor - 1];
  189. }
  190. }
  191. return arr[floor-1];
  192. }
  193. //返回二叉树的深度
  194. int Tree::depth(Linknode* root)
  195. {
  196. int dep = 1;//深度
  197. int fnum = 1;//上一层的节点数
  198. int arr[100] = { 0 };//创建一个数组,存储k层的节点数
  199. queue<Linknode*> q;//同层序遍历相似
  200. if (root == NULL)
  201. return 0;
  202. q.push(root);
  203. while (!q.empty())
  204. {
  205. if (q.front()->left != NULL)
  206. {
  207. q.push(q.front()->left);
  208. arr[dep]++;//+1
  209. }
  210. if (q.front()->right != NULL)
  211. {
  212. q.push(q.front()->right);
  213. arr[dep]++;
  214. }
  215. q.pop();
  216. fnum--;
  217. if (fnum == 0)
  218. {
  219. if (arr[dep] == 0)
  220. return dep;
  221. dep++;
  222. fnum = arr[dep - 1];
  223. }
  224. }
  225. return dep;
  226. }
  227. //返回节点存储值为val的第一个节点
  228. //这里有四种方式返回(即四种遍历的方式返回四种情况)
  229. //这里以前序遍历为例
  230. Linknode* Tree::Find(Linknode* root,int val)
  231. {
  232. if (root == NULL)
  233. return NULL;
  234. if (root->data == val)
  235. return root;//首次找到节点,返回地址
  236. Linknode* ret1=Find(root->left,val);//左子节点的由ret1接受,没有找到ret1为空
  237. if (ret1)//如果ret1不为空返回,直到根节点,然后递归结束
  238. return ret1;
  239. Linknode* ret2=Find(root->right,val);//右子节点的由ret2接受,没有找到ret2为空
  240. if (ret2)//同ret1
  241. return ret2;
  242. }
  243. //判断二叉树是否为完全二叉树
  244. bool Tree::Iscomplete(Linknode* root)
  245. {
  246. queue<Linknode*> q;
  247. //借助层序遍历
  248. //将地址为空的也进入队列
  249. //当队列的第一个元素为NULL时,看队列元素是否全为空,当全为空时,为完全二叉树,反之则不是
  250. if (root == NULL)
  251. return false;
  252. q.push(root);
  253. while (!q.empty())
  254. {
  255. if (q.front() == NULL)
  256. break;
  257. q.push(q.front()->left);
  258. q.push(q.front()->right);
  259. q.pop();
  260. }
  261. while (!q.empty())
  262. {
  263. q.pop();
  264. if (q.front())//碰见元素不为NULL
  265. return false;
  266. }
  267. return true;
  268. }
  269. //销毁二叉树,防止内存泄漏
  270. void Tree::clear(Linknode* root)
  271. {
  272. if (root == NULL)
  273. return;
  274. clear(root->left);
  275. clear(root->right);
  276. delete root;
  277. }

测试

  1. int main()
  2. {
  3.     Tree t;
  4.     t.root = new Linknode;
  5.     t.root->data = 1;
  6.     t.root->left = new Linknode;
  7.     t.root->left->data = 2;
  8.     t.root->left->left = new Linknode;
  9.     t.root->left->left->data = 3;
  10.     t.root->right = new Linknode;
  11.     t.root->right->data = 4;
  12.     t.root->right->left = new Linknode;
  13.     t.root->right->left->data = 5;
  14.     t.root->right->right = new Linknode;
  15.     t.root->right->right->data = 6;
  16.     //t.Gettree(t.root);//使用函数创建树
  17.     cout << "前序遍历打印:";
  18.     t.pre_order(t.root);
  19.     cout << endl;
  20.     cout << "中序遍历打印:";
  21.     t.in_order(t.root);
  22.     cout << endl;
  23.     cout << "后序遍历打印:";
  24.     t.post_order(t.root);
  25.     cout << endl;
  26.     cout << "层序遍历打印:";
  27.     t.level_order(t.root);
  28.     cout << "这个树的节点有:" << t.LNnum(t.root) << "个" << endl;
  29.     cout << "这个树第2层的节点有:" << t.Lnnum(t.root,2) << "个" << endl;
  30.     cout << "深度为:" << t.depth(t.root) << endl;
  31.     cout << t.Find(t.root, 3) << endl;
  32.     cout << t.Iscomplete(t.root) << endl;
  33.     return 0;
  34. }

结果图 

 本文参考了其他博主的文章,通过修改写了这篇,如果有非常相似的地方,请告知。

有错请指正!!!

 

 

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

闽ICP备14008679号