快速排序法有问题,求解析(排列一万个以上有序数列会中断)
数组快速排序,当数组元素大于一万,有序元素排序就出现中断,并且下面的代码都没有执行,弄了大半天都找不到原因。。。代码如下:
#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语言没关系,是操作系统方面的事情了。
[解决办法]
[解决办法]