您的位置:首页 > 其它

非递归二叉树的算法

2016-09-28 11:26 288 查看
  用递归来实现二叉树的算法代码非常简单,但同时也带来效率太低的弊端。为了提高效率我们会选择用非递归的方式来实现二叉树的算法。由于栈就是一种递归的思想,所以在实现非递归的算法时我们要借助栈来实现,主要的原理就是用栈来模拟递归的过程。下面在实现非递归算法的同时,也会将递归的算法给出做一个对比。

一、创建一颗二叉树(先序创建)
   以{1,2,3,'#','#',4,'#','#',5,6}为例:
   先创建左路,每创建一个结点就入栈,cur指向当前结点:



左路创建完毕之后用一个变量top保存栈顶元素3,然后将栈顶的元素3抛出:



然后再创建top的右子树且cur=top->_right,然后再重复上述操作,直到创建完毕。


非递归:
TreeNonR(const T* a, size_t size, const T& invalid)
{
Node* cur = NULL;
stack<Node*> s;
size_t index = 0;
while (index < size)
{
while (index < size&&a[index] != invalid)
{
if (index == 0)                     //根节点特殊处理
{
_root = new Node(a[index++]);
cur = _root;
}
else
{
cur->_left = new Node(a[index++]);
cur = cur->_left;
}
s.push(cur);
}
index++;
Node* top = s.top();
s.pop();
if (index < size&&a[index] != invalid)  //如果右子树的根节点不为空再创建
{
cur = top;
cur->_right = new Node(a[index++]);
cur = cur->_right;
s.push(cur);
}
}
}

递归:
BinaryTree(const T *array,size_t size,const T& invalid)
{
size_t index = 0;
_root=_CreatTree(array,size,index,invalid);
}

Node* _CreatTree(const T *array, size_t size, size_t& index, const T& invalid)
{
assert(array);
Node *root=NULL;
if (index < size&&array[index] != invalid)
{
root = new Node(array[index]);                                  //创建根节点
root->_left = _CreatTree(array,size,++index,invalid);           //递归创建左子树
root->_right= _CreatTree(array,size,++index,invalid);           //递归创建右子树
}
return root;
}


二、先序遍历



  如上图:用一个cur遍历左路,并且将遍历的每一个结点入栈,当左路为空的时候将栈顶元素出栈并保存,并且让cur指向这个出栈元素的右子树重复上述操作,直到栈&&cur同时为空,遍历结束。

非递归:
void PrevOderNonR()
{
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;  //将左路的最后一个结点的右子树的根节点设置为cur,重复上述过程
}
cout <<endl;
}

递归:
void PrevOder()     //前序遍历
{
_PrevPrint(_root);
cout << endl;
}
void _PrevPrint(Node *root)
{
Node *cur =root;
if (cur)
{
cout << cur->_data << " ";
_PrevPrint(cur->_left);
_PrevPrint(cur->_right);
}
}


3、中序遍历
中序遍历与先序遍历是一样的原理。
非递归:
void InOderNonR()
{
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;   //将左路的最后一个结点的右子树的根节点设置为cur,重复上述过程
}
cout << endl;
}

递归:
void InOder()      //中序遍历
{
_InPrint(_root);
cout << endl;
}
void _InPrint(Node *root)
{
Node *cur = root;
if (cur)
{
_InPrint(cur->_left);
cout << cur->_data << " ";
_InPrint(cur->_right);
}
}
4、后序遍历:

