Dlist:在foreach循环中使用stableLinearRemove

时间:2012-08-04 10:20:51

标签: d

我编写了以下代码,但它没有给出正确的结果(例如,如果输入[-1,-1],则返回[-1,-1,-1]。

import std.stdio, std.range, std.container, std.algorithm;

DList!T strandSort(T)(DList!T list) {
    static DList!T merge(DList!T left, DList!T right) {
        DList!T res;
        while (!left.empty && !right.empty) {
            if (left.front <= right.front) {
                res.insertBack(left.front);
                left.removeFront();
            } else {
                res.insertBack(right.front);
                right.removeFront();
            }
        }
        res.insertBack(left[]);
        res.insertBack(right[]);
        return res;
    }

    DList!T result, sorted;

    while (!list.empty) {
        sorted.clear();
        sorted.insertBack(list.front);
        list.removeFront();
        foreach (item; list) {
            if (sorted.back <= item) {
                sorted.insertBack(item);
                list.stableLinearRemove(list[].find(item).take(1)));
            }
        }
        result = merge(sorted, result);
    }

    return result;
}

void main() {
    auto lst = DList!int([-1,-1]);
    foreach (e; strandSort(lst))
        writef("%d ", e);
}

有时,stableLinearRemove不会从列表中删除该项。问题是,这是我的代码或Phobos中的错误吗?

另见Rosettacode.org

的论述

编辑:我怀疑它是由removeFront引起的。删除第一个节点时,它不会将第二个节点的prev节点指针设置为null。当linearRemove要从列表中删除的项恰好是第一个节点时,它将不会被删除。 remove函数检查“之前”和“之后”节点,并且仍然设置“before”。如果我这样写,它确实有效:

if (sorted.back <= item) {
    sorted.insertBack(item);
    if (list.front == item)
        list.removeFront();
    else 
        list.stableLinearRemove(list[].find(item).take(1)));
}

2 个答案:

答案 0 :(得分:0)

我不认为这是Phobos中的一个错误,而是一个陷阱。如果元素可能是列表中的第一个元素,则不应依赖linearRemove来删除元素。首先检查并使用removeFront。也更有效率。

在上述情况中,更好的解决方案是复制列表:

DList!T result, sorted, leftover;

while (!list.empty) {
    leftover.clear();
    sorted.clear();
    sorted.insertBack(list.front);
    list.removeFront();
    foreach (item; list) {
        if (sorted.back <= item)
            sorted.insertBack(item);
        else
            leftover.insertBack(item);
    }
    result = merge(sorted, result);
    list = leftover;
}

答案 1 :(得分:0)

你是对的,它绝对是removeFront中的一个错误。

虽然我可能会指出,即使它被认为有效,通过foreach删除迭代元素也不会有效。你需要一个范围的句柄。考虑:

auto rng = list[];
while(!rng.empty) {
    auto item = rng.front;
    if(sorted.back <= item) {
        sorted.insertBack(item);
        auto rng2 = rng.save();
        rng.popFront();
        list.stableLinearRemove(rng2.take(1)); // O(1) removal!
    }else{
        rng.popFront();
    }
}
啊,好吧。鉴于这个错误,上面可能不起作用。