递归到底是怎么实现的?它的时间复杂度怎么算?

递归到底是个啥?

常听见的一句话就是:自己调用自己。

按照这个说法,写个简单的递归自己推导一下的确可以,但是总是有点绕,推着推着自己把自己陷进去了。

递归函数运行时,实际上会进行一个压栈(思考栈的特点,先进后出,后进先出)的过程。

写个简单的递归排序算法:

public static void main(String[] args) {
        int[] arr={1,3,4,2};
        System.out.println(digui(arr,0,arr.length-1));
    }

    public static int digui(int[] arr,int L,int R){
        if(L==R)
            return arr[L];
        int mid=(L+R)/2;
        int LeftMax=digui(arr,L,mid);
        int RightMax=digui(arr,mid+1,R);
        return Math.max(LeftMax,RightMax);
    }

当第一次进入digui方法时,在第十行,也就是

int LeftMax=digui(arr,L,mid);

1.程序会第一次进入到子方法,也就是调用本身。这时候会往堆栈里面记录此时这个方法的信息,比如L=0,R=3,mid=1等等,并且暂停这个方法的继续运行,先进入到子方法。

2.程序进入子方法,第二次到第十行代码时,依旧会往堆栈里记录此时的方法信息,L=0,R=1,mid=0等等

3.程序再次进入子方法,第三次运行到第十行代码时,此时L=0,R=0。所以会返回arr[0],也就是1.因为返回了数值,没有再次调用自己,所以不用再次压栈

此时的堆栈信息如图

4.由于上一步返回了一个1,那么自然就会先回到其父方法,也就是L=0,R=1,mid=0的这个方法。这时候LeftMax就会接受到其子方法的返回的数据,也就是1.

5.接着运行第十一行代码,继续压栈,然后运行其子方法。自己捋一下,第十一行的子方法返回的是3

6.接着运行第十二行代码,会比较1和3谁大,然后返回。至此,L=0,R=1,mid=0时的这个方法彻底执行完毕,接着就会执行出栈操作。

有了堆栈图的辅助,理清递归过程就清晰多了。大家可以自己捋一捋接下来几步的过程。总比以前光凭一个脑袋想好多了。

递归的时间复杂度怎么算?

一般情况下,可以用以下公式:

T(N)=aT(N/b)+O(N^d);

其中,T是样本,N的样本量。

b代表这个样本被分为了几部分(上面的算法被分为两部分(L+R)/2,所以b=2),a代表运行了多少次(上面的算法需要调用自己两次,所以a=2)。

一定要记住,这个a和b,不需要展开所有堆栈里的情况,只需要看最表面上的代码就行,不用想里面的子方法还调用了多少次本身。

后面接着的O(N^d)代表除了前面那部分主体外,还需要多少时间复杂度,比如前面的aT(N/b)这部分运行完,我还需要O(N^2)的时间复杂度才能最终完成输出,那么d=2。

那么T(N)=aT(N/b)+O(N^d)到底怎么求出具体结果呢?

上面的算法中,a=2,b=2,d=0

所以log(b,a)=1.大于d的。所以时间复杂度为O(N)

猜你喜欢

转载自www.cnblogs.com/lbhym/p/12194350.html
今日推荐