试想一下,非递归遍历一棵二叉树无非三种状态,遍历左路,遍历右子树的根节点,出栈。只要我们用一个标记flag来标记这三个状态。
flag=1,遍历左路,左路为空时将flag设置为2。
flag=2,遍历栈顶元素的右子树的根节点,若这个结点为空则flag=3,否则将这个遍历完这个结点后再将flag设置为1。
flag=3,表明栈顶元素的左右子树已经遍历完毕,将栈顶元素出栈,flag设置为2。
非递归:
//非递归后序遍历二叉树,设置3个状态来分别标记:遍历左路,将右子树的根节点入队,出栈
void PostOderNonR()
{
if (_root == NULL)
return;
Node* cur =_root;
int flag = 1;
stack<Node*> s;
s.push(_root);
while (!s.empty())
{
cur = s.top();
if (flag == 1)        //遍历左路
{
if (cur->_left == NULL)  //左路为空,切换状态到2
{
flag = 2;
}
else
{
cur = cur->_left;
s.push(cur);
}
}
else if (flag == 2)   //将当前结点的右子树的根节点入队
{
if (cur->_right== NULL) //如果右子树的根节点为空,表示该结点访问完毕,切换到出栈
flag = 3;
else
{
cur = cur->_right;
s.push(cur);   //将当前结点的右子树的根节点入队
flag = 1;      //切换状态到遍历左路
}
}
else
{
Node* top = s.top();
cout << top->_data<<" ";
s.pop();
while (!s.empty()&&s.top()->_right==top)  //将上一个已经访问完右子树的结点出栈
{
top = s.top();
s.pop();
cout << top->_data << " ";
}
flag = 2;        //切换状态到2
}
}
cout << endl;
}
递归:
void PostOder()      //后序遍历
{
_BackPrint(_root);
cout << endl;
}
void _BackPrint(Node *root)
{
Node *cur = root;
if (cur)
{
_PostPrint(cur->_left);
_PostPrint(cur->_right);
cout << cur->_data << " ";
}
}
5、求树的结点个数
非递归:
size_t Size()
{
size_t count = 0;
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
count++;        //遍历一个结点就让count++
s.push(cur);
cur = cur->_left;
}
Node * top = s.top();
s.pop();
cur = top->_right;
}
return count;
}

