zoukankan      html  css  js  c++  java
  • 二叉树的非递归遍历

    建立二叉树后通过递归进行遍历时很简单   我们也可以通过合理的使用栈 和 队列进行  前中后 跟层序 遍历

    #include <iostream>
    #include <vector>
    #include <stack>
    using namespace std;
    
    typedef struct treenode
    {
        int data;
        struct treenode * left;
        struct treenode* right;
    }TREE_NODE;
    typedef struct T_N
    {
        TREE_NODE* root;
        int size;
    }TREE;
    
    void PreOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            cout<<root->data<<" ";
            PreOrderTraverse(root->left);
            PreOrderTraverse(root->right);
        }
    }
    
    void InOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            InOrderTraverse(root->left);
            cout<<root->data<<" ";
            InOrderTraverse(root->right);
        }
    }
    void PostOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            PostOrderTraverse(root->left);
            PostOrderTraverse(root->right);
            cout<<root->data<<" ";
        }
    }
    
    void printTreeByLevel(TREE_NODE* root) //层序遍历 
    {
        if(NULL == root)
        {
            return;
        }
        vector<TREE_NODE*>tempVector;
        tempVector.push_back(root);
        int cur=0;
        while(cur<tempVector.size())
        {
            cout<<tempVector[cur]->data<<" ";
            if(tempVector[cur]->left != NULL)
            {
                tempVector.push_back(tempVector[cur]->left);
            }
            if(tempVector[cur]->right !=NULL)
            {
                tempVector.push_back(tempVector[cur]->right);
            }
            cur++;
        }
        cout<<endl;
    }

    我们先考虑中序遍历的非递归形式,顺序是  左  根  右   这个时用到了 栈 先入后出

    我们一定是先找到最左边的叶子节点

    if(NULL == root)
    {
    		return;
    }
    stack<TREE_NODE*>tempS;
    while(root)
    {
    	tempS.push(root);
    	root = root->left;
    }


    保存一路走过的根节点的理由是:中序遍历的需要,遍历完左子树后,需要借助根节点进入右子树。代码走到这里,指针p为空,此时无非两种情况:


        我们的思维接着走,两图情形不同得区别对待: 1.图a中访问的是一个左孩子,按中序遍历顺序,接下来应访问它的根节点。也就是图a中的另一个节点,高兴的是它已被保存在栈中。我们只需这样的代码和上一步一样的代码:

    void InOrderPrint(TREE_NODE* root) //中序遍历  理解下思想  就不难了
    {
        if(NULL == root)
        {
            return;
        }
        stack<TREE_NODE*>tempS;
        while(!tempS.empty() || root)//  理解为什么这样写 tempS.empty()是为了输出全部用的
        {
            if(root)
            {
                tempS.push(root);
                root = root->left;
            }
            else
            {
                root = tempS.top();
                tempS.pop();
                cout<<root->data<<" ";
                root = root->right;
            }
        }
    }
    
    void InOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            InOrderTraverse(root->left);
            cout<<root->data<<" ";
            InOrderTraverse(root->right);
        }
    }

    对于前序遍历一样 的情况 类似 分析后直接给出代码

    void PreOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            cout<<root->data<<" ";
            PreOrderTraverse(root->left);
            PreOrderTraverse(root->right);
        }
    }
    
    void PreOrderPrint(TREE_NODE *root)
    {
        if(NULL == root)
        {
            return;
        }
        stack<TREE_NODE*>tempS;
        while(!tempS.empty() || root)
        {
            if(root)
            {
                cout<<root->data<<" ";
                tempS.push(root);
               root = root->left;
            }
            else
            {
                root = tempS.top();
                tempS.pop();
                root = root->right;
            }
        }
    }

    后序遍历
    分析
    后序遍历递归定义:先左子树,后右子树,再根节点。后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。直接看代码,代码中有详细的注释。

    void PostOrderTraverse(TREE_NODE* root)
    {
        if(root)
        {
            PostOrderTraverse(root->left);
            PostOrderTraverse(root->right);
            cout<<root->data<<" ";
        }
    }
    
    void PostOrderPrint(TREE_NODE* root)
    {
        if(NULL == root)
        {
            return ;
        }
        stack<TREE_NODE*>tempS;
        TREE_NODE* front = NULL;
        while(root)
        {
            tempS.push(root);
            root = root->left;
        }//照样先找到最左边的根节点
    
        while(! tempS.empty())
        {
            root = tempS.top(); //因为上面while 循环后root 为空 此时要先取出 最左边的root
            tempS.pop();
            if(root->right == NULL || root->right == front)// 一个根节点被访问的前提是:无右子树或右子树已被访问过
            {
                cout << root->data << " ";
                front = root;
            }
            else
            {
                tempS.push(root); // 还要把该点入栈 然后 打出右子树
                root = root->right;  //进入右子树,且肯定右子树一定不为空
                while(root)
                {
                    tempS.push(root);
                    root = root->left;
                }
            }
        }
    }


    关注公众号 海量干货等你
  • 相关阅读:
    分块传输编码在WEB安全中的应用——sql注入用,可以直接复用chunkSplitPostData还原
    漏扫是如何做的?——从xunfeng源码看漏扫原理
    WhatWeb使用——可识别Web技术,包括内容管理系统(CMS),博客平台,统计/分析包,Javascript库,服务器和嵌入式设备
    PyCharm单行执行代码 或 运行选中的代码
    PyCharm 改变黑色主题的颜色方案
    Docker四种网络模式
    Does C# have an equivalent to JavaScript's encodeURIComponent()?
    When are you supposed to use escape instead of encodeURI / encodeURIComponent?
    Difference between escape(), encodeURI(), encodeURIComponent()
    How can I trace the HttpClient request using fiddler or any other tool?
  • 原文地址:https://www.cnblogs.com/sowhat1412/p/12734404.html
Copyright © 2011-2022 走看看