【问题标题】:When to delete allocated memory in karatsuba's algorithm?何时删除 karatsuba 算法中分配的内存?
【发布时间】:2015-09-23 12:42:49
【问题描述】:


这是我对 karatsuba 算法的实现, 它在删除部分被注释时效果很好,但是当我将它插入代码时,它会导致错误的输出!
(例如对于测试 n=5,a=b={1, 2, 3, 4, 5})

void conv(int a[], int b[], int c[], int n)
{
    if (n == 1)
    {
        c[0] = a[0]*b[0];
        return;
    }
    int *C0 = new int[n];
    int *C1 = new int[n];
    int *C2 = new int[n];
    conv(a, b, C0, n/2);
    conv(a + n/2, b + n/2, C1, n/2);
    for (int i = 0; i < n/2; i++) 
        a[i] += a[i + n/2], b[i] += b[i + n/2];
    conv(a, b, C2, n/2);
    for (int i = 0; i < n/2; i++)
        a[i] -= a[i + n/2], b[i] -= b[i + n/2];
    for (int i = 0; i < n; i++)
    {
        c[i] += C0[i];
        c[i + n] += C1[i];
        c[i + n/2] += C2[i] - C1[i] - C0[i];
    }
/*  delete[] C0;
    delete[] C1;
    delete[] C2;*/
}

删除有什么问题?我是否以错误的方式释放了分配的内存?
提前致谢!

【问题讨论】:

  • 使用std::vector&lt;int&gt;
  • 您的代码中有一个可疑的部分:您在 c 向量中设置了 i+n 处的值。这是向量 a、b 和 c 的范围(我猜是 n,但没有说明)。
  • a 和 b 的大小为 n,但 c 的大小为 2n。 (我们将大小为 n 的 c 传递给 new n = n/2 的调用)
  • 看起来您在使用 C0 / C1 / C2 数组之前没有完全初始化它们。
  • 你没有问,但无论如何我要告诉你:像这样动态分配和删除你的工作空间使得 Karatsuba 比简单的逐字节乘法要慢。相反,您应该在递归的顶层分配三个大数组,并使用动态指针指向这些数组。这必须小心。

标签: c++ algorithm memory-management dynamic-memory-allocation


【解决方案1】:

您可以将它们声明为向量,而不是将它们声明为指针,然后您不必担心删除。此处删除的问题在于您的代码参数中您实际上将 c 作为指针发送,因此当您删除指针时,您仍然指向您已删除的地址而不是值。

【讨论】:

    【解决方案2】:

    在这个循环中:

    for (int i = 0; i < n; i++) {
            c[i] += C0[i];
            c[i + n] += C1[i];
            c[i + n/2] += C2[i] - C1[i] - C0[i];
        }
    

    您正在添加到从未初始化过的c 的元素。 (大概,您打算将它们初始化为 0,不是吗?)

    我不知道您使用的是什么平台,但让我们假设它是一个平台,在该平台上,当没有内存被释放时,新的内存分配恰好全为零,但是一旦内存分配被释放,它有可能收到释放的分配,这将具有随机值。在这种情况下,删除 delete 语句使所有内存分配更有可能是新的,而包含它们则很有可能内存块将被回收。

    无论如何,使用未初始化的值是未定义的行为。您可能应该将新分配的 C0C1C2 向量显式设置为 0。

    【讨论】:

    • 每次调用函数时,c的大小等于2*n。 (当我将 n/2 传递给函数时,传递数组的大小为 n)。所以 c[0] ... c[2n-1] 元素之前已经被初始化了!是真的吗?
    • 现在我明白你的意思了!你是对的 ;) 这一行解决了这个问题:fill(c, c + 2*n, 0);
    【解决方案3】:

    您可以定义 IntArray 类,并在堆栈上创建它,而不是直接分配内存。通过这种方式,定义的类自己管理分配的内存。 (当它超出范围时,它会释放其成员 int 数组“数据”。)

    class IntArray{
    public:
    int* data;
    int n;
    IntArray(int n){
        this->n = n;
        data = new int[n];
        for(int i=0; i<n; i++){
            data[i] = 0;
        }
    }
    ~IntArray(){
        if(data != NULL){
            delete[] data;
            data = NULL;
        }
    }
    
    };
    
    void conv(int a[], int b[], IntArray &c, int n)
    {
    if (n == 1)
    {
        c.data[0] = a[0]*b[0];
        return;
    }
    /*
    int *C0 = new int[n];
    int *C1 = new int[n];
    int *C2 = new int[n];
    */
    IntArray C0(n);
    IntArray C1(n);
    IntArray C2(n);
    
    conv(a, b, C0, n/2);
    conv(a + n/2, b + n/2, C1, n/2);
    for (int i = 0; i < n/2; i++)
        a[i] += a[i + n/2], b[i] += b[i + n/2];
    conv(a, b, C2, n/2);
    for (int i = 0; i < n/2; i++)
        a[i] -= a[i + n/2], b[i] -= b[i + n/2];
    for (int i = 0; i < n; i++)
    {
        c.data[i] += C0.data[i];
        c.data[i + n] += C1.data[i];
        c.data[i + n/2] += C2.data[i] - C1.data[i] - C0.data[i];
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 2013-12-27
      • 1970-01-01
      • 2011-06-17
      相关资源
      最近更新 更多