今天鞋百科给各位分享排序的递归怎么算的知识,其中也会对使用递归方法实现合并排序应该注意什么,(请用递归方法写出归并排序法的主要思想和算法)进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在我们开始吧!
使用递归方法实现合并排序应该注意什么,
不知道你具体指的什么意思?
感觉如果使用归并排序你要注意以下几点:
注意递归的退出条件,不然将无法返回
注意边界条件的处理
你是使用C语言实现的,所以注意指针的使用
其实这也是所有问题应该注意的两点。
快速排序算法在平均情况下的时间复杂度为 求详解
时间复杂度为O(nlogn) n为元素个数
1. 快速排序的三个步骤:
1.1. 找到序列中用于划分序列的元素
1.2. 用元素划分序列
1.3. 对划分后的两个序列重复1,2两个步骤指导序列无法再划分
所以对于n个元素其排序时间为
T(n) = 2*T(n/2) + n (表示将长度为n的序列划分为两个子序列,每个子序列需要T(n/2)
的时间,而划分序列需要n的时间)
而 T(1) = 1 (表示长度为1的序列无法划分子序列,只需要1的时间即可)
T(n) = 2^logn + logn * n (n被不断二分最终只能二分logn次(最优的情况,每次选取
的元素都均分序列))
= n + nlogn
因此T(n) = O(nlogn)
以上是最优情况的推导,因此快速排序在最优情况下其排序时间为O(nlogn),通常平均情况
我们也认为是此值。
在最坏情况下其会退化为冒泡排序,T(n) = T(n - 1) + n (每次选取的元素只能将序列划分为
一段,即自身是 最小元素或最大元素)
因此T(n) = n * (n-1) / 2 相当于O(n^2)
计算机快速排序法是怎么排的?
以第一个数为基准 key = 66 ,从小到大排序,第一轮结果是将比66的结果小的数据放到66的左边,比66大的数据放到66的右边。为了好说明位置变化,将每个数设置一个位置,从0开始
0 1 2 3 4 5 6
66、13、21、54、71、89、23
首先从右边位置i = 6开始找比key小的数,第一个是23,比66小,这里的i只是一个变量,下j同,不必介意,将23代替66,数组变为:
23、13、21、54、71、89、23
然后,从左边开始找比66大的数,直到位置j = 4 才找到71,比66大,然后将71代替位置i的数,序列变为:
23、13、21、54、71、89、71
这时候i j,继续上诉过程,从右边i -1位置开始找比66的数,直到i 跟j碰到都没找到,这时候将key代替j =4 位置的数,序列变为:
23、13、21、54、66、89、71
上面便是第一轮的结果。
然后快速排序66左边的序列,快速快速66右边的数,最终得到一个从小大的序列。
怎样使用递归实现归并排序
第一步:先写一个合并两个排序好数组的方法,方法名就叫做merge,如下:
[java] view plain copy
public static void merge(int[] a, int aSize, int[] b, int bSize, int[] c){
int tempA = 0, tempB = 0, tempC = 0;
while(tempA < aSize && tempB < bSize){
if(a[tempA] > b[tempB]){
c[tempC++] = b[tempB++];
}else{
c[tempC++] = a[tempA++];
}
}
while(tempA < aSize){
c[tempC++] = a[tempA++];
}
while(tempB < bSize){
c[tempC++] = b[tempB++];
}
这个方法非常简单,一共有着5个参数(也可以简化为3个参数),其中a,b数组是待合并数组,aSize,bSize是数组长度(这两个参数可以去掉),c为目标数组。主要的流程就是不断的比较a,b数组的大小,然后将较小数据复制进c中。这里面关键的一点就是使用了3个临时变量,用于标志每个数组对应的位置,这样子可以极大简化我们的代码设计。下面是对应的图示过程:
有了这个方法之后,我们就可以开始写归并排序的主体方法了。写主体方法也很简单,思想就是分治算法。
第一步:就是将大数组分成两个小的数组
第二部:排序这两个数组,使用的是递归排序方法,也就是自己调用自己
第三部:调用上面的合并方法合并起来即可
代码非常简单,直接贴上
[java] view plain copy
public class TowersApp{
public static void main(String[] args){
int[] a = {1,1,0,1,1,5,3};
mergeSort(a);
for(int i=0; i<a.length; i++){
System.out.print(a[i]);
}
}
public static void mergeSort(int[] source){
//递归出口
if(source.length == 1) return;
//将大数组分成两个小数组
int middle = source.length / 2;
int[] left = new int[middle];
for(int i=0; i<middle; i++){
left[i] = source[i];
}
int[] right = new int[source.length - middle];
for(int i=middle; i<source.length; i++){
right[i-middle] = source[i];
}
//对数据进行排序(这里使用递归排序)
mergeSort(left);
mergeSort(right);
//合并排序好的数据
merge(left, left.length, right, right.length, source);
}
public static void merge(int[] a, int aSize, int[] b, int bSize, int[] c){
int tempA = 0, tempB = 0, tempC = 0;
while(tempA < aSize && tempB < bSize){
if(a[tempA] > b[tempB]){
c[tempC++] = b[tempB++];
}else{
c[tempC++] = a[tempA++];
}
}
while(tempA < aSize){
c[tempC++] = a[tempA++];
}
while(tempB < bSize){
c[tempC++] = b[tempB++];
}
}
}
总结:要记住归并排序算法的核心核心思想:分而治之。
递归函数到底是怎么进行调用的,栈怎么变化?快速排序算法的递归过程是怎么样的
快速排序中,首先要进行一次划分以确定轴值(即序列中在它右边都大于它,左边的都小于它)的位置,快速排序中其实就是不停的对序列划分.比如:序列 23 13 49 6 31 19 28进行一次划分(即用一个函数实现)后 【 19 13 6】 23 【31 49 28】此时23为轴值,然后对括号中的俩子序列分别进行快速排序!(既递归,调用自身函数)。
什么是递归算法
递归算法就是一个函数通过不断对自己的调用而求得最终结果的一种思维巧妙但是开销很大的算法。
比如:
汉诺塔的递归算法:
void move(char x,char y){
printf("%c-->%c\n",x,y);
}
void hanoi(int n,char one,char two,char three){
/*将n个盘从one座借助two座,移到three座*/
if(n==1) move(one,three);
else{
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
main(){
int n;
printf("input the number of diskes:");
scanf("%d",&n);
printf("The step to moving %3d diskes:\n",n);
hanoi(n,'A','B','C');
}
我说下递归的理解方法
首先:对于递归这一类函数,你不要纠结于他是干什么的,只要知道他的一个模糊功能是什么就行,等于把他想象成一个能实现某项功能的黑盒子,而不去管它的内部操作先,好,我们来看下汉诺塔是怎么样解决的
首先按我上面说的把递归函数想象成某个功能的黑盒子,void hanoi(int n,char one,char two,char three); 这个递归函数的功能是:能将n个由小到大放置的小长方形从one 位置,经过two位置 移动到three位置。那么你的主程序要解决的问题是要将m个的"汉诺块"由A借助B移动到C,根据我们上面说的汉诺塔的功能,我相信傻子也知道在主函数中写道:hanoi(m,A,B,C)就能实现将m个块由A借助B码放到C,对吧?所以,mian函数里面有hanoi(m,'A','C','B');这个调用。
接下来我们看看要实现hannoi的这个功能,hannoi函数应该干些什么?
在hannoi函数里有这么三行
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
同样以黑盒子的思想看待他,要想把n个块由A经过B搬到C去,是不是可以分为上面三步呢?
这三部是:第一步将除了最后最长的那一块以外的n-1块由one位置经由three搬到two 也就是从A由C搬到B 然后把最下面最长那一块用move函数把他从A直接搬到C 完事后 第三步再次将刚刚的n-1块借助hannoi函数的功能从B由A搬回到C 这样的三步实习了n块由A经过B到C这样一个功能,同样你不用纠结于hanoi函数到底如何实现这个功能的,只要知道他有这么一个神奇的功能就行
最后:递归都有收尾的时候对吧,收尾就是当只有一块的时候汉诺塔怎么个玩法呢?很简单吧,直接把那一块有Amove到C我们就完成了,所以hanoni这个函数最后还要加上 if(n==1)move(one,three);(当只有一块时,直接有Amove到C位置就行)这么一个条件就能实现hanoin函数n>=1时将n个块由A经由B搬到C的完整功能了。
递归这个复杂的思想就是这样简单解决的,呵呵 不知道你看懂没?纯手打,希望能帮你理解递归
总结起来就是不要管递归的具体实现细节步骤,只要知道他的功能是什么,然后利用他自己的功能通过调用他自己去解决自己的功能(好绕口啊,日)最后加上一个极限情况的条件即可,比如上面说的1个的情况。
C语言,二路归并排序,递归调用到底是怎么调用的?求详解!
程序代码都是顺序执行的,当然是把一路调用完再做第二路调用,最后把排好序的2路进行合并;
在排序每一路的时候也是使用归并的方式,把一路分成2路,层层深入。
理解的话,你可以这样:
比如8个数,你从上到下竖着排成一列,然后中间一条横线分割。
横线上面的部分再从中间分割成2部分,2部分放在第二列;
依次往后分割。得到形如这样的图:
然后按照红色箭头先按A反推一层,再按B向下一层,这样就会合并一次产生排好序的前一层。如此反复,这就是递归实际的执行流程。