二叉树遍历的各种方式
来源:互联网 发布:linux系统配置ip地址 编辑:程序博客网 时间:2024/05/20 15:59
/*======================================树的所有操作初始化二叉树, 先序,中序,后序建立二叉树先序,中序,后序递归, 非递归 遍历二叉树层次遍历二叉树等2013-08-12 By Mei=======================================*/#include <iostream>#include <cstdlib>#include <queue>#include <stack>#define N 20;using namespace std;typedef struct Binode // 树的数据结构{ int data; struct Binode *lchild, *rchild;}Binode, *Bitree;typedef struct s_stack{ Bitree *top; Bitree *base; int size;}s_stack;typedef struct qnode{ Bitree *rear; Bitree *front;}qnode;int a[] = {1, 2, 3, 0, 0, 4, 5, 0, 6, 0, 0, 7, 0, 0, 0};// Bitree Create_Tree(Bitree &T)//必须用二级指针 // {// int x;// cin>>x;// if(x==0)// 输入二叉树的节点,左右节点不存在必须以0 代替,否则递归不能结束// T = NULL;// else// {// T = new Binode;// T->data = x;// cout<<T->data<<endl;// Create_Tree(T->lchild);// Create_Tree(T->rchild);// }// return T;// }Bitree Create_Tree(){ Bitree p; static int num = 0; if (num <= 20) { if(a[num]==0) { p = NULL; num++; } else { p=new Binode; p->data = a[num]; p->lchild = p->rchild = NULL; cout <<p->data<<" "; num++; p->lchild = Create_Tree(); p->rchild = Create_Tree();// 尼玛 指针被这里覆盖了.. } } else //递归出来的时候需注意.. p = NULL; return p;}//先序递归遍历void Rec_PreorderTraverse(Bitree root) { if(root != NULL) { cout<<root->data<<" "; Rec_PreorderTraverse(root->lchild); Rec_PreorderTraverse(root->rchild); }}// 先序非递归遍历/*思想:利用栈实现,首先根节点进站,然后右节点进栈,接着左节点进栈然后弹出栈顶节点,判断栈顶节点的右节点是否存在,存在则压入栈,继续判断其左节点是否存在,存在则压入栈中,然后继续弹出栈顶元素,反复循环,知道栈为空为止*/void PreorderTraverse(Bitree root) { s_stack st; Bitree p = root; st.base = new Bitree[20]; st.size = N; st.top = st.base; *st.top++ = p; while(st.top!=st.base) { p=*--st.top; cout<<p->data<<" "; if(p->rchild!=NULL) { *st.top++ = p->rchild; } if(p->lchild!=NULL) { *st.top++ = p->lchild; } }}//中序递归遍历void Rec_InorderTraverse(Bitree root) { if(root != NULL) { Rec_InorderTraverse(root->lchild); cout<<root->data<<" "; Rec_InorderTraverse(root->rchild); }}//中序非递归遍历/*思想:首先压入根节点,如果其左节点存在,继续压入其左节点,知道左节点为空然后弹出栈顶元素,判断其右节点是否存在,若存在压入栈中,继续判断其左节点是否存在若存在,继续压入其左节点,知道其左节点不存在为止,然后反复循环,知道栈为空为止*/void InorderTraverse(Bitree root) { s_stack st; Bitree p = root; Bitree x, y; st.base = new Bitree[20]; st.size = N; st.top = st.base; while(p!=NULL) { *st.top++ = p; p = p->lchild; } while(st.top!=st.base) { x = *--st.top; cout<<x->data<<" "; if(x->rchild!=NULL) { *st.top++ = x->rchild; y = x->rchild; while(y->lchild!=NULL) { *st.top++ = y->lchild; y = y->lchild; } } }}void Rec_PostorderTraverse(Bitree root) //后序递归遍历{ if(root != NULL) { Rec_PostorderTraverse(root->lchild); Rec_PostorderTraverse(root->rchild); cout<<root->data<<" "; }}//后序非递归遍历/*先压入根节点到栈中,如果其左节点非空,一直压入左节点,知道左节点为空为止,此时取出栈顶元素只是去取,并非弹栈,然后标记这个节点,表示这个节点的右子节点已经被访问过,下次遇到这个节点直接弹出即可(1)判断这个节点是否有右子节点 或者右子节点是否被访问过,如果是,则弹出这个节点(2)如果这个节点的右子节点没有被访问过,则右子节点压入栈中,重复刚开始的其是否存在左子节点的判断*/void PostorderTraverse(Bitree root){ s_stack st; Bitree p = root; st.base = new Bitree[20]; st.top = st.base; Bitree x,y; int flag[10];//标记是否访问过这个节点 while(p!=NULL) { *st.top++ = p; p = p->lchild; flag[st.top-st.base-1] = 0; } while(st.top!=st.base) { p = *(st.top-1); if(flag[st.top-st.base-1]==0) { flag[st.top-st.base-1] = 1; if(p->rchild!=NULL) { x = p->rchild; while(x!=NULL) { *st.top++ = x; x = x->lchild; flag[st.top-st.base-1] = 0; } } } else { x = *--st.top; cout<<x->data<<" "; } }}//层次遍历void TraversalOfLevel(Bitree root){ qnode st; Bitree p; st.front = new Bitree[20]; st.rear = st.front; *st.front++ = root; while(st.front!=st.rear) { p = *st.rear++; cout<<p->data<<" "; if(p->lchild!=NULL) *st.front++ = p->lchild; if(p->rchild!=NULL) *st.front++ = p->rchild; }}//先序,中序,后序 非递归遍历的第二种思路//先序非递归遍历的第二种方法/*对任一节点来说(1)访问节点p,节点入栈(2)判断其左孩子是否为空,如果为空,进行出栈操作,并将栈顶元素的右孩子设置为p, 循环到1,若不为空,则将节点p的左孩子设置为当前的节点P(3)若P为NULL 且栈为空,则结束遍历*/void PreorderTraverse1(Bitree root){ stack<Bitree> s; Bitree p = root; while(p!=NULL||!s.empty()) { while(p!=NULL) { cout<<p->data<<" "; s.push(p); p = p->lchild; } if(!s.empty()) { p = s.top(); s.pop(); p = p->rchild; } }}//中序非递归遍历/*对任一节点来说:(1)若左节点不空,则将p入栈,并将p的左孩子置为P,重复这个操作,直到p的左孩子为空为止(2)若左孩子为空,则取栈顶元素并出栈,访问栈顶元素,然后将P的右孩子置为P为止(3)当P为NULL,且栈为空 则遍历完成*/void InorderTraverse1(Bitree root){ stack<Bitree> s; Bitree p = root; while(p!=NULL||!s.empty()) { while(p!=NULL) { s.push(p); p = p->lchild; } if(!s.empty()) { p = s.top(); cout<<p->data<<" "; s.pop(); p = p->rchild; } }}// 后序非递归遍历第二种实现方式/*对任一节点P,将其入栈,然后沿左子树一起向下搜索,知道左子树为空为止此时获取栈顶元素,但是此时还不能出栈访问,因为其右孩子还未被访问,此时对其标记一下,表示右节点已经访问过,然后让右节点入栈,重复前面的操作,知道遇到已经标记过的节点,此时表明此节点的右节点已经都被访问完成*/void PostorderTraverse1(Bitree root){ stack<Bitree> s; int flag[20]; int x; Bitree p = root; while(p!=NULL||!s.empty()) { while(p!=NULL) { s.push(p); flag[s.size()] = 0; p = p->lchild; } if(!s.empty()) { x = flag[s.size()]; p = s.top(); if(x == 0) { flag[s.size()] = 1; p = p->rchild; } else { cout<<p->data<<" "; s.pop(); p = NULL; } } }}// 后序遍历的第三种形式/*要保证先访问左右节点,然后再访问根节点,可以先把根节点入栈,然后其右节点,左节点分别入栈如果根节点没有左右节点,或者左右节点已经被访问过,根节点就可以出战,这样可以保证每次取栈顶元素的时候,左节点在右节点前面被访问,根节点在左节点,右节点前面被访问*/void PostorderTraverse2(Bitree root){ stack <Bitree> s; Bitree cur, pre=NULL; s.push(root); while(!s.empty()) { cur = s.top(); if((cur->rchild==NULL && cur->lchild==NULL)||(pre!=NULL &&(pre==cur->lchild||pre==cur->rchild))) { cout<<cur->data<<" "; s.pop(); pre = cur; } else { if(cur->rchild!=NULL) s.push(cur->rchild); if(cur->lchild!=NULL) s.push(cur->lchild); } }}int main(){ Bitree T, root; root = Create_Tree(); cout<<endl; cout<<"先序遍历结果:"<<endl; Rec_PreorderTraverse(root); cout<<endl; PreorderTraverse(root); cout<<endl; PreorderTraverse1(root); cout<<endl; cout <<"中序遍历结果:"<<endl; Rec_InorderTraverse(root); cout<<endl; InorderTraverse1(root); cout<<endl; InorderTraverse(root); cout<<endl; cout << "后序遍历结果:"<<endl; Rec_PostorderTraverse(root); cout<<endl; PostorderTraverse(root); cout<<endl; PostorderTraverse1(root); cout <<endl; PostorderTraverse2(root); cout<<endl; cout<<"层次遍历结果:"<<endl; TraversalOfLevel(root); cout<<endl; return 0;}