zoukankan      html  css  js  c++  java
  • 二叉树

    先序非递归

      递归算法使用栈的特性——先进后出,因此非递归遍历二叉树时也需要用栈来模拟递归调用。递归处理内容如下:

    1. 当前节点的右子树若存在压栈
    2. 当前节点的左子树若存在压栈
    3. 当前节点再次压栈(以便下次非递归时访问)

      非递归处理内容

    1. 访问当前节点
    2. 弹出当前节点
    typedef struct TreeNode {
        int val;
        TreeNode *left, *right;
    }TreeNode;
    
    vector<int> preorderTraversal(TreeNode *root) {
        if(root == nullptr) {
            return {};
        }
        
        vector<int> res;
        stack<TreeNode *> call;
        call.push(root)
        while(!call.empty()) {
            TreeNode *tmp = call.top();
            call.pop();
            if(tmp != nullptr) { //当前节点没有被访问过 
                if(tmp->right) {
                    call.push(tmp->right); //1.栈的最底层,最后处理右子树 
                }
                if(tmp->left) { //2.左子树在右子树上,因为先序遍历先访问左子树 
                    call.push(tmp->left);
                }
                call.push(tmp); //3.当前访问的结点(可以看做根节点)在左子树上方,先序遍历根节点在左子树前被访问 
                call.push(nullptr); //4.标记当前结点被访问过 
            }
            else { //当前节点被访问过 
                res.push_back(call.top()->val); //5.访问当前节点,也就是加入结果集中 
                call.pop(); //6.彻底删除当前节点 
            }
        }
        return res;
    }

    中序非递归

      栈低到栈顶的顺序为:右子树-根节点-左子树,下次递归时左子树要弹出标记为被访问的节点

    vector<int> inorderTraversal(TreeNode *root) {
        if(root == nullptr) {
            return {};
        }
        
        vector<int> res;
        stack<TreeNode *> call;
        call.push(root);
        while(!call.empty()) {
            TreeNode *tmp = call.top();
            call.pop();
            if(tmp != nullptr) {
                if(tmp->right) {
                    call.push(tmp->right);
                }
                call.push(tmp);
                call.push(nullptr);//标记为要访问的结点,待处理;当左右子树都不存在时当前节点就是最后一个访问的结点 
                if(tmp->left) {
                    call.push(tmp->left); //沿着左子树一直往左下方走 
                }
            }
            else {
                res.push_back(call.top()->val);
                call.pop(); 
            }
        }
        return res;
    }

    后序非递归

    vector<int> postorderTraversal(TreeNode *root) {
        if(root == nullptr) {
            return {};
        }
        
        vector<int> res;
        stack<TreeNode *> call;
        call.push(root);
        while(!call.empty()) {
            TreeNode *tmp = call.top();
            call.pop();
            if(tmp != nullptr) {
                call.push(tmp);
                call.push(nullptr);
                if(tmp->right) {
                    call.push(tmp->right);
                }
                if(tmp->left) {
                    call.push(tmp->left);
                }
            }
            else {
                res.push_back(call.top()->val);
                call.pop();
            }
        }
        return res;
    } 

    分治法

      递归(先序递归遍历,从上到下)和分治遍历(先序遍历,从下向上合并子集)区别:前者一般将结果通过参数传递,后者递归返回结果合并。

      先分别处理局部,再合并结果。

    //先序 
    vector<int> inorderTraversal(TreeNode *root) {
        if(root == nullptr) {
            return {};
        }
        
        vector<int> res;
        vector<int> left = inorderTraversal(root->left);
        vector<int> right = inorderTraversal(root->right);
        
        res.push_back(root->val);
        res.insert(res.back(), left.begin(), left.end());
        res.insert(res.back(), right.begin(), right.end());
        return res;
    }

    BFS按层遍历

    vector<vector<int>> leverOrder(TreeNode *root) {
        if(root == nullptr) {
            return {};
        }
        
        vector<vector<int>> res;
        vector<int> tmp;
        queue<TreeNode *> q;
        TreeNode *last = root, *nlast = nullptr;//last代表当前行最右结点;nlast代表下一行最右结点 
        q.push(root);
        while(!q.empty()) {
            TreeNode *cur = q.front();
            q.pop();
            tmp.push_back(cur->val);//访问操作 
            if(cur->left) {
                q.push(cur->left);
                nlast = cur->left;
            }
            if(cur->right) {
                q.push(cur->right);
                nlast = cur->right;
            }
            
            if(cur == last) { //当前节点 == 当前行最右节点证明当前行已经访问完毕 
                res.push_back(tmp);
                tmp.clear();
                last = nlast;
            }
        }
        return res;
    }

    DFS按层遍历

    vector<vector<int>> res;
    void levelOrder(TreeNode* root, int level) {
        if(root == nullptr) {
            return ;
        }
        
        if(res.size() == level) {
            res.resize(level+1);
        }
        res[level].push_back(root->val);
        levelOrder(root->left, level+1);
        levelOrder(root->right, level+1);
    }

    序列化与反序列化

    void serialize(TreeNode* head,vector<char> &B)//先序序列化:B存放序列化结果
    {
        if(!head)//1.遍历到空节点时做什么事
        {
            B.push_back('#');
            B.push_back('!');
            return;
        }
        //2.结点不为空
        int value=head->val;
        if(!value)//2.1值是否为真
        {
            B.push_back('0');
            B.push_back('!');
            serialize(head->left,B);
            serialize(head->right,B);
            return;
        }
        //数字数值可能超过一位
        int a=0;
        vector<int> A;
        while(value)
        {
            a=value%10;
            A.push_back(a);
            value/=10;
        }
        while(!A.empty())
        {
            a=A.back();
            A.pop_back();
            B.push_back('0'+a);
        }
        B.push_back('!');
    
        serialize(head->left,B);
        serialize(head->right,B);
        return;
    }
    
    void deserialize(vector<char> A,TreeNode* & head)//先序反序列化:#空结点,!当前结点结束,n表示当前读的字符位置,A为输入原序列
    {
        int i,j,value=0;
        if((n>A.size()-1)||A[n]=='#')
            return;
    
        i=j=n;
        while(A[j]!='!')
            j++;
        while(j>i)
        {
            value=(A[i]-'0')+value*10;
            i++;
        }
    
        head=(TreeNode*)malloc(sizeof(TreeNode));
        (*head).val=value;
        (*head).right=(*head).left=NULL;
        n=i+1;
        deserialize(A,(*head).left);
        deserialize(A,(*head).right);
    }

    分治应用

      适用场景

    1. 快速排序
    2. 归并排序
    3. 二叉树相关问题

      分治法模板

    1. 递归返回条件
    2. 分段处理
    3. 合并结果

      递归结束需要对返回结果进行合并

    void _merge(vector<int>& num, int start, int mid, int end) {
        int *tmp = new int[start-end+1];//合并两个临时区
        int i = start;
        int j = mid+1;
        int k = 0;
        
        while(i <= mid && j <= end) {
            tmp[k++] = num[i] < num[j] ? num[i++] : num[j++];
        } 
        
        while(i <= mid) {
            tmp[k++] = num[i++];
        }
        while(j <= end) {
            tmp[k++] = num[j++];
        }
        
        for(i = 0; i < k; ++i) {
            num[start+i] = tmp[i];
        }
        delete []tmp;
    }
    void mergeSortUpToDown(vector<int>& num, int start, int end) {
        if(num.empty() || start >= end) {
            return ;
        }
        
        int mid = start+(end-start)/2;
        mergeSortUpToDown(num, start, mid);
        mergeSortUpToDown(num, mid+1, end);
        
        _merge(num, start, mid, end);
    }

    快排

      快排由于是原地交换所以没有合并过程 传入的索引是存在的索引(如:0、length-1 等),越界可能导致崩溃

    void quickSort(vector<int>& num, int start, int end) {
        if(start >= end || num.empty()) {
            return;
        }
        
        int left = start;
        int right = end;
        int key = num[start];
        while(left < right) {
            while(left < right && num[right] >= key) {
                --right;
            }
            num[left] = num[right];
            
            while(left < right && num[left] <= key) {
                ++left;
            }
            num[right] = num[left];
        }
        
        num[left] = key;
        quickSort(num, start, left);
        quickSort(num, left+1, end);
    }

    题目

    求给定二叉树的最大深度

      按层求高度

    int maxDepth(TreeNode* root) {
        if(!root)
            return 0;
        
        queue<TreeNode*> q;
        q.push(root);
        int depth=0;
        while(!q.empty())
        {
            ++depth;
            int layer=q.size();
            while(layer>0)//按层处理,把每层的结点处理完
            {
                auto tmp=q.front();
                q.pop();
                if(tmp->left)
                    q.push(tmp->left);
                if(tmp->right)
                    q.push(tmp->right);
                --layer;
            }
        }
        return depth;
    }

      分治求,先递归求左子树高度,再递归求右子树高度,合并左右子树高度返回

    int maxDepth(TreeNode* root) {
        if(root == NULL)
            return 0;
        
        int leftHeight = maxDepth(root->left);
        int rightHeight = maxDepth(root->right);
    
        return max(leftHeight, rightHeight)+1;
    }
  • 相关阅读:
    直接插入排序学习笔记
    选择排序学习笔记
    冒泡排序学习笔记
    阿里云ssl证书申请及域名绑定流程
    Nginx user_agent、if指令及全局变量
    rewrite和return笔记
    rewrite和return的简单需求
    Nginx Rewrite正则表达式案例
    linux下WordPress伪静态规则设置
    集群前后端分离(api接口)
  • 原文地址:https://www.cnblogs.com/tianzeng/p/13735416.html
Copyright © 2011-2022 走看看