3


1

C# - LinkedList - 指定されたノードの後に​​すべてのノードを削除する方法?

私はundo / redoバッファをgeneric LinkedListで実装しています。

この状態では: [Top]
state4(元に戻す)+ state3(元に戻す)+ state2 ←現在の状態+ state1
[bottom]

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

私の現在のバイパスは、 `while(currentState!= list.last)、list.removeLast();`を実行することですが、それはしゃれています

LinkedListはRemove、RemoveFirstのみをサポートします。

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

すべてのノードを反復することなく、どうやってそれをうまくコーディングできますか? たぶん拡張機能がありますか?…​

7 Answer


6


これを可能にする標準の `LinkedList`には何も見えません。 お望みならhttp://www.codeplex.com/PowerCollections[PowerCollections]とhttp://www.itu.dk/research/c5/[C5 collection]を見ることもできます - あるいはあなた自身の `LinkedList`を転がすこともできます。タイプ。 特に「ジャストインタイム」で機能を追加できる場合は、実装するのがより簡単なコレクションの1つです。


5


私がこれを自分で実装するのであれば、私はこれを実装する別の方法を選びます。

.RemoveAllNodesAfter(node)`メソッドの代わりに、 `node`の次のノードから始まる新しいリンクリストを返す .SplitAfter(node) メソッドを作ることを選びます。 これは単に尾を切り落とすことができるよりも便利な道具になるでしょう。 あなたの `RemoveAllNodesAfter`メソッドが欲しいなら、それは内部的に SplitAfter`メソッドを呼び出して結果を破棄する必要があるでしょう。

単純な実装

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

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

    return new LinkedList(nextNode);
}

public void RemoveAllNodesAfter(Node node)
{
    SplitAfter(node);
}


4


リンクリスト(特に単独リンクリスト)は、最も基本的な基本的なコレクション構造の1つです。 私はあなたがたぶん少しの努力でそれを(そしてあなたの必要な振る舞いを追加する)実装することができることを確信しています。

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

パブリッククラスSingleLinkedListNode {プライベート読み取り専用T値;次にプライベートのSingleLinkedListNode。

public SingleLinkedListNode(T値、SingleLinkedListNode next){this.value = value; }

public SingleLinkedListNode(T値、SingleLinkedListNode next):this(値){this.next = next; }

public SingleLinkedListNode Next {get {return next;}} set {next = value;}を設定します。 }}

public T Value {get {戻り値; }}}

しかし、可能な実装に興味があるなら、これはやや単純なSingleLinkedList実装です。

パブリッククラスSingleLinkedList {プライベートSingleLinkedListNodeヘッド;プライベートSingleLinkedListNodeテール。

public SingleLinkedListNode Head {get {return head;}​​; {head = value;}を設定します。 }}

public IEnumerable> Nodes {get {SingleLinkedListNode current = head;}​​; while(current!= null){現在の収益を返します。 current = current.Next; }}}

public SingleLinkedListNode AddToTail(T value){if(head == null)}の場合はcreateNewHead(value);

if(tail == null)tail = findTail(); SingleLinkedListNode newNode = new SingleLinkedListNode(value、null); tail.Next = newNode; newNodeを返します。 }

public SingleLinkedListNode InsertAtHead(T value){if(head == null)を返す場合createNewHead(value);

SingleLinkedListNode oldHead = Head; SingleLinkedListNode newNode = new SingleLinkedListNode(value、oldHead); head = newNode; newNodeを返します。 }

public SingleLinkedListNode InsertBefore(T値、SingleLinkedListNode toInsertBefore){if(head == null)の場合、新しいInvalidOperationExceptionがスローされます( "空のリストには挿入できません")。 if(head == toInsertBefore)はInsertAtHead(value)を返します。

SingleLinkedListNode nodeBefore = findNodeBefore(toInsertBefore); SingleLinkedListNode toInsert = new SingleLinkedListNode(value、toInsertBefore); nodeBefore.Next = toInsert; toInsertを返します。 }

