Linked list implementation along with unit testLinked list implementation along with unit test - Round...

What's the output of a record cartridge playing an out-of-speed record

Can I ask the recruiters in my resume to put the reason why I am rejected?

Is it unprofessional to ask if a job posting on GlassDoor is real?

Have astronauts in space suits ever taken selfies? If so, how?

Schoenfled Residua test shows proportionality hazard assumptions holds but Kaplan-Meier plots intersect

Finding angle with pure Geometry.

Why do falling prices hurt debtors?

can i play a electric guitar through a bass amp?

Why, historically, did Gödel think CH was false?

In Japanese, what’s the difference between “Tonari ni” (となりに) and “Tsugi” (つぎ)? When would you use one over the other?

Is it legal for company to use my work email to pretend I still work there?

Do I have a twin with permutated remainders?

Is it important to consider tone, melody, and musical form while writing a song?

The Clique vs. Independent Set Problem

Unknown notation: What do three bars mean?

Pattern match does not work in bash script

What does it mean to describe someone as a butt steak?

Today is the Center

Fully-Firstable Anagram Sets

Accidentally leaked the solution to an assignment, what to do now? (I'm the prof)

How can bays and straits be determined in a procedurally generated map?

What's the point of deactivating Num Lock on login screens?

How to format long polynomial?

Email Account under attack (really) - anything I can do?



Linked list implementation along with unit test


Linked list implementation along with unit test - Round 2Writing to a newly created file, with support for unit testingAll your bases are belong to DijkstraInsert a Node at the Tail of a Linked ListConverting a 2D Array into a 2D Linked ListDoubly-linked list implementation in Python with unit-testsC++11 Singly Linked List with raw pointersPersistent List with constexpr and pointersLinked List using templates and smart pointersLeetcode #146. LRUCache solution in Java (Doubly Linked List + HashMap)Linked list implementation along with unit test - Round 2






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







7












$begingroup$


I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]



I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.



I've made the Node class public so I can use it for a binary tree implementation later.



namespace DataStructuresAndAlgorithms.DataStructures
{
public class Node<T>
{
public T Data { get; set; }
public Node<T> Next { get; set; }
public Node<T> Previous { get; set; }

public Node() { }

public Node(T t)
{
Data = t;
}
}
}


Implementation



using System;
using System.Collections.Generic;

namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }

public LinkedList(Node<T> node)
{
Head = node;
Tail = node;
}

public void AddToFirst(Node<T> toAdd)
{
toAdd.Next = Head;
Head = toAdd;
}

public void AddToLast(Node<T> toAdd)
{
Tail.Next = toAdd;
Tail = toAdd;
}

public void RemoveFirst()
{
Head = Head.Next;
}

public void RemoveLast()
{
var pointer = Head;
while (pointer.Next != Tail)
{
pointer = pointer.Next;
}
// pointer is now before Tail
Tail = pointer;
Tail.Next = null;
}

public IEnumerator<Node<T>> GetEnumerator()
{
var pointer = Head;
while (pointer != null)
{
yield return pointer;
pointer = pointer.Next;
}
}
}
}



Unit Test



using System;
using Xunit;

using DataStructuresAndAlgorithms.DataStructures;

namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddToFirst_Node_Should_Become_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(45));

// Act
var nodeToAdd = new Node<int>(67);
myLinkedList.AddToFirst(nodeToAdd);

// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
Assert.Equal(45, theNode.Next.Data);
}

[Fact]
public void AddToLast_Node_Should_Become_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(35));

// Act
var nodeToAdd = new Node<int>(14);
myLinkedList.AddToLast(nodeToAdd);

// Assert
var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
Assert.Equal(nodeToAdd, theNode);
}

[Fact]
public void RemoveFirst_Next_Node_Should_Be_Head()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));

var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);

var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);

var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);

// Act
myLinkedList.RemoveFirst();

// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node1);
Assert.Equal(node1, myLinkedList.Head);
}

[Fact]
public void RemoveLast_Next_Node_Should_Be_Tail()
{
// Arrange
var myLinkedList = new LinkedList<int>(new Node<int>(777));

var node1 = new Node<int>(1);
myLinkedList.AddToLast(node1);

var node2 = new Node<int>(2);
myLinkedList.AddToLast(node2);

var node3 = new Node<int>(3);
myLinkedList.AddToLast(node3);

// Act
myLinkedList.RemoveLast();

// Assert
var theNode = GetNodeFromList<int>(myLinkedList, node2);
Assert.Equal(node2, myLinkedList.Tail);
}

public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
{
using (var itr = someLinkedList.GetEnumerator())
{
while (itr.Current != someNode)
{
itr.MoveNext();
}
return itr.Current;
}
}
}
}



Presentation



using System;
using System.Collections;

using DataStructuresAndAlgorithms.DataStructures;

namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string[] args)
{
RunNode();
System.Console.WriteLine();
RunLinkedList();
}

static void RunNode()
{
System.Console.WriteLine("Running the Node class");
System.Console.WriteLine("----------------------");
var myNode = new Node<int>(32);
System.Console.WriteLine(myNode.Data);
}

static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>(new Node<int>(99));
myLinkedList.AddToFirst(new Node<int>(56));
myLinkedList.AddToFirst(new Node<int>(23));
myLinkedList.AddToFirst(new Node<int>(33));
myLinkedList.AddToLast(new Node<int>(8888));
myLinkedList.RemoveLast();
myLinkedList.RemoveFirst();
System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);

using (var linkedListEnumerator = myLinkedList.GetEnumerator())
{
while (linkedListEnumerator.MoveNext())
{
System.Console.WriteLine(linkedListEnumerator.Current.Data);
}
}
}
}
}

