数据结构 — 二叉树的基本操作(递归实现)
2017-05-08 22:10
513 查看
二叉树
我们直接切入主题相信大家都应该知道什么叫二叉树吧。二叉树里面有几个常见的操作,他们分别是构造二叉树,前序遍历,中序遍历,后序遍历,还有求树的叶子结点,树的深度,树中第K层的节点个数,树中结点的个数,以及在树中查找一个结点。
注意这里大部分都是用递归实现的!! (也就是这篇文章是入门的,非递归我还会写一个博客)
好了现在开始,我们一个一个的解决他们吧。
科普:
所谓的前序遍历,中序遍历,后序遍历分别代表着什么?
template<class T> struct BinaryTreeNode { BinaryTreeNode<T>* _letf; BinaryTreeNode<T>* _right; T _data; BinaryTreeNode(const T& x) :_letf(NULL) , _right(NULL) , _data(x) {} };
这是我定义的一个二叉树的结点。
接下来 typedef BinaryTreeNode<T> Node;
也就是接下来我们看到的每一个Node表示的就是一个二叉树的结点。
构造二叉树
在这里invalid就是所谓的非法值,而index就是数组的下标。比如:int array[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
这里的invalid就是'#'.
BinaryTree() :_root(NULL) {} BinaryTree(T* a, size_t n, const T& invalid) { size_t index = 0; _root = CreateTree(a, n, invalid, index); } //注意这里的index 要使用引用, 若是没有使用 上一层递归里面的++index 对上一层没有任何影响. //构建二叉树表 Node* CreateTree(T* a, size_t n, const T& invalid, size_t& index) { Node* root = NULL; if (index < n && a[index] != invalid) { root = new Node(a[index]); root->_letf = CreateTree(a, n, invalid, ++index); root->_right = CreateTree(a, n, invalid, ++index); } return root; }
在这里我用一个图来还原实现过程,因为涉及递归那么我就少说话多画图:
这里呢,按照代码一步一步的在图中移动,相信你会理解的,毕竟我这么笨的人都理解了。
二叉树的前序遍历
//前序遍历 void _prevOrder(Node* root) { if (root == NULL) { return ; } cout << root->_data << " "; _prevOrder(root->_letf); _prevOrder(root->_right); }
图解:
二叉树的中序遍历
//中序遍历 void _InOrder(Node* root) { if (root == NULL) { return; } _InOrder(root->_letf); cout << root->_data << " "; _InOrder(root->_right); }
二叉树的后序遍历
//后序遍历 void PosOrder() { return _PosOrder(_root); } void _PosOrder(Node* root) { if (root == NULL) { return; } _PosOrder(root->_letf); _PosOrder(root->_right); cout << root->_data <<" "; }
图解:
二叉树的层序遍历
void _LevelOrder(Node* root) { queue<Node*> q; if (root != NULL) { q.push(root); while (!q.empty()) { Node* front = q.front(); cout << front->_data << " "; if (front->_letf) { q.push(front->_letf); } if (front->_right) { q.push(front->_right); } q.pop(); } } }
这里层序遍历就是少数没办法用递归实现的函数,在这里它借助了队列-/-,具体的过程:
二叉树叶子结点个数
在这里就要对问题进行分解:1.这里所有的叶子结点其实就是 左孩子里面的叶子结点个数+右孩子里面的叶子节点个数
2.当你把每一个结点看做根节点时,一层一层的把叶子结点总数就统计出来了
(这里当你为叶子节点是你只返回1就好)
size_t _LeafSize(Node* root) { if (root == NULL) { return 0; } if (root->_letf == NULL &&root->_right == NULL) { return 1; } size_t i = _LeafSize(root->_letf); size_t j = _LeafSize(root->_right); return i + j; }
二叉树深度
size_t _Depth(Node* root) { if (root == NULL) { return 0; } else { size_t i = _Depth(root->_letf); size_t j = _Depth(root->_right); if (i > j) { return i + 1; } else { return j + 1; } } }
图解:
二叉树总结点数
这里也是把主问题分解成无数个子问题:左孩子总结点数 + 1 + 右孩子总结点
2.当你使用递归时也就是每一个结点都可以看成根节点,所以就是每个结点的左孩子+1+右孩子总结点个数.
size_t _Size(Node* root) { if (root == NULL) { return 0; } size_t i = _Size(root->_letf); size_t j = _Size(root->_right); return i + j + 1; }
二叉树第K层节点个数
size_t _GetKLevel(Node* root, size_t k) { if (root == NULL) { return 0; } if (k == 1) { return 1; } return _GetKLevel(root->_letf, k - 1) + _GetKLevel(root->_right, k - 1); }
二叉树查找节点
Node* _find(Node* root,const T& x) { if (root == NULL) { return NULL; } if (root->_data == x) { return root; } Node* ret = _find(root->_letf, x); if (ret) { return ret; } return _find(root->_right, x); }
拷贝构造:
BinaryTree(const BinaryTree<T>& t) { _root = _Copy(t._root); } Node* _Copy(Node* root) { if (NULL == root) { return NULL; } Node* newroot = new Node(root->_data); newroot->_letf = _Copy(root->_letf); newroot->_right = _Copy(root->_right); return newroot; }
这里和树的创建很相似,可以思考一下
赋值运算符重载
BinaryTree<T>& operator = (const BinaryTree<T> t) { if (this != &t) { swap(t._root, _root); return *this; } }
或许你会觉得意外代码为什么这么简单,我们的参数采用的是值传递,所以当你传参进来的时候会创建一个跟你一模一样的局部变
量,这个局部变量在函数调用结束后就被销毁了,然后现在我们让局部变量的根节点和我们的根节点交换,现在我们的根节点指向
的就是我们需要赋值成的那棵树,而局部变量的根节点指向的使我们以前的内容,现在刚刚好在作用域结束后局部变量帮我们释放
空间,而我们现在的根节点_root,已经指向我想要的内容了,不知道大家有没有明白一点呢。
实现代码:
#include<iostream>
#include<Windows.h>
#include<queue>
using namespace std;
template<class T> struct BinaryTreeNode { BinaryTreeNode<T>* _letf; BinaryTreeNode<T>* _right; T _data; BinaryTreeNode(const T& x) :_letf(NULL) , _right(NULL) , _data(x) {} };
template<class T>
class BinaryTree
{
typedef BinaryTreeNode<T> Node;
public:
BinaryTree()
:_root(NULL)
{}
BinaryTree(T* a, size_t n, const T& invalid)
{
size_t index = 0;
_root = CreateTree(a, n, invalid, index);
}
BinaryTree(const BinaryTree<T>& t)
{
_root = _Copy(t._root);
}
BinaryTree<T>& operator = (const BinaryTree<T> t)
{
if (this != &t)
{
swap(t._root, _root);
}
}
//前序遍历
void PrevOrder()
{
return _prevOrder(_root);
}
//中序遍历
void InOrder()
{
return _InOrder(_root);
}
//后序遍历
void PosOrder()
{
return _PosOrder(_root);
}
//层序遍历
void LevelOrder()
{
return _LevelOrder(_root);
}
//尺寸大小
size_t Size()
{
return _Size(_root);
}
//叶子结点
size_t LeafSize()
{
return _LeafSize(_root);
}
//第K个结点的节点个数
size_t GetKLevel(size_t k)
{
return _GetKLevel(_root, k);
}
//树深度
size_t Depth()
{
return _Depth(_root);
}
//查找
Node* find(const T& x)
{
return _find(_root,x);
}
protected:
//第K层的节点数
size_t _GetKLevel(Node* root, size_t k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return _GetKLevel(root->_letf, k - 1) + _GetKLevel(root->_right, k - 1);
}
//查找
Node* _find(Node* root,const T& x) { if (root == NULL) { return NULL; } if (root->_data == x) { return root; } Node* ret = _find(root->_letf, x); if (ret) { return ret; } return _find(root->_right, x); }
//深度
size_t _Depth(Node* root) { if (root == NULL) { return 0; } else { size_t i = _Depth(root->_letf); size_t j = _Depth(root->_right); if (i > j) { return i + 1; } else { return j + 1; } } }
//叶子结点求解
size_t _LeafSize(Node* root) { if (root == NULL) { return 0; } if (root->_letf == NULL &&root->_right == NULL) { return 1; } size_t i = _LeafSize(root->_letf); size_t j = _LeafSize(root->_right); return i + j; }
//层序遍历
void _LevelOrder(Node* root) { queue<Node*> q; if (root != NULL) { q.push(root); while (!q.empty()) { Node* front = q.front(); cout << front->_data << " "; if (front->_letf) { q.push(front->_letf); } if (front->_right) { q.push(front->_right); } q.pop(); } } }
//总成员数
size_t _Size(Node* root)
{
if (root == NULL)
{
return 0;
}
size_t i = _Size(root->_letf);
size_t j = _Size(root->_right);
return i + j + 1;
}
//后序遍历
void _PosOrder(Node* root)
{
if (root == NULL)
{
return;
}
_PosOrder(root->_letf);
_PosOrder(root->_right);
cout << root->_data <<" ";
}
//中序遍历
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_letf);
cout << root->_data << " ";
_InOrder(root->_right);
}
//前序遍历
void _prevOrder(Node* root)
{
if (root == NULL)
{
return ;
}
cout << root->_data << " ";
_prevOrder(root->_letf);
_prevOrder(root->_right);
}
//注意这里的index 要使用引用, 若是没有使用 上一层递归里面的++index 对上一层没有任何影响.
Node* _Copy(Node* root)
{
if (NULL == root)
{
return NULL;
}
Node* newroot = new Node(root->_data);
newroot->_letf = _Copy(root->_letf);
newroot->_right = _Copy(root->_right);
return newroot;
}
Node* CreateTree(T* a, size_t n, const T& invalid, size_t& index)
{
Node* root = NULL;
if (index < n && a[index] != invalid)
{
root = new Node(a[index]);
root->_letf = CreateTree(a, n, invalid, ++index);
root->_right = CreateTree(a, n, invalid, ++index);
}
return root;
}
protected:
Node* _root;
size_t index;
size_t invalid;
};
void Test1()
{
int array[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
BinaryTree<int> t1(array, sizeof(array) / sizeof(array[0]), '#');
BinaryTree<int> t2(t1);
//t1.PrevOrder();
//t1.InOrder();
//t1.PosOrder();
//cout<<t1.Size()<<" ";
//t1.LevelOrder();
//cout<<t1.LeafSize();
//cout<<t1.Depth();
//cout<<(t1.find(3));
//cout<<t1.GetKLevel(3);
}
相关文章推荐
- 【数据结构】二叉树基本操作的程序实现
- 二叉树的基本操作-递归实现
- 二叉树的建立和基本操作(递归实现)
- 数据结构第四次作业(二叉树的基本操作实现)
- 【 数据结构】实现二叉树以及其基本操作
- c++模板实现二叉树,线索化,线索化遍历,非递归遍历及一些基本操作
- 算法与数据结构-二叉树的基本操作C语言实现
- javascript实现数据结构: 树和二叉树,二叉树的遍历和基本操作
- 二叉树的递归遍历非递归遍历以及其他二叉树的相关操作实现(数据结构)
- 数据结构面试之五—二叉树的常见操作(递归实现部分)
- 第4章第3节 二叉树的基本操作(非递归实现)
- 二叉树的基本操作实现(递归和非递归)
- 二叉树的建立(非递归建立与定义建立)与基本操作(广度和深度遍历,求叶子树高)实现
- 数据结构:二叉树的基本操作(JAVA实现)
- 第4章第2节 二叉树的基本操作(递归实现)
- 数据结构学习之单向链表的基本操作(非递归实现)
- C语言实现二叉树的递归和非递归算法的基本操作
- 二叉树的基本操作(含遍历算法非递归实现全收录)
- 数据结构——排序/搜索二叉树(非递归)的基本操作实现
- 数据结构学习之双向循环链表的基本操作(非递归实现)