我有一个二进制合并插入排序,它接受一个 void 指针(数组的第一个元素),并且,可以处理 int 和 string 数组(所有统一测试都通过)。
现在我尝试将它与以下数组一起使用:
struct record{
int id;
char* string_field_1;
int integer_field_2;
double float_field_3;
};
我必须根据所选字段进行订购。
这是从 csv 文件获取数据的示例
选择
switch (field) {
case 1://struct_array_get(array,0) return the first element of the array
merge_binary_insertion_sort(struct_array_get(array,0), struct_array_size(array), sizeof(struct record), k, precedes_record_string_field);
数组已正确加载,因为打印功能
for(unsigned long i=0;i<el_num;i++){
array_element = (struct record *)struct_array_get(array, i);
printf("<POSIZION:%d, ID:%d, String:%s, Integer:%d, Float:%lf >\n",i,array_element->id,array_element->string_field_1,array_element->integer_field_2,array_element->float_field_3);
}
可以显示数组中的所有记录。所以当调用排序函数时出现问题:
void merge_binary_insertion_sort(void *base, size_t nitems, size_t size, size_t k, CompareFunction compare){
if(base == NULL){
fprintf(stderr,"the given array cannot be null");
exit(EXIT_FAILURE);
}
else merge_binary_insertion_sort_rec(base, 0, nitems-1, k, size, compare);
}
void merge_binary_insertion_sort_rec(void *arr, int left, int right, size_t k, size_t elementSize, CompareFunction compare) {
if (left < right) {
if (right - left + 1 <= k) {
// Use bin_insertion_sort for small subarrays
bin_insertion_sort(arr + (left * elementSize), right - left + 1, elementSize, compare);
} else {
int mid = left + (right - left) / 2;
// Sort the left and right halves recursively
merge_binary_insertion_sort_rec(arr, left, mid, k, elementSize, compare);
merge_binary_insertion_sort_rec(arr, mid + 1, right, k, elementSize, compare);
// Merge the sorted halves
merge(arr, left, mid, right, elementSize, compare);
}
}
}
int binary_search(void *arr, void *item, int low, int high, CompareFunction compare, size_t elementSize) {
if (high <= low){
return (compare(item, arr + low * elementSize) > 0) ? (low + 1) : low ;
}
int mid = (low + high) / 2;
int cmpResult = compare(item, arr + mid * elementSize);
if (cmpResult == 0)
return mid + 1;
if (cmpResult > 0)
return binary_search(arr, item, mid + 1, high, compare, elementSize);
return binary_search(arr, item, low, mid - 1, compare, elementSize);
}
void bin_insertion_sort(void *arr, int n, size_t elementSize, CompareFunction compare) {
int i, loc, j;
void *selected = malloc(elementSize);
if (selected == NULL) {
fprintf(stderr, "Errore nell'allocazione di memoria per 'selected'\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < n; ++i) {
j = i - 1;
memcpy(selected, arr + i * elementSize, elementSize);
// Find location where selected should be inserted
loc = binary_search(arr, selected, 0, j, compare, elementSize);
// Move all elements after location to create space
while (j >= loc) {
memcpy(arr + (j + 1) * elementSize, arr + j * elementSize, elementSize);
j--;
}
memcpy(arr + (j + 1) * elementSize, selected, elementSize);
}
free(selected);
}
void merge(void *arr, int left, int mid, int right, size_t elementSize, CompareFunction compare) {
int i, j, k;
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temporary arrays for the left and right subarrays
void *L = malloc(n1 * elementSize);
void *R = malloc(n2 * elementSize);
// Copy data from the original array to the temporary arrays
memcpy(L, arr + (left * elementSize), n1 * elementSize);
memcpy(R, arr + ((mid + 1) * elementSize), n2 * elementSize);
// Merge the temporary arrays back into the original array
i = 0; // Initial index of left subarray
j = 0; // Initial index of right subarray
k = left; // Initial index of merged subarray
while (i < n1 && j < n2) {
void *leftElem = L + (i * elementSize);
void *rightElem = R + (j * elementSize);
if (compare(leftElem, rightElem) <= 0) {
// If left element <= right element, copy the left element to the merged subarray
memcpy(arr + (k * elementSize), leftElem, elementSize);
i++;
} else {
// If left element > right element, copy the right element to the merged subarray
memcpy(arr + (k * elementSize), rightElem, elementSize);
j++;
}
k++;
}
// Copy any remaining elements from the left subarray
while (i < n1) {
memcpy(arr + (k * elementSize), L + (i * elementSize), elementSize);
i++;
k++;
}
// Copy any remaining elements from the right subarray
while (j < n2) {
memcpy(arr + (k * elementSize), R + (j * elementSize), elementSize);
j++;
k++;
}
// Free the temporary arrays
free(L);
free(R);
}
我们只能关注binary_search,问题是:
当我调用 return (compare(item, arr + low * elementSize) > 0) 时? (低+1):低; 对于记录数组,使用此比较函数
static int precedes_record_string_field(const void* r1_p, const void* r2_p) {
if (r1_p == NULL || r2_p == NULL) {
fprintf(stderr, "precedes_record_string_field: one of the parameters is a null pointer\n");
exit(EXIT_FAILURE);
}
const struct record* rec1_p = (const struct record*)r1_p;
const struct record* rec2_p = (const struct record*)r2_p;
printf("Record 1: ID=%d, String=%s, Integer=%d, Float=%f\n", rec1_p->id, rec1_p->string_field_1, rec1_p->integer_field_2, rec1_p->float_field_3);
sleep(1);
printf("Record 2: ID=%d, String=%s, Integer=%d, Float=%f\n", rec2_p->id, rec2_p->string_field_1, rec2_p->integer_field_2, rec2_p->float_field_3);
sleep(5);
return strcmp(rec1_p->string_field_1, rec2_p->string_field_1);
}
它打印rec2数据,但不打印rec1数据,所以我认为它可以转换arr + low * elementSize指针,但不能转换void * item指针。我在内存地址管理中做错了什么?
我陷入困境,因为我对数组中的单个、空和多个字符串和 int 进行的所有统一测试都工作正常。
谢谢大家。
Maybe you could test the functions first...
I will show you a methodical way of writing his,
using your `struct` and `qsort`,
that you can easily adapt...
将物品分开typedef struct
{
int id;
char* string;
int i_field;
double d_field;
} Target;
int cmp_1(const void*, const void*);
int cmp_2(const void*, const void*);
int cmp_3(const void*, const void*);
int cmp_4(const void*, const void*);
int so_show(unsigned, Target[], const char*);
这里有您的数据记录、4 个必需的函数和一个显示结果的函数使用
封装并围绕数据编写代码。
看这个:
Target some_value[] = {
[0] =
{.id = 42,
.string = "value 33",
.i_field = 4242,
.d_field = 42.42},
[1] =
{.id = 4,
.string = "stack",
.i_field = 42,
.d_field = 42.242},
[2] =
{.id = 342,
.string = "overflow",
.i_field = 4,
.d_field = 142.42},
[3] =
{.id = 412,
.string = "take the survey",
.i_field = 2,
.d_field = 2142.42},
};
这是测试你所有功能的数据。###'
main
测试###这里:
so_show(4, some_value, "\nBefore sort:\t");
qsort(some_value, 4, sizeof(Target), cmp_1);
so_show(4, some_value, "\nAfter sort by id:\t");
qsort(some_value, 4, sizeof(Target), cmp_2);
so_show(
4, some_value, "\nAfter sort by string field:\t");
qsort(some_value, 4, sizeof(Target), cmp_3);
so_show(
4, some_value, "\nAfter sort by integer field:\t");
qsort(some_value, 4, sizeof(Target), cmp_4);
so_show(
4, some_value, "\nAfter sort by integer field:\t");
输出
Before sort: 4 records
|=========================================================|
| id | string value | integer | double |
|=========================================================|
| 42 | " value 33" | 4242 | 42.4200 |
| 4 | " stack" | 42 | 42.2420 |
| 342 | " overflow" | 4 | 142.4200 |
| 412 | " take the survey" | 2 | 2142.4200 |
|=========================================================|
After sort by id: 4 records
|=========================================================|
| id | string value | integer | double |
|=========================================================|
| 4 | " stack" | 42 | 42.2420 |
| 42 | " value 33" | 4242 | 42.4200 |
| 342 | " overflow" | 4 | 142.4200 |
| 412 | " take the survey" | 2 | 2142.4200 |
|=========================================================|
After sort by string field: 4 records
|=========================================================|
| id | string value | integer | double |
|=========================================================|
| 342 | " overflow" | 4 | 142.4200 |
| 4 | " stack" | 42 | 42.2420 |
| 412 | " take the survey" | 2 | 2142.4200 |
| 42 | " value 33" | 4242 | 42.4200 |
|=========================================================|
After sort by integer field: 4 records
|=========================================================|
| id | string value | integer | double |
|=========================================================|
| 412 | " take the survey" | 2 | 2142.4200 |
| 342 | " overflow" | 4 | 142.4200 |
| 4 | " stack" | 42 | 42.2420 |
| 42 | " value 33" | 4242 | 42.4200 |
|=========================================================|
After sort by integer field: 4 records
|=========================================================|
| id | string value | integer | double |
|=========================================================|
| 4 | " stack" | 42 | 42.2420 |
| 42 | " value 33" | 4242 | 42.4200 |
| 342 | " overflow" | 4 | 142.4200 |
| 412 | " take the survey" | 2 | 2142.4200 |
|=========================================================|
而且好像还可以。这样更简单:首先测试所有功能。
既然您说代码已经适用于整数,那么只需确保排序代码真正抽象了数据记录即可。 一般来说,这只是编写正确的交换函数的情况。并特别注意导航过程...
完整
C
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int id;
char* string;
int i_field;
double d_field;
} Target;
int cmp_1(const void*, const void*);
int cmp_2(const void*, const void*);
int cmp_3(const void*, const void*);
int cmp_4(const void*, const void*);
int so_show(unsigned, Target[], const char*);
int main(void)
{
Target some_value[] = {
[0] =
{.id = 42,
.string = "value 33",
.i_field = 4242,
.d_field = 42.42},
[1] =
{.id = 4,
.string = "stack",
.i_field = 42,
.d_field = 42.242},
[2] =
{.id = 342,
.string = "overflow",
.i_field = 4,
.d_field = 142.42},
[3] =
{.id = 412,
.string = "take the survey",
.i_field = 2,
.d_field = 2142.42},
};
so_show(4, some_value, "\nBefore sort:\t");
qsort(some_value, 4, sizeof(Target), cmp_1);
so_show(4, some_value, "\nAfter sort by id:\t");
qsort(some_value, 4, sizeof(Target), cmp_2);
so_show(
4, some_value, "\nAfter sort by string field:\t");
qsort(some_value, 4, sizeof(Target), cmp_3);
so_show(
4, some_value, "\nAfter sort by integer field:\t");
qsort(some_value, 4, sizeof(Target), cmp_4);
so_show(
4, some_value, "\nAfter sort by integer field:\t");
}; // main
int cmp_1(void* one, void* other)
{
Target* a = one;
Target* b = other;
if (a->id < b->id) return -1;
if (a->id == b->id) return 0;
return 1;
};
int cmp_2(void* one, void* other)
{ // now for the string
Target* a = one;
Target* b = other;
return strcmp(a->string, b->string);
};
int cmp_3(void* one, void* other)
{
Target* a = one;
Target* b = other;
if (a->i_field < b->i_field) return -1;
if (a->i_field == b->i_field) return 0;
return 1;
};
int cmp_4(void* one, void* other)
{
Target* a = one;
Target* b = other;
if (a->d_field < b->d_field) return -1;
if (a->d_field == b->d_field) return 0;
return 1;
};
int so_show(unsigned N, Target r[], const char* msg)
{
if (r == NULL) return -1;
if (msg != NULL) printf("%s", msg);
printf("%d records\n", N);
const char* l0 =
"\
| id | string value | integer | double |";
const char* l1 =
"\
|=========================================================|";
printf("%s\n%s\n%s\n", l1,l0,l1);
for ( unsigned u=0;u<N;u+=1)
printf(
"| %4d | \"%20s\" | %8d | %12.4f |\n", r[u].id,
r[u].string, r[u].i_field, r[u].d_field);
printf("%s\n\n",l1);
return 0;
}