数据结构-王道2017-第4章 树与二叉树-二叉树的遍历
typedef int ElemType; typedef struct BitNode { ElemType data; //数据域 struct BitNode *lchild, *rchild; //左右孩子指针 }BitNode,*BitTree; void visit(BitNode *b) { printf("%d ", b->data); } //无论采用哪种遍历方法,时间复杂度都是O(n),因为每个结点都访问一次且仅访问一次,递归工作栈的栈深恰好为树的深度,空间复杂都为O(n) //先序遍历根左右 void PreOrder(BitTree T) { if (T != NULL) { visit(T); PreOrder(T->lchild); PreOrder(T->rchild); } } //中序遍历左根右 void InOrder(BitTree T) { if (T != NULL) { InOrder(T->lchild); visit(T); InOrder(T->rchild); } } //后序遍历左根右 void PostOrder(BitTree T) { if (T != NULL) { PostOrder(T->lchild); PostOrder(T->rchild); visit(T); } } //递归算法转换为非递归, void Inorder2(BitTree T) { stack<BitTree> s; BitTree p = T; while (p != NULL || !s.empty()) { //栈不空时或p不空时循环 if (p) { s.push(p); p = p->lchild; } else { p = s.top; s.pop(); //弹出时,p没有左指针 visit(p); p = p->rchild; } } } //二叉树层次遍历,借助队列 void LevelOrder(BitTree T) { queue<BitTree> q; BitTree p = T; q.push(p); while (!q.empty) { p = q.front; q.pop(); visit(p); if (p->lchild) q.push(p->lchild); //左子树不空,则左子树入队 if (p->rchild) q.push(p->rchild); } }
注意:由遍历序列构造二叉树,由二叉树的先序序列和中序序列,后续序列和中序序列,层序序列和中序序列可以唯一地确定一棵二叉树,如果只知道二叉树的先序序列和后序序列则无法唯一确定一棵二叉树
线索二叉树:
#include <cstdlib> #include <cstdio> #include <iostream> #include <stack> #include <queue> using namespace std; typedef int ElemType; typedef struct ThreadNode { ElemType data; //数据域 struct ThreadNode *lchild, *rchild; //左右孩子指针 int ltag, rtag; //左右线索标志,0,孩子结点,1为指向前驱或者后继结点 }ThreadNode, *ThreadTree; //线索二叉树的构造,遍历过程中检查当前结点左右指针域是否为空,若为空,将它们改为指向前驱结点或者后驱结点的线索 //中序遍历二叉树线索化 void InThread(ThreadTree &p, ThreadTree &pre) { if (p != NULL) { InThread(p->lchild, pre); //递归,线索化左子树 if (p->lchild == NULL) { //左子树为空,建立前驱线索 p->lchild = pre; p->ltag = 1; } if (pre != NULL&&pre->rchild == NULL) { pre->rchild = p; //建立前驱结点的后继线索 pre->rtag = 1; } pre = p; //标记当前结点为刚刚访问过的结点 InThread(p->rchild, pre); //递归线索化右子树 } } void CreateInthread(ThreadTree T) { ThreadTree pre = NULL; if (T != NULL) { InThread(T, pre); //非空二叉树,线索化 pre->rchild = NULL; //处理遍历后的最后一个结点 pre->rtag = 1; } } //线索二叉树的遍历,这种遍历不再借助栈 //求中序线索二叉树中序序列下的第一个结点,不一定是叶子结点 ThreadNode *FirstNode(ThreadNode *p) { while (p->ltag == 0) p = p->lchild; return p; } //中序线索二叉树中结点p在中序序列下的后继结点 ThreadNode *NextNode(ThreadNode *p) { if (p->rtag == 0) return FirstNode(p->rchild); else return p->rchild; //rtag==1直接返回后继线索 } //最后一个结点 ThreadNode *GetLast(ThreadNode *p) { while(p->rtag == 0) p = p->rchild; return p; } //不含头结点的中序遍历二叉树算法 void InOrder(ThreadNode *T) { for (ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p)) visit(p); } void visit(ThreadNode *b) { printf("%d ", b->data); }