• 二叉树的非递归遍历--京东2015笔试回顾


    题目回顾:

    C/C++研发试卷:偏重于数据结构的考察。编程题有2题+1题附加题:

    1.输入整数n,求m,m>9,m中各个数位的乘积=n的最小整数;如n=36,m=49;

    2.二叉树前序遍历的非递归实现(本文的总结)

    3.求第n个数。这个序列满足(2^i)*(3^j)*(5^k),前7个为:2,3,4,5,6,8,10 。。。

    小题有主要的数据结构、程序执行结果、SQL题目。

    4.删除表格用DROP命令,死锁产生的条件:

    4.1相互排斥使用(资源独占) 
     一个资源每次仅仅能给一个进程使用 
    4.2、不可强占(不可剥夺) 
        资源申请者不能强行的从资源占有者手中夺取资源,资源仅仅能由占有者自愿释放 
    4.3、请求和保持(部分分配,占有申请) 
    一个进程在申请新的资源的同一时候保持对原有资源的占有(仅仅有这样才是动态申请。动态分配) 
    4.4、循环等待 
    存在一个进程等待队列 
        {P1 , P2 , … , Pn}, 
        当中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路
    5.用7 7 7 1四个数和加减乘除计算出48(每一个数字用一次)
    (7+1/7)*7=50
    7*(7-1/7)=48

    二叉树的非递归遍历

             二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的。

    对于二叉树,有前序、中序以及后序三种遍历方法。由于树的定义本身就是递归定义,因此採用递归的方法去实现树的三种遍历不仅easy理解并且代码非常简洁。而对于树的遍历若採用非递归的方法,就要採用栈去模拟实现。

    在三种遍历中。前序和中序遍历的非递归算法都非常easy实现。非递归后序遍历实现起来相对来说要难一点。

    一.前序遍历

       前序遍历依照“根结点-左孩子-右孩子”的顺序进行訪问。

       1.递归实现

    复制代码
    void preOrder1(BinTree *root)     //递归前序遍历 
    {
    if(root!=NULL)
    {
    cout
    <<root->data<<" ";
    preOrder1(root
    ->lchild);
    preOrder1(root
    ->rchild);
    }
    }
    复制代码

       2.非递归实现

        依据前序遍历訪问的顺序,优先訪问根结点。然后再分别訪问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此能够直接訪问,訪问完之后。若其左孩子不为空。按同样规则訪问它的左子树;当訪问其左子树时,再訪问它的右子树。因此其处理步骤例如以下:

         对于任一结点P:

         1)訪问结点P,并将结点P入栈;

         2)推断结点P的左孩子是否为空。若为空,则取栈顶结点并进行出栈操作。并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空。则将P的左孩子置为当前的结点P;

         3)直到P为NULL而且栈为空,则遍历结束。

    复制代码
    void preOrder2(BinTree *root)     //非递归前序遍历 
    {
    stack
    <BinTree*> s;
    BinTree
    *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.递归实现

    复制代码
    void inOrder1(BinTree *root)      //递归中序遍历
    {
    if(root!=NULL)
    {
    inOrder1(root
    ->lchild);
    cout
    <<root->data<<" ";
    inOrder1(root
    ->rchild);
    }
    }
    复制代码

       2.非递归实现

        依据中序遍历的顺序,对于任一结点,优先訪问其左孩子,而左孩子结点又能够看做一根结点,然后继续訪问其左孩子结点,直到遇到左孩子结点为空的结点才进行訪问,然后按同样的规则訪问其右子树。

    因此其处理步骤例如以下:

       对于任一结点P,

      1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P。然后对当前结点P再进行同样的处理;

      2)若其左孩子为空,则取栈顶元素并进行出栈操作,訪问该栈顶结点,然后将当前的P置为栈顶结点的右孩子。

      3)直到P为NULL而且栈为空则遍历结束

    复制代码
    void inOrder2(BinTree *root)      //非递归中序遍历
    {
    stack
    <BinTree*> s;
    BinTree
    *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;
    }
    }
    }
    复制代码

      三.后序遍历

          后序遍历依照“左孩子-右孩子-根结点”的顺序进行訪问。

          1.递归实现

    复制代码
    void postOrder1(BinTree *root)    //递归后序遍历
    {
    if(root!=NULL)
    {
    postOrder1(root
    ->lchild);
    postOrder1(root
    ->rchild);
    cout
    <<root->data<<" ";
    }
    }
    复制代码

          2.非递归实现

           后序遍历的非递归实现是三种遍历方式中最难的一种。由于在后序遍历中,要保证左孩子和右孩子都已被訪问而且左孩子在右孩子前訪问才干訪问根结点,这就为流程的控制带来了难题。以下介绍两种思路。

          第一种思路:对于任一结点P。将其入栈,然后沿其左子树一直往下搜索。直到搜索到没有左孩子的结点,此时该结点出如今栈顶,可是此时不能将其出栈并訪问。因此其右孩子还未被訪问。所以接下来依照同样的规则对其右子树进行同样的处理,当訪问完其右孩子时,该结点又出如今栈顶。此时能够将其出栈并訪问。

    这样就保证了正确的訪问顺序。

    能够看出。在这个过程中,每一个结点都两次出如今栈顶。仅仅有在第二次出如今栈顶时。才干訪问它。

    因此须要多设置一个变量标识该结点是否是第一次出如今栈顶。

    复制代码
    void postOrder2(BinTree *root)    //非递归后序遍历
    {
    stack
    <BTNode*> s;
    BinTree
    *p=root;
    BTNode
    *temp;
    while(p!=NULL||!s.empty())
    {
    while(p!=NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
    {
    BTNode
    *btn=(BTNode *)malloc(sizeof(BTNode));
    btn
    ->btnode=p;
    btn
    ->isFirst=true;
    s.push(btn);
    p
    =p->lchild;
    }
    if(!s.empty())
    {
    temp
    =s.top();
    s.pop();
    if(temp->isFirst==true) //表示是第一次出如今栈顶
    {
    temp
    ->isFirst=false;
    s.push(temp);
    p
    =temp->btnode->rchild;
    }
    else //第二次出如今栈顶
    {
    cout
    <<temp->btnode->data<<" ";
    p
    =NULL;
    }
    }
    }
    }
    复制代码

            另外一种思路:要保证根结点在左孩子和右孩子訪问之后才干訪问,因此对于任一结点P,先将其入栈。假设P不存在左孩子和右孩子。则能够直接訪问它。或者P存在左孩子或者右孩子,可是其左孩子和右孩子都已被訪问过了。则相同能够直接訪问该结点。若非上述两种情况。则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被訪问,左孩子和右孩子都在根结点前面被訪问。

    复制代码
    void postOrder3(BinTree *root)     //非递归后序遍历
    {
    stack
    <BinTree*> s;
    BinTree
    *cur; //当前结点
    BinTree *pre=NULL; //前一次訪问的结点
    s.push(root);
    while(!s.empty())
    {
    cur
    =s.top();
    if((cur->lchild==NULL&&cur->rchild==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);
    }
    }
    }
    复制代码

     四.整个程序完整的代码

    复制代码
    /*二叉树的遍历* 2011.8.25*/ 

    #include
    <iostream>
    #include
    <string.h>
    #include
    <stack>
    using namespace std;

    typedef
    struct node
    {
    char data;
    struct node *lchild,*rchild;
    }BinTree;

    typedef
    struct node1
    {
    BinTree
    *btnode;
    bool isFirst;
    }BTNode;


    void creatBinTree(char *s,BinTree *&root) //创建二叉树。s为形如A(B,C(D,E))形式的字符串
    {
    int i;
    bool isRight=false;
    stack
    <BinTree*> s1; //存放结点
    stack<char> s2; //存放分隔符
    BinTree *p,*temp;
    root
    ->data=s[0];
    root
    ->lchild=NULL;
    root
    ->rchild=NULL;
    s1.push(root);
    i
    =1;
    while(i<strlen(s))
    {
    if(s[i]=='(')
    {
    s2.push(s[i]);
    isRight
    =false;
    }
    else if(s[i]==',')
    {
    isRight
    =true;
    }
    else if(s[i]==')')
    {
    s1.pop();
    s2.pop();
    }
    else if(isalpha(s[i]))
    {
    p
    =(BinTree *)malloc(sizeof(BinTree));
    p
    ->data=s[i];
    p
    ->lchild=NULL;
    p
    ->rchild=NULL;
    temp
    =s1.top();
    if(isRight==true)
    {
    temp
    ->rchild=p;
    cout
    <<temp->data<<"的右孩子是"<<s[i]<<endl;
    }
    else
    {
    temp
    ->lchild=p;
    cout
    <<temp->data<<"的左孩子是"<<s[i]<<endl;
    }
    if(s[i+1]=='(')
    s1.push(p);
    }
    i
    ++;
    }
    }

    void display(BinTree *root) //显示树形结构
    {
    if(root!=NULL)
    {
    cout
    <<root->data;
    if(root->lchild!=NULL)
    {
    cout
    <<'(';
    display(root
    ->lchild);
    }
    if(root->rchild!=NULL)
    {
    cout
    <<',';
    display(root
    ->rchild);
    cout
    <<')';
    }
    }
    }

    void preOrder1(BinTree *root) //递归前序遍历
    {
    if(root!=NULL)
    {
    cout
    <<root->data<<" ";
    preOrder1(root
    ->lchild);
    preOrder1(root
    ->rchild);
    }
    }

    void inOrder1(BinTree *root) //递归中序遍历
    {
    if(root!=NULL)
    {
    inOrder1(root
    ->lchild);
    cout
    <<root->data<<" ";
    inOrder1(root
    ->rchild);
    }
    }

    void postOrder1(BinTree *root) //递归后序遍历
    {
    if(root!=NULL)
    {
    postOrder1(root
    ->lchild);
    postOrder1(root
    ->rchild);
    cout
    <<root->data<<" ";
    }
    }

    void preOrder2(BinTree *root) //非递归前序遍历
    {
    stack
    <BinTree*> s;
    BinTree
    *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;
    }
    }
    }

    void inOrder2(BinTree *root) //非递归中序遍历
    {
    stack
    <BinTree*> s;
    BinTree
    *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;
    }
    }
    }

    void postOrder2(BinTree *root) //非递归后序遍历
    {
    stack
    <BTNode*> s;
    BinTree
    *p=root;
    BTNode
    *temp;
    while(p!=NULL||!s.empty())
    {
    while(p!=NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
    {
    BTNode
    *btn=(BTNode *)malloc(sizeof(BTNode));
    btn
    ->btnode=p;
    btn
    ->isFirst=true;
    s.push(btn);
    p
    =p->lchild;
    }
    if(!s.empty())
    {
    temp
    =s.top();
    s.pop();
    if(temp->isFirst==true) //表示是第一次出如今栈顶
    {
    temp
    ->isFirst=false;
    s.push(temp);
    p
    =temp->btnode->rchild;
    }
    else //第二次出如今栈顶
    {
    cout
    <<temp->btnode->data<<" ";
    p
    =NULL;
    }
    }
    }
    }

    void postOrder3(BinTree *root) //非递归后序遍历
    {
    stack
    <BinTree*> s;
    BinTree
    *cur; //当前结点
    BinTree *pre=NULL; //前一次訪问的结点
    s.push(root);
    while(!s.empty())
    {
    cur
    =s.top();
    if((cur->lchild==NULL&&cur->rchild==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(int argc, char *argv[])
    {
    char s[100];
    while(scanf("%s",s)==1)
    {
    BinTree
    *root=(BinTree *)malloc(sizeof(BinTree));
    creatBinTree(s,root);
    display(root);
    cout
    <<endl;
    preOrder2(root);
    cout
    <<endl;
    inOrder2(root);
    cout
    <<endl;
    postOrder2(root);
    cout
    <<endl;
    postOrder3(root);
    cout
    <<endl;
    }
    return 0;
    }
  • 相关阅读:
    HDU 4870 Rating(高斯消元 )
    iOS开发者账号详细介绍
    iOS之Block
    CocoaPods 安装和使用
    搭建自己的局域网服务器
    MarkDown语法收集
    正则表达式参考表
    iOS企业级应用打包与部署
    iOS开发之代码加载方式进入APP的界面
    shell脚本小Demo
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5244454.html
Copyright © 2020-2023  润新知