C Quicksort 使程序在排序不同类型的数组时崩溃
C Quicksort makes the program crash when ordering different kind of arrays
概览:
我正在实现一个程序,该程序使用快速排序算法来排序具有不同大小并以不同方式排序的不同数组。然后我打印出每个数组排序用了多长时间,交换和比较了多少次。
这是一个作业,我需要知道所有的不同时间,交流和比较。
我试过的
看了网上的文章,发现可能是我编译器的问题,可能是内存占用太少导致编译过程阻塞,只好在release模式下编译。发布模式给了我同样的问题。我尝试了在线编译器,但是 none 的 em 工作。
我的程序如何工作
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
typedef enum {ORINATO, INVERS, PARZ_ORDINATO, RANDOM} Ordine;
typedef enum{FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT} Dimensione;
int qconfronti=0, qscambi=0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int* array, int primo, int ultimo);
void quickSort(int* array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
int main(){
automaticQS();
return 0;
}
int *generaArray(int dimensione, Ordine ordine) {
int i, j, n;
int *array = malloc(dimensione * sizeof(int));
if (!array){
return NULL;
}
switch (ordine){
case ORINATO:
for (i = 0; i < dimensione; i++){
array[i] = i;
}
break;
case INVERS:
n =0;
for ( i = dimensione-1; i >= 0 ; i--) {
array[i] = n;
n++;
}break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione/2 ; i++) {
array[i] = i;
}
for (j = i+1; j <dimensione; j++){
n = rand();
array[j] = n;
}
printf("\n");break;
case RANDOM:
for ( i = 0; i <= dimensione ; i++) {
array[i] = rand();
}break;
case ESCI:
break;
default:
break;
}
return array;
}
int perno(int* array, int primo, int ultimo){
int i=primo;
int j=ultimo+1;
int supp=0;
int pivot=array[primo];
while(i<j){
do{
i=i+1;
qconfronti++;
}while(array[i]<=pivot);
do{
j=j-1;
qconfronti++;
}while(array[j]>pivot);
if(i<j){
supp=array[i];
array[i]=array[j];
array[j]=supp;
qscambi++;
}
}
supp=array[primo];
array[primo]=array[j];
array[j]=supp;
qscambi++;
return j;
}
void quickSort(int* array, int u, int v){
int q=0;
if(u==v){
return ;
}
q=perno(array, u, v);
if(u<q){
quickSort(array, u, q-1);
}
if(q<v){
quickSort(array, q+1, v);
}
}
void calculateQuicktime(int *array, int dim){
clock_t start, end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array,0, dim);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nConfronti: %d \t Scambi: %d", qconfronti, qscambi);
printf("\nTempo impiegato per %d elementi : %lf secondi", dim, t);
}
void automaticQS() {
printf("\nQuick Sort");
printf("\n\nOrdinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, ORINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, ORINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, ORINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, ORINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, ORINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, ORINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, ORINATO), CINQUANTAMILA);
printf("\n\nParzialmente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, PARZ_ORDINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, PARZ_ORDINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, PARZ_ORDINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, PARZ_ORDINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, PARZ_ORDINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, PARZ_ORDINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, PARZ_ORDINATO), CINQUANTAMILA);
printf("\n\nInversamente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, INVERS), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, INVERS), MILLE);
calculateQuicktime(generaArray(DUEMILA, INVERS), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, INVERS), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, INVERS), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, INVERS), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, INVERS), CINQUANTAMILA);
printf("\n\nCasuali:\n");
calculateQuicktime(generaArray(CINQUECENTO, RANDOM), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, RANDOM), MILLE);
calculateQuicktime(generaArray(DUEMILA, RANDOM), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, RANDOM), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, RANDOM), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, RANDOM), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, RANDOM), CINQUANTAMILA);
}
- 它生成一个数组,其中可以包含有序数 (0,1, 2, 3,4, 5...),部分有序数 (0,1,2,3,6,64,44.. .), 倒数 (...6,5,4,3,2,1,0) 和随机数 (42,64,2,7,53,25,1...);
- 它对各种数组进行快速排序;
- 它打印出我们需要的东西。
问题
为什么我的程序只打印出有序数字数组然后崩溃并给我退出代码 11?
Ps。我用 CLion
你有一些错误......
您当前遇到的错误...
在 perno
中,虽然你有 while (i < j)
,但这 不会 阻止 i
的 do/while
循环超出数组末尾。
当primo
为500,ultimo
为1000时出现段错误,但i
会达到333800。
我对 i
和 j
循环添加了一个修复程序,以便在越界时停止。这可能是也可能不是正确的修复。
应用该修复程序并重新运行 程序后,您[似乎] 无限期地递归。 quickSort
被调用时 v
设置为 1000,但 u
被递归设置为 u + 1
(可能枢轴值设置不好)。
最终,您 无限地 递归 u
值为 0 且 v
值为 1
您 return 早于 quickSort
if (u == v)
。那[可能] 不是一个足够好的测试。
我试过if ((v - u) < 2)
。
现在它 [最终] 无限递归 u==251
和 v==455
。
这表明 quickSort
中的 if (u < q)
and/or if (q < v)
测试 [可能] 不足以防止 无限递归。
我在那里添加了一些 assert
调用,以便 [至少] 在第一次这样的递归时尽早中止。
当您分配一个具有维度的数组时(例如 500
),您分配了那么多元素。
但是,将此值传递给 quickSort
是不正确的。那是因为第三个 quickSort
参数是 last 元素的索引并且 而不是 长度。
因此,在 calculateQuicktime
中,您需要:
quickSort(array,0,dim - 1);
旁注: calculateQuicktime
不会 在 array
上调用 free
,所以你正在泄漏内存 [我添加了一个 free
调用]。
无论如何,这是我对您的代码进行的[稍微]重构版本。我用 dbgprt
宏添加了调试打印。
但是,我确实在gdb
下运行找到了上面的bug。
虽然这段代码不是一个完整的修复,它应该给你一些想法:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <assert.h>
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
typedef enum { ORINATO, INVERS, PARZ_ORDINATO, RANDOM } Ordine;
typedef enum { FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT } Dimensione;
int qconfronti = 0,
qscambi = 0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int *array, int primo, int ultimo);
void quickSort(int *array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
#ifdef DEBUG
#define dbgprt(_lvl,_fmt...) \
do { \
if (opt_d >= _lvl) \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int opt_d;
int svlvl;
void
dbgpush(int newlvl)
{
svlvl = opt_d;
if (opt_d)
opt_d = newlvl;
}
void
dbgpop(void)
{
opt_d = svlvl;
}
int
main(int argc,char **argv)
{
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = (*cp != 0) ? atoi(cp) : 1;
break;
}
}
setlinebuf(stdout);
automaticQS();
return 0;
}
int *
generaArray(int dimensione, Ordine ordine)
{
int i,
j,
n;
int *array = malloc(dimensione * sizeof(int));
if (!array) {
return NULL;
}
printf("generaArray: %d\n",dimensione);
switch (ordine) {
case ORINATO:
for (i = 0; i < dimensione; i++) {
array[i] = i;
}
break;
case INVERS:
n = 0;
for (i = dimensione - 1; i >= 0; i--) {
array[i] = n;
n++;
}
break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione / 2; i++) {
array[i] = i;
}
for (j = i + 1; j < dimensione; j++) {
n = rand();
array[j] = n;
}
printf("\n");
break;
case RANDOM:
for (i = 0; i <= dimensione; i++) {
array[i] = rand();
}
break;
#if 0
case ESCI:
break;
#endif
default:
break;
}
return array;
}
int
perno(int *array, int primo, int ultimo)
{
int i = primo;
int j = ultimo + 1;
int supp = 0;
int pivot = array[primo];
dbgprt(1,"perno: ENTER primo=%d ultimo=%d pivot=%d\n",primo,ultimo,pivot);
while (i < j) {
dbgprt(2,"perno: OUTLOOP i=%d j=%d\n",i,j);
do {
i = i + 1;
#if FIX1
if (i >= j)
break;
#endif
dbgprt(3,"perno: ILOOP i=%d array=%d\n",i,array[i]);
qconfronti++;
} while (array[i] <= pivot);
do {
#if FIX1
if (i >= j)
break;
#endif
j = j - 1;
dbgprt(3,"perno: JLOOP j=%d array=%d\n",j,array[j]);
qconfronti++;
} while (array[j] > pivot);
if (i < j) {
dbgprt(2,"perno: SWAP\n");
supp = array[i];
array[i] = array[j];
array[j] = supp;
qscambi++;
}
}
supp = array[primo];
array[primo] = array[j];
array[j] = supp;
qscambi++;
dbgprt(1,"perno: EXIT j=%d\n",j);
return j;
}
void
quickSort(int *array, int u, int v)
{
int q = 0;
dbgprt(1,"quickSort: ENTER u=%d v=%d\n",u,v);
#if ! FIX2
if (u == v) {
#else
if ((v - u) < 2) {
#endif
dbgprt(1,"quickSort: EXIT\n");
return;
}
q = perno(array, u, v);
if (u < q) {
assert(! ((q - 1) == v));
quickSort(array, u, q - 1);
}
if (q < v) {
assert(! ((q + 1) == u));
quickSort(array, q + 1, v);
}
dbgprt(1,"quickSort: EXIT\n");
}
void
calculateQuicktime(int *array, int dim)
{
clock_t start,
end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array, 0, dim - 1);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nConfronti: %d \t Scambi: %d", qconfronti, qscambi);
printf("\nTempo impiegato per %d elementi : %lf secondi", dim, t);
// NOTE/BUG: array is never freed (i.e. a memory leak)
#if 1
free(array);
#endif
}
void
automaticQS()
{
printf("\nQuick Sort");
printf("\n\nOrdinati:\n");
dbgpush(2);
calculateQuicktime(generaArray(CINQUECENTO, ORINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, ORINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, ORINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, ORINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, ORINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, ORINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, ORINATO), CINQUANTAMILA);
dbgpop();
dbgpush(3);
printf("\n\nParzialmente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, PARZ_ORDINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, PARZ_ORDINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, PARZ_ORDINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, PARZ_ORDINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, PARZ_ORDINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, PARZ_ORDINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, PARZ_ORDINATO), CINQUANTAMILA);
dbgpop();
printf("\n\nInversamente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, INVERS), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, INVERS), MILLE);
calculateQuicktime(generaArray(DUEMILA, INVERS), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, INVERS), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, INVERS), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, INVERS), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, INVERS), CINQUANTAMILA);
printf("\n\nCasuali:\n");
calculateQuicktime(generaArray(CINQUECENTO, RANDOM), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, RANDOM), MILLE);
calculateQuicktime(generaArray(DUEMILA, RANDOM), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, RANDOM), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, RANDOM), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, RANDOM), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, RANDOM), CINQUANTAMILA);
}
更新:
以上仅使用 gdb
完成,但 未 根据有效的 [Hoare] 算法检查您的代码。
因此,使用 wikipedia 条目进行快速排序:https://en.wikipedia.org/wiki/Quicksort 修复了更多错误 ...
在 perno
中,i
循环因 两个 原因而失败:
-
i
的初始化是 int i = primo;
而不是 int i = primo - 1;
这导致循环跳过 [ignore] array[primo]
作为候选。参见:ORIG3
i
循环终止条件是 while (array[i] <= pivot)
而不是 while (array[i] < pivot)
。请参阅:ORIG5
请注意,您的 j
循环 没有 有此问题。
通过这些修复,我在 i
和 j
循环中添加的额外边界检查不再需要(参见:ORIG1
)。
quickSort
会无限递归的原因是它内部的递归调用是:quickSort(array,u,q-1);
而不是 quickSort(array,u,q);
请参阅:ORIG4
我在 calculateQuicktime
中添加了检查以检查实际排序的最终数组。
通过此检查,某些测试不会崩溃[或无限递归],但最终数组不会排序。
这是因为我[尝试]将 if (u == v)
更改为 if ((v - u) < 2
的修复 不正确 。您的原始代码是正确的。参见:ORIG2
一些额外的文体建议:
虽然对某些常量使用 #define
是一个 好的 想法(例如 #define PI 3.14159
),但对于简单的数字来说可读性较差(例如 #define ONE 1
和 #define TWO 2
)。所以,我会消除 CINQUECENTO
,等等
我会用 static/global 数组替换它作为测试长度(例如 testlen
)。
而且,即使没有使用它们,FIVEH
等也是如此
而且,automaticQS
中的测试代码很繁琐。每个部分都在复制相当数量的代码。通过创建辅助函数(例如testall
),可以大大简化测试代码。
无论如何,这是包含所有其他更改的完整工作代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <assert.h>
#ifndef ORIG1
#define ORIG1 1
#endif
#ifndef ORIG2
#define ORIG2 1
#endif
#ifndef ORIG3
#define ORIG3 0
#endif
#ifndef ORIG4
#define ORIG4 0
#endif
#ifndef ORIG5
#define ORIG5 0
#endif
#if 0
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
#else
int testlen[] = {
500, 1000, 2000, 5000, 10000, 20000, 50000, -1
};
#endif
typedef enum { ORINATO, INVERS, PARZ_ORDINATO, RANDOM } Ordine;
#if 0
typedef enum { FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT } Dimensione;
#endif
int qconfronti = 0, qscambi = 0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int *array, int primo, int ultimo);
void quickSort(int *array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
#ifdef DEBUG
#define dbgprt(_lvl,_fmt...) \
do { \
if (opt_d >= _lvl) \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int opt_d;
int svlvl;
void
dbgpush(int newlvl)
{
svlvl = opt_d;
if (opt_d)
opt_d = newlvl;
}
void
dbgpop(void)
{
opt_d = svlvl;
}
int
main(int argc,char **argv)
{
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = (*cp != 0) ? atoi(cp) : 1;
break;
}
}
setlinebuf(stdout);
automaticQS();
return 0;
}
int *
generaArray(int dimensione, Ordine ordine)
{
int i, j, n;
int *array = malloc(dimensione * sizeof(int));
if (array == NULL)
return NULL;
dbgprt(1,"generaArray: %d\n",dimensione);
switch (ordine) {
case ORINATO:
for (i = 0; i < dimensione; i++) {
array[i] = i;
}
break;
case INVERS:
n = 0;
for (i = dimensione - 1; i >= 0; i--) {
array[i] = n;
n++;
}
break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione / 2; i++) {
array[i] = i;
}
for (j = i + 1; j < dimensione; j++) {
n = rand();
array[j] = n;
}
printf("\n");
break;
case RANDOM:
for (i = 0; i <= dimensione; i++)
array[i] = rand();
break;
#if 0
case ESCI:
break;
#endif
default:
break;
}
return array;
}
int
perno(int *array, int primo, int ultimo)
{
#if ORIG3
int i = primo;
#else
int i = primo - 1;
#endif
int j = ultimo + 1;
int supp = 0;
int pivot = array[primo];
dbgprt(1,"perno: ENTER primo=%d ultimo=%d pivot=%d\n",primo,ultimo,pivot);
while (i < j) {
dbgprt(2,"perno: OUTLOOP i=%d j=%d\n",i,j);
do {
i = i + 1;
#if (! ORIG1)
if (i >= j)
break;
#endif
dbgprt(3,"perno: ILOOP i=%d array=%d\n",i,array[i]);
qconfronti++;
#if ORIG5
} while (array[i] <= pivot);
#else
} while (array[i] < pivot);
#endif
do {
#if (! ORIG1)
if (i >= j)
break;
#endif
j = j - 1;
dbgprt(3,"perno: JLOOP j=%d array=%d\n",j,array[j]);
qconfronti++;
} while (array[j] > pivot);
if (i < j) {
dbgprt(2,"perno: SWAP\n");
supp = array[i];
array[i] = array[j];
array[j] = supp;
qscambi++;
}
}
supp = array[primo];
array[primo] = array[j];
array[j] = supp;
qscambi++;
dbgprt(1,"perno: EXIT j=%d\n",j);
return j;
}
void
quickSort(int *array, int u, int v)
{
int q = 0;
dbgprt(1,"quickSort: ENTER u=%d v=%d\n",u,v);
#if ORIG2
if (u == v) {
#else
if ((v - u) < 2) {
#endif
dbgprt(1,"quickSort: EXIT\n");
return;
}
q = perno(array, u, v);
if (u < q) {
assert((q - 1) != v);
#if ORIG4
quickSort(array, u, q - 1);
#else
quickSort(array, u, q);
#endif
}
if (q < v) {
assert((q + 1) != u);
quickSort(array, q + 1, v);
}
dbgprt(1,"quickSort: EXIT\n");
}
void
calculateQuicktime(int *array, int dim)
{
clock_t start, end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array, 0, dim - 1);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Confronti: %d \t Scambi: %d\n", qconfronti, qscambi);
printf("Tempo impiegato per %d elementi : %lf secondi\n", dim, t);
// check array to ensure it's sorted
int err = 0;
int old = array[0];
for (int idx = 1; idx < dim; ++idx) {
int cur = array[idx];
if (cur < old) {
printf("calculateQuicktime: BADSORT idx=%d old=%d cur=%d\n",
idx,old,cur);
err = 1;
}
old = cur;
}
if (err)
exit(1);
// NOTE/BUG: array is never freed (i.e. a memory leak)
#if 1
free(array);
#endif
}
void
testall(Ordine order,const char *reason)
{
printf("\n\n%s:\n",reason);
for (int *len = testlen; *len >= 0; ++len) {
printf("\n");
int *arr = generaArray(*len,order);
calculateQuicktime(arr,*len);
}
}
void
automaticQS()
{
printf("\nQuick Sort");
testall(ORINATO,"Ordinati");
testall(PARZ_ORDINATO,"Parzialmente ordinati");
testall(INVERS,"Inversamente ordinati");
testall(RANDOM,"Casuali");
}
概览:
我正在实现一个程序,该程序使用快速排序算法来排序具有不同大小并以不同方式排序的不同数组。然后我打印出每个数组排序用了多长时间,交换和比较了多少次。
这是一个作业,我需要知道所有的不同时间,交流和比较。
我试过的
看了网上的文章,发现可能是我编译器的问题,可能是内存占用太少导致编译过程阻塞,只好在release模式下编译。发布模式给了我同样的问题。我尝试了在线编译器,但是 none 的 em 工作。
我的程序如何工作
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
typedef enum {ORINATO, INVERS, PARZ_ORDINATO, RANDOM} Ordine;
typedef enum{FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT} Dimensione;
int qconfronti=0, qscambi=0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int* array, int primo, int ultimo);
void quickSort(int* array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
int main(){
automaticQS();
return 0;
}
int *generaArray(int dimensione, Ordine ordine) {
int i, j, n;
int *array = malloc(dimensione * sizeof(int));
if (!array){
return NULL;
}
switch (ordine){
case ORINATO:
for (i = 0; i < dimensione; i++){
array[i] = i;
}
break;
case INVERS:
n =0;
for ( i = dimensione-1; i >= 0 ; i--) {
array[i] = n;
n++;
}break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione/2 ; i++) {
array[i] = i;
}
for (j = i+1; j <dimensione; j++){
n = rand();
array[j] = n;
}
printf("\n");break;
case RANDOM:
for ( i = 0; i <= dimensione ; i++) {
array[i] = rand();
}break;
case ESCI:
break;
default:
break;
}
return array;
}
int perno(int* array, int primo, int ultimo){
int i=primo;
int j=ultimo+1;
int supp=0;
int pivot=array[primo];
while(i<j){
do{
i=i+1;
qconfronti++;
}while(array[i]<=pivot);
do{
j=j-1;
qconfronti++;
}while(array[j]>pivot);
if(i<j){
supp=array[i];
array[i]=array[j];
array[j]=supp;
qscambi++;
}
}
supp=array[primo];
array[primo]=array[j];
array[j]=supp;
qscambi++;
return j;
}
void quickSort(int* array, int u, int v){
int q=0;
if(u==v){
return ;
}
q=perno(array, u, v);
if(u<q){
quickSort(array, u, q-1);
}
if(q<v){
quickSort(array, q+1, v);
}
}
void calculateQuicktime(int *array, int dim){
clock_t start, end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array,0, dim);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nConfronti: %d \t Scambi: %d", qconfronti, qscambi);
printf("\nTempo impiegato per %d elementi : %lf secondi", dim, t);
}
void automaticQS() {
printf("\nQuick Sort");
printf("\n\nOrdinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, ORINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, ORINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, ORINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, ORINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, ORINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, ORINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, ORINATO), CINQUANTAMILA);
printf("\n\nParzialmente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, PARZ_ORDINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, PARZ_ORDINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, PARZ_ORDINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, PARZ_ORDINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, PARZ_ORDINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, PARZ_ORDINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, PARZ_ORDINATO), CINQUANTAMILA);
printf("\n\nInversamente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, INVERS), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, INVERS), MILLE);
calculateQuicktime(generaArray(DUEMILA, INVERS), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, INVERS), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, INVERS), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, INVERS), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, INVERS), CINQUANTAMILA);
printf("\n\nCasuali:\n");
calculateQuicktime(generaArray(CINQUECENTO, RANDOM), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, RANDOM), MILLE);
calculateQuicktime(generaArray(DUEMILA, RANDOM), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, RANDOM), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, RANDOM), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, RANDOM), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, RANDOM), CINQUANTAMILA);
}
- 它生成一个数组,其中可以包含有序数 (0,1, 2, 3,4, 5...),部分有序数 (0,1,2,3,6,64,44.. .), 倒数 (...6,5,4,3,2,1,0) 和随机数 (42,64,2,7,53,25,1...);
- 它对各种数组进行快速排序;
- 它打印出我们需要的东西。
问题
为什么我的程序只打印出有序数字数组然后崩溃并给我退出代码 11?
Ps。我用 CLion
你有一些错误......
您当前遇到的错误...
在 perno
中,虽然你有 while (i < j)
,但这 不会 阻止 i
的 do/while
循环超出数组末尾。
当primo
为500,ultimo
为1000时出现段错误,但i
会达到333800。
我对 i
和 j
循环添加了一个修复程序,以便在越界时停止。这可能是也可能不是正确的修复。
应用该修复程序并重新运行 程序后,您[似乎] 无限期地递归。 quickSort
被调用时 v
设置为 1000,但 u
被递归设置为 u + 1
(可能枢轴值设置不好)。
最终,您 无限地 递归 u
值为 0 且 v
值为 1
您 return 早于 quickSort
if (u == v)
。那[可能] 不是一个足够好的测试。
我试过if ((v - u) < 2)
。
现在它 [最终] 无限递归 u==251
和 v==455
。
这表明 quickSort
中的 if (u < q)
and/or if (q < v)
测试 [可能] 不足以防止 无限递归。
我在那里添加了一些 assert
调用,以便 [至少] 在第一次这样的递归时尽早中止。
当您分配一个具有维度的数组时(例如 500
),您分配了那么多元素。
但是,将此值传递给 quickSort
是不正确的。那是因为第三个 quickSort
参数是 last 元素的索引并且 而不是 长度。
因此,在 calculateQuicktime
中,您需要:
quickSort(array,0,dim - 1);
旁注: calculateQuicktime
不会 在 array
上调用 free
,所以你正在泄漏内存 [我添加了一个 free
调用]。
无论如何,这是我对您的代码进行的[稍微]重构版本。我用 dbgprt
宏添加了调试打印。
但是,我确实在gdb
下运行找到了上面的bug。
虽然这段代码不是一个完整的修复,它应该给你一些想法:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <assert.h>
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
typedef enum { ORINATO, INVERS, PARZ_ORDINATO, RANDOM } Ordine;
typedef enum { FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT } Dimensione;
int qconfronti = 0,
qscambi = 0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int *array, int primo, int ultimo);
void quickSort(int *array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
#ifdef DEBUG
#define dbgprt(_lvl,_fmt...) \
do { \
if (opt_d >= _lvl) \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int opt_d;
int svlvl;
void
dbgpush(int newlvl)
{
svlvl = opt_d;
if (opt_d)
opt_d = newlvl;
}
void
dbgpop(void)
{
opt_d = svlvl;
}
int
main(int argc,char **argv)
{
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = (*cp != 0) ? atoi(cp) : 1;
break;
}
}
setlinebuf(stdout);
automaticQS();
return 0;
}
int *
generaArray(int dimensione, Ordine ordine)
{
int i,
j,
n;
int *array = malloc(dimensione * sizeof(int));
if (!array) {
return NULL;
}
printf("generaArray: %d\n",dimensione);
switch (ordine) {
case ORINATO:
for (i = 0; i < dimensione; i++) {
array[i] = i;
}
break;
case INVERS:
n = 0;
for (i = dimensione - 1; i >= 0; i--) {
array[i] = n;
n++;
}
break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione / 2; i++) {
array[i] = i;
}
for (j = i + 1; j < dimensione; j++) {
n = rand();
array[j] = n;
}
printf("\n");
break;
case RANDOM:
for (i = 0; i <= dimensione; i++) {
array[i] = rand();
}
break;
#if 0
case ESCI:
break;
#endif
default:
break;
}
return array;
}
int
perno(int *array, int primo, int ultimo)
{
int i = primo;
int j = ultimo + 1;
int supp = 0;
int pivot = array[primo];
dbgprt(1,"perno: ENTER primo=%d ultimo=%d pivot=%d\n",primo,ultimo,pivot);
while (i < j) {
dbgprt(2,"perno: OUTLOOP i=%d j=%d\n",i,j);
do {
i = i + 1;
#if FIX1
if (i >= j)
break;
#endif
dbgprt(3,"perno: ILOOP i=%d array=%d\n",i,array[i]);
qconfronti++;
} while (array[i] <= pivot);
do {
#if FIX1
if (i >= j)
break;
#endif
j = j - 1;
dbgprt(3,"perno: JLOOP j=%d array=%d\n",j,array[j]);
qconfronti++;
} while (array[j] > pivot);
if (i < j) {
dbgprt(2,"perno: SWAP\n");
supp = array[i];
array[i] = array[j];
array[j] = supp;
qscambi++;
}
}
supp = array[primo];
array[primo] = array[j];
array[j] = supp;
qscambi++;
dbgprt(1,"perno: EXIT j=%d\n",j);
return j;
}
void
quickSort(int *array, int u, int v)
{
int q = 0;
dbgprt(1,"quickSort: ENTER u=%d v=%d\n",u,v);
#if ! FIX2
if (u == v) {
#else
if ((v - u) < 2) {
#endif
dbgprt(1,"quickSort: EXIT\n");
return;
}
q = perno(array, u, v);
if (u < q) {
assert(! ((q - 1) == v));
quickSort(array, u, q - 1);
}
if (q < v) {
assert(! ((q + 1) == u));
quickSort(array, q + 1, v);
}
dbgprt(1,"quickSort: EXIT\n");
}
void
calculateQuicktime(int *array, int dim)
{
clock_t start,
end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array, 0, dim - 1);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("\nConfronti: %d \t Scambi: %d", qconfronti, qscambi);
printf("\nTempo impiegato per %d elementi : %lf secondi", dim, t);
// NOTE/BUG: array is never freed (i.e. a memory leak)
#if 1
free(array);
#endif
}
void
automaticQS()
{
printf("\nQuick Sort");
printf("\n\nOrdinati:\n");
dbgpush(2);
calculateQuicktime(generaArray(CINQUECENTO, ORINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, ORINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, ORINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, ORINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, ORINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, ORINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, ORINATO), CINQUANTAMILA);
dbgpop();
dbgpush(3);
printf("\n\nParzialmente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, PARZ_ORDINATO), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, PARZ_ORDINATO), MILLE);
calculateQuicktime(generaArray(DUEMILA, PARZ_ORDINATO), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, PARZ_ORDINATO), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, PARZ_ORDINATO), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, PARZ_ORDINATO), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, PARZ_ORDINATO), CINQUANTAMILA);
dbgpop();
printf("\n\nInversamente ordinati:\n");
calculateQuicktime(generaArray(CINQUECENTO, INVERS), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, INVERS), MILLE);
calculateQuicktime(generaArray(DUEMILA, INVERS), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, INVERS), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, INVERS), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, INVERS), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, INVERS), CINQUANTAMILA);
printf("\n\nCasuali:\n");
calculateQuicktime(generaArray(CINQUECENTO, RANDOM), CINQUECENTO);
calculateQuicktime(generaArray(MILLE, RANDOM), MILLE);
calculateQuicktime(generaArray(DUEMILA, RANDOM), DUEMILA);
calculateQuicktime(generaArray(CINQUEMILA, RANDOM), CINQUEMILA);
calculateQuicktime(generaArray(DIECIMILA, RANDOM), DIECIMILA);
calculateQuicktime(generaArray(VENTIMILA, RANDOM), VENTIMILA);
calculateQuicktime(generaArray(CINQUANTAMILA, RANDOM), CINQUANTAMILA);
}
更新:
以上仅使用 gdb
完成,但 未 根据有效的 [Hoare] 算法检查您的代码。
因此,使用 wikipedia 条目进行快速排序:https://en.wikipedia.org/wiki/Quicksort 修复了更多错误 ...
在 perno
中,i
循环因 两个 原因而失败:
-
i
的初始化是int i = primo;
而不是int i = primo - 1;
这导致循环跳过 [ignore]array[primo]
作为候选。参见:ORIG3
i
循环终止条件是while (array[i] <= pivot)
而不是while (array[i] < pivot)
。请参阅:ORIG5
请注意,您的j
循环 没有 有此问题。
通过这些修复,我在 i
和 j
循环中添加的额外边界检查不再需要(参见:ORIG1
)。
quickSort
会无限递归的原因是它内部的递归调用是:quickSort(array,u,q-1);
而不是 quickSort(array,u,q);
请参阅:ORIG4
我在 calculateQuicktime
中添加了检查以检查实际排序的最终数组。
通过此检查,某些测试不会崩溃[或无限递归],但最终数组不会排序。
这是因为我[尝试]将 if (u == v)
更改为 if ((v - u) < 2
的修复 不正确 。您的原始代码是正确的。参见:ORIG2
一些额外的文体建议:
虽然对某些常量使用 #define
是一个 好的 想法(例如 #define PI 3.14159
),但对于简单的数字来说可读性较差(例如 #define ONE 1
和 #define TWO 2
)。所以,我会消除 CINQUECENTO
,等等
我会用 static/global 数组替换它作为测试长度(例如 testlen
)。
而且,即使没有使用它们,FIVEH
等也是如此
而且,automaticQS
中的测试代码很繁琐。每个部分都在复制相当数量的代码。通过创建辅助函数(例如testall
),可以大大简化测试代码。
无论如何,这是包含所有其他更改的完整工作代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <assert.h>
#ifndef ORIG1
#define ORIG1 1
#endif
#ifndef ORIG2
#define ORIG2 1
#endif
#ifndef ORIG3
#define ORIG3 0
#endif
#ifndef ORIG4
#define ORIG4 0
#endif
#ifndef ORIG5
#define ORIG5 0
#endif
#if 0
#define CINQUECENTO 500
#define MILLE 1000
#define DUEMILA 2000
#define CINQUEMILA 5000
#define DIECIMILA 10000
#define VENTIMILA 20000
#define CINQUANTAMILA 50000
#else
int testlen[] = {
500, 1000, 2000, 5000, 10000, 20000, 50000, -1
};
#endif
typedef enum { ORINATO, INVERS, PARZ_ORDINATO, RANDOM } Ordine;
#if 0
typedef enum { FIVEH, ONET, TWOT, FIVET, TENT, TWENTYT, FIFTYT } Dimensione;
#endif
int qconfronti = 0, qscambi = 0;
int *generaArray(int dimensione, Ordine ordine);
int perno(int *array, int primo, int ultimo);
void quickSort(int *array, int u, int v);
void calculateQuicktime(int *array, int dim);
void automaticQS();
#ifdef DEBUG
#define dbgprt(_lvl,_fmt...) \
do { \
if (opt_d >= _lvl) \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int opt_d;
int svlvl;
void
dbgpush(int newlvl)
{
svlvl = opt_d;
if (opt_d)
opt_d = newlvl;
}
void
dbgpop(void)
{
opt_d = svlvl;
}
int
main(int argc,char **argv)
{
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = (*cp != 0) ? atoi(cp) : 1;
break;
}
}
setlinebuf(stdout);
automaticQS();
return 0;
}
int *
generaArray(int dimensione, Ordine ordine)
{
int i, j, n;
int *array = malloc(dimensione * sizeof(int));
if (array == NULL)
return NULL;
dbgprt(1,"generaArray: %d\n",dimensione);
switch (ordine) {
case ORINATO:
for (i = 0; i < dimensione; i++) {
array[i] = i;
}
break;
case INVERS:
n = 0;
for (i = dimensione - 1; i >= 0; i--) {
array[i] = n;
n++;
}
break;
case PARZ_ORDINATO:
for (i = 0; i < dimensione / 2; i++) {
array[i] = i;
}
for (j = i + 1; j < dimensione; j++) {
n = rand();
array[j] = n;
}
printf("\n");
break;
case RANDOM:
for (i = 0; i <= dimensione; i++)
array[i] = rand();
break;
#if 0
case ESCI:
break;
#endif
default:
break;
}
return array;
}
int
perno(int *array, int primo, int ultimo)
{
#if ORIG3
int i = primo;
#else
int i = primo - 1;
#endif
int j = ultimo + 1;
int supp = 0;
int pivot = array[primo];
dbgprt(1,"perno: ENTER primo=%d ultimo=%d pivot=%d\n",primo,ultimo,pivot);
while (i < j) {
dbgprt(2,"perno: OUTLOOP i=%d j=%d\n",i,j);
do {
i = i + 1;
#if (! ORIG1)
if (i >= j)
break;
#endif
dbgprt(3,"perno: ILOOP i=%d array=%d\n",i,array[i]);
qconfronti++;
#if ORIG5
} while (array[i] <= pivot);
#else
} while (array[i] < pivot);
#endif
do {
#if (! ORIG1)
if (i >= j)
break;
#endif
j = j - 1;
dbgprt(3,"perno: JLOOP j=%d array=%d\n",j,array[j]);
qconfronti++;
} while (array[j] > pivot);
if (i < j) {
dbgprt(2,"perno: SWAP\n");
supp = array[i];
array[i] = array[j];
array[j] = supp;
qscambi++;
}
}
supp = array[primo];
array[primo] = array[j];
array[j] = supp;
qscambi++;
dbgprt(1,"perno: EXIT j=%d\n",j);
return j;
}
void
quickSort(int *array, int u, int v)
{
int q = 0;
dbgprt(1,"quickSort: ENTER u=%d v=%d\n",u,v);
#if ORIG2
if (u == v) {
#else
if ((v - u) < 2) {
#endif
dbgprt(1,"quickSort: EXIT\n");
return;
}
q = perno(array, u, v);
if (u < q) {
assert((q - 1) != v);
#if ORIG4
quickSort(array, u, q - 1);
#else
quickSort(array, u, q);
#endif
}
if (q < v) {
assert((q + 1) != u);
quickSort(array, q + 1, v);
}
dbgprt(1,"quickSort: EXIT\n");
}
void
calculateQuicktime(int *array, int dim)
{
clock_t start, end;
double t;
qconfronti = 0;
qscambi = 0;
start = clock();
quickSort(array, 0, dim - 1);
end = clock();
t = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("Confronti: %d \t Scambi: %d\n", qconfronti, qscambi);
printf("Tempo impiegato per %d elementi : %lf secondi\n", dim, t);
// check array to ensure it's sorted
int err = 0;
int old = array[0];
for (int idx = 1; idx < dim; ++idx) {
int cur = array[idx];
if (cur < old) {
printf("calculateQuicktime: BADSORT idx=%d old=%d cur=%d\n",
idx,old,cur);
err = 1;
}
old = cur;
}
if (err)
exit(1);
// NOTE/BUG: array is never freed (i.e. a memory leak)
#if 1
free(array);
#endif
}
void
testall(Ordine order,const char *reason)
{
printf("\n\n%s:\n",reason);
for (int *len = testlen; *len >= 0; ++len) {
printf("\n");
int *arr = generaArray(*len,order);
calculateQuicktime(arr,*len);
}
}
void
automaticQS()
{
printf("\nQuick Sort");
testall(ORINATO,"Ordinati");
testall(PARZ_ORDINATO,"Parzialmente ordinati");
testall(INVERS,"Inversamente ordinati");
testall(RANDOM,"Casuali");
}