public SingleLinkedListNode AppendAfter(T値、SingleLinkedListNode toAppendAfter){SingleLinkedListNode newNode = new SingleLinkedListNode(値、toAppendAfter.Next); toAppendAfter.Next = newNode; newNodeを返します。 }

public void TruncateBefore(SingleLinkedListNode toTruncateBefore){if(head == toTruncateBefore){head = null; tail = null。戻る}

SingleLinkedListNode nodeBefore = findNodeBefore(toTruncateBefore); if(nodeBefore!= null)nodeBefore.Next = null。 }

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

private SingleLinkedListNode createNewHead(T値){SingleLinkedListNode newNode = new SingleLinkedListNode(value、null); head = newNode; tail = newNode; newNodeを返します。 }

private SingleLinkedListNode findTail(){if(head == null)はnullを返します。 SingleLinkedListNode current = head; while(current.Next!= null){current = current.Next; }現在を返します。 }

private SingleLinkedListNode findNodeBefore(SingleLinkedListNode nodeToFindNodeBefore){SingleLinkedListNode current = head; while(current!= null){if(current.Next!= null)

今これをすることができます:

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

SingleLinkedListNode current = null; foreach(list.Nodes内のSingleLinkedListNodeノード){if(node.Value!= "state2")を続けます。

current = node;ブレーク; }

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

事はあなたの状況に依存しています、それはこれよりずっと良くありません:

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

現在=最初; while(current!= null){if(current.Value!= "state2")を続けます。 current.Next = null; current = current.Next;ブレーク; }}

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


2


あるいは、これを行うことができます。

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

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

これは私があなたのアンドゥ/リドゥ操作をサポートするためにちょうど十分な機能(http://en.wikipedia.org/wiki/You_Ain’t_Gonna_Need_It[YAGNI]を読む)をサポートすることをハックしたものです:

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

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

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

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

        return Last;
    }

    public void SevereAt(LinkedListNode 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)this).GetEnumerator();
    }

    public IEnumerator GetEnumerator()
    {
        var walk = Last;

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

}

それから、コードの中で `SevereAt`メソッドを使ってリンクリストをきれいにそして単純に"カット "することができます。


0


頭に浮かぶ最初のアイデアは Node.Next.Previous = null(それが二重にリンクされたリストなら)そしてそれから` Node.Next = null`を設定することです。

残念ながら、LinkedListの.NET実装では LinkedListNode.Next`と LinkedListNode.Previous`は読み取り専用のプロパティなので、この機能を実現するには独自の構造体を実装する必要があるかもしれません。

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


0


if(this.ptr != null && this.ObjectName != null)
{
    LinkedListNode it = ObjectName.Last;
                for (; it != this.ptr; it = it.Previous)
                {
                    this.m_ObjectName.Remove(it);
                }
}

this.ptr`は LinkedListNode`型で、ただのfyiです。

`this.ptr`はあなたが現在いるノードを指し示すポインタです、私はあなたがその右側にあるものすべてを削除したいと思います。

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


0


「特定のノードの前のすべてのノードを削除する」と「特定のノードの後のすべてのノードを削除する」という2つの拡張方法を作りました。 ただし、これらの拡張メソッドは、単に便宜上、LinkedList自体ではなく、LinkedListNodeの拡張です。

public static class Extensions {public static void RemoveAllBefore(this LinkedListNode node){while(node.Previous!= null)node.List.Remove(node.Previous); }

public static void RemoveAllAfter(このLinkedListNodeノード){while(node.Next!= null)node.List.Remove(node.Previous); }}

使用例

void Main(){//リンクリストを作成していくつかの値で埋めます

LinkedList list = new LinkedList(); (int i = 0; i <10; i)list.AddLast(i);

//リストからノードを選びます(ここでは値3のノードです)

LinkedListNode node = list.First.Next.Next.Next;

//今トリックのために

node.RemoveAllBefore();

//または

node.RemoveAllAfter(); }

これは最も効果的な方法ではありません。このリストを大規模なリストで呼び出す場合、または他の方法で分割することができる独自のリンクリストクラスを作成する場合など)これは単純で非常に直感的であるよりも、時々「あちこちにノードを削除する」ことです。