一、问题概述

树是n个有限个数据的集合,形如:

它像不像倒着的树呢?我们把它看成是一种数据结构----树。它的第一个节点称作树的根,最底下的那些节点称作树的叶子。

我们今天所要研究的是二叉树,即父节点最多只有两个孩子(左孩子和右孩子)。

二叉树还有两种特殊的结构,分为完全二叉树和满二叉树。

如:

满二叉树:高度为N的满二叉树有2^N-1个节点。

完全二叉树:高度为N,前N-1层为满二叉树,第N层为连续的叶子节点。

二叉树有四种遍历方式:

前序遍历(根左右),中序遍历(左根右),后序遍历(左右根),层序遍历(从上往下,从左往右)。

那么,如何实现一个二叉树的数据结构呢?

二、数据结构的设计

在这里,我们采取链表的方式,即创建节点,将节点与节点链接起来的方式实现二叉树。

节点的结构:

(1)将要创建的节点的数据部分存储到数组里,然后创建节点。读取数组,我们将指针指向空的部分当作是非法字符,在这里非法字符是‘#’;

(2)如果不是非法字符,则创建节点并链接到二叉树的根上,按照先序遍历的方式先创建根,再创建根的左,最后创建根的右。

(3)创建完成后,对二叉树进行相应的操作。如:求叶子节点数,第k层节点数,四种遍历方式,递归和非递归实现等。

三、实现代码

//BinaryTree.h