递归:
size_t Size()    //求结点个数
{
return _Size(_root);
}
size_t _Size(Node *root)
{
if (root == NULL)
return 0;
return 1 + _Size(root->_left) + _Size(root->_right);
}
6、求叶子结点的个数
非递归:
size_t Leaft()
{
size_t count = 0;
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
//如果左右子树都为空,则为叶子结点
if (cur->_left == NULL&&cur->_right == NULL)
count++;
s.push(cur);
cur = cur->_left;
}
Node * top = s.top();
s.pop();
cur = top->_right;
}
return count;
}
递归:
size_t Leaf()         //求叶子结点的个数
{
return _leaf(_root);
}
size_t _leaf(Node* root)
{
Node* cur = root;
if (NULL==cur)
return 0;
if (cur->_left == NULL&&cur->_right == NULL)      //如果左右子树都为空,则返回1
return 1;
return _leaf(cur->_left ) + _leaf(cur->_right);
}
7、查找一个结点
非递归:
Node* Find(const T& x)
{
Node* cur = _root;
stack<Node*> s;
while(cur||!s.empty())
{
while (cur)
{
if (cur->_data == x)         //如果找到则直接返回
return cur;
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cur = top->_right;
}
return NULL;
}

递归:
Node* Find(const T& x)
{
return _Find(_root,x);
}
Node* _Find(Node* root,const T& x)
{
if (root == NULL)
return NULL;
if (root->_data == x)
return root;
Node* cur = _Find(root->_left,x);
if (cur == NULL)
cur = _Find(root->_right,x);
return cur;
}
8、求树的深度
非递归:借助队列,一层一层的访问,每访问完一层,deep加一,直到队列为空,则求得深度。
size_t Depth()
{
if (_root == NULL)
return 0;
queue<Node*> q;
size_t deep = 0;
size_t  NodeNum = 1;      //统计有多少数据入过队
size_t  LeveLast = 1;      //标记正在访问的这层的最后一个数据的序号
size_t  VisitNum=0;       //统计已经出队的数据的个数
q.push(_root);
while (!q.empty())
{
Node* cur =q.front();
q.pop();
VisitNum++;
if (NULL != cur->_left)
{
q.push(cur->_left);
NodeNum++;
}
if (NULL != cur->_right)
{
q.push(cur->_right);
NodeNum++;
}
//如果以出队的个数等于这一层的最后一个数据的序号
if (LeveLast == VisitNum)
{
deep++;                //访问完一层就让深度加一
LeveLast = NodeNum;    //更新到下一层的最后一个数据的位置
}
}
return deep;
}

递归:
size_t Depth()          //求深度
{
return _Depth(_root);
}
size_t _Depth(Node *root)
{
Node *cur = root;
if (NULL == cur)
return 0;
size_t left = _Depth(cur->_left);
size_t right = _Depth(cur->_right);
return left > right ? left + 1 : right + 1;
}
9、求第i层的结点的个数

非递归:使用队列,将每一层的元素的个数都统计出来。

size_t GetLeveSize(size_t i)
{
//空树返回0
if (NULL == _root)
return 0;
//第0或第1层返回层号
if (i<=1)
return i;
queue<Node*> q;
q.push(_root);
size_t leve =1;              //标记层号
size_t  NodeNum = 1;          //统计有多少数据入过队
size_t  LeveLast = 1;         //标记正在访问的这层的最后一个数据的序号
size_t  VisitNum = 0;         //统计已经有多少数据已经出队
while (!q.empty())
{
Node* cur = q.front();
q.pop();
VisitNum++;
if (NULL != cur->_left)
{
q.push(cur->_left);
NodeNum++;
}
if (NULL != cur->_right)
{
q.push(cur->_right);
NodeNum++;
}

if (VisitNum == LeveLast)   //如果以出队的个数等于这一层的最后一个数据的序号
{
leve++;
if (leve == i)
break;
LeveLast = NodeNum;        //更新到下一层的最后一个数据的位置
}
}
//用已经入队过的数据个数减去已经出队的个数,得到要求的这一层的个数
return NodeNum - VisitNum;
}

递归:
size_t GetLeveNode(size_t k)
{
return _GetLeveNode(_root,k);
}
size_t _GetLeveNode(Node *root,size_t k)
{
if (root == NULL)
return 0;
if (k <= 1)
return k;
return _GetLeveNode(root->_left,k-1)+_GetLeveNode(root->_right,k-1);
}


非递归二叉树的完整代码:
#pragma once
#include<queue>
#include<stack>
using namespace std;

template<typename T>
struct TreeNode
{
T _data;
TreeNode<T> *_left;
TreeNode<T> *_right;
TreeNode(const T& data=T())
:_data(data)
, _left(NULL)
, _right(NULL)
{}
};

template<typename T>
class TreeNonR
{
typedef TreeNode<T> Node;
public:
TreeNonR()
:_root(NULL)
{}

/*TreeNonR(const T* a, size_t size, const T& invalid)
{
size_t index = 0;
stack<Node*> s;
Node* cur = _root;
int flag = 1;

while (index < size)
{
if (flag == 1)
{
if (a[index] == '#')
flag = 2;
else
{
cur= new Node(a[index]);
if (!s.empty())
{
s.top()->_left = cur;
}
else
{
_root = cur;
}
s.push(cur);
}
}
else if (flag==2)
{
if (a[index] == '#')
flag = 3;
else
{
cur = new Node(a[index]);
s.top()->_right = cur;
s.push(cur);
flag = 1;
}
}
else
{
Node* top = s.top();
s.pop();
while (!s.empty() && s.top()->_right == top)
{
top = s.top();
s.pop();
}
flag = 2;
index--;
}
index++;
}

}*/

TreeNonR(const T* a, size_t size, const T& invalid)
{
Node* cur = NULL;
stack<Node*> s;
size_t index = 0;
while (index < size)
{
while (index < size&&a[index] != invalid)
{
if (index == 0)                     //根节点特殊处理
{
_root = new Node(a[index++]);
cur = _root;
}
else
{
cur->_left = new Node(a[index++]);
cur = cur->_left;
}
s.push(cur);
}
index++;

Node* top = s.top();
s.pop();

if (index < size&&a[index] != invalid)  //如果右子树的根节点不为空再创建
{
cur = top;
cur->_right = new Node(a[index++]);
cur = cur->_right;
s.push(cur);
}
}
}

TreeNonR(const TreeNonR<T>& t)
{
Node* tmp = NULL;
Node* cur = t._root;
stack<Node*> s;
stack<Node*> s2;
while (cur || !s.empty())
{
while (cur)
{
if (cur == t._root)             //根节点特殊处理
{
tmp = new Node(cur->_data);
_root = tmp;
}
else
{
tmp->_left = new Node(cur->_data);
tmp = tmp->_left;
}
s.push(cur);
s2.push(tmp);
cur = cur->_left;
}

Node* top = s.top();
Node* top2 = s2.top();
s.pop();
s2.pop();

cur = top->_right;
if (cur)
{
tmp = top2;
tmp->_right= new Node(cur->_data);
tmp = tmp->_right;
cur = cur->_left;
}
}
}

TreeNonR<T>& operator=(TreeNonR<T>& t)
{
if (this != &t)
{
TreeNonR<T> tmp(t);
swap(_root,tmp._root);
}
return *this;
}

~TreeNonR()
{
Node* cur = _root;
stack<Node*> s;
stack<Node*> del;         //遍历一遍树,将每个结点存入del,最后释放del
while (cur || !s.empty())
{
while (cur)
{
del.push(cur);
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cur = top->_right;
}

while (!del.empty())    //释放del栈中的结点
{
Node* top = del.top();
del.pop();
delete top;
}
}

void PrevOderNonR()
{
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;  //将左路的最后一个结点的右子树的根节点设置为cur,重复上述过程
}
cout <<endl;
}

void InOderNonR()
{
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;   //将左路的最后一个结点的右子树的根节点设置为cur,重复上述过程
}
cout << endl;
}

//非递归后序遍历二叉树,设置3个状态来分别标记:遍历左路,将右子树的根节点入队,出栈
void PostOderNonR()
{
if (_root == NULL)
return;
Node* cur =_root;
int flag = 1;
stack<Node*> s;
s.push(_root);
while (!s.empty())
{
cur = s.top();
if (flag == 1)        //遍历左路
{
if (cur->_left == NULL)  //左路为空,切换状态到2
{
flag = 2;
}
else
{
cur = cur->_left;
s.push(cur);
}
}
else if (flag == 2)   //将当前结点的右子树的根节点入队
{
if (cur->_right== NULL) //如果右子树的根节点为空,表示该结点访问完毕,切换到出栈
flag = 3;
else
{
cur = cur->_right;
s.push(cur);   //将当前结点的右子树的根节点入队
flag = 1;      //切换状态到遍历左路
}
}
else
{
Node* top = s.top();
cout << top->_data<<" ";
s.pop();
while (!s.empty()&&s.top()->_right==top)  //将上一个已经访问完右子树的结点出栈
{
top = s.top();
s.pop();
cout << top->_data << " ";
}
flag = 2;        //切换状态到2
}
}
cout << endl;
}

size_t Size()
{
size_t count = 0;
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
count++;        //遍历一个结点就让count++
s.push(cur);
cur = cur->_left;
}

Node * top = s.top();
s.pop();
cur = top->_right;
}
return count;
}

