6

一般的な LinkedList を使用して元に戻す/やり直しバッファーを実装しています。

この状態では:
[トップ]
state4 (元に戻す)
state3 (元に戻す)
state2 <-- 現在の状態
state1
[下]

プッシュを行うとき、現在の状態の後のすべての状態を削除し、新しい状態をプッシュしたいと思います。

私の現在のバイパスは行うことですwhile (currentState != list.last), list.removeLast();が、それは最悪です

LinkedList は、Remove、RemoveFirst、removeLast のみをサポートしています...

RemoveAllNodesAfter(LinkedListNode ...) のようなものが欲しいですか?

すべてのノードを反復処理せずに、うまくコーディングするにはどうすればよいですか? もしかして拡張機能付き?...

4

7 に答える 7

6

私はあなたがこれをすることを可能にする標準LinkedList<T>で何も見ることができません。必要に応じて、 PowerCollectionsC5コレクションLinkedListを調べることも、独自のタイプをロールすることもできます。これは、特に「ジャストインタイム」の方法で機能を追加できる場合は、実装が簡単なコレクションの1つです。

于 2009-02-24T15:15:43.800 に答える
5

これを自分で実装する場合は、これを実装する別の方法を選択します。

メソッドの代わりに、 の後の次のノードから始まる新しいリンク リストを返すメソッド.RemoveAllNodesAfter(node)を作成することを選択します。これは、尻尾を切り落とすよりも便利なツールになります。メソッドが必要な場合は、メソッドを内部的に呼び出して結果を破棄するだけです。.SplitAfter(node)nodeRemoveAllNodesAfterSplitAfter

単純な実装:

public LinkedList<T> SplitAfter(Node node)
{
    Node nextNode = node.Next;

    // break the chain
    node.Next = null;
    nextNode.Previous = null;

    return new LinkedList<T>(nextNode);
}

public void RemoveAllNodesAfter(Node node)
{
    SplitAfter(node);
}
于 2009-02-24T15:35:09.417 に答える
4

リンク リスト (特に単方向リンク リスト) は、最も基本的なコレクション構造の 1 つです。少しの労力で、おそらくそれを実装 (および必要な動作を追加) できると確信しています。

実際には、リストを管理するためにコレクション クラスは必要ありません。コレクション クラスなしでノードを管理できます。

public class SingleLinkedListNode<T>
{
    private readonly T value;
    private SingleLinkedListNode<T> next;

    public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
    {
        this.value = value;
    }

    public SingleLinkedListNode(T value, SingleLinkedListNode<T> next)
        : this(value)
    {
        this.next = next;
    }

    public SingleLinkedListNode<T> Next
    {
        get { return next; }
        set { next = value; }
    }

    public T Value
    {
        get { return value; }
    }
}

ただし、可能な実装に興味がある場合は、やや単純な SingleLinkedList 実装を次に示します。

public class SingleLinkedList<T>
{
    private SingleLinkedListNode<T> head;
    private SingleLinkedListNode<T> tail;

    public SingleLinkedListNode<T> Head
    {
        get { return head; }
        set { head = value; }
    }

    public IEnumerable<SingleLinkedListNode<T>> Nodes
    {
        get
        {
            SingleLinkedListNode<T> current = head;
            while (current != null)
            {
                yield return current;
                current = current.Next;
            }
        }
    }

    public SingleLinkedListNode<T> AddToTail(T value)
    {
        if (head == null) return createNewHead(value);

        if (tail == null) tail = findTail();
        SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
        tail.Next = newNode;
        return newNode;
    }

    public SingleLinkedListNode<T> InsertAtHead(T value)
    {
        if (head == null) return createNewHead(value);

        SingleLinkedListNode<T> oldHead = Head;
        SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, oldHead);
        head = newNode;
        return newNode;
    }

    public SingleLinkedListNode<T> InsertBefore(T value, SingleLinkedListNode<T> toInsertBefore)
    {
        if (head == null) throw new InvalidOperationException("you cannot insert on an empty list.");
        if (head == toInsertBefore) return InsertAtHead(value);

        SingleLinkedListNode<T> nodeBefore = findNodeBefore(toInsertBefore);
        SingleLinkedListNode<T> toInsert = new SingleLinkedListNode<T>(value, toInsertBefore);
        nodeBefore.Next = toInsert;
        return toInsert;
    }

    public SingleLinkedListNode<T> AppendAfter(T value, SingleLinkedListNode<T> toAppendAfter)
    {
        SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, toAppendAfter.Next);
        toAppendAfter.Next = newNode;
        return newNode;
    }

    public void TruncateBefore(SingleLinkedListNode<T> toTruncateBefore)
    {
        if (head == toTruncateBefore)
        {
            head = null;
            tail = null;
            return;
        }

        SingleLinkedListNode<T> nodeBefore = findNodeBefore(toTruncateBefore);
        if (nodeBefore != null) nodeBefore.Next = null;
    }

    public void TruncateAfter(SingleLinkedListNode<T> toTruncateAfter)
    {
        toTruncateAfter.Next = null;
    }

    private SingleLinkedListNode<T> createNewHead(T value)
    {
        SingleLinkedListNode<T> newNode = new SingleLinkedListNode<T>(value, null);
        head = newNode;
        tail = newNode;
        return newNode;
    }

    private SingleLinkedListNode<T> findTail()
    {
        if (head == null) return null;
        SingleLinkedListNode<T> current = head;
        while (current.Next != null)
        {
            current = current.Next;
        }
        return current;
    }

    private SingleLinkedListNode<T> findNodeBefore(SingleLinkedListNode<T> nodeToFindNodeBefore)
    {
        SingleLinkedListNode<T> current = head;
        while (current != null)
        {
            if (current.Next != null && current.Next == nodeToFindNodeBefore) return current;
            current = current.Next;
        }
        return null;
    }
}

