memcmp排序

时间:2009-02-24 18:52:02

标签: c++ c performance sorting stl

我有一个缓冲区,并有几个指针。我想根据它们指向的缓冲区中的字节对指针进行排序。

qsort()和stl :: sort()可以给出自定义比较函数。例如,如果缓冲区为零终止,我可以使用strcmp:

int my_strcmp(const void* a,const void* b) {
  const char* const one = *(const char**)a,
  const two = *(const char**)b;
  return ::strcmp(one,two);
}

但是,如果缓冲区不是零终止,我必须使用需要长度参数的memcmp()。

在没有全局变量的情况下,是否有一种整齐有效的方法可以将缓冲区的长度放入我的比较函数中?

8 个答案:

答案 0 :(得分:7)

使用std :: sort,您可以使用这样的Functor:

struct CompString {
    CompString(int len) : m_Len(len) {}
    bool operator<(const char *a, const char *b) const {
        return std::memcmp(a, b, m_Len);
    }
private:
    int m_Len;
};

然后你可以这样做:

std::sort(begin(), end(), CompString(4)); // all strings are 4 chars long
来自评论建议的

编辑:(我猜两个字符串都在公共缓冲区中?):

struct CompString {
    CompString (const unsigned char* e) : end(e) {}
    bool operator()(const unsigned char *a, const unsigned char *b) const {
        return std::memcmp(a, b, std::min(end - a, end - b)) < 0;
    }
private:
    const unsigned char* const end;
};

答案 1 :(得分:4)

使用C函数qsort(),否,没有使用全局变量就无法将长度传递给比较函数,这意味着无法以线程安全的方式完成。某些系统具有qsort_r()函数( r 代表可重入),它允许您传递额外的上下文参数,然后将其传递给您的比较函数:

int my_comparison_func(void *context, const void *a, const void *b)
{
    return memcmp(*(const void **)a, *(const void **)b, (size_t)context);
}

qsort_r(data, n, sizeof(void*), (void*)number_of_bytes_to_compare, &my_comparison_func);

答案 2 :(得分:3)

你有没有理由不能终止你的缓冲区?

如果没有,因为您正在使用C ++,您可以编写自己的函数对象:

 struct MyStrCmp {
    MyStrCmp (int n): length(n) { }
    inline bool operator< (char *lhs, char *rhs) {
       return ::strcmp (lhs, rhs, length);
    }
    int length;
 };
 // ...
 std::sort (myList.begin (), myList.end (), MyStrCmp (STR_LENGTH));

答案 3 :(得分:2)

你可以将缓冲区指针+长度打包到一个结构中,并将该结构的指针传递给void *吗?

答案 4 :(得分:1)

你可以使用像:

这样的黑客
int buffcmp(const void *b1, const void *b2)
{
    static int bsize=-1;
    if(b2==NULL) {bsize=*(int*)(b1); return 0;}
    return memcmp(b1, b2, idsize);
}

首先调用buffcmp(&bsize, NULL),然后将其作为比较函数传递给qsort

通过添加更多buffcmp(NULL, NULL)语句,您当然可以在if等情况下更自然地进行比较。

答案 5 :(得分:0)

你可以使用仿函数(给仿函数的构造函数赋予长度)或Boost.Lambda(使用就地长度)。

答案 6 :(得分:0)

我不清楚你在问什么。但我会尝试,假设

  • 您有一个缓冲区
  • 你有一个某种指针数组,它已经以某种方式处理,以便它的部分或全部内容指向缓冲区

这是相当于:

的代码
char *buf = (char*)malloc(sizeof(char)*bufsize);
for (int i=0; i<bufsize; ++i){
    buf[i] = some_cleverly_chosen_value(i);
}

char *ary[arraysize] = {0};
for(int i=0; i<arraysize; ++i){
   ary[i] = buf + some_clever_function(i);
}

/* ...do the sort here */

现在,如果您控制缓冲区的分配,则可以替换

char *buf = (char*)malloc(sizeof(char)*(bufsize+1));
buf[bufsize]='\0';

继续使用strcmp。即使您不控制缓冲区的填充,也可以这样做。

如果你必须忍受其他人递给你的缓冲区,你可以

  1. 使用一些全局存储(您要求避免和好好思考)。
  2. 处理sort函数比原始指针(支持额外数据的结构或类的地址)更复杂。为此,您需要在上面的代码中控制ary的定义。
  3. 使用支持额外输入的排序功能。 Adam所建议的sort_r或家庭推出的解决方案(我建议将其作为学生的练习,不建议在现实生活中使用)。在任何一种情况下,额外数据可能都是指向缓冲区末尾的指针。

答案 7 :(得分:-2)

memcmp应该停在不相等的第一个字节上,因此长度应该很大,即缓冲区的结尾。然后它返回零的唯一方法是它是否到达缓冲区的末尾。

(顺便说一句,我倾向于自己合并排序。它稳定且表现良好。)