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

  • 相关阅读:
    模拟75 题解
    模拟74 题解
    模拟73 题解
    模拟72 题解
    前端学习:html基础学习二
    前端学习:html基础学习一
    JavaScrip:Function函数编程
    MYSQL:RELPACE用法
    MYSQL:插入记录检查记录是否存在,存在则更新,不存在测插入记录SQL
    OpenCASCADE Curve Length Calculation
  • 原文地址:https://www.cnblogs.com/yuelien/p/9696282.html
Copyright © 2011-2022 走看看