代码随想录第十四天 | 1、理论基础,2、递归遍历,3、迭代遍历,4、统一迭代,5、层序遍历

1、理论基础

忘记概念的有:完全二叉树平衡二叉搜索树

完全二叉树:除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层节点数的取值范围为 [1,  2^(h-1) ]

平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

二叉树可以链式存储(链表,更好理解),也可以顺序存储(数组)。

二叉树的遍历方式:

  • 深度优先遍历
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(迭代法)

2、递归遍历

看完想法:刚开始写又不会了( :( )。牢记递归三部曲:

  • 确定递归函数的参数和返回值。确定哪些参数是递归中需要处理的,那么就在递归函数里加上这个参数,并且还要明确每次递归的返回值,进而确定递归函数的类型
  • 确定终止条件。
  • 确定单层递归的逻辑。
    //此处仅列出前序遍历
    void Traversal(TreeNode* root, vector<int>& result){
        //因为参数列表引用了result,所以能够修改主函数中result的值
        if(root == nullptr) return ;
            result.push_back(root->val);
            Traversal(root->left, result);
            Traversal(root->right, result);        
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        Traversal(root, result);
        return result;
    }

在递归遍历的题目中,因为要打印出前序遍历节点的数值,所以参数里需要传入vector来放节点的数值,除了这一点就不需要再处理什么数据了也不需要有返回值,所以递归函数返回类型就是void,

3、迭代遍历

看完想法:是用栈来做二叉树的进入进出。具体来说

vector<int> preorderTraversal(TreeNode* root) {
        //使用栈来存储,栈的数据机构可以为二叉树*,不必为Int
        stack<TreeNode*> st;
        vector<int> result;
        if(root == nullptr) return result;
        st.push(root);
        while( !st.empty()){
            //当st不为空时,记录栈顶元素并弹出
            TreeNode* tmp = st.top();
            st.pop();
            //用result记录下弹出元素的数值
            result.push_back(tmp->val);
            //然后进行下一步的遍历
            //记得左右反过来,因为栈是先入后出的
            if(tmp->right) st.push(tmp->right);
            if(tmp->left) st.push(tmp->left);
            
        }
        return result;
    }

这只是前序遍历,到了中序遍历,又不一样了!因为中序遍历处理顺序和处理顺序是不一样的。(前序遍历遍历到中节点,处理的也是中节点,所以代码简洁)

在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素

vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode* > st;//stack用来遍历
        vector<int> result;//result用来记录
        TreeNode* cur = root;
        if(root == nullptr) return result;
        //st.push(root);
        //这里不需要预先放入root,后面可以放进去
        while( !st.empty() || cur!=NULL ){
            if(cur != NULL){
                //一直先遍历到左边底部
                st.push(cur);
                cur=cur->left;
            }
            else{
                //遍历到头后开始处理节点
                cur = st.top();
                st.pop();
                result.push_back(cur->val);//中
                cur = cur->right;//右
            }
        }
        return result;

    }

后序遍历只需将前序遍历得到的数组反过来就行,因为左→右→中   —→ 中→右→左

4、统一迭代

看完想法:统一迭代的思路是将访问的节点放入栈中,把要处理的节点也放入栈中但是要用空指针做标记

vector<int> preorderTraversal(TreeNode* root) {
        //使用栈来存储,栈的数据机构可以为二叉树*,不必为Int
        stack<TreeNode*> st;
        vector<int> result;
        //TreeNode* cur = root;
        //不能这么定义,cur要在while中更新成为.top()
        if(root == nullptr) return result;
        st.push(root);
        while(!st.empty()){
            TreeNode* cur = st.top();
            if(cur !=NULL){
                //后面一次性将右中左放入,这是为了避免重复操作和防止打乱顺序
                st.pop();
                if(cur->right) st.push(cur->right);
                if(cur->left) st.push(cur->left);
                st.push(cur);
                st.push(NULL);//做标记
                
                }
            else{//这里是处理阶段
                st.pop();
                cur = st.top();
                st.pop();//还需要弹出一次
                result.push_back(cur->val);
            }
        }
        return result;
        }

5、层序遍历

vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode* > que;
        vector<vector<int>> result;//层序的数据格式是这样
        if(root==nullptr) return result;
        que.push(root);
        while(!que.empty()){
            int size = que.size();
            vector<int> vec;
            //每一层遍历完后都要记录下一层节点的值
            //这样才知道每层的节点数量
            for(int i = 0; i<size; i++){
                TreeNode* cur = que.front();
                que.pop();
                vec.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
                //每次pop都把当前节点的左右孩子加入que

            }
            result.push_back(vec);
        }
        return result;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值