我正在尝试使用C中的qsort()对二维2D数组进行排序。数组包含3D点数据,使用fscanf从文件中读取。我的编程技巧相当有限,但我需要处理大量的数据集。如果我的代码很糟糕,请提前抱歉。
23127.947,23127.947,23127.947
523127.790,523127.790,523127.790
523127.747,523127.747,523127.747
523127.761,523127.761,523127.761
523127.768,523127.768,523127.768
(...为3,158,632分)
我使用printf来隔离我的代码中的问题似乎是qsort()行,这会导致分段错误。从我读过的Stack Overflow上的其他问题来看,这可能是我的“比较”功能的一个问题。做一维数组的例子似乎很简单,但我看到的二维数组的例子没有比较其他维度(第一个X,然后如果X1 = X2,比较Y,那么如果Y1 = Y2,则比较Z)。 / p>
int main(int argc, char *argv[]) {
int i,j,c;
double x,y,z;
int ROWS = 3158632;
int COLS = 3;
char buffer[100];
double** data = Make2DDoubleArray(ROWS, COLS);
//Open the plot file to read in, and have an output write file
FILE *fp = fopen("Plot_1-2.txt","r");
if(fp == NULL) {
printf("Can't open file\n");
exit;
}
fgets(buffer, 100, fp); //Ignore header
for(i=0; ; i++){
if ((c = fgetc(fp)) == EOF){
break;
}
fscanf(fp,"%lf, %lf, %lf",&x, &y, &z);
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
printf("First 5 unsorted numbers:\n");
for(j=0;j<5;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
printf("Last 5 unsorted numbers:\n");
for(j=ROWS-5;j<ROWS;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
/* Sort array using Quicksort algorithm: */
printf("Sorting...\n");
qsort(data, ROWS, COLS*sizeof(double), &compare);
printf("First 10 sorted numbers:\n");
for(j=0;j<10;j++){
printf("Line %d: %.3lf, %.3lf, %.3lf\n",j, data[j][0], data[j][0], data[j][0]);
}
fclose(fp);
for (i=0; i<ROWS; i++){
free(data[i]);
}
free(data);
return 0;
}
double** Make2DDoubleArray(int arraySizeX, int arraySizeY) {
double** theArray;
int i;
theArray = (double**) malloc(arraySizeX*sizeof(double*));
for (i = 0; i < arraySizeX; i++)
theArray[i] = (double*) malloc(arraySizeY*sizeof(double));
return theArray;
}
int compare(const void *arg1, const void *arg2) {
//double a, b, c, d, e, f;
double *a = (double*)arg1;
double *b = (double*)arg2;
double *c = ((double*)arg1 + 1);
double *d = ((double*)arg2 + 1);
double *e = ((double*)arg1 + 2);
double *f = ((double*)arg2 + 2);
if(a > b)
return 1;
else if(a < b)
return -1;
else {
if(c > d)
return 1;
else if(c < d)
return -1;
else {
if(e > f)
return 1;
else if(e < f)
return -1;
else
return 0;
}
}
}
我想知道是否告诉qsort去“COLS * sizeof(double)”这是错误的方法,我是如何为2D阵列分配内存的?将此问题视为一维数组会使其余部分工作吗?如果可能的话,我宁愿将它保留为2D数组。
答案 0 :(得分:2)
qsort
期望排序的元素出现在连续的内存块中。如果所有单元格构成一个连续的内存块,可以解释为一维数组并与qsort
一起使用,您仍然可以将数据保存在二维数组中。
不像在Make2DDoubleArray
中那样为每一行分别分配内存,而是一次为所有行分配内存。然后,除了你现在返回的内容:指向行的指针数组;你还必须返回(使用参数指针)包含所有行的内存块。
您正在为每一行分配内存
for (i = 0; i < arraySizeX; i++)
theArray[i] = (double*) malloc(arraySizeY*sizeof(double));
虽然您可以一步分配内存
double *cells = malloc(sizeof(double) * arraySizeX * arraySizeY);
if (cells == NULL) { ... }
for (i = 0; i < arraySizeX; i++)
theArray[i] = &cells[arraySizeY * i];
然后你将有两个数组:你现在拥有的行指针数组(在代码中称为theArray
);和一个新的1D数组,它保存所有行(不是指向行的指针,而是单元格的数组)(,实际上,所有单元格,其中每行,一个三元组,是一个数据点),并且可以使用对于qsort
(在我的代码中称为cells
)。
然后,将后者 - cells
(而不是data
)传递给qsort
qsort(cells, ROWS * COLS, sizeof(double), &compare);
还要注意问题中代码中的调用
qsort(data, ROWS, COLS*sizeof(double), &compare);
是错误的,因为您没有对 ROWS
行进行排序,每行的大小为COLS*sizeof(double)
。
qsort(cells, ROWS, COLS*sizeof(double), &compare);
答案 1 :(得分:1)
尝试使用结构代替数据:
typedef struct {
double x;
double y;
double z;
} point_data;
然后你只需要这种新类型的一维数组:
point_data *array = malloc(linesRead * sizeof *array);
你的比较功能仍然非常相似:
int compare(const void *arg1, const void *arg2) {
point_data *point1 = arg1,
*point2 = arg2;
if ( point1->x > point2->x ) {
return 1;
else if ( point1->x < point2->x ) {
return -1;
} else {
if ( point1->y > point2->y ) {
return 1;
else if ( point1->y < point2->y ) {
return -1;
} else {
if ( point1->z > point2->z ) {
return 1;
else if ( point1->z < point2->z ) {
return -1;
} else {
return 0;
}
}
}
}
此外,请不要硬编码点数,而是计算您读入的数字。
答案 2 :(得分:1)
这些都不代表没有<stdio.h>
,<stdlib.h>
等标题的内容......
请解释exit;
。我想你的意思是exit(0);
。
main
中存在一些问题。由于fgetc
,您的代码可能会丢失第一个值的最重要数字,这是一个微妙的错误。如果您想测试EOF,请测试scanf
的返回值( Jee!我没想到!我希望他们在手册中写下这些东西! Duh,他们这样做。 ..)。文件末尾的示例比这更好,因为该示例确保fscanf
实际解析了三个值。
for(size_t i=0; fscanf(fp,"%lf, %lf, %lf",&x, &y, &z) != EOF; i++){
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
您的Make2DDoubleArray
功能存在问题。它分配许多不相交的数组,qsort
无法处理。一步分配数组不是更清晰吗?
void *Make2DDoubleArray(size_t x) {
double (*theArray)[3] = malloc(x * sizeof *theArray);
return theArray;
}
theArray
被声明为指向3个双精度数组的指针。你甚至不需要Make2DDoubleArray
。
compare
功能存在问题。
double *a = (double*)arg1;
double *b = (double*)arg2;
a
和b
是指针,
if(a > b)
return 1;
else if(a < b)
return -1;
...但是你的代码将它们作为整数进行比较,使得排序失败。 array[0]
的地址始终小于array[1]
的地址。
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(int argc, char *argv[]) {
int j,c;
double x,y,z;
size_t ROWS = 3158632;
size_t COLS = 3;
char buffer[100];
double (*theArray)[COLS] = malloc(ROWS * sizeof *theArray);
//Open the plot file to read in, and have an output write file
FILE *fp = fopen("Plot_1-2.txt","r");
if(fp == NULL) {
printf("Can't open file\n");
exit(0);
}
fgets(buffer, 100, fp); //Ignore header
for(size_t i=0; fscanf(fp,"%lf, %lf, %lf", &x, &y, &z) == 3; i++){
data[i][0] = x;
data[i][1] = y;
data[i][2] = z;
}
printf("First 5 unsorted numbers:\n");
for(size_t j=0; j<5; j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
puts("Last 5 unsorted numbers:");
for(size_t j=ROWS-5; j<ROWS; j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
/* Sort array using Quicksort algorithm: */
puts("Sorting...");
qsort(data, ROWS, sizeof *data, compare);
puts("First 10 sorted numbers:");
for(size_t j=0;j<10;j++){
printf("Line %zu: %.3lf, %.3lf, %.3lf\n", j, data[j][0], data[j][0], data[j][0]);
}
fclose(fp);
free(data);
return 0;
}
int compare(const void *arg1, const void *arg2) {
double (*x)[3] = arg1;
double (*y)[3] = arg2;
if ((*x)[0] > (*y)[0])
return 1;
else if ((*x)[0] < (*y)[0])
return -1;
else if ((*x)[1] > (*y)[1])
return 1;
else if ((*x)[1] < (*y)[1])
return -1;
else if ((*x)[2] > (*y)[2])
return 1;
else if ((*x)[2] < (*y)[2])
return -1;
else
return 0;
}