代码之家  ›  专栏  ›  技术社区  ›  rockeye

C#-LinkedList-如何删除指定节点后的所有节点?

  •  6
  • rockeye  · 技术社区  · 17 年前

    我正在使用通用LinkedList实现撤消/重做缓冲区。


    [顶部]
    状态4(未完成)

    状态2<--当前状态

    [底部]

    当我执行推送操作时,我想删除当前状态之后的所有状态,并推送新状态。

    while (currentState != list.last), list.removeLast();

    我想要像RemoveAllNodesAfter(LinkedListNode…)这样的东西?

    我如何在不迭代所有节点的情况下很好地编写代码?也许有扩展?...

    8 回复  |  直到 17 年前
        1
  •  6
  •   Jon Skeet    17 年前

    我在标准中看不到任何东西 LinkedList<T> 这让你可以做到这一点。你可以进去看看 PowerCollections 和那个 C5 collections 如果你愿意,或者自己滚吧 LinkedList

        2
  •  5
  •   Lasse V. Karlsen    17 年前

    如果我自己实现这一点,我会选择一种不同的方式来实现它。

    .RemoveAllNodesAfter(node) .SplitAfter(node) node RemoveAllNodesAfter SplitAfter 方法内部并丢弃结果。

    天真的执行:

    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);
    }
    
        3
  •  4
  •   Michael Meadows    17 年前

    链表(尤其是单链表)是最基本的集合结构之一。我敢肯定,你可能只需稍加努力就能实现它(并添加你需要的行为)。

    实际上,您并不需要一个集合类来管理列表。您可以在没有集合类的情况下管理节点。

    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;
        }
    }
    

    这完全消除了对集合类的需求。

        4
  •  3
  •   chakrit Dutchie432    17 年前

    或者,您可以这样做:

    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 在代码中“剪切”链表的方法很简单。

        5
  •  0
  •   Mouna Cheikhna    14 年前

    Node.Next.Previous = null Node.Next = null .

    不幸的是,因为 LinkedListNode<T>.Next LinkedListNode<T>.Previous

    链接列表C# .

        6
  •  0
  •   Mouna Cheikhna    14 年前
    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> 仅供参考

    this.ptr 是指向您当前所在节点的指针,我假设您想删除它右侧的所有内容。

    不要复制你的结构,这是有史以来最糟糕的主意。这完全占用了内存,而且结构可能非常大。除非绝对必要,否则复制对象不是一种好的编程实践。尝试进行就地操作。

        7
  •  0
  •   Juraj Maciak    12 年前

    我提出了两种扩展方法,分别是“删除特定节点之前的所有节点”和“删除指定节点之后的所有节点。”。然而,为了方便起见,这些扩展方法是LinkedListNode的扩展,而不是LinkedList本身:

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

    使用示例:

    void Main()
    {
        //create linked list and fill it up with some values
    
        LinkedList<int> list = new LinkedList<int>();
        for(int i=0;i<10;i++) list.AddLast(i);
    
        //pick some node from the list (here it is node with value 3)
    
        LinkedListNode<int> node = list.First.Next.Next.Next;
    
        //now for the trick
    
        node.RemoveAllBefore();
    
        //or
    
        node.RemoveAllAfter();
    }
    

    好吧,这不是最有效的方法,如果你发现自己在大列表上或经常调用这种方法,那么这里描述的其他方法可能更合适(比如编写自己的链表类,它允许像其他答案中描述的那样进行拆分),但如果只是偶尔“删除这里和那里的节点”,那么这很简单,也很直观。