根据std :: sort()实现qsort()

时间:2013-01-01 23:39:56

标签: c++ algorithm std objective-c++ block

由于愚蠢的原因,我想编写一个带有以下签名的函数(其中(^)表示Apple对C ++的"blocks"扩展名):

extern "C" my_qsort_b(void *arr, size_t nelem, size_t eltsize, int (^)(const void *, const void *));

其中函数是根据std::sort实现的。 (注意我不能使用qsort,因为它需要一个函数指针,而不是块指针;我不能使用qsort_b,因为我可能没有Apple的标准库。我不会接受涉及qsort_b的答案。)

是否可以使用std::sort在C ++中实现此功能?或者我是否必须从头开始编写自己的quicksort实现?

请提供工作代码。魔鬼在这里的细节;我不是问“我如何使用std::sort?”

3 个答案:

答案 0 :(得分:1)

要使用std::sort,您必须编写一个迭代器类和一个将块包装在仿函数对象中的类。自己实施quicksort似乎是一个较短的选择。

顺便说一句:块应该返回布尔,而不是空,对吗?

答案 1 :(得分:1)

从这开始:

struct memblockref {
  void* location;
  size_t size;
  memblockref( void* loc, size_t s ):location(loc), size(s) {}
  memblockref& operator=( memblockref const& right ) {
    Assert( size == right.size );
    memcpy( location, right.location, std::min( size, right.size ));
    return *this;
  }
private:
  memblockref( memblockref const& ) = delete; // or leave unimplemented in C++03
  memblockref() = delete; // or leave unimplemented in C++03
};

然后使用http://www.boost.org/doc/libs/1_52_0/libs/iterator/doc/iterator_facade.html为你的内存缓冲区创建memblockref的迭代器。

然后将块转换为函数指针,或将其包装在lambda或functor中,并调用std::sort,在左侧和右侧的location字段上调用基于块的比较memblockref {1}}。

您可能还必须专门化swapiter_swap,但可能不会。

答案 2 :(得分:1)

这样做比现在看起来更难 - 尽管std::sort显然比qsort更强大,但两者之间的阻抗不匹配足以使前者实现后者艰巨的任务。

仍然可以做到。以下是使用my_qsort_b作为主力的block_qsort(此处称为std::sort)的有效实施方案。代码根据qsort的{​​{1}}实现改编为练习,并通过调用块进行简单修改以进行比较。代码经过测试,可以在x86_64 Linux上编译和使用clang ++ 3.3。

std::sort

如果需要从C调用#include <algorithm> #include <cstring> struct Elem { char* location; size_t size; bool needs_deleting; Elem(char* location_, size_t size_): location(location_), size(size_), needs_deleting(false) {} Elem(const Elem& rhs): size(rhs.size) { location = new char[size]; *this = rhs; needs_deleting = true; } Elem& operator=(const Elem& rhs) { memcpy(location, rhs.location, size); return *this; } ~Elem() { if (needs_deleting) delete[] location; } }; struct Iter: public std::iterator<std::random_access_iterator_tag, Elem> { Elem elem; Iter(char* location, size_t size): elem(location, size) {} // Must define custom copy/assignment to avoid copying of iterators // making copies of elem. Iter(const Iter& rhs): elem(rhs.elem.location, rhs.elem.size) {} Iter& operator=(const Iter& rhs) {elem.location = rhs.elem.location; return *this;} char* adjust(ptrdiff_t offset) const { return elem.location + ptrdiff_t(elem.size) * offset; } // Operations required for random iterator. Iter operator+(ptrdiff_t diff) const {return Iter(adjust(diff), elem.size);} Iter operator-(ptrdiff_t diff) const {return Iter(adjust(-diff), elem.size);} ptrdiff_t operator-(const Iter& rhs) const { return (elem.location - rhs.elem.location) / ptrdiff_t(elem.size); } Iter& operator++() {elem.location=adjust(1); return *this;} Iter& operator--() {elem.location=adjust(-1); return *this;} Iter operator++(int) {Iter old = *this; ++*this; return old;} Iter operator--(int) {Iter old = *this; --*this; return old;} bool operator!=(const Iter& rhs) const {return elem.location != rhs.elem.location;} bool operator==(const Iter& rhs) const {return elem.location == rhs.elem.location;} bool operator<(const Iter& rhs) const {return elem.location < rhs.elem.location;} Elem& operator*() {return elem;} }; struct Cmp_adaptor { typedef int (^Qsort_comparator)(const void*, const void*); Qsort_comparator cmp; Cmp_adaptor(Qsort_comparator cmp_) : cmp(cmp_) {} bool operator()(const Elem& a, const Elem& b) { return cmp(a.location, b.location) < 0; } }; void block_qsort(void* base, size_t nmemb, size_t size, int (^compar)(const void *, const void *)) { Iter begin = Iter(static_cast<char*>(base), size); std::sort(begin, begin + nmemb, Cmp_adaptor(compar)); } ,则可以将其声明为block_qsort,因为它在其接口中不使用C ++功能。要测试该函数,请编译并运行此附加代码:

extern "C"