问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

遍历二叉树

发布网友 发布时间:2022-04-22 02:34

我来回答

4个回答

热心网友 时间:2022-04-18 22:58

遍历方案:
1.遍历方案
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
(1)访问结点本身(N),
(2)遍历该结点的左子树(L),
(3)遍历该结点的右子树(R)。
以上三种操作有六种执行次序:
NLR、LNR、LRN、NRL、RNL、RLN。
注意:
前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。
2.三种遍历的命名
根据访问结点操作发生位置命名:
① NLR:前序遍历(PreorderTraversal亦称(先序遍历))
——访问结点的操作发生在遍历其左右子树之前。
② LNR:中序遍历(InorderTraversal)
——访问结点的操作发生在遍历其左右子树之中(间)。
③ LRN:后序遍历(PostorderTraversal)
——访问结点的操作发生在遍历其左右子树之后。
注意:
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历。
遍历算法
1.中序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
(1)遍历左子树;
(2)访问根结点;
(3)遍历右子树。
2.先序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
(1) 访问根结点;
(2) 遍历左子树;
(3) 遍历右子树。
3.后序遍历得递归算法定义:
若二叉树非空,则依次执行如下操作:
(1)遍历左子树;
(2)遍历右子树;
(3)访问根结点。
4.中序遍历的算法实现
用二叉链表做为存储结构,中序遍历算法可描述为:
void InOrder(BinTree T)
{ //算法里①~⑥是为了说明执行过程加入的标号
① if(T) { // 如果二叉树非空
② InOrder(T->lchild);
③ printf("%c",T->data); // 访问结点
④ InOrder(T->rchild);
⑤ }
⑥ } // InOrder
遍历序列
1.遍历二叉树的执行踪迹
三种递归遍历算法的搜索路线相同(如下图虚线所示)。
具体线路为:
从根结点出发,逆时针沿着二叉树外缘移动,对每个结点均途径三次,最后回到根结点。
2.遍历序列
A
/ \
B C
/ / \
D E F

