标签:
#include<iostream> #include<stack> #include<queue> using namespace std; //二叉树结点 typedef struct BiTNode{ char data; bool isLeft; struct BiTNode *lchild,*rchild,*biTree; }BiTNode,*BiTree; //按先序序列创建二叉树 void CreateBiTree(BiTree &T){ char data; //按先序次序输入二叉树中结点的值(一个字符),‘#’表示空树 cin>>data; if(data == ‘#‘){ T = NULL; } else{ T = (BiTree)malloc(sizeof(BiTNode)); //生成根结点 T->data = data; //构造左子树 CreateBiTree(T->lchild); //构造右子树 CreateBiTree(T->rchild); } } //输出 void Visit(BiTree &T){ if(T->data != ‘#‘){ printf("%c ",T->data); } } //先序遍历 void PreOrder(BiTNode *T){ if(T != NULL){ //访问根节点 Visit(T); //访问左子结点 PreOrder(T->lchild); //访问右子结点 PreOrder(T->rchild); } } //中序遍历 void InOrder(BiTNode *T){ if(T != NULL){ //访问左子结点 InOrder(T->lchild); //访问根节点 Visit(T); //访问右子结点 InOrder(T->rchild); } } //后序遍历 void PostOrder(BiTNode *T){ if(T != NULL){ //访问左子结点 PostOrder(T->lchild); //访问右子结点 PostOrder(T->rchild); //访问根节点 Visit(T); } } /* 先序遍历(非递归) 思路:访问T->data后,将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,再先序遍历T的右子树。 */ void PreOrder2(BiTNode *T){ stack<BiTree> stack; //p是遍历指针 BiTNode *p = T; //栈不空或者p不空时循环 while(p!=NULL || !stack.empty()){ if(p != NULL){ //存入栈中 stack.push(p); //访问根节点 printf("%c ",p->data); //遍历左子树 p = p->lchild; } else{ //退栈 p = stack.top(); stack.pop(); //访问右子树 p = p->rchild; } }//while } /* 中序遍历(非递归) 思路:T是要遍历树的根指针,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。 先将T入栈,遍历左子树;遍历完左子树返回时,栈顶元素应为T,出栈,访问T->data,再中序遍历T的右子树。 */ void InOrder2(BiTNode *T){ stack<BiTree> stack; //p是遍历指针 BiTNode *p = T; //栈不空或者p不空时循环 while(p!=NULL || !stack.empty()){ if(p != NULL){ //存入栈中 stack.push(p); //遍历左子树 p = p->lchild; } else{ //退栈,访问根节点 p = stack.top(); printf("%c ",p->data); stack.pop(); //访问右子树 p = p->rchild; } }//while } //后序遍历(非递归) /* 第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点, 此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。所以接下来按照相同 的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。 这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现 在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。 */ void PostOrder2(BiTree &T){ stack<BiTree> stack; //p是遍历指针 BiTree p = T; BiTree BT; //栈不空或者p不空时循环 while(p != NULL || !stack.empty()){ //遍历左子树 while(p != NULL){ BT = (BiTree)malloc(sizeof(BiTree)); BT = p; //访问过左子树 BT->isLeft=true; stack.push(BT); p = p->lchild; } if(!stack.empty()){ BT = stack.top(); //退栈 stack.pop(); if(BT->isLeft){ BT->isLeft = false; stack.push(BT); p=BT->rchild; }else{ cout<<BT->data<<" "; p=NULL; } } }//while } /* 第二种思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。 如果P不存在左孩子和右孩子,则可以直接访问它;或者P【存在】左孩子或者右孩子,但是其左孩子和右孩 子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈, 这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。 */ void PostOrder3(BiTree &T){ stack<BiTree> stack; //p是遍历指针 BiTree p = T; BiTree BT; //先将p入栈 stack.push(p); while(p || !stack.empty()){ p=stack.top(); //直接访问 存在左子树或右子树已被访问过 或者左右子树为空 if(BT && (BT==p->lchild||BT==p->rchild)||(!p->lchild && !p->rchild)){ cout<<p->data<<" "; stack.pop(); BT = p; p = NULL; }else{ if(p->rchild != NULL)stack.push(p->rchild); if(p->lchild != NULL)stack.push(p->lchild); } }//while } //层次遍历 void LevelOrder(BiTree &T){ BiTree p = T; queue<BiTree> queue; //根节点入队 queue.push(p); while(!queue.empty()){ //对头元素出队 p = queue.front(); //访问p指向的结点 printf("%c ",p->data); //退出队列 queue.pop(); //左子树不空,将左子树入队 if(p->lchild != NULL){ queue.push(p->lchild); } //右子树不空,将右子树入队 if(p->rchild != NULL){ queue.push(p->rchild); } } } int main(){ //输入ABC###D##E## BiTree T; CreateBiTree(T); printf("先序遍历:\n"); PreOrder(T); printf("\n"); printf("先序遍历(非递归):\n"); PreOrder2(T); printf("\n"); printf("中序遍历:\n"); InOrder(T); printf("\n"); printf("中序遍历(非递归):\n"); InOrder2(T); printf("\n"); printf("后序遍历:\n"); PostOrder(T); printf("\n"); printf("后序遍历(非递归):\n"); PostOrder2(T); printf("\n"); printf("后序遍历(非递归):\n"); PostOrder3(T); printf("\n"); printf("层次遍历:\n"); LevelOrder(T); printf("\n"); return 0; }
标签:
原文地址:http://www.cnblogs.com/ddzz2288/p/4529455.html