size_t Depth()
{
if (_root == NULL)
return 0;
queue<Node*> q;
size_t deep = 0;
size_t  NodeNum = 1;      //统计有多少数据入过队
size_t  LeveLast = 1;      //标记正在访问的这层的最后一个数据的序号
size_t  VisitNum=0;       //统计已经出队的数据的个数
q.push(_root);
while (!q.empty())
{
Node* cur =q.front();
q.pop();
VisitNum++;
if (NULL != cur->_left)
{
q.push(cur->_left);
NodeNum++;
}

if (NULL != cur->_right)
{
q.push(cur->_right);
NodeNum++;
}

//如果以出队的个数等于这一层的最后一个数据的序号
if (LeveLast == VisitNum)
{
deep++;                //访问完一层就让深度加一
LeveLast = NodeNum;    //更新到下一层的最后一个数据的位置
}
}
return deep;
}

size_t GetLeveSize(size_t i)
{
//空树返回0
if (NULL == _root)
return 0;
//第0或第1层返回层号
if (i<=1)
return i;

queue<Node*> q;
q.push(_root);
size_t leve =1;              //标记层号
size_t  NodeNum = 1;          //统计有多少数据入过队
size_t  LeveLast = 1;         //标记正在访问的这层的最后一个数据的序号
size_t  VisitNum = 0;         //统计已经有多少数据已经出队
while (!q.empty())
{
Node* cur = q.front();
q.pop();
VisitNum++;
if (NULL != cur->_left)
{
q.push(cur->_left);
NodeNum++;
}

if (NULL != cur->_right)
{
q.push(cur->_right);
NodeNum++;
}

if (VisitNum == LeveLast)   //如果以出队的个数等于这一层的最后一个数据的序号
{
leve++;
if (leve == i)
break;
LeveLast = NodeNum;        //更新到下一层的最后一个数据的位置
}
}
//用已经入队过的数据个数减去已经出队的个数,得到要求的这一层的个数
return NodeNum - VisitNum;
}

size_t Leaft()
{
size_t count = 0;
Node* cur = _root;
stack<Node*> s;
while (cur || !s.empty())
{
while (cur)
{
//如果左右子树都为空,则为叶子结点
if (cur->_left == NULL&&cur->_right == NULL)
count++;
s.push(cur);
cur = cur->_left;
}
Node * top = s.top();
s.pop();
cur = top->_right;
}
return count;
}

Node* Find(const T& x)
{
Node* cur = _root;
stack<Node*> s;
while(cur||!s.empty())
{
while (cur)
{
if (cur->_data == x)         //如果找到则直接返回
return cur;
s.push(cur);
cur = cur->_left;
}

Node* top = s.top();
s.pop();
cur = top->_right;
}
return NULL;
}

protected:
Node *_root;
};


//后序遍历的另一种算法
void PostOderNonR()
{
if (_root == NULL)
return;
Node* cur = _root;
Node* prev = NULL;         //记录前一个访问的结点
stack<Node*> s;
while (cur||!s.empty())
{
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;
}
}
cout << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