今天在实现一个查找功能的时候,需要用到排序,因为用的是C开发,就把自己之前写的快速排序算法直接拿来用了。代码如下:
1 static void QuickSort(ElemType *array,int left,int right) 2 { 3 if(left > right) 4 { 5 return; 6 } 7 int i,j; 8 ElemType temp, base; 9 base = array[left]; 10 i = left; 11 j = right; 12 while(i < j) 13 { 14 //顺序很重要,要先从右边开始找 15 while(array[j] >= base && j > i) 16 { 17 j--; 18 } 19 array[i] = array[j]; 20 while(array[i] <= base && i < j) 21 { 22 i++; 23 } 24 array[j] = array[i]; 25 } 26 //最终将基准数归位 27 array[i] = base; 28 QuickSort(array,left,i-1);//继续处理左边的,这里是一个递归的过程 29 QuickSort(array,i+1,right);//继续处理右边的 ,这里是一个递归的过程 30 }
编译->运行,出现的结果是:Segmentation fault(core dumped)。看到这个报错,我首先想到的是数组越界了,可是不管怎么检查,也没有找到越界的地方。
实在是找不出错误来,于是我就干脆把快排重新写一遍,编译运行成功了。然后一对比,开始我以为我找到原因了,是在代码的第3行:if(left < right)应为if(left <= right),这的确是一个错误,但是却不是导致段错误的原因。因为,即便是没有‘=’,程序也会运行下去的。也就是说,若出现left == right,则在代码的28行这个新的递归中,是会返回来从而结束掉递归的。
到底是哪里有问题?我分享了代码的很多处都没有找到原因,但是,我注意到一个细节:当我传入的数组的元素为5的时候,是会出现Segmentation fault(core dumped)错误,但是当我传入的数组元素为12的时候,却顺利运行。以这一点为突破口,我将传入的数组元素设为了5,然后使用了gdb调试。
传入的原始数组为 83 86 77 15 93,下面是排序的过程:
- 第一次递归调用后,数组就已经拍好了:15 77 83 86 93,且此时基准数base的位置i为2,left为0。接着进入下一个递归Quick(array,left,i-1);
- 新的递归中left = 0,right = 1,经过13~25行的排序后,基准数base的位置i为0,left还是为0。程序进入下一个递归Quick(array,left,i-1),注意到递归中传入的第三个参数为i-1,而此时i = 0,所以,递归调用传入的第三个参数实际上是负值。在我的计算机中为4294967295,这个值也是新的递归中right的值。
但是,导致Segmentation fault(core dumped)错误的原因,真的是简单的数组越界吗?我仔细思考了一下觉得有两个原因:
- 不断递归导致的入栈过程,最终导致栈溢出;
- 数组越界;
乍一看这里应该是情形2的,因为传入的参数是一个越界值。但是,事实上我使用单步调试的时候,在引用array[4294967295]的时候并没有报错。最终的报错的位置为”Quick(array=0x8048034,left = 100,right=17“,从这一句基本结合上面的越界未报错,基本可以判定应该是栈溢出了。
但是这样的判断还是错的。我写了下面的测试程序:
1 #include<stdio.h> 2 #include<stdlib.h> 3 4 static void test(int a); 5 6 int main(void) 7 { 8 test(0); 9 return 0; 10 } 11 12 static void test(int a) 13 { 14 int b; 15 b = ++a; 16 printf("This is the %dth recursion.\n",b); 17 test(b); 18 }
实验结果显示,直到174544次递归调用,才出现了栈溢出的现象。而我统计快排序中的递归次数,发现在第三次就出现段错误了,这到底是怎么回事?
最终修改过后的程序如下:
1 static void QuickSort(ElemType *array,int left,int right) 2 { 3 if(left >= right) 4 { 5 return; 6 } 7 int i,j; 8 ElemType temp, base; 9 base = array[left]; 10 i = left; 11 j = right; 12 while(i < j) 13 { 14 //顺序很重要,要先从右边开始找 15 while(array[j] >= base && j > i) 16 { 17 j--; 18 } 19 if(i < j) 20 { 21 array[i++] = array[j]; 22 } 23 24 while(array[i] <= base && i < j) 25 { 26 i++; 27 } 28 if(i < j) 29 { 30 array[j--] = array[i]; 31 } 32 } 33 //最终将基准数归位 34 array[i] = base; 35 if(i == 0) 36 { 37 return; 38 } 39 QuickSort(array,left,i-1);//继续处理左边的,这里是一个递归的过程 40 QuickSort(array,i+1,right);//继续处理右边的 ,这里是一个递归的过程 41 }
虽然问题解决了,但是我还是不知道确切的出错原因,希望知道答案的大牛能解答一下。