二叉树构造与遍历复习

本文详细介绍了二叉树的构造方法,包括递归和层次遍历,并展示了先序、中序和后序遍历的迭代实现。此外,还探讨了一种通用的迭代中序遍历算法,以及层次遍历的队列应用。这些算法在理解和实现二叉树操作上具有重要意义。
摘要由CSDN通过智能技术生成

二叉树的构造

void createTree(TreeNode* &root)//构造时候尤其要注意,放进去引用,因为修改的是指针本身不是指针所指内容
    {
        int val;
        cin >> val;
        if (val)
        {
            root = new TreeNode(val);
            createTree(root->left);
            createTree(root->right);
        }
        else
        {
            return;
        }
        return;
    }

该情况为“先序”的思路来构造的

  void createTree2(TreeNode*& root)
    {
        int a;
        cin >> a;
        if (a)
            root = new TreeNode(a);
        else
            return;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty())
        {
            TreeNode* p = que.front();
            que.pop();
            cin >> a;
            if (a)
            {
                p->left = new TreeNode(a);
                que.push(p->left);
            }
            cin >> a;
            if (a)
            {
                p->right = new TreeNode(a);
                que.push(p->right);
            }
        }
        return;
    }//层次create

该情况是以层次遍历的思想,利用队列来进行构造

深度优先遍历分为递归法和迭代法,递归法较为简单,下面是中序遍历的递归函数

void midOrderTree(TreeNode* root)//中序遍历
    {
        if (root == NULL)
            return;
        midOrderTree(root->left);
        cout << root->val << ' ';
        midOrderTree(root->right);
        return;
    }

迭代法也有两类,一类是单纯针对每一种顺序遍历来改变思路求解,无通用性。

void pre(TreeNode* root)
    {
        stack<TreeNode*> st;
        if(root!=NULL)
            st.push(root);
        TreeNode* p = NULL;
        while (!st.empty())
        {
            p = st.top();
            st.pop();
            cout << p->val << ' ';
            if(p->right)
                st.push(p->right);
            if(p->left)
                st.push(p->left);
        }
        return;
    }

该情况利用了堆栈,先序遍历时,先把树根入栈,每弹出一个元素指针,就要再进去0~2个元素,注意顺序是先右后左放,才能先左后右出

void mid(TreeNode* root)//把根左边的全放进去,出来时候把右边的左线也放进去
    {
        stack<TreeNode*> st;
        TreeNode* p = root;
        while (p != NULL || !st.empty())//难点之处,利用p的有无,把这次迭代放新东西和处理top()分开
        {
            if (p != NULL)
            {
                st.push(p);
                p = p->left;
            }
            else
            {
                p = st.top();
                st.pop();
                cout << p->val << ' ';
                p = p->right;
            }
        }
    }

中序的思路稍微复杂一点点,while语句的部分,需要借助p来区分开本次迭达的操作是入栈还是处理栈顶元素

void end(TreeNode* root)//针对先序修改输出顺序,中左右->中右左->左右中
    {
        vector<int> re;
        stack<TreeNode*> st;
        if (root != NULL)
            st.push(root);
        while (!st.empty())
        {
            TreeNode* p = st.top();
            st.pop();
            re.push_back(p->val);
            if(p->left != NULL)
                st.push(p->left);
            if(p->right != NULL)
                st.push(p->right);
        }
        for (int i = re.size()-1; i>=0; i--)
        {
            cout << re[i] << ' ';
        }
        return;
    }

后序的处理思路借助于先序的思路,仅改变先序的输出顺序即可

迭代法除了上述三个算法,还有一种比较通用的算法,该通用解法思路需要刻意记一下

    //上面的三种思路清晰,但是不够通用统一,还用一种比较通用的迭代思路,以中序为例
    void midOrder(TreeNode* root)
    {
        TreeNode* p = root;
        stack<TreeNode*> st;
        if (p != NULL)
            st.push(p);
        while (!st.empty())
        {
            p = st.top();
            if (p != NULL)
            {
                st.pop();
                if (p->right != NULL)
                    st.push(p->right);
                st.push(p);
                st.push(NULL);
                if (p->left != NULL)
                    st.push(p->left);
            }
            else
            {
                st.pop();
                p = st.top();
                st.pop();
                cout << p->val << ' ';
            }
        }
    }

这种思路参照于迭代法的中序遍历,同样是通过一个元素是否为空来判定本次迭代是出栈还是入栈处理,把那些已经遍历访问过(访问完又回来是因为需要处理好其左右子节点,按顺序重新放进来),但还未被处理掉的元素之前压入NULL元素,待下次遍历之时再彻底出栈不再回来

层次遍历

    //层序遍历,用到的是队列,出一个,进0~2个
    void levelOrder(TreeNode* root)
    {
        queue<TreeNode*> que;
        if (root != NULL)
            que.push(root);
        while (!que.empty())
        {
            TreeNode* p = que.front();
            que.pop();
            cout << p->val << ' ';
            if (p->left != NULL)
                que.push(p->left);
            if (p->right != NULL)
                que.push(p->right);
            
        }
        return;
    }
};