(1) 中序序列(inorder traversal)
中序遍历二叉树时,对结点的访问次序为中序序列
【例】中序遍历上图所示的二叉树时,得到的中序序列为:
D B A E C F
(2) 先序序列(preorder traversal)
先序遍历二叉树时,对结点的访问次序为先序序列
【例】先序遍历上图所示的二叉树时,得到的先序序列为:
A B D C E F
(3) 后序序列(postorder traversal)
后序遍历二叉树时,对结点的访问次序为后序序列
【例】后序遍历上图所示的二叉树时,得到的后序序列为:
D B E F C A
(4)层次遍历(level traversal)二叉树的操作定义为:若二叉树为空,则退出,否则,按照树的结构,从根开始自上而下,自左而右访问每一个结点,从而实现对每一个结点的遍历
注意:
(1)在搜索路线中,若访问结点均是第一次经过结点时进行的,则是前序遍历;若访问结点均是在第二次(或第三次)经过结点时进行的,则是中序遍历(或后序遍历)。只要将搜索路线上所有在第一次、第二次和第三次经过的结点分别列表,即可分别得到该二叉树的前序序列、中序序列和后序序列。
(2)上述三种序列都是线性序列,有且仅有一个开始结点和一个终端结点,其余结点都有且仅有一个前趋结点和一个后继结点。为了区别于树形结构中前趋(即双亲)结点和后继(即孩子)结点的概念,对上述三种线性序列,要在某结点的前趋和后继之前冠以其遍历次序名称。
【例】上图所示的二叉树中结点C,其前序前趋结点是D,前序后继结点是E;中序前趋结点是E,中序后继结点是F;后序前趋结点是F,后序后继结点是A。但是就该树的逻辑结构而言,C的前趋结点是A,后继结点是E和F。
二叉链表的构造
1. 基本思想
基于先序遍历的构造,即以二叉树的先序序列为输入构造。
注意:
先序序列中必须加入虚结点以示空指针的位置。
【例】
建立上图所示二叉树,其输入的先序序列是:ABD∮∮∮CE∮∮F∮∮。
2. 构造算法
假设虚结点输入时以空格字符表示,相应的构造算法为:
void CreateBinTree (BinTree *T)
{ //构造二叉链表。T是指向根指针的指针,故修改*T就修改了实参(根指针)本身
char ch;
if((ch=getchar())=='') *T=NULL; //读人空格,将相应指针置空
else{ //读人非空格
*T=(BinTNode *)malloc(sizeof(BinTNode)); //生成结点
(*T)->data=ch;
CreateBinTree(&(*T)->lchild); //构造左子树
CreateBinTree(&(*T)->rchild); //构造右子树
}
}
注意:
调用该算法时,应将待建立的二叉链表的根指针的地址作为实参。
【例】
设root是一根指针(即它的类型是BinTree),则调用CreateBinTree(&root)后root就指向了已构造好的二叉链表的根结点。
二叉树建立过程见http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/erchashujianli.htm
下面是关于二叉树的遍历、查找、删除、更新数据的代码(递归算法):
[code]
#include <iostream>
using namespace std;
typedef int T;
class bst{
struct Node{
T data;
Node* L;
Node* R;
Node(const T& d, Node* lp=NULL, Node* rp=NULL):data(d),L(lp),R(rp){}
};
Node* root;
int num;
public:
bst():root(NULL),num(0){}
void clear(Node* t){
if(t==NULL) return;
clear(t->L);
clear(t->R);
delete t;
}
~bst(){clear(root);}
void clear(){
clear(root);
num = 0;
root = NULL;
}
bool empty(){return root==NULL;}
int size(){return num;}
T getRoot(){
if(empty()) throw "empty tree";
return root->data;
}
void travel(Node* tree){
if(tree==NULL) return;
travel(tree->L);
cout << tree->data << ' ';
travel(tree->R);
}
void travel(){
travel(root);
cout << endl;
}
int height(Node* tree){
if(tree==NULL) return 0;
int lh = height(tree->L);
int rh = height(tree->R);
return 1+(lh>rh?lh:rh);
}
int height(){
return height(root);
}
void insert(Node*& tree, const T& d){
if(tree==NULL)
tree = new Node(d);
else if(ddata)
insert(tree->L, d);
else
insert(tree->R, d);
}
void insert(const T& d){
insert(root, d);
num++;
}
Node*& find(Node*& tree, const T& d){
if(tree==NULL) return tree;
if(tree->data==d) return tree;
if(ddata)
return find(tree->L, d);
else
return find(tree->R, d);
}
bool find(const T& d){
return find(root, d)!=NULL;
}
bool erase(const T& d){
Node*& pt = find(root, d);
if(pt==NULL) return false;
combine(pt->L, pt->R);
Node* p = pt;
pt = pt->R;
delete p;
num--;
return true;
}
void combine(Node* lc, Node*& rc){
if(lc==NULL) return;
if(rc==NULL) rc = lc;
else combine(lc, rc->L);
}
bool update(const T& od, const T& nd){
Node* p = find(root, od);
if(p==NULL) return false;
erase(od);
insert(nd);
return true;
}
};
int main()
{
bst b;
cout << "input some integers:";
for(;;){
int n;
cin >> n;
b.insert(n);
if(cin.peek()=='\n') break;
}
b.travel();
for(;;){
cout << "input data pair:";
int od, nd;
cin >> od >> nd;
if(od==-1&&nd==-1) break;
b.update(od, nd);
b.travel();
}
}
[/code]

热心网友 时间:2022-04-19 00:16

同学,你们老师和我们老师留的作业是一模一样的阿,我有现成的做好了的程序,调试成功。这个程序的难点就在于这种很别扭的输入形式,所以我为它设计了一个结构体形式存放输入内容,再将它转化成了线性结构。

#include <iostream.h>
#include <stdlib.h>

struct inform /*建立输入信息结构体inform*/
{ char data;

int l;

int r;

int signl; /*作为标记的signl,signr*/

int signr;
};

struct leafnode /*建立叶子节点结构体*/
{
char leaf;

leafnode* lchild;

leafnode* rchild;

};

void print(inform* ps, int n);

void judge ( inform* ps );

leafnode* creatree(); /*声明二叉树的建立函数*/

void preorder (leafnode* T); /*声明先序遍历函数*/

void inorder (leafnode* T); /*声明中序遍历函数*/

void postorder (leafnode* T); /*声明后序遍历函数*/

char a[100];

int k=1;
int s=0;

inform *p;

