【问题标题】:Why is this merge sort function returning linked list with zeroes (c++)?为什么这个合并排序函数返回带零的链表(c++)?
【发布时间】:2012-11-21 10:45:46
【问题描述】:

我有这个合并排序功能

namespace sorted{

    template<typename T>
    class list {

        /* other stuff */

        list<T>* slice(int from, int to){
            from = (from < 0) ? 0 : from;
            to = (to > this->len) ? this->len : to;
            list<T>* result = new list<T>();
            node<T> *n = this->head;
            int idx = 0;
            while (n && (idx < this->len)){
                if ((from <= idx) && (idx <= to)) result->append(n->value);
                if (idx > to) break;
                n = n->next;
                idx++;
            }
            return result;
        }            
    }

    template<typename T>
    list<T>* merge(list<T>* left, list<T>* right){
        list<T>* result = new list<T>();
        while ((left->length() > 0) || (right->length() > 0)){
            if ((left->length() > 0) && (right->length() > 0)){
                T l = left->get(0);
                T r = right->get(0);
                if (l <= r){
                    result->append(l);
                    left->remove(0);
                } else{
                    result->append(r);
                    right->remove(0);
                }
                continue;
            }

            if (left->length() > 0) {
                result->append(left->get(0));
                left->remove(0);
            }

            if (right->length() > 0) {
                result->append(right->get(0));
                right->remove(0);
            }
        }
        return result;
    }

    template<typename T>
    list<T>* merge_sort(list<T>* original){
        if (original->length() <= 1) {
            return original;
        }
        int len = original->length();
        list<T>* left = NULL;
        list<T>* right = NULL;
        if (len > 2){
            left = original->slice(0,(len/2));
            right = original->slice((len/2)+1,len-1);
        }else if (len == 2){
            left = original->slice(0,0);
            right = original->slice(1,1);
        }
        left = merge_sort(left);
        right = merge_sort(right);
        delete original;
        list<T>* result = merge(left, right);
        delete left;
        delete right;
        return result;
    }

    /* other stuff */    
}

这是我的主要方法

int main(int argc, char** argv){
    sorted::list<int>* l = get_random_list();
    l = merge_sort(l);
    for (int i = 0; i < (l->length() - 1); i++){
        int t = l->get(i);
        int u = l->get(i+1); 
        if (t > u){
            sorted::list<int>* m = l->slice(i - 5, i + 5);
            cout << m << endl;
            delete m;
            break;
        }
    }
    delete l;
    return 0;
}        

链接到bitbucket.org project

我的问题这个。

如果列表从切片函数正确返回,如果以同样的方式完成,为什么不能正确返回到主函数?

[更新] 添加了功能,因为它们目前正在以应有的方式运行。 bitbucket 上有完整版。

【问题讨论】:

  • 您的赋值运算符有问题?你确实有一个赋值运算符,不是吗?
  • 合并排序如何?您只返回一个未排序的切片...不过,这不是您的输出中的内容。
  • 我想他给我们看了简化版
  • 在 Ubuntu 10.10 中使用我的 g++(版本 4.5.1)它可以正常工作。你的操作系统/编译器是什么?
  • 顺便说一句,您的 valgrind 检查将显示您正在访问无效内存(实际上,已释放内存)。正如 Joachim 所说,因为您只是浅拷贝列表,而旧列表的析构函数会破坏数据。

标签: c++ linked-list mergesort


【解决方案1】:

检查您提供的链接中的完整代码后,我可以肯定地说问题是因为您没有赋值运算符。

现在发生的情况是列表的赋值将使用编译器自动生成的默认赋值运算符。这会进行 shallow 复制,因此赋值左侧的列表的指针与右侧列表的指针相同。这意味着当您返回的局部变量超出范围时,它当然会调用删除列表的析构函数。现在副本有指向已删除内存的指针,访问这些指针是未定义的行为。这就是为什么它似乎在一个地方工作而不是另一个地方。

【讨论】:

  • 我不完全确定你所说的“你没有赋值运算符”是什么意思,因为我可以看到到处都是赋值。你的意思是他没有覆盖列表的赋值运算符?这不是必需的,因为他使用的是 STL,并且如果您将 1 个 STL 列表分配给另一个列表,它将执行深层复制(如果他使用指针则不会出现这种情况)。请注意,不是对象的深层副本,而是列表本身的深层副本,在这种情况下这是一个微不足道的区别,因为 int 不能被浅层复制。
  • @Dukeling,他没有使用std::list。他有自己的sorted::list
  • 哦,对了,确实是这样。当人们将事物命名为与某些标准库完全相同时,有时我会感到有些困惑。
  • @Joachim,感谢您的彻底回答。我仍然回到 C++,来自 Python,所以我真的很感谢它为什么在某个地方工作而不是在其他地方工作的背景解释。
猜你喜欢
  • 2018-05-30
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 2021-04-11
相关资源
最近更新 更多