我已经实现了快速排序。但是这段代码给了我分段错误。
#include<stdio.h>
#include<stdlib.h>
void Quick_Sort(int *a,int p,int r);
int partition(int *a,int p,int r);
int main(){
int testcase,num,search;
int i,j,*array;
scanf("%d",&testcase);
for(i=0;i<testcase;i++){
scanf("%d",&num);
array=malloc(sizeof(int)*num);
for(j=0;j<num;j++){
scanf("%d",(array+j));
}
Quick_Sort(array,0,num-1);
scanf("%d",&search);
/*for(j=0;j<num;j++){
if(search==*(array+j)){
printf("%d\n",j+1 );
break;
}
}*/
}
for(i=0;*(array+i)!='\0';++i){
printf("%d ",*(array+i));
}
}
void Quick_Sort(int *a,int p,int r){
int q;
if(p<r){
q=partition(a,p,r);
Quick_Sort(a,p,q);
Quick_Sort(a,q+1,r);
}
}
int partition(int *a,int p,int r){
int i,j,x,temp;
i=p-1;
j=r+1;
x=*(a+p);
while(1){
do{
j=j-1;
}
while(x<=(*(a+j)));
do{
i=i+1;
}
while(x>=(*(a+i)));
if(i<j){
temp=*(a+i);
*(a+i)=*(a+j);
*(a+j)=temp;
}else{
return j;
}
}
答案 0 :(得分:2)
您的数据文件似乎结构为:
T
N1 V11 V12 V13 ... V1N S1
N2 V21 V22 V23 ... V2N S2
...
你有一个测试用例的总数,T。然后对于每个测试用例,你在数组中有许多条目(N1,N2等),每次都跟着适当数量的值,V 1 1 .. V 1 N,以及您应该搜索的备用值(所有使用基于1的数组符号描述;在C中,您将使用基于0的数组)。虽然我已经在一行中显示了每个测试集的数据,但实际的数据文件可以按任意顺序排列数字 - 一切都可以在一行上,或者每行上的每个数字可能都是空白的分隔它们的线条,或这些格式的任何混合。
您展示的main()
程序在阅读该数据时效果不佳。它缺乏所有错误检查。它使用(合法但)奇怪的*(array + i)
符号而不是更简单的理解array[i]
符号,显然相信它会更有效。当您使用指针提高效率时,在取消引用指针之前,不要继续向值添加i
。你的代码动态分配内存,但永远不会释放它,泄漏可怕。
在这个修订过的代码中,我使用return 1;
退出程序。它也应该打印错误信息,但我适度懒惰。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int testcase, num, search;
int i, j, *array;
if (scanf("%d", &testcase) != 1)
return 1;
for (i = 0; i < testcase; i++)
{
if (scanf("%d", &num) != 1)
return 1;
array = malloc(sizeof(int)*num);
if (array == 0)
return 1;
for (j = 0; j < num; j++)
{
if (scanf("%d", &array[j]) != 1)
return 1;
}
//Quick_Sort(array, 0, num-1);
if (scanf("%d", &search) != 1)
return 1;
for (j = 0; j < num; j++)
{
if (search == array[j])
{
printf("%d\n", j+1);
break;
}
}
// Print the array - best encapsulated in a small function
for (j = 0; j < num; j++)
{
printf(" %d", array[j]);
if (j % 10 == 9)
putchar('\n');
}
if (j % 10 != 0)
putchar('\n');
// Prevent memory leaks
free(array);
}
return 0;
}
我顺便提一下,无论QuickSort是否对数据进行排序,搜索循环都会起作用;它没有使用数组排序的事实。您可以在排序之前和排序之后打印数据。您应该标记输出以标识要打印的内容。例如,搜索代码可能会写:
printf("Found %d at %d\n", search, j);
您也无法确定何时找不到要搜索的值。
在您阅读之后以及处理之前打印您阅读的数据通常也是一个好主意,只是为了确保您的程序获得您希望获得的数据。如果程序没有处理您认为正在处理的数据,则可能会导致混淆。
请注意,此代码不会对数组中的值进行任何假设,超出“它们是有效整数”。它确实检查每个输入操作。虽然看似乏味,但有必要避免麻烦。
以下是使用指针或多或少惯用法的代码:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int testcase;
if (scanf("%d", &testcase) != 1)
return 1;
for (int i = 0; i < testcase; i++)
{
int num;
if (scanf("%d", &num) != 1)
return 1;
int *array = malloc(sizeof(int)*num);
if (array == 0)
return 1;
int *end = array + num;
int *ptr;
for (ptr = array; ptr < end; ptr++)
{
if (scanf("%d", ptr) != 1)
return 1;
}
//Quick_Sort(array, 0, num-1);
int search;
if (scanf("%d", &search) != 1)
return 1;
for (ptr = array; ptr < end; ptr++)
{
if (search == *ptr)
{
break;
}
}
if (ptr < end)
printf("Found %d at %td\n", search, ptr - array + 1);
else
printf("Missing %d\n", search);
// Print the array - best encapsulated in a small function
printf("Array (%d):", num);
int j;
for (j = 0; j < num; j++)
{
printf(" %d", array[j]);
if (j % 10 == 9)
putchar('\n');
}
if (j % 10 != 0)
putchar('\n');
// Prevent memory leaks
free(array);
}
return 0;
}
如果使用索引编写,则打印循环最简单,因此我没有将其更改为使用指针。可以这样做,但在'是时候打印换行符'代码中使用(ptr - array)
而不是j
会使它变得不那么值得。该代码使用C99功能,例如在需要时声明变量,在t
中使用%td
限定符作为ptrdiff_t
值。可以编写它来使用VLA而不是malloc()
。
3
2 1 2 1
3 3 2 0 1
4 5 4 3 2 4
Found 1 at 1
Array (2): 1 2
Missing 1
Array (3): 3 2 0
Found 4 at 2
Array (4): 5 4 3 2
您的分区算法有缺陷。它是固定的,标记了关键变化。我在解决问题时使用的调试脚手架留在原位,许多打印操作引导我注释掉。阅读Jon Bentley的Programming Pearls,特别是“第11栏:排序”(第11章,但章节最初是ACM通讯中的专栏,因此标题为第11栏)。在解决问题时,这是一个非常宝贵的指南。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void Quick_Sort(int *a, int p, int r);
static int partition(int *a, int p, int r);
static void dump_partition(char const *tag, int const *data, int lo, int hi);
/* Debugging functions */
static void check_sorted(int const *data, int lo, int hi);
static int *copy_partition(int const *data, int lo, int hi);
static void check_consistency(int const *a1, int const *a2, int lo, int hi);
int main(void)
{
int testcase, num, search;
int i, j, *array;
if (scanf("%d", &testcase) != 1)
return 1;
for (i = 0; i < testcase; i++)
{
if (scanf("%d", &num) != 1)
return 1;
array = malloc(sizeof(int)*num);
if (array == 0)
return 1;
for (j = 0; j < num; j++)
{
if (scanf("%d", &array[j]) != 1)
return 1;
}
printf("\nData set %d:\n", i);
int *copy = copy_partition(array, 0, num-1);
dump_partition("Before:", array, 0, num-1);
//dump_partition("Copy", copy, 0, num-1);
Quick_Sort(array, 0, num-1);
dump_partition("After: ", array, 0, num-1);
check_sorted(array, 0, num-1);
check_consistency(array, copy, 0, num-1);
free(copy);
if (scanf("%d", &search) != 1)
return 1;
for (j = 0; j < num; j++)
{
if (search == array[j])
break;
}
if (j < num && search == array[j])
printf("Found %d at %d\n", search, j+1);
else
printf("Missing %d\n", search);
// Prevent memory leaks
free(array);
}
return 0;
}
/* Although we're interested in data[lo]..data[hi], the copy must have data[0]..data[lo-1] too */
static int *copy_partition(int const *data, int lo, int hi)
{
assert(lo <= hi);
size_t nbytes = (hi + 1) * sizeof(int);
int *space = (int *)malloc(nbytes);
if (space == 0)
{
fputs("Out of memory\n", stderr);
exit(1);
}
memmove(space, data, nbytes);
return(space);
}
/* Check that the two arrays contain the same sets of data */
/* Each value in a1 must be present in a2 and vice versa */
static void check_consistency(int const *a1, int const *a2, int lo, int hi)
{
int *a3 = copy_partition(a1, lo, hi);
int a3_lo = lo;
int a3_hi = hi;
//printf("-->> check_consistency:\n");
//dump_partition("a1", a1, lo, hi);
//dump_partition("a2", a2, lo, hi);
//dump_partition("a3", a3, lo, hi);
for (int i = lo; i <= hi; i++)
{
int found = 0;
for (int j = a3_lo; j <= a3_hi; j++)
{
if (a2[i] == a3[j])
{
/* Found a match for a2[i] at a3[j] */
/* Move a3[j] to end of array and ignore it from here on */
//printf("Found a2[%d] = %d at a3[%d] = %d\n", i, a2[i], j, a3[j]);
int t = a3[a3_hi];
a3[a3_hi] = a3[j];
a3[j] = t;
a3_hi--;
//dump_partition("a3-free", a3, a3_lo, a3_hi);
//dump_partition("a3-used", a3, a3_hi+1, hi);
found = 1;
break;
}
}
if (!found)
{
printf("No value %d for a2[%d] in a1\n", a2[i], i);
dump_partition("a2", a2, lo, hi);
dump_partition("a1-free", a3, a3_lo, a3_hi);
dump_partition("a1-used", a3, a3_hi+1, hi);
}
}
free(a3);
//printf("<<-- check_consistency\n");
}
static void dump_partition(char const *tag, int const *data, int lo, int hi)
{
printf("%s [%d..%d]%s", tag, lo, hi, (hi - lo) > 10 ? "\n" : "");
int i;
for (i = lo; i <= hi; i++)
{
printf(" %2d", data[i]);
if ((i - lo) % 10 == 9)
putchar('\n');
}
if ((i - lo) % 10 != 0 || i == lo)
putchar('\n');
}
static void check_sorted(int const *data, int lo, int hi)
{
//printf("-->> check_sorted:\n");
for (int i = lo; i < hi; i++)
{
if (data[i] > data[i+1])
printf("Out of order: a[%d] = %d bigger than a[%d] = %d\n", i, data[i], i+1, data[i+1]);
}
//printf("<<-- check_sorted\n");
}
void Quick_Sort(int *a, int p, int r)
{
if (p < r)
{
int q = partition(a, p, r);
//dump_partition("Lo Range", a, p, q-1);
//printf("Pivot: a[%d] = %d\n", q, a[q]);
//dump_partition("Hi Range", a, q+1, r);
Quick_Sort(a, p, q-1); // JL: Optimization
Quick_Sort(a, q+1, r);
}
}
static int partition(int *a, int p, int r)
{
assert(p <= r);
if (p == r) // JL: Key change
return p; // JL: Key change
int i = p; // JL: Key change
int j = r + 1;
int x = a[p];
//printf("-->> partition: lo = %d, hi = %d, pivot = %d\n", p, r, x);
while (1)
{
do
{
j--;
//printf("---- partition 1: a[%d] = %d\n", j, a[j]);
} while (x < a[j]); // JL: Key change
do
{
i++;
//printf("---- partition 2: a[%d] = %d\n", i, a[i]);
} while (i <= r && x > a[i]); // JL: Key change
if (i <= j) // JL: Key change
{
//printf("---- partition: swap a[%d] = %d with a[%d] = %d\n", i, a[i], j, a[j]);
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
else
{
// This swap step is crucial.
int temp = a[p]; // JL: Key change
a[p] = a[j]; // JL: Key change
a[j] = temp; // JL: Key change
//dump_partition("a-lo", a, p, j-1);
//printf("a-pivot[%d] = %d\n", j, a[j]);
//dump_partition("a-hi", a, j+1, r);
//printf("<<-- partition: return j = %d; a[%d] = %d; (i = %d; a[%d] = %d)\n", j, j, a[j], i, i, a[i]);
return j;
}
}
}
10
2 1 2 1
3 3 2 0 1
4 5 4 3 2 4
4 3 1 9 3 8
5 3 4 1 9 3 8
9 3 6 4 9 5 1 9 3 3 8
10 3 6 4 9 6 5 1 9 3 3 8
16
3 6 4 9 6 5 1 9 3 3
8 2 1 7 3 5
3
26
3 6 4 9 6 5 1 9 3 3
2 7 8 2 0 8 4 4 7 5
8 2 1 7 3 5
7
96
3 6 4 9 6 5 1 9 3 3
4 0 5 0 7 5 6 3 6 0
1 2 0 7 3 1 7 6 2 3
0 4 6 6 9 8 9 5 3 4
1 9 2 9 2 7 5 9 8 9
4 7 5 8 7 8 5 8 2 7
5 8 2 9 8 3 7 6 5 3
9 1 2 0 3 4 6 5 1 0
2 7 8 2 0 8 4 4 7 5
8 2 1 7 3 5
6
Data set 0:
Before: [0..1] 1 2
After: [0..1] 1 2
Found 1 at 1
Data set 1:
Before: [0..2] 3 2 0
After: [0..2] 0 2 3
Missing 1
Data set 2:
Before: [0..3] 5 4 3 2
After: [0..3] 2 3 4 5
Found 4 at 3
Data set 3:
Before: [0..3] 3 1 9 3
After: [0..3] 1 3 3 9
Missing 8
Data set 4:
Before: [0..4] 3 4 1 9 3
After: [0..4] 1 3 3 4 9
Missing 8
Data set 5:
Before: [0..8] 3 6 4 9 5 1 9 3 3
After: [0..8] 1 3 3 3 4 5 6 9 9
Missing 8
Data set 6:
Before: [0..9] 3 6 4 9 6 5 1 9 3 3
After: [0..9] 1 3 3 3 4 5 6 6 9 9
Missing 8
Data set 7:
Before: [0..15]
3 6 4 9 6 5 1 9 3 3
8 2 1 7 3 5
After: [0..15]
1 1 2 3 3 3 3 4 5 5
6 6 7 8 9 9
Found 3 at 4
Data set 8:
Before: [0..25]
3 6 4 9 6 5 1 9 3 3
2 7 8 2 0 8 4 4 7 5
8 2 1 7 3 5
After: [0..25]
0 1 1 2 2 2 3 3 3 3
4 4 4 5 5 5 6 6 7 7
7 8 8 8 9 9
Found 7 at 19
Data set 9:
Before: [0..95]
3 6 4 9 6 5 1 9 3 3
4 0 5 0 7 5 6 3 6 0
1 2 0 7 3 1 7 6 2 3
0 4 6 6 9 8 9 5 3 4
1 9 2 9 2 7 5 9 8 9
4 7 5 8 7 8 5 8 2 7
5 8 2 9 8 3 7 6 5 3
9 1 2 0 3 4 6 5 1 0
2 7 8 2 0 8 4 4 7 5
8 2 1 7 3 5
After: [0..95]
0 0 0 0 0 0 0 0 1 1
1 1 1 1 1 2 2 2 2 2
2 2 2 2 2 3 3 3 3 3
3 3 3 3 3 3 4 4 4 4
4 4 4 4 5 5 5 5 5 5
5 5 5 5 5 5 6 6 6 6
6 6 6 6 6 7 7 7 7 7
7 7 7 7 7 7 8 8 8 8
8 8 8 8 8 8 9 9 9 9
9 9 9 9 9 9
Found 6 at 57
还在一些更大的数据集(2097随机条目等)上测试了代码。当数据很大时,自动检查功能至关重要 - 因此check_sorted()
和check_consistency()
。它们检查数据是按排序顺序输出的,还是保护属性,输入中的所有值都出现在输出中(就像它们在输入中出现的那样)。排序不应该添加新数据或删除预先存在的数据。
答案 1 :(得分:0)
正如评论中所指出的,打印循环的循环结束测试*(array + i) != '\0'
是一个错误。 array
保持正常整数,C也认为'\0'
是整数0,因为它认为所有字符文字值都是整数,并且比较是合法的,但因为这是一个(希望)排序的整数数组可能有任何值(包括负值和0),可能是某些测试数据中有多个0,或者在这种情况下更可能是测试数据中没有0。如果你弄清楚这些代码在这些情况下会做什么,那么你应该理解错误。