DoublyLinkedList C# Removelast two elements

Viewed 84

i tried to fix a code, which is a LinkedList. The task is to Remove the last X elements of the list. I tried it with RemoveRange, but VS don't accept my solution and says, that RemoveRange doesn't exist.

var list = new DoublyLinkedList<string>();
list.Add("A");
list.Add("B");
list.Add("C");
list.Add("D");
list.Add("E");
list.RemoveLast(2);

This is the Code in the Program (Main). In a second class there should be the method RemoveLast, but i dont get a working code. Can someone explain me, how i get the RemoveLast?

using System;
using System.Collections;
using System.Collections.Generic;

namespace Test
{
    public class DoublyLinkedList<T> : IEnumerable<T>
    {    
        public void RemoveLast(int v)
        {
            int remove = Math.Max(0, this.Count - v);

            this.RemoveRange(v, this.Count - v);              
        }
     }
}

RemoveRange is red underlined

Thank you for your help!

Full DoublyLinkedList:

`using System;
using System.Collections;
using System.Collections.Generic;

namespace Test
{
    public class DoublyLinkedList<T> : IEnumerable<T>
    {
        public void RemoveLast(int v)
        {
            int remove = Math.Max(0, this.Count - v);

            this.RemoveRange(v, this.Count - v);



        }

        private sealed class Node
        {
            public T Item { get; set; }
            public Node Previous { get; set; }
            public Node Next { get; set; }
        }

        private Node first, last;

        public int Count { get; private set; }

        public void Add(T item)
        {
            Node newItem = new Node() { Item = item, Next = null, Previous = null };

            if (first == null)
            {
                first = newItem;
                last = newItem;
            }
            else
            {
                last.Next = newItem;
                newItem.Previous = last;

                last = newItem;
            }
            Count++;
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            Node node = first;

            while (node != null)
            {
                yield return node.Item;
                node = node.Next;
            }
        }

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

        public override string ToString()
        {
            string s = "";

            Node node = first;

            while (node != null)
            {
                s += node.Item.ToString() + " -> ";
                node = node.Next;
            }
            s += "Count: " + Count.ToString();

            return s;
        }

        private Node find(T item)
        {
            Node node = first;

            while (node != null)
            {
                if (node.Item.Equals(item))
                    return node;

                node = node.Next;
            }
            return null;
        }

        private Node findPrevious(T item)
        {
            Node previousNode = null;
            Node node = first;

            while (node != null)
            {
                if (node.Item.Equals(item))
                    return previousNode;

                previousNode = node;
                node = node.Next;
            }
            return null;
        }
    }
}`
3 Answers

You do know there is already a double linked list class, don't you? System.Collections.Generic.LinkedList? My advice would be to use that class.

If it is too much work to redesign your code, for instance because your DoublyLinkedList is already used a lot, my advice would be to make DoublyLinkedList an adapter for LinkedList:

class DoublyLinkedList<T> : IEnumerable<T>, IEnumerable
{
    private readonly LinkedList<T> linkedList = new LinkedList<T>();

    public int Count => this.linkedList.Count;

    public void Add(T item)
    {
        this.LinkedList.Add(item);
    }

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

    ... // etc.
}

You need to add a method to remove the last N items from your list. For example RemoveLast(10) is supposed to remove the last 10 elements from your doubly linked list. If your list has 10 or less elements, this would clear your complete list.

void Clear()
{
    this.LinkedList.Clear();
}

void RemoveLast()
{
    if (this.LinkedList.Count != 0)
        this.linkedList.RemoveLast();
}

void RemoveLast(int removeCount)
{
    if (this.Count <= removeCount)
    {
        this.linkedList.Clear();
    }
    else
    {
        for (int i=0; i<removeCount; ++i)
        {
            this.RemoveLast();
        }
    }
}

It might be that your supervisor is stubborn and does not follow your advise to reuse fully tested trustworthy .NET classes. In that case you'll have to change the RemoveLast() method.

void Clear()
{
    this.first = null;
    this.last = null;
    this.count = 0;
}

void RemoveLast()
{
    switch (this.Count)
    {
        case 0:
            // empty list; do nothing
            break;
        case 1:
            // removing the last element of the list
            this.Clear();
            break;

       default:
           var lastNode = this.last;

           // because more than one element I'm certain there is a previous node
           var previousNode = lastNode.Previous;
           var previousNode.Next = null;
           this.last = previousNode;
           --this.count;
           break;
    }
}

If RemoveRange is not available, you can easiliy roll your own implementation that works on any enumerable without Linq in this way (this code is an idea as I do not have access to all your code).

using System;
using System.Collections;
using System.Collections.Generic;

        public void RemoveRange(int count)
        {
            if (count > this.Count)
                throw new ArgumentOutOfRangeException(nameof(count));

            while (count > 0)
            {
                RemoveTail();
                count--;
            }
        }

        private void RemoveTail()
        {
            if (this.Count == 0)
                return;

            var previous = last.Previous;
            if (previous != null)
            {
                previous.Next = null;
                last = previous;

                this.Count--;
            }
            else
            {
                // this implies count == 1
                last = null;
                first = null;

                this.Count = 0;
            }
        }

Essentially, you can expose your RemoveRange method and then perform an agnostic removal of the last node (tail) one by one.

This answer has been edited to reflect the code changes.

Here is how you can implement RemoveLast(int n) in your DoublyLinkedList:

// Removes last "n" elements.
public void RemoveLast(int n)
{
    for (int i = 0; i < n; i++)
        RemoveLast();
}

// Removes the last element.
public void RemoveLast()
{
    // List is empty. No need to remove elements.
    if (first == null)
    {
        return;
    }
    // List contains only one element. Remove it.
    else if (first == last)
    {
        first = null;
        last = null;
    }
    // List contains more than one element. Remove the last.
    else
    {
        // The next two lines make "last" to point to the element before the last.
        last = last.Previous;
        last.Next = null;
    }

    Count--;
}

Here is complete sample.

Related