#pragma once
#include<assert.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;template<typename T>
struct BinaryTreeNode  //创建节点
{T _data;BinaryTreeNode<T> *_left;BinaryTreeNode<T> *_right;BinaryTreeNode(const T& data):_data(data), _left(NULL), _right(NULL){}
};template<typename T>
class BinaryTree
{typedef BinaryTreeNode<T> Node;
public:BinaryTree():_root(NULL){}BinaryTree(T* arr,size_t size,const T& invalid = T()){assert(arr);size_t index = 0;_root = CreateTree(arr,size,invalid,index);}BinaryTree(BinaryTree<T> &t){assert(t._root);_root = _Copy(t._root);}//传统写法/*BinaryTree<T>& operator=(BinaryTree<T>& t){if (this != &t){Node* tmp = _Copy(t._root);_root = _Destroy(_root);_root = tmp;}return *this;}*///现代写法BinaryTree<T>& operator=(BinaryTree<T>& t){if (this != &t){BinaryTree<T> tmp(t);std::swap(tmp._root, _root);}return *this;}~BinaryTree(){if (_root){_root = _Destroy(_root);}}
public:size_t Size(){return _Size(_root);}size_t Depth(){return _Depth(_root);}void PreOrder(){_PreOrder(_root);cout << endl;}void InOrder(){_InOrder(_root);cout << endl;}void PostOrder(){_PostOrder(_root);cout << endl;}void LevelOrder(){_LevelOrder(_root);cout << endl;}Node* Find(const T& x){return _Find(_root,x);}public://创建二叉树Node* CreateTree(T* arr, size_t size, const T& invalid,size_t& index){Node* root = NULL;if (index < size){if (arr[index] != invalid){root = new Node(arr[index]);root->_left = CreateTree(arr, size, invalid, ++index);root->_right = CreateTree(arr, size, invalid, ++index);}}return root;}//拷贝二叉树Node* _Copy(Node* root){Node* cur = NULL;if (root){cur = new Node(root->_data);cur->_left = _Copy(root->_left);cur->_right = _Copy(root->_right);}return cur;}//释放二叉树节点Node* _Destroy(Node* root){if (root != NULL){root->_left = _Destroy(root->_left);root->_right = _Destroy(root->_right);delete root;root = NULL;}return root;}//递归求解二叉树节点的个数size_t _Size(Node* root)     {if (root == NULL)return 0;return _Size(root->_left) + _Size(root->_right) + 1;}//二叉树的深度求解size_t _Depth(Node* root){size_t maxDepth = 1;if (root){size_t depth = 1;if (root->_left)             //左不为空则遍历左树的深度{depth += _Depth(root->_left);}if (depth > maxDepth){maxDepth = depth;}if (root->_right)          //右不为空则在左树的深度基础上+1{depth = _Depth(root->_right) + 1;}if (depth > maxDepth){maxDepth = depth;}}return maxDepth;}//二叉树前序遍历的递归实现void _PreOrder(Node* root){if (root){cout << root->_data << " ";_PreOrder(root->_left);_PreOrder(root->_right);}}//二叉树中序遍历的递归实现void _InOrder(Node* root){if (root){_InOrder(root->_left);cout << root->_data << " ";_InOrder(root->_right);}}//二叉树后序遍历的递归实现void _PostOrder(Node* root){if (root){_PostOrder(root->_left);_PostOrder(root->_right);cout << root->_data << " ";}}//二叉树层序遍历的实现void _LevelOrder(Node* root){queue<Node*> q;if (root)q.push(root);while (!q.empty()){Node* front = q.front();cout << front->_data << " ";q.pop();if (front->_left){q.push(front->_left);}if (front->_right){q.push(front->_right);}}}//二叉树中查找某个值的节点Node* _Find(Node* root,const T& data){Node* cur = root;if(root == NULL)return NULL;if(root->_data == data)         //找到则返回节点return root;Node* ret = _Find(cur->_left,data);if(ret == NULL){ret = _Find(cur->_right,data);}return ret;}
public:void PreOrderNonR(){_PreOrderNonR(_root);cout<<endl;}void InOrderNonR(){_InOrderNonR(_root);cout<<endl;}void PostOrderNonR(){_PostOrderNonR(_root);cout<<endl;}
public://二叉树前序遍历的非递归实现void _PreOrderNonR(Node* root){Node* cur = root;stack<Node*> s;while(!s.empty() || cur){while(cur){cout<<cur->_data<<" ";s.push(cur);cur = cur->_left;}Node* top = s.top();s.pop();cur = top->_right;}}//二叉树中序遍历的非递归实现void _InOrderNonR(Node* root){Node* cur = root;stack<Node*> s;while(!s.empty() || cur){while(cur){s.push(cur);cur = cur->_left;}Node* top = s.top();cout<<top->_data<<" ";s.pop();cur = top->_right;}}//二叉树后序遍历的非递归实现void _PostOrderNonR(Node* root){Node* cur = root;stack<Node*> s;Node* prev = NULL;while(!s.empty() || cur){while(cur){s.push(cur);cur = cur->_left;}Node* top = s.top();if(top->_right == NULL || top->_right == prev){cout<<top->_data<<" ";prev = top;s.pop();}else{cur = top->_right;}}}
public:size_t GetKLevelSize(size_t k){assert(_root);size_t level = 1;size_t count = 0;_GetKLevelSize(_root,k,level,count);return count;}//获取第k层节点的个数(当k等于层数level时,count++,否则分别遍历左树和右树)void _GetKLevelSize(Node* root,size_t k,size_t level,size_t& count){if(root == NULL)return;if(k == level){count++;return;}_GetKLevelSize(root->_left,k,level+1,count);_GetKLevelSize(root->_right,k,level+1,count);}size_t GetLeafSize(){size_t count = 0;_GetLeafSize(_root,count);return count;}//获取叶子节点(当节点的左树为空且右树为空时,即叶子数加1)void _GetLeafSize(Node* root,size_t& count){if(root == NULL)return;if(root->_left == NULL && root->_right == NULL){count++;return;}_GetLeafSize(root->_left,count);_GetLeafSize(root->_right,count);}size_t SizePrev(){size_t count = 0;_SizePrev(_root,count);return count;}//用引用的方法获取二叉数节点的个数(需要入栈)void _SizePrev(Node* root,size_t& count){if(root == NULL)return;Node* cur = root;stack<Node*> s;while(!s.empty() || cur){while(cur){s.push(cur);count++;cur = cur->_left;}Node* top = s.top();s.pop();cur = top->_right;}}
private:Node* _root;
};void FunTest()
{int arr[] = {1,2,3,'#','#',4,'#','#',5,6};int arr1[] = { 1, 2,'#', 3, '#', '#', 4, 5,'#',6 ,'#', 7,'#','#',8};BinaryTree<int> b1(arr,sizeof(arr)/sizeof(arr[0]),'#');BinaryTree<int> b6(arr1, sizeof(arr1) / sizeof(arr1[0]), '#');BinaryTree<int> b2(b1);BinaryTree<int> b3;b3 = b2;cout << b1.Size() << endl;cout << b2.Size() << endl;cout << b3.Size() << endl;cout << b1.Depth() << endl;cout << b6.Depth() << endl;cout<<"b1:递归先序遍历->";b1.PreOrder();cout<<"b1:递归中序遍历->";b1.InOrder();cout<<"b1:递归后序遍历->";b1.PostOrder();cout<<"b1:层序遍历->";b1.LevelOrder();cout<<"b1:非递归先序遍历->";b1.PreOrderNonR();cout<<"b1:非递归中序遍历->";b1.InOrderNonR();cout<<"b1:非递归后序遍历->";b1.PostOrderNonR();cout<<"Find(4)?"<<endl;cout<<b1.Find(4)->_data<<endl;cout<<"GetLeafSize:"<<b1.GetLeafSize()<<endl;cout<<"_SizePrev:"<<b1.SizePrev()<<endl;cout<<"b6:递归先序遍历->";b6.PreOrder();cout<<"b6:递归中序遍历->";b6.InOrder();cout<<"b6:递归后序遍历->";b6.PostOrder();cout<<"b6:递归层序遍历->";b6.LevelOrder();cout<<"第三层节点数:"<<b6.GetKLevelSize(3)<<endl;cout<<"第四层节点数:"<<b6.GetKLevelSize(4)<<endl;cout<<"第五层节点数:"<<b6.GetKLevelSize(5)<<endl;cout<<"GetLeafSize:"<<b6.GetLeafSize()<<endl;cout<<"_SizePrev:"<<b6.SizePrev()<<endl;
}

//BinaryTree.cpp

#include<iostream>
using namespace std;
#include"BinaryTree.h"
int main()
{FunTest();return 0;
}

四、运行结果

前一篇广义表的数据结构和二叉树的数据结构也有一些类似哦。大家可以看看哒^-^

【数据结构】普通二叉树的实现相关推荐

  1. 【数据结构】二叉树及其相关操作

    二叉树的定义 二叉树是一个由结点构成的有限集合,这个集合或者为空,或者由一个根节点及两棵互不相交的分别称作这个根节点的左子树和右子树的二叉树组成. 二叉树并非一般的树形结构的特殊形式,它们是两种不同的 ...

  2. 数据结构之二叉树(遍历、建立、深度)

    数据结构之二叉树(遍历.建立.深度) 1.二叉树的深度遍历 二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树的所有结点,使得每个结点被访问一次且仅被访问一次. 对于二叉树的深度遍历,有前序遍历 ...

  3. python数据结构 树_python数据结构之二叉树的建立实例

    先建立二叉树节点,有一个data数据域,left,right 两个指针域 复制代码 代码如下: # -*- coding: utf - 8 - *- class TreeNode(object): d ...

  4. 【关于封装的那些事】 缺失封装 【关于封装的那些事】 泄露的封装 【关于封装的那些事】 不充分的封装 【图解数据结构】二叉查找树 【图解数据结构】 二叉树遍历...

    [关于封装的那些事] 缺失封装 目录 - 缺失封装 为什么不能缺失封装? 缺失封装潜在的原因 未意识到关注点会不断变化 混合关注点 幼稚的设计决策 示例分析一 示例分析二 总结 缺失封装 没有将实现变 ...

  5. python处理mysql数据结构_python环境下使用mysql数据及数据结构和二叉树算法(图)...

    python环境下使用mysql数据及数据结构和二叉树算法(图): 1 python环境下使用mysql 2使用的是 pymysql库 3 开始-->创建connection-->获取cu ...

  6. 数据结构之二叉树:折纸问题——11

    数据结构之二叉树:Python代码解决折纸问题 折纸问题 要求:请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开.此时折痕是凹下去的,即折痕突起的方向指向纸条的背面.如果从纸 ...

  7. 数据结构树二叉树计算节点_查找二叉树中叶节点的数量 数据结构

    数据结构树二叉树计算节点 Algorithm: 算法: One of the popular traversal techniques to solve this kind of problems i ...

  8. 【数据结构】二叉树的python实现

    [数据结构]二叉树的python实现 本博文描述的二叉树是任意二叉树,可以使完全二叉树,也可以是非完全二叉树. 首先声明一个二叉树节点的初始化类TNode,每一个节点都有三个组成部分,节点的元素值,节 ...

  9. 大一新生必看,自学必看,里昂详解数据结构之二叉树

    数据结构之二叉树 有幸掌握浅薄知识,不吝分享,保持独立思考,自主学习,共同进步.另求关注,点赞,评论,感谢!(tips:主页有数据结构全部知识点,以及知识点讲解,建立完善的数据结构知识体) 核心算法思 ...

  10. 初阶数据结构 初识二叉树

    初阶数据结构 初识二叉树 一. 树 1. 基本概念 2. 常用术语 3. 代码表示 4. 实际运用 二. 二叉树 1. 基本概念 2. 特殊的二叉树 3. .二叉树的顺序结构及实现 (1)顺序结构 ( ...

最新文章

  1. 谷歌BERT预训练源码解析(二):模型构建
  2. 拿到饿了么 P7 Offer,却一轮游途虎……
  3. Git查看、删除、重命名远程分支和tag
  4. 前端学习(3324):你不知道javascript说闭包
  5. 2000年考研英语阅读理解文章二
  6. LeetCode 2091. 从数组中移除最大值和最小值(一次遍历)
  7. pyinstaller--将py文件转化成exe
  8. 电脑的服务器操作系统是什么,电脑的服务器操作系统是什么
  9. 解决js跨域使用nginx配置问题
  10. 【javascript】基于javascript的小时钟
  11. 简单的在线出入库管理用哪个系统好
  12. 谷歌地球Google Earth打不开的解决办法
  13. 图片标签及以图搜图场景应用
  14. RabbitMQ之发布确认
  15. 山东省2013高职分数线
  16. Python绘制双对数曲线
  17. JavaWeb专栏之(三):Eclipse创建JavaWeb项目
  18. catboost 的实例应用附带特征重要度打印
  19. mac如何查看是否安装了git?
  20. 12、MTU的概念,什么是路径MTU? MTU发现机制,TraceRoute(了解)

热门文章

  1. Azure DevOps Server (TFS)中代码文件换行问题解决方案(Git)
  2. 洛谷 P3835: 【模板】可持久化平衡树
  3. 跳槽上班第一天的感受
  4. 201621123065《JAVA程序设计》第11周学习总结
  5. Bundle Identifier
  6. 小试---EF5.0入门实例1
  7. WCF中的方法重载 实现
  8. android dp转px的公式_公式px到dp,dp到px android
  9. 如何获取注解中的值_如何在运行时利用注解信息
  10. php8更新,PHP 8 中新特性以及重大调整