读书人

快速排序法有有关问题求解析(排列一

发布时间: 2012-11-04 10:42:41 作者: rapoo

快速排序法有问题,求解析(排列一万个以上有序数列会中断)
数组快速排序,当数组元素大于一万,有序元素排序就出现中断,并且下面的代码都没有执行,弄了大半天都找不到原因。。。代码如下:

#include <stdio.h>
#include <time.h>
#include <windows.h>
/*
快速排序十万个数,仅需0.031秒
就是弄不懂一个现象,当待排序的个数在一万(精确到9962)以上并且此数是有序的(从大到小或从小到大)时,
比如排过一次的数组,再次排序时就没有往下执行。。。什么原因呢?
*/

#define NN 9963//9593//9963

int one_pai(int a[],int tou,int wei);
void digui(int a[],int tou,int wei);

int one_pai(int a[],int tou,int wei)
{
int i,j,tmp,tmp_1=tou,tmp_2=wei;
while(1)
{
for(i=tmp_1+1;i<wei;i++)//从左往右找比头大的数
{
if(a[tou]<a[i])
{
break;
}
}
for(j=tmp_2;j>tou;j--)//从右往左找比头小的数
{
if(a[tou]>a[j])
{
break;
}
}
if(j>i)//如果i和j还没相遇
{
//交换i位置和j位置的数,并且记录当前值
a[i]=a[i]+a[j];
a[j]=a[i]-a[j];
a[i]=a[i]-a[j];
tmp_1=i;
tmp_2=j-1;
}
else//如果i、j相遇(交错)
{
//头和j交换,并且返回j的位置
tmp=a[j];
a[j]=a[tou];
a[tou]=tmp;
return j;
}
}

}

void digui(int a[],int tou,int wei)
{
int k;
if(tou<wei)
{
k=one_pai(a,tou,wei);
digui(a,tou,k-1);
digui(a,k+1,wei);
}
}


int main(void)
{
int i;
int a[NN]={0};
srand((unsigned)time(NULL));//初始化随机函数种子
for(i=0;i<NN;i++)
{
a[i]=rand();//产生一个随机数赋值给a[i]
}

//排序前
printf("排序前:\n");
for(i=0;i<NN;i+=1000)
{
printf("a[%d]=%d\n",i,a[i]);
}
printf("a[%d]=%d\n\n",NN-1,a[NN-1]);//最后一个数

digui(a,0,NN-1);//快速排序

//排序后
printf("排序后:\n");
for(i=0;i<NN;i+=1000)
{
printf("a[%d]=%d\n",i,a[i]);
}
printf("a[%d]=%d\n\n\n",NN-1,a[NN-1]);//最后一个数


//已经排好序了,重排一次
printf("已经排好序了,重排一次:\n");
digui(a,0,NN-1);//快速排序
printf("这一句都没有执行!!\n");
for(i=0;i<NN;i+=1000)
{
printf("a[%d]=%d\n",i,a[i]);
}
printf("a[%d]=%d\n",NN-1,a[NN-1]);//最后一个数

return 0;
}

[解决办法]
完全随机的数组,可以认为大约压栈log2(N)次,也就是几乎每次都平分成两个数组
基本有序的数组,可以认为大约压栈N次,也就是几乎每次都分成一个数据和剩下的所有数据

压栈次数取决于栈大小(例如VS默认1M,可以改大,但原理限制不可能改太大)和每次调用递归函数时压栈数据的大小(你定义越多的局部变量,每次占用的栈空间就越大),9962就是你的代码和编译器根据上面两个数据计算出来的必然结果
程序中断是因为栈溢出异常,这个异常一般不允许程序员捕获,因为程序员处理异常的代码一般也需要用到栈,在栈已经坏掉的情况下无法正确处理该异常,于是该异常一路跳到程序结束——不过这些跟C语言没关系,是操作系统方面的事情了。
[解决办法]

探讨

2楼观点是栈溢出,此程序调用digui(a,0,NN-1)两次,第一次没问题,程序可以排序,第二次就中断,下面代码没有执行。。。但,如果我将a[NN]用for循环赋值i++,即数组元素是有序的从0、1、2、3···9963,并不是采用随机数作为数组元素,那样的快速排序,第一次digui(a,0,NN-1);都发生中断,程序下面的代码也没有运行,所以,这样说明,这个排序与数组元素是否有序的有关系,并非是栈溢出问题。。。还有一个方法可以证明:如果我声明两个数组a[NN],b[NN],两个数组元素都采用随机数,a排完就排b,一样是调用两次digui(,0,NN-1),这个就可以完成两次排序的。。。所以,最终结论是:有序的排序数量大到一万以上时程序就会发生中断,无序的数组可以排到十万多,这个数值应该就是32位int型数的最大值了,这个好理解。

[解决办法]
探讨
log2(N)<N,那么随机数组压栈的次数更小,那应该是随机数组排序中断的啊!!!

读书人网 >C语言

热点推荐