1.二叉树的特点:
二叉树的特点:
1.每个节点最多有两棵子树,即二叉树中不存在度大于2的节点(分支数最大不超过2)
2.二叉树的子树有左右之分,也就是说二叉树是有序的。
2.二叉树的基本操作(递归):
以下面的二叉树为例:
1.求二叉树的节点个数:
思路:
(1)root 为空(整个二叉树的根节点为空) return 0;
(2)root不为空 —>左子树的节点个数 + 右子树的节点个数 + 1(当前节点)
代码如下:
size_t _Size(Node* root)
{
if (root == NULL)
{
return 0;
}
return _Size(root->_left) + _Size(root->_right) + 1;
}
代码如下:
size_t _LeafSize(Node* root)
{
if (root == 0)
{
return 0;
}
if (NULL == root->_left && NULL == root->_right)
{
return 1;
}
return _LeafSize(root->_left) + _LeafSize(root->_right);
}
代码如下:
size_t _GetKLevel(Node* root, size_t k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return _GetKLevel(root->_left, k - 1) + _GetKLevel(root->_right, k - 1);
}
代码如下:
size_t _Depth(Node* root)
{
if (NULL == root)
{
return 0;
}
if (NULL == root->_left && NULL == root->_right)
{
return 1;
}
size_t leftDepth = _Depth(root->_left);
size_t rightDepth = _Depth(root->_right);
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
代码如下:
Node* _Find(Node* root, const T& x)
{
if (NULL == root)
{
return NULL;
}
if (root->_data == x)
{
return root;
}
Node* ret = _Find(root->_left, x);
if (ret)
{
return ret;
}
return _Find(root->_right, x);
}
递归算法的前序遍历的图解:
注明:紫颜色标记左子树的路径、蓝颜色标记返回路径、红色标记右子树的路径。
这里只画出了前序遍历的调用过程,而中序和后序遍历是相似的过程。
全部代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<queue>
//二叉树节点的定义
template<class T>
struct BinaryTreeNode
{
BinaryTreeNode(const T& data)
:_data(data)
, _left(NULL)
, _right(NULL)
{}
T _data;
BinaryTreeNode<T>* _left;
BinaryTreeNode<T>* _right;
};
//定义二叉树
template<class T>
class BinaryTree
{
typedef BinaryTreeNode<T> Node;
public:
//创建二叉树
BinaryTree(T* arr, size_t n, const T& invalid)
{
size_t index = 0;
_root = _CreatBinaryTree(arr, n, invalid, index);
}
BinaryTree()
:_root(NULL)
{}
//拷贝构造函数
BinaryTree(const BinaryTree<T>& bt)
{
_root = _CopyBinaryTree(bt._root);
}
//赋值运算符的重载
BinaryTree<T>& operator=(const BinaryTree<T>& bt)
{
if (this != &bt)
{
this->~BinaryTree();//释放旧空间
_root = _CopyBinaryTree(bt._root);
}
return *this;
}
//先序遍历
void PreOrder()
{
_PreOrder(_root);
cout << endl;
}
//中序遍历
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//后序遍历
void PostOrder()
{
_PostOrder(_root);
cout << endl;
}
//层序遍历
void LevelOrder()
{
queue<Node*> q;
if (_root)
{
q.push(_root);
}
while (!q.empty())
{
Node* front = q.front();
cout << front->_data << " ";
if (front->_left)
{
q.push(front->_left);
}
if (front->_right)
{
q.push(front->_right);
}
q.pop();
}
}
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);
}
//查找值为x的节点
Node* Find(const T& x)
{
return _Find(_root, x);
}
~BinaryTree()
{
_Destroy(_root);
}
protected:
Node* _CopyBinaryTree(Node* root)
{
if (NULL == root)
{
return NULL;
}
Node* newRoot = new Node(root->_data);//拷贝根节点
newRoot->_left = _CopyBinaryTree(root->_left);
newRoot->_right = _CopyBinaryTree(root->_right);
return newRoot;
}
Node* _Find(Node* root, const T& x)
{
if (NULL == root)
{
return NULL;
}
if (root->_data == x)
{
return root;
}
Node* ret = _Find(root->_left, x);
if (ret)
{
return ret;
}
return _Find(root->_right, x);
}
size_t _Depth(Node* root)
{
if (NULL == root)
{
return 0;
}
if (NULL == root->_left && NULL == root->_right)
{
return 1;
}
size_t leftDepth = _Depth(root->_left);
size_t rightDepth = _Depth(root->_right);
return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
size_t _GetKLevel(Node* root, size_t k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return _GetKLevel(root->_left, k - 1) + _GetKLevel(root->_right, k - 1);
}
size_t _LeafSize(Node* root)
{
if (root == 0)
{
return 0;
}
if (NULL == root->_left && NULL == root->_right)
{
return 1;
}
return _LeafSize(root->_left) + _LeafSize(root->_right);
}
Node* _CreatBinaryTree(T* arr, size_t n, const T& invalid, size_t& index)
{
Node* root = NULL;
if (index < n && arr[index] != invalid)
{
root = new Node(arr[index]);
root->_left = _CreatBinaryTree(arr, n, invalid, ++index);
root->_right = _CreatBinaryTree(arr, n, invalid, ++index);
}
return root;
}
void _Destroy(Node* root)
{
if (root)
{
_Destroy(root->_left);
_Destroy(root->_right);
delete root;
root = NULL;
}
}
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 << " ";
}
}
size_t _Size(Node* root)
{
if (root == NULL)
{
return 0;
}
return _Size(root->_left) + _Size(root->_right) + 1;
}
private:
Node* _root;
};
测试代码如下:
void Test()
{
int array[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
BinaryTree<int> bt(array, sizeof(array) / sizeof(int), '#');
/*bt.PreOrder();
bt.InOrder();
bt.PostOrder();
bt.LevelOrder();*/
cout << bt.Size() << endl;
/*cout << bt.LeafSize() << endl;
cout << bt.GetKLevel(3) << endl;
cout << bt.GetKLevel(2) << endl;
cout << bt.GetKLevel(1) << endl;
cout << bt.GetKLevel(8) << endl;*/
cout << bt.Depth() << endl;
BinaryTreeNode<int>* ret = bt.Find(6);
if (ret)
{
cout << ret->_data << endl;
}
}
void Test2()
{
int array[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
BinaryTree<int> bt(array, sizeof(array) / sizeof(int), '#');
bt.PreOrder();
int array2[15] = { 1, 2, '#', 3, '#', '#', 4, 5, '#', 6, '#', 7, '#', '#', 8 };
BinaryTree<int> bt2(array2, sizeof(array2) / sizeof(int), '#');
bt2.PreOrder();
bt2 = bt;
bt2.PreOrder();
}
int main()
{
Test2();
return 0;
}
3.前序、中序及后序的非递归遍历:
前序遍历的代码如下:
//先序遍历(非递归)
void PreOrderR()
{
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
//将左支路的节点均压栈
while (cur)
{
cout << cur->_data << " ";
s.push(cur);
cur = cur->_left;
}
//栈中保存的节点的左子树都已访问过
//只剩下栈中节点的右子树没有访问
Node* top = s.top();
s.pop();
cur = top->_right;//循环的子问题
}
}
中序遍历的代码如下:
//中序遍历的非递归
void InOrderR()
{
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
//栈中节点的左子树已经遍历完
//栈中节点自身和右子树还没有遍历
Node* top = s.top();
cout << top->_data << " ";
s.pop();
cur = top->_right;
}
cout << endl;
}
后序遍历的两种方法:
第一种方法:
后序遍历的非递归算法
使用一个栈index来标记栈s的栈顶元素出现的次数,并且栈index与栈s同入栈和同出栈
void PostOrderR()
{
Node* cur = _root;
stack<Node*> s;
stack<int> index;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
index.push(0);//第一次出现在栈顶时标记为0
cur = cur->_left;
}
if (index.top() == 1)
{
Node* top = s.top();
cout << top->_data << " ";
s.pop();
index.pop();
}
else
{
Node* top = s.top();//第二次出现
index.top() = 1;//将其设置为1
cur = top->_right;//循环的子问题
}
}
}
第二种方法:
//后序遍历的非递归算法
//使用一个标记位:每次访问一个节点,则更新标记位
void PostOrderR()
{
Node* cur = _root;
stack<Node*> s;
Node* prev = NULL;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
if (NULL == top->_right || top->_right == prev)
{
cout << top->_data << " ";
s.pop();
prev = top;
}
else
{
cur = top->_right;//循环的子问题
}
}
}