```









share|improve this question











$endgroup$



















    7












    $begingroup$


    I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]



    I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.



    I've made the Node class public so I can use it for a binary tree implementation later.



    namespace DataStructuresAndAlgorithms.DataStructures
    {
    public class Node<T>
    {
    public T Data { get; set; }
    public Node<T> Next { get; set; }
    public Node<T> Previous { get; set; }

    public Node() { }

    public Node(T t)
    {
    Data = t;
    }
    }
    }


    Implementation



    using System;
    using System.Collections.Generic;

    namespace DataStructuresAndAlgorithms.DataStructures
    {
    public class LinkedList<T>
    {
    public Node<T> Head { get; private set; }
    public Node<T> Tail { get; private set; }

    public LinkedList(Node<T> node)
    {
    Head = node;
    Tail = node;
    }

    public void AddToFirst(Node<T> toAdd)
    {
    toAdd.Next = Head;
    Head = toAdd;
    }

    public void AddToLast(Node<T> toAdd)
    {
    Tail.Next = toAdd;
    Tail = toAdd;
    }

    public void RemoveFirst()
    {
    Head = Head.Next;
    }

    public void RemoveLast()
    {
    var pointer = Head;
    while (pointer.Next != Tail)
    {
    pointer = pointer.Next;
    }
    // pointer is now before Tail
    Tail = pointer;
    Tail.Next = null;
    }

    public IEnumerator<Node<T>> GetEnumerator()
    {
    var pointer = Head;
    while (pointer != null)
    {
    yield return pointer;
    pointer = pointer.Next;
    }
    }
    }
    }



    Unit Test



    using System;
    using Xunit;

    using DataStructuresAndAlgorithms.DataStructures;

    namespace DataStructuresAndAlgorithms.DataStructures.Tests
    {
    public class LinkedListTest
    {
    [Fact]
    public void AddToFirst_Node_Should_Become_Head()
    {
    // Arrange
    var myLinkedList = new LinkedList<int>(new Node<int>(45));

    // Act
    var nodeToAdd = new Node<int>(67);
    myLinkedList.AddToFirst(nodeToAdd);

    // Assert
    var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
    Assert.Equal(nodeToAdd, theNode);
    Assert.Equal(45, theNode.Next.Data);
    }

    [Fact]
    public void AddToLast_Node_Should_Become_Tail()
    {
    // Arrange
    var myLinkedList = new LinkedList<int>(new Node<int>(35));

    // Act
    var nodeToAdd = new Node<int>(14);
    myLinkedList.AddToLast(nodeToAdd);

    // Assert
    var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
    Assert.Equal(nodeToAdd, theNode);
    }

    [Fact]
    public void RemoveFirst_Next_Node_Should_Be_Head()
    {
    // Arrange
    var myLinkedList = new LinkedList<int>(new Node<int>(777));

    var node1 = new Node<int>(1);
    myLinkedList.AddToLast(node1);

    var node2 = new Node<int>(2);
    myLinkedList.AddToLast(node2);

    var node3 = new Node<int>(3);
    myLinkedList.AddToLast(node3);

    // Act
    myLinkedList.RemoveFirst();

    // Assert
    var theNode = GetNodeFromList<int>(myLinkedList, node1);
    Assert.Equal(node1, myLinkedList.Head);
    }

    [Fact]
    public void RemoveLast_Next_Node_Should_Be_Tail()
    {
    // Arrange
    var myLinkedList = new LinkedList<int>(new Node<int>(777));

    var node1 = new Node<int>(1);
    myLinkedList.AddToLast(node1);

    var node2 = new Node<int>(2);
    myLinkedList.AddToLast(node2);

    var node3 = new Node<int>(3);
    myLinkedList.AddToLast(node3);

    // Act
    myLinkedList.RemoveLast();

    // Assert
    var theNode = GetNodeFromList<int>(myLinkedList, node2);
    Assert.Equal(node2, myLinkedList.Tail);
    }

    public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
    {
    using (var itr = someLinkedList.GetEnumerator())
    {
    while (itr.Current != someNode)
    {
    itr.MoveNext();
    }
    return itr.Current;
    }
    }
    }
    }



    Presentation



    using System;
    using System.Collections;

    using DataStructuresAndAlgorithms.DataStructures;

    namespace DataStructuresAndAlgorithms.Presentation.Console
    {
    class Program
    {
    static void Main(string[] args)
    {
    RunNode();
    System.Console.WriteLine();
    RunLinkedList();
    }

    static void RunNode()
    {
    System.Console.WriteLine("Running the Node class");
    System.Console.WriteLine("----------------------");
    var myNode = new Node<int>(32);
    System.Console.WriteLine(myNode.Data);
    }

    static void RunLinkedList()
    {
    System.Console.WriteLine("Running the LinkedList class");
    System.Console.WriteLine("----------------------------");
    var myLinkedList = new LinkedList<int>(new Node<int>(99));
    myLinkedList.AddToFirst(new Node<int>(56));
    myLinkedList.AddToFirst(new Node<int>(23));
    myLinkedList.AddToFirst(new Node<int>(33));
    myLinkedList.AddToLast(new Node<int>(8888));
    myLinkedList.RemoveLast();
    myLinkedList.RemoveFirst();
    System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
    System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);

    using (var linkedListEnumerator = myLinkedList.GetEnumerator())
    {
    while (linkedListEnumerator.MoveNext())
    {
    System.Console.WriteLine(linkedListEnumerator.Current.Data);
    }
    }
    }
    }
    }

    ```









    share|improve this question











    $endgroup$















      7












      7








      7





      $begingroup$


      I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]



      I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.



      I've made the Node class public so I can use it for a binary tree implementation later.



      namespace DataStructuresAndAlgorithms.DataStructures
      {
      public class Node<T>
      {
      public T Data { get; set; }
      public Node<T> Next { get; set; }
      public Node<T> Previous { get; set; }

      public Node() { }

      public Node(T t)
      {
      Data = t;
      }
      }
      }


      Implementation



      using System;
      using System.Collections.Generic;

      namespace DataStructuresAndAlgorithms.DataStructures
      {
      public class LinkedList<T>
      {
      public Node<T> Head { get; private set; }
      public Node<T> Tail { get; private set; }

      public LinkedList(Node<T> node)
      {
      Head = node;
      Tail = node;
      }

      public void AddToFirst(Node<T> toAdd)
      {
      toAdd.Next = Head;
      Head = toAdd;
      }

      public void AddToLast(Node<T> toAdd)
      {
      Tail.Next = toAdd;
      Tail = toAdd;
      }

      public void RemoveFirst()
      {
      Head = Head.Next;
      }

      public void RemoveLast()
      {
      var pointer = Head;
      while (pointer.Next != Tail)
      {
      pointer = pointer.Next;
      }
      // pointer is now before Tail
      Tail = pointer;
      Tail.Next = null;
      }

      public IEnumerator<Node<T>> GetEnumerator()
      {
      var pointer = Head;
      while (pointer != null)
      {
      yield return pointer;
      pointer = pointer.Next;
      }
      }
      }
      }



      Unit Test



      using System;
      using Xunit;

      using DataStructuresAndAlgorithms.DataStructures;

      namespace DataStructuresAndAlgorithms.DataStructures.Tests
      {
      public class LinkedListTest
      {
      [Fact]
      public void AddToFirst_Node_Should_Become_Head()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(45));

      // Act
      var nodeToAdd = new Node<int>(67);
      myLinkedList.AddToFirst(nodeToAdd);

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
      Assert.Equal(nodeToAdd, theNode);
      Assert.Equal(45, theNode.Next.Data);
      }

      [Fact]
      public void AddToLast_Node_Should_Become_Tail()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(35));

      // Act
      var nodeToAdd = new Node<int>(14);
      myLinkedList.AddToLast(nodeToAdd);

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
      Assert.Equal(nodeToAdd, theNode);
      }

      [Fact]
      public void RemoveFirst_Next_Node_Should_Be_Head()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(777));

      var node1 = new Node<int>(1);
      myLinkedList.AddToLast(node1);

      var node2 = new Node<int>(2);
      myLinkedList.AddToLast(node2);

      var node3 = new Node<int>(3);
      myLinkedList.AddToLast(node3);

      // Act
      myLinkedList.RemoveFirst();

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, node1);
      Assert.Equal(node1, myLinkedList.Head);
      }

      [Fact]
      public void RemoveLast_Next_Node_Should_Be_Tail()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(777));

      var node1 = new Node<int>(1);
      myLinkedList.AddToLast(node1);

      var node2 = new Node<int>(2);
      myLinkedList.AddToLast(node2);

      var node3 = new Node<int>(3);
      myLinkedList.AddToLast(node3);

      // Act
      myLinkedList.RemoveLast();

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, node2);
      Assert.Equal(node2, myLinkedList.Tail);
      }

      public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
      {
      using (var itr = someLinkedList.GetEnumerator())
      {
      while (itr.Current != someNode)
      {
      itr.MoveNext();
      }
      return itr.Current;
      }
      }
      }
      }



      Presentation



      using System;
      using System.Collections;

      using DataStructuresAndAlgorithms.DataStructures;

      namespace DataStructuresAndAlgorithms.Presentation.Console
      {
      class Program
      {
      static void Main(string[] args)
      {
      RunNode();
      System.Console.WriteLine();
      RunLinkedList();
      }

      static void RunNode()
      {
      System.Console.WriteLine("Running the Node class");
      System.Console.WriteLine("----------------------");
      var myNode = new Node<int>(32);
      System.Console.WriteLine(myNode.Data);
      }

      static void RunLinkedList()
      {
      System.Console.WriteLine("Running the LinkedList class");
      System.Console.WriteLine("----------------------------");
      var myLinkedList = new LinkedList<int>(new Node<int>(99));
      myLinkedList.AddToFirst(new Node<int>(56));
      myLinkedList.AddToFirst(new Node<int>(23));
      myLinkedList.AddToFirst(new Node<int>(33));
      myLinkedList.AddToLast(new Node<int>(8888));
      myLinkedList.RemoveLast();
      myLinkedList.RemoveFirst();
      System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
      System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);

      using (var linkedListEnumerator = myLinkedList.GetEnumerator())
      {
      while (linkedListEnumerator.MoveNext())
      {
      System.Console.WriteLine(linkedListEnumerator.Current.Data);
      }
      }
      }
      }
      }

      ```









      share|improve this question











      $endgroup$




      I've already made all the changes suggested here. Here is the link for round 2: Linked list implementation along with unit test [Round 2]



      I want to see how other people think of my code, so here it goes. This is my first time writing a unit test. I'm wondering if there needs to be more tests for the LinkedList class and also if I'm writing them correctly.



      I've made the Node class public so I can use it for a binary tree implementation later.



      namespace DataStructuresAndAlgorithms.DataStructures
      {
      public class Node<T>
      {
      public T Data { get; set; }
      public Node<T> Next { get; set; }
      public Node<T> Previous { get; set; }

      public Node() { }

      public Node(T t)
      {
      Data = t;
      }
      }
      }


      Implementation



      using System;
      using System.Collections.Generic;

      namespace DataStructuresAndAlgorithms.DataStructures
      {
      public class LinkedList<T>
      {
      public Node<T> Head { get; private set; }
      public Node<T> Tail { get; private set; }

      public LinkedList(Node<T> node)
      {
      Head = node;
      Tail = node;
      }

      public void AddToFirst(Node<T> toAdd)
      {
      toAdd.Next = Head;
      Head = toAdd;
      }

      public void AddToLast(Node<T> toAdd)
      {
      Tail.Next = toAdd;
      Tail = toAdd;
      }

      public void RemoveFirst()
      {
      Head = Head.Next;
      }

      public void RemoveLast()
      {
      var pointer = Head;
      while (pointer.Next != Tail)
      {
      pointer = pointer.Next;
      }
      // pointer is now before Tail
      Tail = pointer;
      Tail.Next = null;
      }

      public IEnumerator<Node<T>> GetEnumerator()
      {
      var pointer = Head;
      while (pointer != null)
      {
      yield return pointer;
      pointer = pointer.Next;
      }
      }
      }
      }



      Unit Test



      using System;
      using Xunit;

      using DataStructuresAndAlgorithms.DataStructures;

      namespace DataStructuresAndAlgorithms.DataStructures.Tests
      {
      public class LinkedListTest
      {
      [Fact]
      public void AddToFirst_Node_Should_Become_Head()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(45));

      // Act
      var nodeToAdd = new Node<int>(67);
      myLinkedList.AddToFirst(nodeToAdd);

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
      Assert.Equal(nodeToAdd, theNode);
      Assert.Equal(45, theNode.Next.Data);
      }

      [Fact]
      public void AddToLast_Node_Should_Become_Tail()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(35));

      // Act
      var nodeToAdd = new Node<int>(14);
      myLinkedList.AddToLast(nodeToAdd);

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, nodeToAdd);
      Assert.Equal(nodeToAdd, theNode);
      }

      [Fact]
      public void RemoveFirst_Next_Node_Should_Be_Head()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(777));

      var node1 = new Node<int>(1);
      myLinkedList.AddToLast(node1);

      var node2 = new Node<int>(2);
      myLinkedList.AddToLast(node2);

      var node3 = new Node<int>(3);
      myLinkedList.AddToLast(node3);

      // Act
      myLinkedList.RemoveFirst();

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, node1);
      Assert.Equal(node1, myLinkedList.Head);
      }

      [Fact]
      public void RemoveLast_Next_Node_Should_Be_Tail()
      {
      // Arrange
      var myLinkedList = new LinkedList<int>(new Node<int>(777));

      var node1 = new Node<int>(1);
      myLinkedList.AddToLast(node1);

      var node2 = new Node<int>(2);
      myLinkedList.AddToLast(node2);

      var node3 = new Node<int>(3);
      myLinkedList.AddToLast(node3);

      // Act
      myLinkedList.RemoveLast();

      // Assert
      var theNode = GetNodeFromList<int>(myLinkedList, node2);
      Assert.Equal(node2, myLinkedList.Tail);
      }

      public static Node<T> GetNodeFromList<T>(LinkedList<T> someLinkedList, Node<T> someNode) where T : struct
      {
      using (var itr = someLinkedList.GetEnumerator())
      {
      while (itr.Current != someNode)
      {
      itr.MoveNext();
      }
      return itr.Current;
      }
      }
      }
      }



      Presentation



      using System;
      using System.Collections;

      using DataStructuresAndAlgorithms.DataStructures;

      namespace DataStructuresAndAlgorithms.Presentation.Console
      {
      class Program
      {
      static void Main(string[] args)
      {
      RunNode();
      System.Console.WriteLine();
      RunLinkedList();
      }

      static void RunNode()
      {
      System.Console.WriteLine("Running the Node class");
      System.Console.WriteLine("----------------------");
      var myNode = new Node<int>(32);
      System.Console.WriteLine(myNode.Data);
      }

      static void RunLinkedList()
      {
      System.Console.WriteLine("Running the LinkedList class");
      System.Console.WriteLine("----------------------------");
      var myLinkedList = new LinkedList<int>(new Node<int>(99));
      myLinkedList.AddToFirst(new Node<int>(56));
      myLinkedList.AddToFirst(new Node<int>(23));
      myLinkedList.AddToFirst(new Node<int>(33));
      myLinkedList.AddToLast(new Node<int>(8888));
      myLinkedList.RemoveLast();
      myLinkedList.RemoveFirst();
      System.Console.WriteLine("HEAD = " + myLinkedList.Head.Data);
      System.Console.WriteLine("TAIL = " + myLinkedList.Tail.Data);

      using (var linkedListEnumerator = myLinkedList.GetEnumerator())
      {
      while (linkedListEnumerator.MoveNext())
      {
      System.Console.WriteLine(linkedListEnumerator.Current.Data);
      }
      }
      }
      }
      }

      ```






      c# beginner linked-list unit-testing






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 29 at 21:12







      feature_creep

















      asked Mar 28 at 22:44









      feature_creepfeature_creep

      585




      585






















          1 Answer
          1






          active

          oldest

          votes


















          8












          $begingroup$


          I've made the Node class public so I can use it for a binary tree implementation later




          I don't think you can use this Node type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent, Left and Right. So IMO keep this Node class as a dedicated node type for this linked list:



            public class LinkedList<T>
          {
          class Node
          {
          public T Data { get; }
          public Node Next { get; set; }
          public Node Previous { get; set; }

          public Node(T data)
          {
          Data = data;
          }
          }


          In this way you can skip the type parameter on the Node class. As shown above I've also made the Node class immutable for the Data property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node.






          public Node<T> Head { get; private set; }
          public Node<T> Tail { get; private set; }



          It's fine to have a public Head and Tail property, but they should be of type T and not Node. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T with it:



          public T Head => _headNode.Data; // TODO check for null
          public T Tail => _tailNode.Data; // TODO check for null


          This will require that you have private nodes for head and tail as illustrated above.






          public LinkedList(Node<T> node)
          {
          Head = node;
          Tail = node;
          }



          Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:



          public LinkedList()
          {
          }


          You could also consider to have a constructor with a vector of items:



          public LinkedList(IEnumerable<T> items)
          {
          foreach (var item in items)
          {
          AddTail(item);
          }
          }





          public void AddToFirst(Node toAdd) {...}
          public void AddToLast(Node toAdd) {...}



          You would typically call these methods AddHead and AddTail:



          public void AddHead(T item) {...}
          public void AddTail(T item) {...}


          as you would call RemoveFirst() RemoveHead()...






          public void AddToFirst(Node<T> toAdd)
          {
          toAdd.Next = Head;
          Head = toAdd;
          }

          public void AddToLast(Node<T> toAdd)
          {
          Tail.Next = toAdd; //OBS: This will fail if Tail is null!
          Tail = toAdd;
          }



          Your Node<T> class has a Previous property, why don't you use that (doubly linked list)?






          public void RemoveFirst()
          {
          Head = Head.Next;
          }



          This will fail, if Head is null.






          public void RemoveLast()
          {
          var pointer = Head;
          while (pointer.Next != Tail)
          {
          pointer = pointer.Next;
          }
          // pointer is now before Tail
          Tail = pointer;
          Tail.Next = null;
          }



          Why iterate through the entire list, when you have a reference to the last node in Tail?:



          public void RemoveLast()
          {
          if (Tail != null)
          {
          Tail = Tail.Previous;
          Tail.Next = null;
          }
          }


          You could consider to return the Data value from the removed nodes.



          public T RemoveLast() {...}





          public IEnumerator<Node<T>> GetEnumerator()
          {
          var pointer = Head;
          while (pointer != null)
          {
          yield return pointer;
          pointer = pointer.Next;
          }
          }



          It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T> interface instead - where T is the T from your list - not Node<T>.



          If you do that, instead of this




            using (var linkedListEnumerator = myLinkedList.GetEnumerator())
          {
          while (linkedListEnumerator.MoveNext())
          {
          Console.WriteLine(linkedListEnumerator.Current.Data);
          }
          }



          you would be able to do



            foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }


          And besides that, by implementing IEnumerable<T>, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).





          Consider to implement this:



          public bool Remove(T item)
          {
          // TODO: implement this
          return <wasRemoved>;
          }




          You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)



          Your use case should look as something like:



          void RunLinkedList()
          {
          Console.WriteLine("Running the LinkedList class");
          Console.WriteLine("----------------------------");
          var myLinkedList = new LinkedList<int>();
          myLinkedList.AddHead(99);
          myLinkedList.AddHead(56);
          myLinkedList.AddHead(23);
          myLinkedList.AddHead(33);
          myLinkedList.AddTail(8888);
          myLinkedList.RemoveTail();
          myLinkedList.RemoveHead();
          Console.WriteLine("HEAD = " + myLinkedList.Head);
          Console.WriteLine("TAIL = " + myLinkedList.Tail);

          foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }

          }





          share|improve this answer











          $endgroup$









          • 1




            $begingroup$
            With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
            $endgroup$
            – feature_creep
            Mar 29 at 14:47






          • 1




            $begingroup$
            +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
            $endgroup$
            – VisualMelon
            Mar 29 at 14:56










          • $begingroup$
            @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:08










          • $begingroup$
            @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:12














          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216453%2flinked-list-implementation-along-with-unit-test%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          8












          $begingroup$


          I've made the Node class public so I can use it for a binary tree implementation later




          I don't think you can use this Node type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent, Left and Right. So IMO keep this Node class as a dedicated node type for this linked list:



            public class LinkedList<T>
          {
          class Node
          {
          public T Data { get; }
          public Node Next { get; set; }
          public Node Previous { get; set; }

          public Node(T data)
          {
          Data = data;
          }
          }


          In this way you can skip the type parameter on the Node class. As shown above I've also made the Node class immutable for the Data property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node.






          public Node<T> Head { get; private set; }
          public Node<T> Tail { get; private set; }



          It's fine to have a public Head and Tail property, but they should be of type T and not Node. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T with it:



          public T Head => _headNode.Data; // TODO check for null
          public T Tail => _tailNode.Data; // TODO check for null


          This will require that you have private nodes for head and tail as illustrated above.






          public LinkedList(Node<T> node)
          {
          Head = node;
          Tail = node;
          }



          Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:



          public LinkedList()
          {
          }


          You could also consider to have a constructor with a vector of items:



          public LinkedList(IEnumerable<T> items)
          {
          foreach (var item in items)
          {
          AddTail(item);
          }
          }





          public void AddToFirst(Node toAdd) {...}
          public void AddToLast(Node toAdd) {...}



          You would typically call these methods AddHead and AddTail:



          public void AddHead(T item) {...}
          public void AddTail(T item) {...}


          as you would call RemoveFirst() RemoveHead()...






          public void AddToFirst(Node<T> toAdd)
          {
          toAdd.Next = Head;
          Head = toAdd;
          }

          public void AddToLast(Node<T> toAdd)
          {
          Tail.Next = toAdd; //OBS: This will fail if Tail is null!
          Tail = toAdd;
          }



          Your Node<T> class has a Previous property, why don't you use that (doubly linked list)?






          public void RemoveFirst()
          {
          Head = Head.Next;
          }



          This will fail, if Head is null.






          public void RemoveLast()
          {
          var pointer = Head;
          while (pointer.Next != Tail)
          {
          pointer = pointer.Next;
          }
          // pointer is now before Tail
          Tail = pointer;
          Tail.Next = null;
          }



          Why iterate through the entire list, when you have a reference to the last node in Tail?:



          public void RemoveLast()
          {
          if (Tail != null)
          {
          Tail = Tail.Previous;
          Tail.Next = null;
          }
          }


          You could consider to return the Data value from the removed nodes.



          public T RemoveLast() {...}





          public IEnumerator<Node<T>> GetEnumerator()
          {
          var pointer = Head;
          while (pointer != null)
          {
          yield return pointer;
          pointer = pointer.Next;
          }
          }



          It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T> interface instead - where T is the T from your list - not Node<T>.



          If you do that, instead of this




            using (var linkedListEnumerator = myLinkedList.GetEnumerator())
          {
          while (linkedListEnumerator.MoveNext())
          {
          Console.WriteLine(linkedListEnumerator.Current.Data);
          }
          }



          you would be able to do



            foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }


          And besides that, by implementing IEnumerable<T>, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).





          Consider to implement this:



          public bool Remove(T item)
          {
          // TODO: implement this
          return <wasRemoved>;
          }




          You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)



          Your use case should look as something like:



          void RunLinkedList()
          {
          Console.WriteLine("Running the LinkedList class");
          Console.WriteLine("----------------------------");
          var myLinkedList = new LinkedList<int>();
          myLinkedList.AddHead(99);
          myLinkedList.AddHead(56);
          myLinkedList.AddHead(23);
          myLinkedList.AddHead(33);
          myLinkedList.AddTail(8888);
          myLinkedList.RemoveTail();
          myLinkedList.RemoveHead();
          Console.WriteLine("HEAD = " + myLinkedList.Head);
          Console.WriteLine("TAIL = " + myLinkedList.Tail);

          foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }

          }





          share|improve this answer











          $endgroup$









          • 1




            $begingroup$
            With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
            $endgroup$
            – feature_creep
            Mar 29 at 14:47






          • 1




            $begingroup$
            +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
            $endgroup$
            – VisualMelon
            Mar 29 at 14:56










          • $begingroup$
            @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:08










          • $begingroup$
            @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:12


















          8












          $begingroup$


          I've made the Node class public so I can use it for a binary tree implementation later




          I don't think you can use this Node type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent, Left and Right. So IMO keep this Node class as a dedicated node type for this linked list:



            public class LinkedList<T>
          {
          class Node
          {
          public T Data { get; }
          public Node Next { get; set; }
          public Node Previous { get; set; }

          public Node(T data)
          {
          Data = data;
          }
          }


          In this way you can skip the type parameter on the Node class. As shown above I've also made the Node class immutable for the Data property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node.






          public Node<T> Head { get; private set; }
          public Node<T> Tail { get; private set; }



          It's fine to have a public Head and Tail property, but they should be of type T and not Node. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T with it:



          public T Head => _headNode.Data; // TODO check for null
          public T Tail => _tailNode.Data; // TODO check for null


          This will require that you have private nodes for head and tail as illustrated above.






          public LinkedList(Node<T> node)
          {
          Head = node;
          Tail = node;
          }



          Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:



          public LinkedList()
          {
          }


          You could also consider to have a constructor with a vector of items:



          public LinkedList(IEnumerable<T> items)
          {
          foreach (var item in items)
          {
          AddTail(item);
          }
          }





          public void AddToFirst(Node toAdd) {...}
          public void AddToLast(Node toAdd) {...}



          You would typically call these methods AddHead and AddTail:



          public void AddHead(T item) {...}
          public void AddTail(T item) {...}


          as you would call RemoveFirst() RemoveHead()...






          public void AddToFirst(Node<T> toAdd)
          {
          toAdd.Next = Head;
          Head = toAdd;
          }

          public void AddToLast(Node<T> toAdd)
          {
          Tail.Next = toAdd; //OBS: This will fail if Tail is null!
          Tail = toAdd;
          }



          Your Node<T> class has a Previous property, why don't you use that (doubly linked list)?






          public void RemoveFirst()
          {
          Head = Head.Next;
          }



          This will fail, if Head is null.






          public void RemoveLast()
          {
          var pointer = Head;
          while (pointer.Next != Tail)
          {
          pointer = pointer.Next;
          }
          // pointer is now before Tail
          Tail = pointer;
          Tail.Next = null;
          }



          Why iterate through the entire list, when you have a reference to the last node in Tail?:



          public void RemoveLast()
          {
          if (Tail != null)
          {
          Tail = Tail.Previous;
          Tail.Next = null;
          }
          }


          You could consider to return the Data value from the removed nodes.



          public T RemoveLast() {...}





          public IEnumerator<Node<T>> GetEnumerator()
          {
          var pointer = Head;
          while (pointer != null)
          {
          yield return pointer;
          pointer = pointer.Next;
          }
          }



          It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T> interface instead - where T is the T from your list - not Node<T>.



          If you do that, instead of this




            using (var linkedListEnumerator = myLinkedList.GetEnumerator())
          {
          while (linkedListEnumerator.MoveNext())
          {
          Console.WriteLine(linkedListEnumerator.Current.Data);
          }
          }



          you would be able to do



            foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }


          And besides that, by implementing IEnumerable<T>, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).





          Consider to implement this:



          public bool Remove(T item)
          {
          // TODO: implement this
          return <wasRemoved>;
          }




          You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)



          Your use case should look as something like:



          void RunLinkedList()
          {
          Console.WriteLine("Running the LinkedList class");
          Console.WriteLine("----------------------------");
          var myLinkedList = new LinkedList<int>();
          myLinkedList.AddHead(99);
          myLinkedList.AddHead(56);
          myLinkedList.AddHead(23);
          myLinkedList.AddHead(33);
          myLinkedList.AddTail(8888);
          myLinkedList.RemoveTail();
          myLinkedList.RemoveHead();
          Console.WriteLine("HEAD = " + myLinkedList.Head);
          Console.WriteLine("TAIL = " + myLinkedList.Tail);

          foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }

          }





          share|improve this answer











          $endgroup$









          • 1




            $begingroup$
            With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
            $endgroup$
            – feature_creep
            Mar 29 at 14:47






          • 1




            $begingroup$
            +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
            $endgroup$
            – VisualMelon
            Mar 29 at 14:56










          • $begingroup$
            @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:08










          • $begingroup$
            @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:12
















          8












          8








          8





          $begingroup$


          I've made the Node class public so I can use it for a binary tree implementation later




          I don't think you can use this Node type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent, Left and Right. So IMO keep this Node class as a dedicated node type for this linked list:



            public class LinkedList<T>
          {
          class Node
          {
          public T Data { get; }
          public Node Next { get; set; }
          public Node Previous { get; set; }

          public Node(T data)
          {
          Data = data;
          }
          }


          In this way you can skip the type parameter on the Node class. As shown above I've also made the Node class immutable for the Data property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node.






          public Node<T> Head { get; private set; }
          public Node<T> Tail { get; private set; }



          It's fine to have a public Head and Tail property, but they should be of type T and not Node. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T with it:



          public T Head => _headNode.Data; // TODO check for null
          public T Tail => _tailNode.Data; // TODO check for null


          This will require that you have private nodes for head and tail as illustrated above.






          public LinkedList(Node<T> node)
          {
          Head = node;
          Tail = node;
          }



          Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:



          public LinkedList()
          {
          }


          You could also consider to have a constructor with a vector of items:



          public LinkedList(IEnumerable<T> items)
          {
          foreach (var item in items)
          {
          AddTail(item);
          }
          }





          public void AddToFirst(Node toAdd) {...}
          public void AddToLast(Node toAdd) {...}



          You would typically call these methods AddHead and AddTail:



          public void AddHead(T item) {...}
          public void AddTail(T item) {...}


          as you would call RemoveFirst() RemoveHead()...






          public void AddToFirst(Node<T> toAdd)
          {
          toAdd.Next = Head;
          Head = toAdd;
          }

          public void AddToLast(Node<T> toAdd)
          {
          Tail.Next = toAdd; //OBS: This will fail if Tail is null!
          Tail = toAdd;
          }



          Your Node<T> class has a Previous property, why don't you use that (doubly linked list)?






          public void RemoveFirst()
          {
          Head = Head.Next;
          }



          This will fail, if Head is null.






          public void RemoveLast()
          {
          var pointer = Head;
          while (pointer.Next != Tail)
          {
          pointer = pointer.Next;
          }
          // pointer is now before Tail
          Tail = pointer;
          Tail.Next = null;
          }



          Why iterate through the entire list, when you have a reference to the last node in Tail?:



          public void RemoveLast()
          {
          if (Tail != null)
          {
          Tail = Tail.Previous;
          Tail.Next = null;
          }
          }


          You could consider to return the Data value from the removed nodes.



          public T RemoveLast() {...}





          public IEnumerator<Node<T>> GetEnumerator()
          {
          var pointer = Head;
          while (pointer != null)
          {
          yield return pointer;
          pointer = pointer.Next;
          }
          }



          It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T> interface instead - where T is the T from your list - not Node<T>.



          If you do that, instead of this




            using (var linkedListEnumerator = myLinkedList.GetEnumerator())
          {
          while (linkedListEnumerator.MoveNext())
          {
          Console.WriteLine(linkedListEnumerator.Current.Data);
          }
          }



          you would be able to do



            foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }


          And besides that, by implementing IEnumerable<T>, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).





          Consider to implement this:



          public bool Remove(T item)
          {
          // TODO: implement this
          return <wasRemoved>;
          }




          You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)



          Your use case should look as something like:



          void RunLinkedList()
          {
          Console.WriteLine("Running the LinkedList class");
          Console.WriteLine("----------------------------");
          var myLinkedList = new LinkedList<int>();
          myLinkedList.AddHead(99);
          myLinkedList.AddHead(56);
          myLinkedList.AddHead(23);
          myLinkedList.AddHead(33);
          myLinkedList.AddTail(8888);
          myLinkedList.RemoveTail();
          myLinkedList.RemoveHead();
          Console.WriteLine("HEAD = " + myLinkedList.Head);
          Console.WriteLine("TAIL = " + myLinkedList.Tail);

          foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }

          }





          share|improve this answer











          $endgroup$




          I've made the Node class public so I can use it for a binary tree implementation later




          I don't think you can use this Node type as a node in a binary tree, because nodes in binary trees typically has references to other nodes like Parent, Left and Right. So IMO keep this Node class as a dedicated node type for this linked list:



            public class LinkedList<T>
          {
          class Node
          {
          public T Data { get; }
          public Node Next { get; set; }
          public Node Previous { get; set; }

          public Node(T data)
          {
          Data = data;
          }
          }


          In this way you can skip the type parameter on the Node class. As shown above I've also made the Node class immutable for the Data property and hence no default constructor. It's easier to maintain, if you know that there is a one-to-one relationship between a data object and a Node.






          public Node<T> Head { get; private set; }
          public Node<T> Tail { get; private set; }



          It's fine to have a public Head and Tail property, but they should be of type T and not Node. The client should be agnostic about the inner implementation of your list and only "communicate" objects of type T with it:



          public T Head => _headNode.Data; // TODO check for null
          public T Tail => _tailNode.Data; // TODO check for null


          This will require that you have private nodes for head and tail as illustrated above.






          public LinkedList(Node<T> node)
          {
          Head = node;
          Tail = node;
          }



          Having a one and only constructor that takes a node (or item) is not a good idea, because you often want to instantiate an empty list and provide it as argument to a method or something like that. So your list should have a default constructor with no arguments:



          public LinkedList()
          {
          }


          You could also consider to have a constructor with a vector of items:



          public LinkedList(IEnumerable<T> items)
          {
          foreach (var item in items)
          {
          AddTail(item);
          }
          }





          public void AddToFirst(Node toAdd) {...}
          public void AddToLast(Node toAdd) {...}



          You would typically call these methods AddHead and AddTail:



          public void AddHead(T item) {...}
          public void AddTail(T item) {...}


          as you would call RemoveFirst() RemoveHead()...






          public void AddToFirst(Node<T> toAdd)
          {
          toAdd.Next = Head;
          Head = toAdd;
          }

          public void AddToLast(Node<T> toAdd)
          {
          Tail.Next = toAdd; //OBS: This will fail if Tail is null!
          Tail = toAdd;
          }



          Your Node<T> class has a Previous property, why don't you use that (doubly linked list)?






          public void RemoveFirst()
          {
          Head = Head.Next;
          }



          This will fail, if Head is null.






          public void RemoveLast()
          {
          var pointer = Head;
          while (pointer.Next != Tail)
          {
          pointer = pointer.Next;
          }
          // pointer is now before Tail
          Tail = pointer;
          Tail.Next = null;
          }



          Why iterate through the entire list, when you have a reference to the last node in Tail?:



          public void RemoveLast()
          {
          if (Tail != null)
          {
          Tail = Tail.Previous;
          Tail.Next = null;
          }
          }


          You could consider to return the Data value from the removed nodes.



          public T RemoveLast() {...}





          public IEnumerator<Node<T>> GetEnumerator()
          {
          var pointer = Head;
          while (pointer != null)
          {
          yield return pointer;
          pointer = pointer.Next;
          }
          }



          It's fine to provide an enumerator. But it would be better to implement the IEnumerable<T> interface instead - where T is the T from your list - not Node<T>.



          If you do that, instead of this




            using (var linkedListEnumerator = myLinkedList.GetEnumerator())
          {
          while (linkedListEnumerator.MoveNext())
          {
          Console.WriteLine(linkedListEnumerator.Current.Data);
          }
          }



          you would be able to do



            foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }


          And besides that, by implementing IEnumerable<T>, you'll be able to use LINQ extensions on the list. (see also VisualMelons comment).





          Consider to implement this:



          public bool Remove(T item)
          {
          // TODO: implement this
          return <wasRemoved>;
          }




          You could try to implement the above and make a new post with an updated version with unit tests and we could then review that... :-)



          Your use case should look as something like:



          void RunLinkedList()
          {
          Console.WriteLine("Running the LinkedList class");
          Console.WriteLine("----------------------------");
          var myLinkedList = new LinkedList<int>();
          myLinkedList.AddHead(99);
          myLinkedList.AddHead(56);
          myLinkedList.AddHead(23);
          myLinkedList.AddHead(33);
          myLinkedList.AddTail(8888);
          myLinkedList.RemoveTail();
          myLinkedList.RemoveHead();
          Console.WriteLine("HEAD = " + myLinkedList.Head);
          Console.WriteLine("TAIL = " + myLinkedList.Tail);

          foreach (var item in myLinkedList)
          {
          Console.WriteLine(item);
          }

          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 29 at 15:29

























          answered Mar 29 at 11:47









          Henrik HansenHenrik Hansen

          8,30011231




          8,30011231








          • 1




            $begingroup$
            With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
            $endgroup$
            – feature_creep
            Mar 29 at 14:47






          • 1




            $begingroup$
            +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
            $endgroup$
            – VisualMelon
            Mar 29 at 14:56










          • $begingroup$
            @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:08










          • $begingroup$
            @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:12
















          • 1




            $begingroup$
            With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
            $endgroup$
            – feature_creep
            Mar 29 at 14:47






          • 1




            $begingroup$
            +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
            $endgroup$
            – VisualMelon
            Mar 29 at 14:56










          • $begingroup$
            @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:08










          • $begingroup$
            @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
            $endgroup$
            – Henrik Hansen
            Mar 29 at 15:12










          1




          1




          $begingroup$
          With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
          $endgroup$
          – feature_creep
          Mar 29 at 14:47




          $begingroup$
          With your suggestion, public T RemoveLast() {...}, doesn't it violate Command-Query Separation? RemoveLast() modifies state. Is It okay to break the rule sometimes?
          $endgroup$
          – feature_creep
          Mar 29 at 14:47




          1




          1




          $begingroup$
          +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
          $endgroup$
          – VisualMelon
          Mar 29 at 14:56




          $begingroup$
          +1; sadly (IMO) you can already use foreach on the OP's class, but properly implementing IEnumerable<T> will facilitate much more.
          $endgroup$
          – VisualMelon
          Mar 29 at 14:56












          $begingroup$
          @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
          $endgroup$
          – Henrik Hansen
          Mar 29 at 15:08




          $begingroup$
          @VisualMelon: You're right. I know you can, but what I intended to show was that the Enumerator enumerates the T's and not the Node<T>s. By implementing IEnumerable<T> you'll be able to use the standard Linq extensions etc.
          $endgroup$
          – Henrik Hansen
          Mar 29 at 15:08












          $begingroup$
          @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
          $endgroup$
          – Henrik Hansen
          Mar 29 at 15:12






          $begingroup$
          @feature_creep: IMO CQS is about not changing the object (the list) when querying it. Here I do the opposite: changing the object and provide the "change" to the client - it's not a query. It's a little different.
          $endgroup$
          – Henrik Hansen
          Mar 29 at 15:12




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216453%2flinked-list-implementation-along-with-unit-test%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

          How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

          Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...