BinaryTreesTravel
代码来自张铭的数据结构与算法
此篇文章仅为记录代码
略简略,不易阅读
以下有7种周游算法
深度优先搜索
- 前序递归/非递归
. 中序递归/非递归
. 后序递归/非递归
广度优先搜索
仅供参考
#include<iostream>
#include<stack>
using namespace std;
//空间时间复杂度均为O(n)
//二叉树结点
template<class T>
class BinaryTreeNode{
friend class BinaryTree<T>;
private:
T info;
public:
BinaryTreeNode();
BinaryTreeNode(const T& ele);
BinaryTreeNode(const T& ele,BinaryTreeNode<T>*l,BinaryTreeNode<T>*r);//子树构造结点
T value()const;//返回当前结点的数据
BinaryTreeNode<T>* leftChild()const;//返回当前结点的左子树
BinaryTreeNode<T>* rightChild()const;//返回当前结点的右子树
void setLeftChild(BinaryTreeNode<T>*);//设置当前结点的左子树
void setRightChild(BinaryTreeNode<T>*);//设置当前结点的右子树
void setValue(const T&val);//设置当前结点的值
bool isLeaf()const;//判断当前结点是否为叶节点
BinaryTreeNode<T>& operator = (const BinaryTreeNode<T>& Node)//重载赋值操作符
}
//二叉树
template<class T>
class BinaryTree{
private:
BinaryTreeNode<T>* root;//根节点
public:
BinaryTree(){root=NULL;};
~BinaryTree(){deleteBinaryTree(root);};
bool isEmpty()const;//判断二叉树是否为空数
BinaryTreeNode<T>* Root(){return root;};//返回二叉树根节点
BinaryTreeNode<T>* Parent(BinaryTreeNode<T>* current);//返回当前结点的父节点
BinaryTreeNode<T>* leftSibling(BinaryTreeNode<T>* current);//返回当前结点的左兄弟
BinaryTreeNode<T>* rightSibling(BinaryTreeNode<T>* current);//返回当前结点的右兄弟
void createTree(const T& info,BinaryTree<T>&leftTree,BinaryTree<T>&rightTree);//创建新树
void preOrder(BinaryTreeNode<T>* root);//前序周游二叉树
void inOrder(BinaryTreeNode<T>* root);//中序周游二叉树
void postOrder(BinaryTreeNode<T>* root);//后序周游二叉树
void levelOrder(BinaryTreeNode<T>* root);//按层次周游二叉树
void deleteBinaryTree(BinaryTreeNode<T>* root);//删除二叉树
}
//深度优先周游二叉树
//递归版
//前序周游
template<class T>
void BinaryTree<T>::preOrder(BinaryTreeNode<T>* root)
{
if(root!=NULL){
visit(root->value());
preOrder(root->leftChild());
preOrder(root->rightchild());
}
}
//中序周游
template<class T>
void BinaryTree<T>::inOrder(BinaryTreeNode<T>* root)
{
if(root!=NULL){
inOrder(root->leftChild());
visit(root->value());
inOrder(root->rightchild());
}
}
//后序周游
template<class T>
void BinaryTree::postOrder(BinaryTreeNode<T>* root)
{
if(root!=NULL){
postOrder(root->leftChild());
postOrder(root->rightchild());
visit(root->value());
}
}
//非递归版
//栈存所有非空右子树的结点
template<class T>
void BinaryTree::preOrderWithoutRecursion(BinaryTreeNode<T>* root)
{
stack<BinaryTreeNode<T>* > aStack;
BinaryTreeNode<T>* point=root;
aStack.push(NULL);//栈底监视哨
while(point){
visit(point->value());//访问当前结点
if(point->rightChild()!=NULL)//非空右孩子入栈
{
aStack.push(point->rightChild());
}
if(point->leftChild()!=NULL)
{
visit(point->value());//左路下降
point=point->leftChild();
}
else{ //左子树访问完毕,转向访问右子树
point=aStack.top(); //获得栈顶元素
aStack.pop(); //栈顶元素退栈
}
}
}
//中序,存的是根节点
template<class T>
void BinaryTree::inOrderWithoutRecursion(BinaryTreeNode<T>* root)
{
stack<BinaryTreeNode<T>*> aStack;
BinaryTreeNode<T>* point=root;
while(!aStack.empty()||point)
{
if(point)
{
aStack.push(point);//当前指针入栈(根节点)
point=point->leftChild();//左路下降
}
else
{
point=aStack.top();//左子树访问完毕,转向访问右子树,获得栈顶元素
aStack.pop();//栈顶元素退栈
visit(point->value());//访问当前结点
point=point->rightChild();//指针指向右孩子
}
}
}
//后序
enum Tags{left,right};//定义枚举类型标志位
template<class T>
class StackElement{
public:
BinaryTreeNode* point;//指向树结点的指针(各个根节点)
Tags tag; //标志位
}
template<class T>
void BinaryTree::postOrderWithoutRecursion(BinaryTreeNode<T>* root)
{
StackElement<T> element;
stack<StackElement<T>> aStack;
BinaryTreeNode<T>* point;
if(root==NULL) //如果是空树则返回
return;
else
point=root;
while(!aStack.empty()||point)
{
while(point!=NULL) //如果当前指针非空则压栈并下降到最左子树
{
element.point=point;
element.tag=left; //置标志位为left。进入左子树
aStack.push(element);
point=point->leftChild();
}
element=aStack.top(); //获得栈顶元素
aStack.pop(); //栈顶元素退栈
point=element.point;
if(element.tag==left) //如果从左子树返回
{
element.tag=right; //置标志位为right,进入右子树
aStack.push(element);
point=point->rightChild();
}
else
{ //如果从右子树返回,
visit(point->value()); //访问当前结点
point=NULL; //置point指针为空,以继续弹栈
}
}
}
//时间O(n)
//最大存储空间(有数目最多的一层决定)(n+1)/2
//广度优先周游二叉树
//一层一层的按次序搜下去
template<class T>
void BinaryTree<T>::levelOrder(BinaryTreeNode<T>* root)
{
using std::queue;
queue<BinaryTreeNode<T>*> aQueue;
BinaryTreeNode<T>* point=root;
if(point)
aQueue.push(point); //根节点入队列
while(!aQueue.empty()) //队列非空
{
point=aQueue.front(); //获得队列首节点
aQueue.pop(); //当前结点出队列
visit(point->value()); //访问当前结点
if(point->leftChild()!=NULL)
aQueue.push(point->leftChild());//左子树进队列
if(point->rightChild()!=NULL)
aQueue.push(point->rightChild());//右子树进队列
}
}