和深度遍历非递归法最大不同之处在于用到的是队列,思路较为简单

详细代码如下

#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;

struct TreeNode {//节点
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class tree
{
public:
    tree()
    {}
    void createTree(TreeNode* &root)//构造时候尤其要注意,放进去引用,因为修改的是指针本身不是指针所指内容
    {
        int val;
        cin >> val;
        if (val)
        {
            root = new TreeNode(val);
            createTree(root->left);
            createTree(root->right);
        }
        else
        {
            return;
        }
        return;
    }

    void createTree2(TreeNode*& root)
    {
        int a;
        cin >> a;
        if (a)
            root = new TreeNode(a);
        else
            return;
        queue<TreeNode*> que;
        que.push(root);
        while (!que.empty())
        {
            TreeNode* p = que.front();
            que.pop();
            cin >> a;
            if (a)
            {
                p->left = new TreeNode(a);
                que.push(p->left);
            }
            cin >> a;
            if (a)
            {
                p->right = new TreeNode(a);
                que.push(p->right);
            }
        }
        return;
    }//层次create

    //深度优先遍历
    void preOrderTree(TreeNode* root)//先序遍历
    {
        if (root != NULL)
            cout << root->val << ' ';
        else
            return;
        preOrderTree(root->left);
        preOrderTree(root->right);
        return;
    }
    void midOrderTree(TreeNode* root)//中序遍历
    {
        if (root == NULL)
            return;
        midOrderTree(root->left);
        cout << root->val << ' ';
        midOrderTree(root->right);
        return;
    }
    void endOrderTree(TreeNode* root)//后序遍历
    {
        if (root == NULL)
            return;
        endOrderTree(root->left);
        endOrderTree(root->right);
        cout << root->val << ' ';
        
    }

    //迭代法遍历
    void pre(TreeNode* root)
    {
        stack<TreeNode*> st;
        if(root!=NULL)
            st.push(root);
        TreeNode* p = NULL;
        while (!st.empty())
        {
            p = st.top();
            st.pop();
            cout << p->val << ' ';
            if(p->right)
                st.push(p->right);
            if(p->left)
                st.push(p->left);
        }
        return;
    }
    void mid(TreeNode* root)//把根左边的全放进去,出来时候把右边的左线也放进去
    {
        stack<TreeNode*> st;
        TreeNode* p = root;
        while (p != NULL || !st.empty())//难点之处,利用p的有无,把这次迭代放新东西和处理top()分开
        {
            if (p != NULL)
            {
                st.push(p);
                p = p->left;
            }
            else
            {
                p = st.top();
                st.pop();
                cout << p->val << ' ';
                p = p->right;
            }
        }
    }
    void end(TreeNode* root)//针对先序修改输出顺序,中左右->中右左->左右中
    {
        vector<int> re;
        stack<TreeNode*> st;
        if (root != NULL)
            st.push(root);
        while (!st.empty())
        {
            TreeNode* p = st.top();
            st.pop();
            re.push_back(p->val);
            if(p->left != NULL)
                st.push(p->left);
            if(p->right != NULL)
                st.push(p->right);
        }
        for (int i = re.size()-1; i>=0; i--)
        {
            cout << re[i] << ' ';
        }
        return;
    }

    //上面的三种思路清晰,但是不够通用统一,还用一种比较通用的迭代思路,以中序为例
    void midOrder(TreeNode* root)
    {
        TreeNode* p = root;
        stack<TreeNode*> st;
        if (p != NULL)
            st.push(p);
        while (!st.empty())
        {
            p = st.top();
            if (p != NULL)
            {
                st.pop();
                if (p->right != NULL)
                    st.push(p->right);
                st.push(p);
                st.push(NULL);
                if (p->left != NULL)
                    st.push(p->left);
            }
            else
            {
                st.pop();
                p = st.top();
                st.pop();
                cout << p->val << ' ';
            }
        }
    }



    //层序遍历,用到的是队列,出一个,进0~2个
    void levelOrder(TreeNode* root)
    {
        queue<TreeNode*> que;
        if (root != NULL)
            que.push(root);
        while (!que.empty())
        {
            TreeNode* p = que.front();
            que.pop();
            cout << p->val << ' ';
            if (p->left != NULL)
                que.push(p->left);
            if (p->right != NULL)
                que.push(p->right);
            
        }
        return;
    }
};




int main()
{
    TreeNode* root = NULL;
    tree Tree;

    Tree.createTree(root);

    //Tree.preOrderTree(root);
    //cout << endl;
    //Tree.pre(root);
    //cout << endl;

    //Tree.midOrderTree(root);
    //cout << endl;
    //Tree.mid(root);
    //cout << endl;

    //Tree.endOrderTree(root);
    //cout << endl;
    //Tree.end(root);
    //cout << endl;
    //
    //Tree.midOrder(root);
    //cout << endl;


    Tree.levelOrder(root);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值