桶排序、递归、迭代、尾递归

1. 桶排序:桶排序将[0,1)区间划分为n个相同的大小的子区间,这些子区间被称为。然后将n个输入元素分别放入各自的桶中。因为输入时均匀独立的,所以一般不会有很多数同时落在一个桶中的情况。这样,我们想对各个桶中的数据进行排序,然后遍历每个桶,按照次序把各个桶中的元素列出来即可。 

桶排序、递归、迭代、尾递归

对于N个待排数据,M个桶,平均每个桶[N/M]个数据的桶排序平均时间复杂度为:

O(N)+O(M*(N/M)*log(N/M))=O(N+N*(logN-logM))=O(N+N*logN-N*logM)

当N=M时,即极限情况下每个桶只有一个数据时。桶排序的最好效率能够达到O(N)。

总结:桶排序的平均时间复杂度为线性的O(N+C),其中C=N*(logN-logM)。如果相对于同样的N,桶数量M越大,其效率越高,最好的时间复杂度达到O(N)。当然桶排序的空间复杂度为O(N+M),如果输入数据非常庞大,而桶的数量也非常多,则空间代价无疑是昂贵的。此外,桶排序是稳定的

2.递归:函数自己调用自己。在使用递归时, 必须有一个明确的递归结束条件, 称为递归出口。

优点:代码简洁清晰,可读性强。 缺点:有空间消耗,递归深度太大,可能会造成栈溢出。

3. 迭代:就是A不停的调用B。利用变量的原值推算出变量的一个新值

优点:迭代效率高,运行时间只因循环次数增加而增加。没什么额外开销,空间上也没有什么增加。

缺点:代码不易理解,没有递归简洁。(循环斐波那契额数列)

4. 尾递归:

桶排序、递归、迭代、尾递归

如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。

尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。比如f(n, sum) = f(n-1) + value(n) + sum;会保存n个函数调用堆栈,而使用尾递归f(n, sum) = f(n-1, sum+value(n)); 这样则只保留后一个函数堆栈即可,之前的可优化删去。

5. 递归转为非递归:1.循环代替递归(斐波那契数列) 2.借助堆栈循环代替递归。