今、あなたはこれを行うことができます:

public static void Main(string[] args)
{
    SingleLinkedList<string> list = new SingleLinkedList<string>();
    list.InsertAtHead("state4");
    list.AddToTail("state3");
    list.AddToTail("state2");
    list.AddToTail("state1");

    SingleLinkedListNode<string> current = null;
    foreach (SingleLinkedListNode<string> node in list.Nodes)
    {
        if (node.Value != "state2") continue;

        current = node;
        break;
    }

    if (current != null) list.TruncateAfter(current);
}

これは状況によって異なりますが、これよりもはるかに優れているわけではありません。

public static void Main(string[] args)
{
    SingleLinkedListNode<string> first =
        new SingleLinkedListNode<string>("state4");
    first.Next = new SingleLinkedListNode<string>("state3");
    SingleLinkedListNode<string> current = first.Next;
    current.Next = new SingleLinkedListNode<string>("state2");
    current = current.Next;
    current.Next = new SingleLinkedListNode<string>("state1");

    current = first;
    while (current != null)
    {
        if (current.Value != "state2") continue;
        current.Next = null;
        current = current.Next;
        break;
    }
}

これにより、コレクション クラスが完全に不要になります。

于 2009-02-24T15:26:04.323 に答える
3

または、これを行うことができます:

while (currentNode.Next != null)
    list.Remove(currentNode.Next);

実際には、リンクされたリストは、特にマネージ コードで実装するのにかなり簡単なデータ構造です (読み取り: メモリ管理の面倒はありません)。

元に戻す/やり直し操作をサポートするのに十分な機能 (読み取り: YAGNI ) をサポートする、私がハッキングしたものを次に示します。

public class LinkedListNode<T>
{
    public LinkedList<T> Parent { get; set; }
    public T Value { get; set; }
    public LinkedListNode<T> Next { get; set; }
    public LinkedListNode<T> Previous { get; set; }
}

public class LinkedList<T> : IEnumerable<T>
{
    public LinkedListNode<T> Last { get; private set; }

    public LinkedListNode<T> AddLast(T value)
    {
        Last = (Last == null)
            ? new LinkedListNode<T> { Previous = null }
            : Last.Next = new LinkedListNode<T> { Previous = Last };

        Last.Parent = this;
        Last.Value = value;
        Last.Next = null;

        return Last;
    }

    public void SevereAt(LinkedListNode<T> node)
    {
        if (node.Parent != this)
            throw new ArgumentException("Can't severe node that isn't from the same parent list.");

        node.Next.Previous = null;
        node.Next = null;
        Last = node;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable<T>)this).GetEnumerator();
    }

    public IEnumerator<T> GetEnumerator()
    {
        var walk = Last;

        while (walk != null) {
            yield return walk.Value;
            walk = walk.Previous;
        }
    }

}

次に、コードでメソッドを使用してSevereAt、リンクされたリストを簡単に「切り取る」ことができます。

于 2009-02-24T16:12:09.173 に答える
0
if(this.ptr != null && this.ObjectName != null)
{
    LinkedListNode<ObjectType> it = ObjectName.Last;
                for (; it != this.ptr; it = it.Previous) 
                {
                    this.m_ObjectName.Remove(it);
                }
}

this.ptrタイプはLinkedListNode<ObjectType>ちょうどfyiです

this.ptrは現在のノードを指すポインタです。その右側のすべてを削除したいと思います。

構造の新しいコピーを作成しないでください。これまでで最悪のアイデアです。これは完全なメモリホッグであり、構造が非常に大きくなる可能性があります。オブジェクトをコピーすることは、絶対に必要でない限り、プログラミングの良い習慣ではありません。インプレース操作を実行してみてください。

于 2011-12-28T16:28:24.543 に答える
0

頭に浮かぶ最初のアイデアは、Node.Next.Previous = null(二重にリンクされたリストの場合)を設定してからNode.Next = null.

残念ながら、LinkedListNode<T>.NextLinkedListNode<T>.Previousはリンク リストの .NET 実装では読み取り専用プロパティであるため、この機能を実現するには独自の構造を実装する必要があると思います。

しかし、他の人が言ったように、それは十分に簡単なはずです。リンクされたリスト C#を Google で検索するだけであれば、出発点として使用できるリソースがたくさんあります。

于 2009-02-24T15:47:00.793 に答える