您的位置:首页 > 理论基础 > 数据结构算法

数据结构——二叉树

2017-09-19 23:15 316 查看

二叉树是数据结构的一个重要内容之一,那么对于我们这些学习编程的人来说,掌握二叉树的各种遍历(递归遍历和非递归遍历)是必不可少的,下面我们就分析一下,二叉树的各种遍历方法:

1首先得建立一个二叉树:

1.二叉树节点

struct BinaryTreeNode//二叉树节点
{
BinaryTreeNode* _left;
BinaryTreeNode* _right;
T _data;
BinaryTreeNode(const T data)
:_left(NULL)//二叉树左孩子
,_right(NULL)//右孩子
,_data(data)
{
}
};


2.造二叉树

BinaryTree(const T* a, size_t size, const T& invalid)//二叉树构造函数
:_root(NULL)
{
size_t index=0;
_root=CreatBinaryTree(a,size,index,invalid);
}


Node* CreatBinaryTree(const T* a,size_t size,size_t& index,const T& invalid)//制造二叉树(前序)
{
Node* root=NULL;
if(a[index]!=invalid&&index<size)
{
root=new Node(a[index]);//new一个根节点,先造根节点
root->_left=CreatBinaryTree(a,size,++index,invalid);//再造左节点
root->_right=CreatBinaryTree(a,size,++index,invalid);//再造右节点
}
return root;
}


3.遍历二叉树(递归)

①前序遍历,前序遍历是1.遍历根节点、2.遍历左节点、3.遍历有节点

void PrevOrder()//前序遍历
{
_PrevOrder(_root);//传根节点
cout<<endl;
}
void _PrevOrder(Node* T)
{
if(T==NULL)
return;
else
{
cout<<T->_data<<" ";//先访问根节点,在这里是直接输出
_PrevOrder(T->_left);//访问左节点
_PrevOrder(T->_right);//访问有节点
}
}


②中序遍历(递归),中序遍历和前序遍历类似,只不过是将访问顺序变为1.左节点、2.根节点、3.有节点

void InOrder()
{
_InOrder(_root);
cout<<endl;
}
void _InOrder(Node* T)
{
if(T==NULL)
return;
else
{
_InOrder(T->_left);
cout<<T->_data<<" ";
_InOrder(T->_right);
}
}
void PostOrder()
{
_PostOrder(_root);
cout<<endl;
}


③后序遍历,也不例外,1.访问左节点、2.访问右节点、3.访问根节点

void PostOrder()
{
_PostOrder(_root);
cout<<endl;
}
void _PostOrder(Node* T)
{
if(T==NULL)
return;
else
{
_PostOrder(T->_left);//访问左节点
_PostOrder(T->_right);//访问右节点
cout<<T->_data<<" ";//访问根节点
}
}


4.非递归遍历二叉树

①前序序访问二叉树



前序采用栈来处理,如图所示,先压1,然后出1,压 2,3,这里先压3,后压2,是栈的特点,后进先出所以先出2,压 5、 4;然后出4,压9、 8;出 8,然后出9、出 5、出3;压 7 、6,出7,出6;

得到1,2,4,8,9,5,3,7,6;

void PrevOrder_NonR()
{
Node* T = _root;
stack<Node*> s;
while(T!=NULL||!s.empty())
{
if(T!=NULL)
{
cout<<T->_data<<" ";
s.push(T);
T=T->_left;
}
else
{   T=s.top();
s.pop();
T=T->_right;
}
}
cout<<endl;
}


②中序遍历

中序遍历和前序是一样的采用栈来处理,只不过是先访问左节点,然后根节点、右节点

void InOrder_NonR()
{
Node* T = _root;
stack<Node*> s;
if(T==NULL)
return;
else
{
Node* temp=T;
while(!s.empty()||temp!=NULL)
{
if(temp!=NULL)
{
s.push(temp);//先将所有的走节点压进去
temp=temp->_left;
}
else
{
temp=s.top();//访问节点
cout<<temp->_data<<" ";//记录
s.pop();//出栈
temp=temp->_right;//判断有节点;
}
}
cout<<endl;
}
}


③后序访问

后序访问就比较复杂了,我解决他的办法是采用俩个栈,首先要说明的是:后序和前序是有关系的,来对比一下,前序:1.根节点、2.左节点、3.右节点后续:1.左节点、2、右节点、3.根节点。那么我们可以采用类似的方法:处理先以1.根节点、2.右节点、3.左节点 这种方式遍历并将遍历结果压入output栈中,然后出栈退栈,既得到1.左节点、2.右节点、3.根节点。

void PostOrder_NonR()
{
Node* T = _root;
stack<Node*> s,output;
while(T!=NULL||!s.empty())
{
if(T!=NULL)
{
s.push(T);//先根节点
output.push(T);//入栈
T=T->_right;//右节点
}
else
{
T=s.top();
s.pop();
T=T->_left;//走左节点
}
}
while(output.size()!=0)
{
Node* temp = output.top();
cout<<temp->_data<<" ";
output.pop();
}
cout<<endl;
}


④层序访问二叉树

#下图是层序访问的结构图





有上述结构图可以看出这种访问方式,与队列是一模一样的,所以我们采用队列的方式解决。1.现将1入队,先记录1 然后出队(访问),通过1来使得2、3入队;然后2,记录后2出队,4 、5入队;然后3,记录后出队,6 、7入队….,就这样一直走下去直到队列为空为止。

void LevelOrder()
{
Node* root = _root;
queue<Node*> q;
if(root)
q.push(root);//先使得第一个节点入队
while(q.size()!=0)
{
Node* temp=q.front();//记录
q.pop();//出队
cout<<temp->_data<<" ";
if(temp->_left!=NULL)//先左
q.push(temp->_left);
if(temp->_right!=NULL)//后右
q.push(temp->_right);
}
cout<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 二叉树