以下是该方案:
void quicksort(void *data, size_t size);
void mergesort(void *data, size_t size);
void heapsort(void *data, size_t size);
size_t binary_search(void *data, size_t size, size_t key)
{
// Usual binary search implementation
// ...
return 0; // just a placeholder
}
我希望用户指定用于对数据进行排序的算法,然后根据该排序算法进行排序,然后调用二进制搜索以搜索该数据中的密钥。
如何对用户实施这种强加的最低责任?
答案 0 :(得分:2)
您问题的具体说明:
不要混合排序和搜索。
首先,线性搜索是O(N),而sort_and_search最多是O(N log N),即线性搜索会更快。只有在已经排序的数据上多次搜索时,二进制搜索才是算法的好选择。
其次,您注意到调用者需要控制排序算法。为什么不让呼叫者这样做:
quicksort(data,size);
size_t result = binary_search(data,size);
概括:使用你的例子的方法:
(1)Functor参数,如Naveen所示
这会使sort_and_search
成为一个模板,这可能不适合某些用途。
但它是一种类似的常见模式。
这个解决方案的优点是当binary_search对functor进行很多短调用时(在这种情况下它不会),这是额外的优化可能性。缺点是如果sort_and_search
本身具有较大的主体,则生成的代码量。
(2)功能指针,如roe
所示
虽然这看起来像“C-ish”,但它是一个简单,直截了当的解决方案。缺点:您无法对sort函数进行参数化(例如,通过指定如何在二进制排序中选择一个pivot)。
(3)多态性
基本上你:
定义一个抽象基类
struct ISort
{
virtual void Sort(void * data, size_t size) = 0;
virtual ~ISortData() {}
}
从中继承具体实现:
struct BinarySort : public ISort { ... }
struct MergeSort : public ISort { ... }
struct HeapSort : public ISort { ... }
并将排序作为参数提供给sort_and_search
:
size_t sort_and_search(void * data, size_t size, ISort & sort);
优点/缺点:绑定通常在运行时发生。这强烈隔离了排序和搜索实现(它们可以驻留在不同的二进制文件中)。但是,呼叫开销明显大于
的情况 更多说明:(void * data, size_t size)
界面
此界面不提供类型安全性。它可以工作,但编译器无法告诉您何时传递无效参数。
STL在这里应用了三个概括:
使元素类型成为模板参数:
template <typename T>
size_t sas(T * values, size_t count)
这提供了类型检查,并支持类型为T的重载比较运算符。
使用迭代器而不是数组:
它们弄乱了语法,但它允许算法在没有连续存储的容器上工作。此外,您可以将容器视为单个实体,而不是指针和调用者必须匹配的计数。
可选的比较函子:
包含用于比较的仿函数的可选参数。这允许在相同类型T上使用不同的排序条件。
答案 1 :(得分:1)
我建议接受一个仿函数作为binary_search
的参数。用户需要编写结构并为operator()
提供实现。在operator()
内,他可以使用他喜欢的任何方法进行排序。这种方法与标准库中使用的方法类似。
修改强>
示例代码:
void quicksort(void *data, size_t size)
{
}
void mergesort(void* data, size_t size)
{
}
struct QuickSort
{
void operator()(void* data, size_t size) const
{
quicksort(data,size);
}
};
struct MergeSort
{
void operator()(void* data, size_t size) const
{
mergesort(data,size);
}
};
template<typename Functor>
size_t binary_search(void *data, size_t size, size_t key, Functor sort)
{
sort(data, size);
//Rest of the code
return 0;
}
int main()
{
binary_search(NULL,0, 0, QuickSort());
binary_search(NULL,0, 0, MergeSort());
return 0;
}
答案 2 :(得分:1)
如果要提供一组用于排序的函数,并在搜索前在binary_search
函数中进行排序,请尝试以下操作:
void quicksort(void *data, size_t size);
void mergesort(void *data, size_t size);
void heapsort(void *data, size_t size);
size_t binary_search(void *data, size_t size, size_t key, void(*algorithm)(void*,size_t) = &quicksort)
{
alogrithm(data,size); // sort it..
// Usual binary search implementation
return 0; // just a placeholder
}
这是一个C风格的解决方案,添加了C ++的默认参数,让用户根本不指定任何内容。要使用更多C ++,您的算法应该是Naveen建议的算子,并让用户指定其中一个。虽然这将消耗更多内存并导致一个间接(和缓存未命中),因为'operator()'必然是虚拟的,但这可能是微不足道的。或者你可以模板化,在这种情况下你将只使用更多的代码。仿函数具有额外的好处,您可以参数化算法(例如,升序或降序)。
也就是说,感觉这是一种奇怪的方式,让'binary_search'进行排序。我强加了数据必须排序的限制,因为排序已排序的数据是浪费时间(例如,如果您进行多次搜索)。此外,快速排序在排序数据上趋于O(n ^ 2)。