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

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

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

    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时大佬们自己体会吧……

  • 相关阅读:
    DOM attributes and properties
    SVN目录对号图标(更新、冲突)不显示
    GIS空间参考及坐标转换
    ArcGIS Engine开发之旅09--几何对象和空间参考
    ArcGIS Engine开发之旅08--和查询相关的对象和接口
    ArcGIS Engine开发之旅07---文件地理数据库、个人地理数据库和 ArcSDE 地理数据库中的栅格存储加以比较 、打开栅格数据
    ArcGIS Engine开发之旅05---空间数据库
    10.Action中的method属性
    11.使用ForwardAction实现页面屏蔽。
    9.初识拦截器
  • 原文地址:https://www.cnblogs.com/yuelien/p/9696282.html
Copyright © 2011-2022 走看看