我需要一种没有回调的高效排序,但可以像使用qsort()一样自定义。我想要的是它像迭代器一样工作,它在循环中不断调用排序API直到完成,在循环中进行比较而不是在回调函数中进行比较。这样,自定义比较对于调用函数是本地的(因此可以访问局部变量,可能更有效等)。我已经为低效的选择排序实现了这个,但需要它有效,所以更喜欢快速排序派生。
有人做过这样的事吗?我试图快速排序,但试图将算法彻底改变,对我的大脑造成太大伤害。
以下是它的外观。
// the array of data we are sorting
MyData array[5000], *firstP, *secondP;
// (assume data is filled in)
Sorter sorter;
// initialize sorter
int result = sortInit (&sorter, array, 5000,
(void **)&firstP, (void **)&secondP, sizeof(MyData));
// loop until complete
while (sortIteration (&sorter, result) == 0) {
// here's where we do the custom comparison...here we
// just sort by member "value" but we could do anything
result = firstP->value - secondP->value;
}
答案 0 :(得分:2)
按照你的建议将排序功能彻底改变,不太可能让它更快。你在物品指针的间接比较函数上进行间接交易。
您希望比较功能可以访问状态信息。假设您不会同时拥有多个线程,这是创建全局变量或全局结构的快速方法。在对所有数据进行排序之前,qsort函数不会返回,因此在单线程环境中这应该是安全的。
我建议的另一件事是将源定位到qsort并修改它以获取额外的参数,指向您的状态结构的指针。然后,您可以将此指针传递给比较函数。
答案 1 :(得分:1)
获取qsort的现有实现并更新它以引用Sorter对象的局部变量。它不会调用传入的比较函数,而是更新其状态并返回调用者。
由于qsort中的递归,您需要在Sorter对象中保留某种状态堆栈。您可以使用动态分配(效率较低)使用数组或链表完成此操作。由于大多数qsort实现对较大的一半使用尾递归,并对枢轴点的较小一半进行qsort的递归调用,因此如果数组可以包含n个状态,则可以对至少2个 n 元素进行排序。
答案 2 :(得分:1)
一个简单的解决方案是使用内联排序函数和内联比较回调。在使用优化进行编译时,两个调用都会完全按照您的需要相互拼接。唯一的缺点是您选择的排序算法是有限的,因为如果您递归或分配更多内存,您可能会因此而失去任何好处。像这样小开销的方法最适合小数据集。
您可以使用泛型排序函数与比较方法,大小,偏移量和步幅。这种方式自定义比较可以通过参数而不是回调来完成。通过这种方式,您可以使用任何算法。只需使用一些宏来填充最常见的情况,因为你会有很多函数参数。
另外,请查看STB库(https://github.com/nothings/stb)。 它具有与许多其他有用的C工具类似的排序功能。
答案 3 :(得分:0)
您要求的内容已经完成 - 它被称为std::sort
,它已经在C ++标准库中了。更好地支持这个(以及许多其他事情)是为什么编写良好的C ++通常比C更快的部分原因。
答案 4 :(得分:0)
您可以编写预处理器宏来输出排序例程,并让宏将比较表达式作为参数。
#define GENERATE_SORT(name, type, comparison_expression) \
void name(type* begin, type* end) \
{ /* ... when needed, fill a and b and use comparison_expression */ }
GENERATE_SORT(sort_ints, (*a<*b))
void foo()
{
int array[10];
sort_ints(array, array+10);
}
答案 5 :(得分:0)
两点。我)。
_asm
II)。编译器的基本设计限制。
编译器的基本目标是避免汇编程序或机器代码。他们通过施加一定的限制来实现这一目标。在这种情况下,我们放弃了可以在汇编代码中轻松实现的灵活性。即在调用compare函数时将生成的排序代码分为两部分。将前半部分复制到某个地方。接下来,将复制比较函数的代码复制到第一部分的上一个复制代码之后。然后复制排序代码的最后一半。最后,我们必须处理一系列次要细节。另请参阅正在运行的程序的“热修补”概念。