数据结构-二叉树的遍历
二叉树的定义:
又称二分树,它是有限的节点集合,这个集合或者是空,或者是由一个根节点和两棵互不相交的称为左子树和右子树的二叉树组成。
他和度为2的树是不同的,差别在于
1、度为2的树中至少有一个节点的度为2,而二叉树没有这种要求
2、度为2的数不区分左右子树而二叉树严格区分左右子树。
遍历方案
二叉树的前序遍历
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
⑴访问结点本身(N),
⑵遍历该结点的左子树(L),
⑶遍历该结点的右子树(R)。
以上三种操作有六种执行次序:
NLR、LNR、LRN、NRL、RNL、RLN。
注意:
前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。
常规的三种递归遍历方法
1、先序遍历:
访问根节点,先序遍历左子树,先序遍历右子树
2、中序遍历:
中序遍历左子树,访问根节点,中序遍历右子树
3、后序遍历
后序遍历左子树,访问根节点,后序遍历右子树。
关于层次遍历法从上到下从左到右遍历所有节点。
一般而言,先序遍历不会有什么问题,最主要的是中序遍历。
如下例:
三种遍历结果(可以利用文章提供的算法验证正确性)如下
先序遍历 ABCDEFGHIJKMN
中序遍历 DFEGCHBAMKNJI
后序遍历 FGEDHCBMNKJIA
上面二叉树中序遍历的错误写法:
FEGDCHBAMKNJI
错误写法的关键在于错误的选择了E(F,G)二叉树作为遍历的起点,实际上我们应该选择D(,tree)作为遍历的起点。[其中tree指的E(F,G)]
中序遍历遍历二叉树的过程是:中序遍历左子树,访问根节点,中序遍历右子树。这表明二叉树的遍历是个递归过程,拿中序遍历的递归算法来说
void InOrder(BTNode *b) //中序遍历的递归算法 { if (b!=NULL) { InOrder(b->lchild); //递归访问左子树 printf("%c ",b->data); //访问根节点 InOrder(b->rchild); //递归访问右子树 } }
中序遍历中选取的遍历起点应该是由整棵二叉树根节点一直往左持续延伸最后形成的叶子节点 。
此外 二叉树的中序遍历可以使用投影法来快速解决比如
二叉树遍历的算法源码:
//文件名:exp7-2.cpp #include <stdio.h> #include <malloc.h> #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; //数据元素 struct node *lchild; //指向左孩子 struct node *rchild; //指向右孩子 } BTNode; #define MaxSize 100 typedef char ElemType; void CreateBTNode(BTNode *&b,char *str); void DispBTNode(BTNode *b); void DestroyBTNode(BTNode *&b); void PreOrder(BTNode *b) //先序遍历的递归算法 { if (b!=NULL) { printf("%c ",b->data); //访问根节点 PreOrder(b->lchild); //递归访问左子树 PreOrder(b->rchild); //递归访问右子树 } } void PreOrder1(BTNode *b) { BTNode *St[MaxSize],*p; int top=-1; if (b!=NULL) { top++; //根节点入栈 St[top]=b; while (top>-1) //栈不为空时循环 { p=St[top]; //退栈并访问该节点 top--; printf("%c ",p->data); if (p->rchild!=NULL) //右孩子入栈 { top++; St[top]=p->rchild; } if (p->lchild!=NULL) //左孩子入栈 { top++; St[top]=p->lchild; } } printf("\n"); } } void InOrder(BTNode *b) //中序遍历的递归算法 { if (b!=NULL) { InOrder(b->lchild); //递归访问左子树 printf("%c ",b->data); //访问根节点 InOrder(b->rchild); //递归访问右子树 } } void InOrder1(BTNode *b) { BTNode *St[MaxSize],*p; int top=-1; if (b!=NULL) { p=b; while (top>-1 || p!=NULL) { while (p!=NULL) { top++; St[top]=p; p=p->lchild; } if (top>-1) { p=St[top]; top--; printf("%c ",p->data); p=p->rchild; } } printf("\n"); } } void PostOrder(BTNode *b) //后序遍历的递归算法 { if (b!=NULL) { PostOrder(b->lchild); //递归访问左子树 PostOrder(b->rchild); //递归访问右子树 printf("%c ",b->data); //访问根节点 } } void PostOrder1(BTNode *b) { BTNode *St[MaxSize]; BTNode *p; int flag,top=-1; //栈指针置初值 if (b!=NULL) { do { while (b!=NULL) //将t的所有左节点入栈 { top++; St[top]=b; b=b->lchild; } p=NULL; //p指向当前节点的前一个已访问的节点 flag=1; while (top!=-1 && flag) { b=St[top]; //取出当前的栈顶元素 if (b->rchild==p) //右子树不存在或已被访问,访问之 { printf("%c ",b->data); //访问*b节点 top--; p=b; //p指向则被访问的节点 } else { b=b->rchild; //t指向右子树 flag=0; } } } while (top!=-1); printf("\n"); } } void TravLevel(BTNode *b) { BTNode *Qu[MaxSize]; //定义循环队列 int front,rear; //定义队首和队尾指针 front=rear=0; //置队列为空队列 if (b!=NULL) printf("%c ",b->data); rear++; //节点指针进入队列 Qu[rear]=b; while (rear!=front) //队列不为空 { front=(front+1)%MaxSize; b=Qu[front]; //队头出队列 if (b->lchild!=NULL) //输出左孩子,并入队列 { printf("%c ",b->lchild->data); rear=(rear+1)%MaxSize; Qu[rear]=b->lchild; } if (b->rchild!=NULL) //输出右孩子,并入队列 { printf("%c ",b->rchild->data); rear=(rear+1)%MaxSize; Qu[rear]=b->rchild; } } printf("\n"); } void CreateBTNode(BTNode *&b,char *str) //由str串创建二叉链 { BTNode *St[MaxSize],*p=NULL; int top=-1,k,j=0; char ch; b=NULL; //建立的二叉树初始时为空 ch=str[j]; while (ch!='\0') //str未扫描完时循环 { switch(ch) { case '(':top++;St[top]=p;k=1; break; //为左节点 case ')':top--;break; case ',':k=2; break; //为右节点 default:p=(BTNode *)malloc(sizeof(BTNode)); p->data=ch;p->lchild=p->rchild=NULL; if (b==NULL) //p指向二叉树的根节点 b=p; else //已建立二叉树根节点 { switch(k) { case 1:St[top]->lchild=p;break; case 2:St[top]->rchild=p;break; } } } j++; ch=str[j]; } } BTNode *FindNode(BTNode *b,ElemType x) //返回data域为x的节点指针 { BTNode *p; if (b==NULL) return NULL; else if (b->data==x) return b; else { p=FindNode(b->lchild,x); if (p!=NULL) return p; else return FindNode(b->rchild,x); } } BTNode *LchildNode(BTNode *p) //返回*p节点的左孩子节点指针 { return p->lchild; } BTNode *RchildNode(BTNode *p) //返回*p节点的右孩子节点指针 { return p->rchild; } int BTNodeDepth(BTNode *b) //求二叉树b的深度 { int lchilddep,rchilddep; if (b==NULL) return(0); //空树的高度为0 else { lchilddep=BTNodeDepth(b->lchild); //求左子树的高度为lchilddep rchilddep=BTNodeDepth(b->rchild); //求右子树的高度为rchilddep return (lchilddep>rchilddep)? (lchilddep+1):(rchilddep+1); } } void DispBTNode(BTNode *b) //以括号表示法输出二叉树 { if (b!=NULL) { printf("%c",b->data); if (b->lchild!=NULL || b->rchild!=NULL) { printf("("); DispBTNode(b->lchild); if (b->rchild!=NULL) printf(","); DispBTNode(b->rchild); printf(")"); } } } int BTWidth(BTNode *b) //求二叉树b的宽度 { struct { int lno; //节点的层次编号 BTNode *p; //节点指针 } Qu[MaxSize]; //定义顺序非循环队列 int front,rear; //定义队首和队尾指针 int lnum,max,i,n; front=rear=0; //置队列为空队 if (b!=NULL) { rear++; Qu[rear].p=b; //根节点指针入队 Qu[rear].lno=1; //根节点的层次编号为1 while (rear!=front) //队列不为空 { front++; b=Qu[front].p; //队头出队 lnum=Qu[front].lno; if (b->lchild!=NULL) //左孩子入队 { rear++; Qu[rear].p=b->lchild; Qu[rear].lno=lnum+1; } if (b->rchild!=NULL) //右孩子入队 { rear++; Qu[rear].p=b->rchild; Qu[rear].lno=lnum+1; } } max=0;lnum=1;i=1; while (i<=rear) { n=0; while (i<=rear && Qu[i].lno==lnum) { n++;i++; } lnum=Qu[i].lno; if (n>max) max=n; } return max; } else return 0; } int Nodes(BTNode *b) //求二叉树b的节点个数 { int num1,num2; if (b==NULL) return 0; else if (b->lchild==NULL && b->rchild==NULL) return 1; else { num1=Nodes(b->lchild); num2=Nodes(b->rchild); return (num1+num2+1); } } int LeafNodes(BTNode *b) //求二叉树b的叶子节点个数 { int num1,num2; if (b==NULL) return 0; else if (b->lchild==NULL && b->rchild==NULL) return 1; else { num1=LeafNodes(b->lchild); num2=LeafNodes(b->rchild); return (num1+num2); } } void DestroyBTNode(BTNode *&b) { if (b!=NULL) { DestroyBTNode(b->lchild); DestroyBTNode(b->rchild); free(b); } } void main() { /* BTNode *b; CreateBTNode(b,"A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))"); printf("二叉树b:");DispBTNode(b);printf("\n"); printf("层次遍历序列:"); TravLevel(b); printf("先序遍历序列:\n"); printf(" 递归算法:");PreOrder(b);printf("\n"); printf(" 非递归算法:");PreOrder1(b); printf("中序遍历序列:\n"); printf(" 递归算法:");InOrder(b);printf("\n"); printf(" 非递归算法:");InOrder1(b); printf("后序遍历序列:\n"); printf(" 递归算法:");PostOrder(b);printf("\n"); printf(" 非递归算法:");PostOrder1(b); DestroyBTNode(b); */ BTNode *b; CreateBTNode(b,"A(B(C(D(,E(F,G)),H)),I(J(K(M,N))))"); //"a(b(d(,g)),c(e,f(h)))" //"A(B(D(E(F(,H),G(I)))),C(,J(K(M,N),L(O(,P)))))" //A(C(,D),E(H,F(G,O))) //A(B(C(D(,E(F,G)),H)),I(J(K(M,N)))) printf("二叉树b:");DispBTNode(b);printf("\n"); printf("层次遍历序列:"); TravLevel(b); printf("先序遍历序列:\n"); printf(" 递归算法:");PreOrder(b);printf("\n"); printf(" 非递归算法:");PreOrder1(b); printf("中序遍历序列:\n"); printf(" 递归算法:");InOrder(b);printf("\n"); printf(" 非递归算法:");InOrder1(b); printf("后序遍历序列:\n"); printf(" 递归算法:");PostOrder(b);printf("\n"); printf(" 非递归算法:");PostOrder1(b); DestroyBTNode(b); }