void main()
{
/*-------------------------------按格式输入信息-----------------------------------*/

int n;

cout<<"请输入二叉树内容:第一行为节点总数n ,后面的n行是节点的具体形式:"<<endl;

cout<<"n= ";

cin>>n;

p=(inform* )malloc( n*sizeof(inform) ); /*开辟的一个叶子结构体型的指针数组*/
inform *p1; p1=p;

for(int i=0; i<n; i++)

{
cin>>(p+i)->data>>(p+i)->l>>(p+i)->r;
if((p+i)->l != -1) (p+i)->signl=1; /*用signl signr 的0,1标示输入的信息中是否有左或右孩子*/
else (p+i)->signl= 0;
if((p+i)->r !=-1) (p+i)->signr=1;
else (p+i)->signr= 0;
}

/*--------------------------------------------------------------------------------------------*/
a[0]= p->data;

judge ( p1 ); /*用递归算法将输入数据信息转为线性字符串*/

cout<<endl<<"输出转换的线性字符串: "<<endl;

cout<<a<<endl<<endl;
/*------------------------------------------遍历-----------------------------------*/
leafnode* T;

T= creatree();

/*先续遍历二叉树*/
cout<<"先序遍历二叉树: "<<endl;
preorder( T );

cout<<endl<<"中序遍历二叉树: "<<endl;
inorder ( T );

cout<<endl<<"后序遍历二叉树: "<<endl;
postorder( T );
cout<<endl<<endl;

}

/*------------------------------------------函数定义-------------------------------*/

void judge( inform* ps ) /*用函数的递归来将输入的信息转化为线性的数组*/
{
inform* b;

if (ps->signl==0)
{
a[k]='@';
k++;
}
else
{
b = p+(ps->l);
a[k] = b->data;
k++;
judge(b);
}

if ((ps->signr) == 0)
{
a[k]='@';
k++;
}
else
{
b = p+(ps->r );
a[k] = b->data;
k++;
judge(b);
}

}

leafnode* creatree() /*建立二叉树函数*/
{
char ch;

leafnode *t;

ch= a[s];
s++;

if(ch=='@')
{
t=NULL;
}
else
{
t=(leafnode* )malloc(sizeof(leafnode));
t->leaf=ch;
t->lchild=creatree();
t->rchild=creatree();
}
return t;

}

/*先序遍历的递归函数*/
void preorder (leafnode* T)
{
if(T)
{
cout<<T->leaf;
preorder(T->lchild);
preorder(T->rchild);
}
}
/*中序遍历的递归函数*/
void inorder (leafnode* T)
{
if(T)
{
inorder(T->lchild);
cout<<T->leaf;
inorder(T->rchild);
}
}
/*后序遍历的递归函数*/
void postorder (leafnode* T)
{
if(T)
{
postorder(T->lchild);
postorder(T->rchild);
cout<<T->leaf;
}
}

热心网友 时间:2022-04-19 01:51

按你的描述,应该采用顺序表来存储数据。
楼上用的是动态链表来存储,显然不合要求。
但是按你描述的结构操作不方便,可不可以在后面的n行中再加一个整数表示其父结点,当父节点值为-1时表示根结点?
这样数据结构为:
typedef struct BTreeNode{
char ch;
int parent;
int lchild;
int rchild;
}BTreeNode;

struct BTree{
BTreeNode *body;/*用于存储二叉树的所有节点*/
int root;/*根节点序号*/
int count;/*节点数*/
}
待续。。。。

源代码:
typedef struct BTreeNode{
char ch;
int parent;
int lchild;
int rchild;
}BTreeNode;

struct BTree{
BTreeNode *body;/*用于存储二叉树的所有节点*/
int root;/*根节点序号*/
int count;/*节点数*/
}

/*创建二叉树*/
BTree createBTree(){
int i,n;
BTree bTree;
printf("请输入节点数:");
scanf("%d",&n);
bTree.body = (BTreeNode) malloc(sizeof(BTreeNode)*n);
bTree.root = -1;
bTree.count = n;
do{
for( i=0; i<n; i++ ){
printf("请输入:节点字符 父节点序号 左节点序号 右节点序号:\n");
scanf("%c %d %d %d",bTree.body[i]->ch,
bTree.body[i]->parent,
bTree.body[i]->lchild,
bTree.body[i]->rchild);
if( bTree.body[i]->parent == -1 ){
bTree.root = i;
break;
}
}
}while( bTree.root == -1 );
return bTree;
}

