树的遍历三种算法
❶ 编程中的树的遍历分为哪三种
先根遍历、中根遍历、后根遍历
❷ 二叉树的三种遍历,先,中,后遍历
二叉树的遍历分为以下三种:
先序遍历:遍历顺序规则为【根左右】
中序遍历:遍历顺序规则为【左根右】
后序遍历:遍历顺序规则为【左右根】
什么是【根左右】?就是先遍历根,再遍历左孩子,最后遍历右孩子;
举个例子,看下图(图从网上找的):
先序遍历:ABCDEFGHK
中序遍历:BDCAEHGKF
后序遍历:DCBHKGFEA
以中序遍历为例:
中序遍历的规则是【左根右】,我们从root节点A看起;
此时A是根节点,遍历A的左子树;
A的左子树存在,找到B,此时B看做根节点,遍历B的左子树;
B的左子树不存在,返回B,根据【左根右】的遍历规则,记录B,遍历B的右子树;
B的右子树存在,找到C,此时C看做根节点,遍历C的左子树;
C的左子树存在,找到D,由于D是叶子节点,无左子树,记录D,无右子树,返回C,根据【左根右】的遍历规则,记录C,遍历C的右子树;
C的右子树不存在,返回B,B的右子树遍历完,返回A;
至此,A的左子树遍历完毕,根据【左根右】的遍历规则,记录A,遍历A的右子树;
A的右子树存在,找到E,此时E看做根节点,遍历E的左子树;
E的左子树不存在,返回E,根据【左根右】的遍历规则,记录E,遍历E的右子树;
E的右子树存在,找到F,此时F看做根节点,遍历F的左子树;
F的左子树存在,找到G,此时G看做根节点,遍历G的左子树;
G的左子树存在,找到H,由于H是叶子节点,无左子树,记录H,无右子树,返回G,根据【左根右】的遍历规则,记录G,遍历G的右子树;
G的右子树存在,找到K,由于K是叶子节点,无左子树,记录K,无右子树,返回G,根据【左根右】的遍历规则,记录F,遍历F的右子树;
F的右子树不存在,返回F,E的右子树遍历完毕,返回A;
至此,A的右子树也遍历完毕;
最终我们得到上图的中序遍历为BDCAEHGKF,无非是按照遍历规则来的;
根据“中序遍历”的分析,相信先序遍历和后序遍历也可以轻松写出~
❸ 树的三种主要遍历方法是什么啊,谢谢了
分别为先根遍历(或前序遍历)、中根(或中序)遍历、后根(或后序)遍历。三种遍历方法的定义如下:
先根遍历 若需遍历的二叉树为空,执行空操作;否则,依次执行下列操作:
①访问根结点;
②先根遍历左子树;
③先根遍历右子树。
中根遍历 若需遍历的二叉树为空,执行空操作,否则,依次执行下列操作:
①中根遍历左子树;②访问根结点;③中根遍右子树。
后根遍历 若需遍历的二叉树为空,执行空操作,否则,依次执行下列操作:
①后根遍历左子树。②后根遍历右子树。③访问根结点。
❹ 二叉树的层次遍历算法
二叉树的层次遍历算法有如下三种方法:
给定一棵二叉树,要求进行分层遍历,每层的节点值单独打印一行,下图给出事例结构:
之后大家就可以自己画图了,下面给出程序代码:
[cpp] view plain
void print_by_level_3(Tree T) {
vector<tree_node_t*> vec;
vec.push_back(T);
int cur = 0;
int end = 1;
while (cur < vec.size()) {
end = vec.size();
while (cur < end) {
cout << vec[cur]->data << " ";
if (vec[cur]->lchild)
vec.push_back(vec[cur]->lchild);
if (vec[cur]->rchild)
vec.push_back(vec[cur]->rchild);
cur++;
}
cout << endl;
}
}
最后给出完成代码的测试用例:124##57##8##3#6##
[cpp] view plain
#include<iostream>
#include<vector>
#include<deque>
using namespace std;
typedef struct tree_node_s {
char data;
struct tree_node_s *lchild;
struct tree_node_s *rchild;
}tree_node_t, *Tree;
void create_tree(Tree *T) {
char c = getchar();
if (c == '#') {
*T = NULL;
} else {
*T = (tree_node_t*)malloc(sizeof(tree_node_t));
(*T)->data = c;
create_tree(&(*T)->lchild);
create_tree(&(*T)->rchild);
}
}
void print_tree(Tree T) {
if (T) {
cout << T->data << " ";
print_tree(T->lchild);
print_tree(T->rchild);
}
}
int print_at_level(Tree T, int level) {
if (!T || level < 0)
return 0;
if (0 == level) {
cout << T->data << " ";
return 1;
}
return print_at_level(T->lchild, level - 1) + print_at_level(T->rchild, level - 1);
}
void print_by_level_1(Tree T) {
int i = 0;
for (i = 0; ; i++) {
if (!print_at_level(T, i))
break;
}
cout << endl;
}
void print_by_level_2(Tree T) {
deque<tree_node_t*> q_first, q_second;
q_first.push_back(T);
while(!q_first.empty()) {
while (!q_first.empty()) {
tree_node_t *temp = q_first.front();
q_first.pop_front();
cout << temp->data << " ";
if (temp->lchild)
q_second.push_back(temp->lchild);
if (temp->rchild)
q_second.push_back(temp->rchild);
}
cout << endl;
q_first.swap(q_second);
}
}
void print_by_level_3(Tree T) {
vector<tree_node_t*> vec;
vec.push_back(T);
int cur = 0;
int end = 1;
while (cur < vec.size()) {
end = vec.size();
while (cur < end) {
cout << vec[cur]->data << " ";
if (vec[cur]->lchild)
vec.push_back(vec[cur]->lchild);
if (vec[cur]->rchild)
vec.push_back(vec[cur]->rchild);
cur++;
}
cout << endl;
}
}
int main(int argc, char *argv[]) {
Tree T = NULL;
create_tree(&T);
print_tree(T);
cout << endl;
print_by_level_3(T);
cin.get();
cin.get();
return 0;
}
❺ 二叉树的遍历算法
这里有二叉树先序、中序、后序三种遍历的非递归算法,此三个算法可视为标准算法。
1.先序遍历非递归算法
#define
maxsize
100
typedef
struct
{
Bitree
Elem[maxsize];
int
top;
}SqStack;
void
PreOrderUnrec(Bitree
t)
{
SqStack
s;
StackInit(s);
p=t;
while
(p!=null
||
!StackEmpty(s))
{
while
(p!=null)
//遍历左子树
{
visite(p->data);
push(s,p);
p=p->lchild;
}//endwhile
if
(!StackEmpty(s))
//通过下一次循环中的内嵌while实现右子树遍历
{
p=pop(s);
p=p->rchild;
}//endif
}//endwhile
}//PreOrderUnrec
2.中序遍历非递归算法
#define
maxsize
100
typedef
struct
{
Bitree
Elem[maxsize];
int
top;
}SqStack;
void
InOrderUnrec(Bitree
t)
{
SqStack
s;
StackInit(s);
p=t;
while
(p!=null
||
!StackEmpty(s))
{
while
(p!=null)
//遍历左子树
{
push(s,p);
p=p->lchild;
}//endwhile
if
(!StackEmpty(s))
{
p=pop(s);
visite(p->data);
//访问根结点
p=p->rchild;
//通过下一次循环实现右子树遍历
}//endif
}//endwhile
}//InOrderUnrec
3.后序遍历非递归算法
#define
maxsize
100
typedef
enum{L,R}
tagtype;
typedef
struct
{
Bitree
ptr;
tagtype
tag;
}stacknode;
typedef
struct
{
stacknode
Elem[maxsize];
int
top;
}SqStack;
void
PostOrderUnrec(Bitree
t)
{
SqStack
s;
stacknode
x;
StackInit(s);
p=t;
do
{
while
(p!=null)
//遍历左子树
{
x.ptr
=
p;
x.tag
=
L;
//标记为左子树
push(s,x);
p=p->lchild;
}
while
(!StackEmpty(s)
&&
s.Elem[s.top].tag==R)
{
x
=
pop(s);
p
=
x.ptr;
visite(p->data);
//tag为R,表示右子树访问完毕,故访问根结点
}
if
(!StackEmpty(s))
{
s.Elem[s.top].tag
=R;
//遍历右子树
p=s.Elem[s.top].ptr->rchild;
}
}while
(!StackEmpty(s));
}//PostOrderUnrec
❻ 树的遍历的定义
树的这3种遍历方式可递归地定义如下:
如果T是一棵空树,那么对T进行前序遍历、中序遍历和后序遍历都是空操作,得到的列表为空表。
如果T是一棵单结点树,那么对T进行前序遍历、中序遍历和后序遍历都只访问这个结点。这个结点本身就是要得到的相应列表。
否则,设T如图6所示,它以n为树根,树根的子树从左到右依次为T1,T2,..,Tk,那么有:
对T进行前序遍历是先访问树根n,然后依次前序遍历T1,T2,..,Tk。
对T进行中序遍历是先中序遍历T1,然后访问树根n,接着依次对T2,T3,..,Tk进行中序遍历。
对T进行后序遍历是先依次对T1,T2,..,Tk进行后序遍历,最后访问树根n。
n
/ |
/ |
/ |
/ ... | ...
T1 T2 T3
前序遍历和中序遍历可形式地依次描述如下 :
三种遍历可以形式地描述如下,其中用到了树的ADT操作:
Procere Preorder_Traversal(v:NodeType); {前序遍历算法}
begin
Visite(v); {访问节点v}
i:=Leftmost_Child(v);
while i<>∧ do
begin
Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
end;
Procere Inorder_Traversal(v:NodeType); {中序遍历算法}
begin
if Leftmost_Child(v)=∧ {判断v是否是叶节点}
then Visite(v)
else
begin
Inorder_Traversal(Leftmost_Child(v)); {中序遍历v的左边第一个儿子节点}
Visite(v); {访问节点v}
i:=Right_Sibling(Leftmost_Child(v)); {i=v的左边第二个儿子}
while i<>∧ do
begin
Inorder_Traversal(i);
{从左边第二个开始到最右边一个为止依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
end;
end;
Procere Postorder_Traversal(v:NodeType); {后序遍历算法}
begin
i:=Leftmost_Child(v);
while i<>∧ do
begin
Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
Visite(v); {访问节点v}
end;
❼ 遍历的树
树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次。树的3种最重要的遍历方式分别称为前序遍历、中序遍历和后序遍历。以这3种方式遍历一棵树时,若按访问结点的先后次序将结点排列起来,就可分别得到树中所有结点的前序列表、中序列表和后序列表。相应的结点次序分别称为结点的前序、中序和后序。 树的这3种遍历方式可递归地定义如下:
如果T是一棵空树,那么对T进行前序遍历、中序遍历和后序遍历都是空操作,得到的列表为空表。
如果T是一棵单结点树,那么对T进行前序遍历、中序遍历和后序遍历根,树根的子树从左到右依次为T1,T2,..,Tk,那么有:
对T进行前序遍历是先访问树根n,然后依次前序遍历T1,T2,..,Tk。
对T进行中序遍历是先中序遍历T1,然后访问树根n,接着依次对T2,T2,..,Tk进行中序遍历。
对T进行后序遍历是先依次对T1,T2,..,Tk进行后序遍历,最后访问树根n。
n
/ |
/|
/ |
/ ... | ...
T1T2T3 前序遍历和中序遍历可形式地依次描述如下 :
三种遍历可以形式地描述如下,其中用到了树的ADT操作:
Procere Preorder_Traversal(v:NodeType); {前序遍历算法}
begin
Visite(v); {访问节点v}
i:=Leftmost_Child(v);
while i<>;∧ do
begin
Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
end;
Procere Inorder_Traversal(v:NodeType); {中序遍历算法}
begin
if Leftmost_Child(v)=∧ {判断v是否是叶节点}
then Visite(v)
else
begin
Inorder_Traversal(Leftmost_Child(v)); {中序遍历v的左边第一个儿子节点}
Visite(v); {访问节点v}
i:=Right_Sibling(Leftmost_Child(v)); {i=v的左边第二个儿子}
while i<>;∧ do
begin
Inorder_Traversal(i);
{从左边第二个开始到最右边一个为止依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
end;
end;
Procere Postorder_Traversal(v:NodeType); {后序遍历算法}
begin
i:=Leftmost_Child(v);
while i<>;∧ do
begin
Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}
i:=Right_Sibling(i);
end;
Visite(v); {访问节点v}
end;
为了将一棵树中所有结点按某种次序列表,只须对树根调用相应过程。例如对图7中的树进行前序遍历、中序遍历和后序遍历将分别得到前序列表:A B E F I J C D G H;中序列表:E B I F J A CG D H;后序列表:E I J F B G H D C A。
下面介绍一种方法可以产生上述3种遍历方式的结点列表。设想我们从树根出发,依逆时针方向沿树的外缘绕行(例如围绕图7中的树绕行的路线如图8所示)。绕行途中可能多次经过同一结点。如果我们按第一次经过的时间次序将各个结点列表,就可以得到前序列表;如果按最后一次经过的时间次序列表,也就是在即将离开某一结点走向其父亲时将该结点列出,就得到后序列表。为了产生中序列表,要将叶结点与内部结点加以区别。叶结点在第一次经过时列出,而内部结点在第二次经过时列出。
在上述3种不同次序的列表方式中,各树叶之间的相对次序是相同的,它们都按树叶之间从左到右的次序排列。3种列表方式的差别仅在于内部结点之间以及内部结点与树叶之间的次序有所不同。
一棵树进行前序列表或后序列表有助于查询结点间的祖先子孙关系。假设结点v在后序列表中的序号(整数)为postorder(v),我们称这个整数为结点v的后序编号。例如在图7中,结点E,I和J的后序编号分别为1,2和3。 结点的后序编号具有这样的特点:设结点v的真子孙个数为desc(v),那么在以v为根的子树中的所有结点的后序编号恰好落在postorder(v)- desc(v)与postorder(v)之间。因此为了检验结点x是否为结点y的子孙,我们只要判断它们的后序编号是否满足:
postorder(y)-desc(y)≤postorder(x)≤postorder(y)
前序编号也具有类似的性质。
❽ 二叉树前序遍历法举例!急急急!!!
二叉树的三种金典遍历法
1.前序遍历法:
前序遍历(DLR)
前序遍历(DLR)
前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。
若二叉树为空则结束返回,否则:
(1)访问根结点
(2)前序遍历左子树
(3)前序遍历右子树
注意的是:遍历左右子树时仍然采用前序遍历方法。
如上图所示二叉树
前序遍历,也叫先根遍历,遍历的顺序是,根,左子树,右子树
遍历结果:ABDECF
中序遍历,也叫中根遍历,顺序是左子树,根,右子树
遍历结果:DBEAFC
后序遍历,也叫后根遍历,遍历顺序,左子树,右子树,根
遍历结果:DEBFCA
2.中序遍历法:
中序遍历
中序遍历(LDR)
中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。在遍历左、右子树时,仍然先遍历左子树,再访问根结点,最后遍历右子树。即:
若二叉树为空则结束返回,否则:
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树。
注意的是:遍历左右子树时仍然采用中序遍历方法。
3.后序遍历法:
后序遍历
简介
后序遍历是二叉树遍历的一种。后序遍历指在访问根结点、遍历左子树与遍历右子树三者中,首先遍历左子树,然后遍历右子树,最后遍历访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。后序遍历有递归算法和非递归算法两种。
递归算法
算法描述:
(1)若二叉树为空,结束
(2)后序遍历左子树
(3)后序遍历右子树
(4)访问根结点
伪代码
PROCEDUREPOSTRAV(BT)
IFBT<>0THEN
{
POSTRAV(L(BT))
POSTRAV(R(BT))
OUTPUTV(BT)
}
RETURN
c语言描述
structbtnode
{
intd;
structbtnode*lchild;
structbtnode*rchild;
};
voidpostrav(structbtnode*bt)
{
if(bt!=NULL)
{
postrav(bt->lchild);
postrav(bt->rchild);
printf("%d",bt->d);
}
}
非递归算法
算法1(c语言描述):
voidpostrav1(structbtnode*bt)
{
structbtnode*p;
struct
{
structbtnode*pt;
inttag;
}st[MaxSize];
}
inttop=-1;
top++;
st[top].pt=bt;
st[top].tag=1;
while(top>-1)/*栈不为空*/
{
if(st[top].tag==1)/*不能直接访问的情况*/
{
p=st[top].pt;
top--;
if(p!=NULL)
{
top++;/*根结点*/
st[top].pt=p;
st[top].tag=0;
top++;/*右孩子结点*/
st[top].pt=p->p->rchild;
st[top].tag=1;
top++;/*左孩子结点*/
st[top].pt=p->lchild;
st[top].tag=1;
}
}
if(st[top].tag==0)/*直接访问的情况*/
{
printf("%d",st[top].pt->d);
top--;
}
}
}
算法2:
voidpostrav2(structbtnode*bt)
{
structbtnode*st[MaxSize],*p;
intflag,top=-1;
if(bt!=NULL)
{
do
{
while(bt!=NULL)
{
top++;
st[top]=bt;
bt=bt->lchild;
}
p=NULL;
flag=1;
while(top!=-1&&flag)
{
bt=st[top];
if(bt->rchild==p)
{
printf("%d",bt->d);
top--;
p=bt;
}
else
{
bt=bt->rchild;
flag=0;
}
}
}while(top!=-1)
printf(" ");
}
}
老曹回答必属佳作记得给分谢谢合作!
❾ c++二叉树的几种遍历算法
遍历二叉树的所有结点且仅访问一次。按照根节点位置的不同分为前序遍历,中序遍历,后序遍历(除此之外还有层次遍历,但不常用,此处不做解释)。
1.前序遍历:根节点->左子树->右子树(根节点在前面)。
2.中序遍历:左子树->根节点->右子树(根节点在中间)。
3.后序遍历:左子树->右子树->根节点(根节点在后边)。
例如:求下面树的三种遍历:
前序遍历:abdefgc;
中序遍历:debgfac;
后序遍历:edgfbca。
❿ 按照二叉树的递归定义,对二叉树遍历的常用算法有哪三种
前序遍历,中序遍历,后序遍历。