我正在尝试使用void*
进行合并排序。如果我保留数字,我想排序为1字节,它完美地工作。但是,如果数字位于1个字节以上,则效果不佳。我相信它需要2个数字。我用500号测试了它,最后我有256和244没有排序......
#include "msort.h"
#include <iostream>
using namespace std;
void Mergesort( void* base, size_t nelem, size_t width,
int (*fcmp)( const void*, const void* ) )
{
if (nelem <=1)
return;
int lhsnelem = nelem/2;
int rhsnelem = nelem - lhsnelem;
char* midpoint = (char*)(base) + ((nelem/2)*width);
cout << "width is: " << width << endl;
Mergesort(base, lhsnelem, width, fcmp);
Mergesort(midpoint, rhsnelem, width, fcmp);
//ItemType* temp= new ItemType[nelem];
int temp[20];
char* lhs = (char*)(base);
char* rhs = midpoint;
char* end = rhs + (rhsnelem*width);
int count = 0;
while ((lhs != midpoint) && (rhs != end))
{
int num = fcmp( lhs, rhs );
if (num <= 0)
{
temp[count] = *lhs;
lhs = lhs + width;
}
else
{
temp[count] = *rhs;
rhs = rhs + width;
}
count++;
}
if (lhs == midpoint)
{
while (rhs != end)
{
temp[count] = *rhs;
rhs = rhs + width;
count++;
}
}
else
{
while (lhs != midpoint)
{
temp[count] = *lhs;
lhs = lhs + width;
count++;
}
}
for (int i=0; i<nelem; i++)
{
lhs = (char*)(base)+ (width*i);
*lhs = temp[i];
lhs = lhs + width;
}
}
/////// main.cpp ///////////////////////
// here is my comparison function in main.cpp
int compare(const void *one, const void *two)
{
if (*(int*)one > *(int*)two) return 1;
if (*(int*)one < *(int*)two) return -1;
return 0;
}
1字节数字的输出正常:
In: 5 8 7 4 1 6 11 41 160 47 38 120 40 58 12 43 66 98 17 140
Out: 1 4 5 6 7 8 11 12 17 38 40 41 43 47 58 66 98 120 140 160
如果有一个2字节的数字输出不正常排序不能正常工作:
In: 500 50 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Out: 256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 50 244
答案 0 :(得分:1)
您当前的问题是您使用char *lhs
复制整数。在进行复制之前,您需要将指针转换回int *
。
#include <iostream>
using namespace std;
static void Mergesort(void *base, size_t nelem, size_t width,
int (*fcmp)(const void *, const void *))
{
if (nelem <= 1)
return;
int lhsnelem = nelem/2;
int rhsnelem = nelem - lhsnelem;
char* midpoint = (char*)(base) + ((nelem/2)*width);
Mergesort(base, lhsnelem, width, fcmp);
Mergesort(midpoint, rhsnelem, width, fcmp);
int temp[20];
char* lhs = (char*)(base);
char* rhs = midpoint;
char* end = rhs + (rhsnelem*width);
int count = 0;
while ((lhs != midpoint) && (rhs != end))
{
int num = fcmp(lhs, rhs);
if (num <= 0)
{
temp[count] = *(int *)lhs; // Here!
lhs += width;
}
else
{
temp[count] = *(int *)rhs; // Here!
rhs += width;
}
count++;
}
while (rhs != end)
{
temp[count] = *(int *)rhs; // Here!
rhs = rhs + width;
count++;
}
while (lhs != midpoint)
{
temp[count] = *(int *)lhs; // Here!
lhs = lhs + width;
count++;
}
for (int i = 0; i < nelem; i++)
{
lhs = (char *)(base)+ (width*i);
*(int *)lhs = temp[i]; // Here!
lhs = lhs + width;
}
}
static int compare(const void *one, const void *two)
{
if (*(int*)one > *(int*)two) return 1;
if (*(int*)one < *(int*)two) return -1;
return 0;
}
#define DIM(x) (sizeof(x)/sizeof(*(x)))
int array1[] = { 5, 8, 7, 4, 1, 6, 11, 41, 160, 47, 38, 120,
40, 58, 12, 43, 66, 98, 17, 140 };
int array2[] = { 500, 50, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
static void PrintArray(int *array, size_t n_items)
{
const char *pad = "";
for (size_t i = 0; i < n_items; i++)
{
cout << pad << array[i];
pad = ", ";
}
cout << endl;
}
int main()
{
PrintArray(array1, DIM(array1));
Mergesort(array1, DIM(array1), sizeof(array1[0]), compare);
PrintArray(array1, DIM(array1));
PrintArray(array2, DIM(array2));
Mergesort(array2, DIM(array2), sizeof(array2[0]), compare);
PrintArray(array2, DIM(array2));
return 0;
}
你不幸使用小端(Intel)机器;如果你一直在使用大端机器(SPARC,PPC),你可能会为小数测试用例获得一个零数组。
还有一个更严重,更深层次的问题。该代码实际上仅可用于对最多20个整数的数组进行排序,因为int temp[20];
(将大小限制为20并将类型限制为int
)并且由于“固定”赋值
分配应该用内存移动(可能调用memmove()
)代替,这反过来意味着代码只适用于POD(普通ol'数据)类型。需要将temp
数组分配为适当大小(nelem * width
)的字节数组。内存分配很糟糕;它会减慢代码的速度。 '好消息'是将temp数组复制到原始数组的最终循环可以替换为memmove()
。
目前尚不清楚这是一个好的C ++代码 - 我认为模板化的实现会更明智。作为C代码,将内存移动问题整理出来,没关系。
static void Mergesort(void *base, size_t nelem, size_t width,
int (*fcmp)(const void *, const void *))
{
if (nelem <= 1)
return;
int lhsnelem = nelem/2;
int rhsnelem = nelem - lhsnelem;
char* midpoint = (char*)(base) + ((nelem/2)*width);
Mergesort(base, lhsnelem, width, fcmp);
Mergesort(midpoint, rhsnelem, width, fcmp);
char *temp = new char[nelem * width];
char* lhs = (char*)(base);
char* rhs = midpoint;
char* end = rhs + (rhsnelem*width);
int count = 0;
while ((lhs != midpoint) && (rhs != end))
{
int num = fcmp(lhs, rhs);
if (num <= 0)
{
memmove(&temp[count], lhs, width);
lhs += width;
}
else
{
memmove(&temp[count], rhs, width);
rhs += width;
}
count += width;
}
while (rhs != end)
{
memmove(&temp[count], rhs, width);
rhs += width;
count += width;
}
while (lhs != midpoint)
{
memmove(&temp[count], lhs, width);
lhs += width;
count += width;
}
memmove(base, temp, nelem * width);
delete[] temp;
}