/*以输出遍历序列为例的遍历方法*/
void travel(BTree *bTree, int i, int pattern ){
/**
* pattern=0表示先序遍历,1表示中序,2表示后序;
*
*/

if( pattern == 0 )
printf("%c",bTree->body[i]->ch);
if( bTree->body[i]->lchild != -1 ){
travel(bTree, bTree->body[i]->lchild, pattern);
if( pattern == 1 )
printf("%c",bTree->body[i]->ch);
}
if( bTree->body[i]->rchild != -1 ){
travel(bTree, bTree->body[i]->rchild, pattern);
if( pattern == 2 )
printf("%c",bTree->body[i]->ch);
}
}

void travelBTree(BTree *bTree , int pattern ){
if( pattern == 0) printf("先序遍历:");
if( pattern == 1) printf("中序遍历:");
if( pattern == 2) printf("后序遍历:");
travel( bTree, bTree->root, pattern );
printf("\n");
}

/*通用遍历方法*/
void travel2(BTree *bTree, int i, int pattern, void (*func)(BTree *bTree,int i) ){
/**
* pattern=0表示先序遍历,1表示中序,2表示后序;
* void (*func)(BTree *bTree,int i)中func为函数指针,用于指定遍历进行的操作。
*/

if( pattern == 0 )
(*func)( bTree, i );
if( bTree->body[i]->lchild != -1 ){
travel2(bTree, bTree->body[i]->lchild, pattern, func);
if( pattern == 1 )
(*func)( bTree, i)
}
if( bTree->body[i]->rchild != -1 ){
travel2(bTree, bTree->body[i]->rchild, pattern, func);
if( pattern == 2 )
(*func)( bTree, i);
}
}

/*测试,数据自定*/

void print( BTree *bTree, int i ){
printf("%c",bTree->body[i]->ch );
}

void main(){
BTree bTree;
void (*func)( BTree *bTree, int i );
bTree = createBTree();
travelBTree( &bTree, 0 );
travelBTree( &bTree, 1 );
travelBTree( &bTree, 2 );
/*通用遍历算法测试*/
func = print;
travel2( &bTree, bTree.root, 0, func);
printf("\n");
travel2( &bTree, bTree.root, 1, func);
printf("\n");
travel2( &bTree, bTree.root, 2, func);
printf("\n");
}

运行时可能会报错,因为我没有调试,你自己调试一下。

热心网友 时间:2022-04-19 03:42

我来了
O(∩_∩)O~
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
刘备与宋江哪个损? 做一个2分钟的flash小动画,我一定加50分 谢谢各位flash高手了 求一个一分钟左右的关于励志奋斗的FLASH动画 “次子论列于朝”的出处是哪里 中华情·走进生态寿光晚会节目单 驾照审核过期了怎么办? 小车d档代表什么意思 学生办理信用卡条件是什么? 农村院子用水泥毯怎样 水泥毯好不好用,水泥毯能取代水泥墙吗 二叉树的遍历问题 《木兰诗》中 “将”字的意思 2叉树遍历 将字多音字组词 二叉树遍历程序 将进酒里“将”是什么意思? 二叉树的遍历问题,高手请进 用“将”字多音字组词 一道二叉树的遍历 将进酒中“将”的发音 将进酒的“将”字是什么意思 二叉树遍历 如何把一个的联系人同步到另一个 “将”在汉语中是什么词性 怎么把一个微信的手机号转到另一个上? 将字的含义是什么 怎么把一个的数据转到另一个的数据? 将字能组什么词 “将”的多音字怎么组词(两个都要) 将字有几个读音 java 2叉树的遍历 二叉树的遍历是什么意思? C# 遍历2叉树的语句 1.二叉树的遍历(难度****) quartusⅡ9 中entity框图被叉掉如何找回,个种键都... 建筑材料员,要哪些证书? 工地安全员和材料员要有哪些证件 施工员证,资料员证,材料员有用吗? 资料员和材料员都需要什么证书啊? 天天p图在扣图中如何不使用背景图片 天天抠图软件抠好图怎样保存 缺血再灌注损伤是怎么导致的? 再灌注损伤是什么?有什么影响?类型是什么? 试述心肌缺血/再灌注损伤的机制. 缺血再灌注损伤的机制是啥? 有哪些?2.缺血-再灌注时氧自由基生成过多的机制是... 病理生理学缺血再灌注损伤(完整) 缺血再灌注的损伤程度 心肌缺血损伤与缺血再灌注损伤表现有何不同? 求求大家帮帮我