• 【解递归】二叉树遍历的递归与非递归写法启发下的对非线性增长递归程序的非递归写法总结(上)


    验证了一下在图书馆脑洞出来的算法实现的正确性

      当谈到一个程序的递归与非递归写法时,一般首先想到数据结构中二叉树三种遍历对应的递归与非递归写法。当递归程序中只有一次对自身的调用,也就是线性增长时,很容易解递归。例如二分查找的递归与非递归写法。

    int find(int a[],int key,int low,int high){//a为升序序列
            if(low<=high){
                int mid=(low+high)/2;
                if(a[mid]==key) return mid;
                else if(a[mid]<key) return find(a,key,mid+1,high);
                else return find(a,key,low,mid-1);
            }
            return -1;
        }
        int find_2(int a[],int key,int low,int high){//a为升序序列
            int i=low,j=high;
            int mid=0;
            while (i<=j){
                mid=(low+high)/2;
                if(a[mid]==key)return mid;
                else if(a[mid]<key) i=mid+1;
                else j=mid-1;
            }
            return -1;
        }
    View Code

       而程序中有多次自身调用时,例如二叉树的遍历、快速排序的递归写法,均为二次调用,此时递归非线性增长,故需要引入数据结构--栈用来保存现场,实现程序的非递归写法。

      为了有个二叉树做测试,用递归写了个先序和中序序列确定一颗二叉树:

    class node{
            public char e;
            public node left,right;
        }
        class child{
            public int left_low,left_high;
            public int right_low,right_high;
        }
        public child findInOrder(char in[],int root,int low,int high){
            for(int i=low;i<=high;i++){
                if(in[i]==root){
                    child child=new child();
                    child.left_low=low;child.left_high=i-1;
                    child.right_low=i+1;child.right_high=high;
                    return child;
                }
            }
            return null;
        }
        public void PreInBuild(node parent,char pre[],int p_low,char in[],int in_low,int in_high){
            if (p_low<pre.length){
                parent.e=pre[p_low];
                child child= findInOrder(in,pre[p_low],in_low,in_high);
                if (child.left_low<=child.left_high) {
                    parent.left=new node();
                    PreInBuild(parent.left, pre, p_low + 1
                            , in, child.left_low, child.left_high);
                }
                if (child.right_low<=child.right_high) {
                    parent.right=new node();
                    PreInBuild(parent.right, pre, p_low + child.left_high - child.left_low + 2,
                            in, child.right_low, child.right_high);
                }
            }
        }
    View Code

    char pre[]={'a','b','d','e','h','c','f','g','i','k','j'};
    char in[]={'d','b','h','e','a','f','c','i','k','g','j'};

    对应的先序遍历:

       public void preOrder(node tree){
            if(tree!=null){
                System.out.print(tree.e+"");
                preOrder(tree.left);
                preOrder(tree.right);
            }
        }

     非递归写法:

        public void preOrder_2(node tree){
            node p=tree;
            Stack<node>stack=new Stack<>();
            while (p!=null||!stack.empty()){
                while (p!=null){
                    System.out.print(p.e+"");
                    stack.push(p);
                    p=p.left;
                }
                if(!stack.empty()){
                    p=stack.pop().right;
                }
            }
        }

       接着让我们看一下快排的递归写法:

     1   public int patition(int a[],int low,int high){
     2         if(low<high&&high<a.length) {
     3             int key = a[high];
     4             while (low < high) {
     5                 while (low < high && a[low] <= key)
     6                     low++;
     7                 a[high] = a[low];
     8                 while (low < high && a[high] >= key)
     9                     high--;
    10                 a[low] = a[high];
    11             }
    12             a[low] = key;
    13             return low;
    14         }
    15         return -1;
    16     }
    View Code
       public void quickSort(int a[],int low,int high){
            if(low<high&&high<a.length){
                int mid=patition(a,low,high);
                quickSort(a,low,mid-1);
                quickSort(a,mid+1,high);
            }
        }

    形式上与二叉树先序遍历的递归写法相似,所以将二叉树节点视为对场景的保存,出栈的也就是我们以线性方式实现非线性时忽略的部分,(在二叉树中是每个节点的右子树,故在快排中是partition后key值的右侧。我们要对右半的起止下标压栈,故有:

        class SharpShot{
            public int low,high;
        }
        public void quickSort_2(int a[],int low,int high){
            Stack<SharpShot>stack=new Stack<>();
            int i=low,j=high;
            while (i<j||!stack.empty()){
                while (i<j) {
                    int mid = patition(a, i, j);
                    SharpShot shot=new SharpShot();
                    shot.low=mid+1;
                    shot.high=j;
                    stack.push(shot);
                    j=mid-1;
                }
                if(!stack.empty()){
                    SharpShot shot=stack.pop();
                    i=shot.low;
                    j=shot.high;
                }
            }
        }

     由此可见递归生成k叉树,k>2时大佬们自己体会吧……

  • 相关阅读:
    [数字证书] 怎么打开windows的数字证书管理器
    [RF] 安装好Robot Framework之后怎样让启动的界面后面不带命令行窗口,且图片以机器人显示
    [RF]怎样用Robot Framework写好Test Case?
    iptables的疑问
    centos6.5安装jenkins文档部署全过程
    haproxy+keepalived以及haproxy的原理特点
    rhel6.5安装ansible
    客户端执行rsync出现的错误
    LVS_DR 安装后无法转发真实服务器,但是配置其他方面都检查的没有问题了。就剩在realserver这边没有在lo口上绑定VIP了
    架构设计:负载均衡层设计方案(1)——负载场景和解决方式
  • 原文地址:https://www.cnblogs.com/yuelien/p/9696282.html
Copyright © 2020-2023  润新知