简体   繁体   English

算法缺陷和算法性能

[英]Flaws in algorithm and algorithm performance

char *stringmult(int n)
{
    char *x = "hello ";
    for (int i=0; i<n; ++i)
    {
        char *y = new char[strlen(x) * 2];
        strcpy(y,x);
        strcat(y,x);
        delete[] x;
        x=y;
    }
    return x;
}

I'm trying to figure out what the flaws of this segment is. 我试图弄清楚此细分市场的缺陷。 For one, it deletes x and then tries to copy it's values over to y. 例如,它删除x,然后尝试将其值复制到y。 Another is that y is twice the size of x and that y never gets deleted. 另一个是y的大小是x的两倍,并且y永远不会被删除。 Is there anything that I'm missing? 有什么我想念的吗? And also, I need to figure out how to get algorithm performance. 而且,我需要弄清楚如何获得算法性能。 If you've got a quick link where you learned how, I'd appreciate it. 如果您有一个快速的链接来学习如何做,我将不胜感激。

y needs one more byte than strlen(x) * 2 to make space for the terminating nul character -- just for starters. y需要比strlen(x) * 2多一个字节来为终止的nul字符留出空间-仅适用于初学者。

Anyway, as you're returning a new ed memory area, it's up to the caller to delete it (eek). 无论如何,当您返回一个new ed内存区域时,由调用方删除它(eek)。

What you're missing, it seems to me, is std::string ...!-) 在我看来,您缺少的是std::string ...!-)

As for performance, copying N characters with strcpy is O(N); 至于性能,用strcpy复制N个字符是O(N); concatenating N1 characters to a char array with a previous strlen of N2 is O(N1+N2) (std::string is faster as it keeps the length of the string in an O(1)-accessible attribute!-). 将N1个字符连接到前一个字符为N2的char数组是O(N1 + N2)(std :: string更快,因为它将字符串的长度保留在O(1)可访问的属性中!-)。 So just sum N+N**2 for N up to whatever your limit of interest is (you can ignore the N+ part if all you want is a big-O estimate since it's clearly going to drop away for larger and larger values of N!-). 因此,只要将N的N + N ** 2加到您感兴趣的极限范围内即可(如果您想要的只是大O估计,则可以忽略N+部分,因为随着N的值越来越大,它显然会消失!-)。

For starters delete[] x; 对于初学者,delete [] x; operates for the first time round the loop on some static memory. 第一次在某些静态存储器上循环运行。 Not good. 不好。

It looks like an attempt to return a buffer containing 2^n copies of the string "hello ". 看起来像是尝试返回一个缓冲区,该缓冲区包含字符串“ hello”的2 ^ n个副本。 So the fastest way to do that would be to figure out the number of copies, then allocate a big enough buffer for the whole result, then fill it with the content and return it. 因此,最快的方法是找出份数,然后为整个结果分配足够大的缓冲区,然后用内容填充并返回。

void repeat_string(const std::string &str, int count, std::vector<char> &result)
{
    result.resize(str.size() * count);
    for (int n = 0; n < count; n++)
        str.copy(&result[n * s.size()], s.size());
}

void foo(int power, std::vector<char> &result)
{
    repeat_string("hello ", 1 << (power + 1), result); 
}
  1. no need to call strlen() in a loop - only call it once; 无需循环调用strlen()-只需调用一次;
  2. when new is called no space is requested for the null-character - will cause undefined behaviour; 当调用new时,不要求为空字符提供空间-会导致不确定的行为;
  3. should use strcpy instead of strcat - you already know where to copy the second string and findig the end of string by strcat requires extra computation; 应该使用strcpy而不是strcat-您已经知道要在哪里复制第二个字符串并通过strcat查找字符串的结尾需要额外的计算;
  4. delete[] is used on a statically allocated string literal - will cause undefined behaviour; delete []用于静态分配的字符串文字-会导致未定义的行为;
  5. memory is constantly reallocated although you know the result length well in advance - memory reallocation is quite expensive 内存会不断地重新分配,尽管您已经提前知道结果的长度-内存重新分配非常昂贵

You should instead compute the result length at once and allocate memory at once and pass the char* as an in-parameter: 相反,您应该立即计算结果长度并立即分配内存,然后将char *作为参数传入:

char* stringMult(const char* what, int n)
{
     const size_t sourceLen = strlen( what );
     int i;
     size_t resultLen = sourceLen;
     // this computation can be done more cleverly and faster
     for( i = 0; i < n; i++ ) {
        resultLen *= 2;
     }
     const int numberOfCopies = resultLen / sourceLen;
     char* result = new char[resultLen + 1];
     char* whereToWrite = result;
     for( i = 0; i < numberOfCopies; i++ ) {
        strcpy( whereToWrite, what );
        whereToWrite += sourceLen;
     }
     return result;
}

Certain parts of my implementation can be optimized but still it is much better and (I hope) contains no undefined-behaviour class errors. 我的实现的某些部分可以优化,但仍然会更好,并且(希望)不包含未定义行为的类错误。

您必须为NULL终止字符串的Y分配空间时添加一个。请检查以下位置的代码http://codepad.org/tkGhuUDn

char * stringmult (int n)
{
    int i;
    size_t m;
    for (i = 0, m = 1; i < n; ++i; m *= 2);
    char * source = "hello ";
    int source_len = strlen(source);
    char * target = malloc(source_len*m+1) * sizeof(char));
    char * tmp = target;
    for (i = 0; i < m; ++i) {
        strcpy(tmp, source);
        tmp += source_len;
    }
    *tmp = '\0';
    return target;
}

Here a better version in plain C. Most of the drawbacks of your code have been eliminated, ie deleting a non-allocated pointer, too many uses of strlen and new . 这是普通C语言中的一个更好的版本。已消除了代码的大多数缺点,即删除了未分配的指针,过多使用strlennew Nonetheless, my version may imply the same memory leak as your version, as the caller is responsible to free the string afterwards. 但是,我的版本可能暗含与您的版本相同的内存泄漏,因为调用者负责随后释放字符串。

Edit: corrected my code, thanks to sharptooth. 编辑:更正了我的代码,这归功于Sharpothoth。

char* string_mult(int n) 字符* string_mult(int n)

{ {

const char* x = "hello ";

char* y;

    int i;



for (i = 0; i < n; i++)

{

    if ( i == 0)

    {

        y = (char*) malloc(strlen(x)*sizeof(char));

        strcpy(y, x);

    }

    else

    {

        y = (char*)realloc(y, strlen(x)*(i+1));

        strcat(y, x);

    }

}

return y;

} }

Nobody is going to point out that " y " is in fact being deleted? 没有人会指出“ y ”实际上被删除了吗?

Not even one reference to Schlmeiel the Painter ? 甚至没有提到画家Schlmeiel吗?

But the first thing I'd do with this algorithm is: 但是我要用此算法做的第一件事是:

int l = strlen(x);
int log2l = 0;
int log2n = 0;
int ncopy = n;
while (log2l++, l >>= 1);
while (log2n++, n >>= 1);
if (log2l+log2n >= 8*(sizeof(void*)-1)) {
    cout << "don't even bother trying, you'll run out of virtual memory first";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM