Linked list implementation along with unit test [Round 3]
$begingroup$
Here are the changes I've made thanks to suggestions made by @vnp, and @Henrik Hansen. Here is the link to the previous code review: Linked list implementation along with unit test [Round 2]
I've made some new additions that were not mentioned and added more unit tests :). I really feel like I'm improving!
Implementation
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T> : IEnumerable<T>
{
class Node
{
public T Data { get; set; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
private Node _head, _tail;
public T Head => _head == null ? throw new NullReferenceException() : _head.Data;
public T Tail => _tail == null ? throw new NullReferenceException() : _tail.Data;
public bool IsEmpty { get { return Count > 0 ? false : true; } }
public int Count { get; private set; } = 0;
public LinkedList() { }
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddHead(T item)
{
var node = new Node(item);
if (_head == null && _tail == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Next = _head;
_head.Previous = node;
Count += 1;
}
_head = node;
}
public void AddTail(T item)
{
var node = new Node(item);
if (_tail == null && _head == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Previous = _tail;
_tail.Next = node;
Count += 1;
}
_tail = node;
}
public T RemoveHead()
{
if (_head == null) return default;
else
{
var temp = _head.Next;
_head = _head.Next;
if (_head != null) _head.Previous = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public T RemoveTail()
{
if (_tail == null) return default;
else
{
var temp = _tail.Previous;
_tail = _tail.Previous;
if (_tail != null) _tail.Next = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public bool Find(T item)
{
if (_head == null || _tail == null) return false;
var node = _head;
while (node.Data.Equals(item) == false)
{
if (node.Next == null)
return false;
node = node.Next;
}
return true;
}
public bool Remove(int index)
{
if (_head == null || _tail == null) return false;
var node = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
node = node.Next;
}
// Remove the node
if (node == null) return false;
bool isRemoved = NodeAwareRemove(node);
return isRemoved;
}
private bool NodeAwareRemove(Node node)
{
if (node.Next != null && node.Previous != null)
{
// In between nodes
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
Count -= 1;
return true;
}
if (node.Next != null && node.Previous == null)
{
// Head node
RemoveHead();
return true;
}
if (node.Previous != null && node.Next == null)
{
// Tail node
RemoveTail();
return true;
}
if (node.Next == null && node.Previous == null)
{
// Only node
_head = null;
_tail = null;
Count -= 1;
return true;
}
return false;
}
public int RemoveAll(T item)
{
if (_head == null || _tail == null) return -1;
var node = _head;
int numberRemoved = 0;
while (node != null)
{
if (node.Data.Equals(item))
{
if (NodeAwareRemove(node)) numberRemoved += 1;
}
node = node.Next;
}
return numberRemoved;
}
public T GetIndex(int index)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) return _head.Data;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
return temp.Data;
}
public bool SetIndex(int index, T item)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) _head.Data = item;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
temp.Data = item;
return true;
}
public object this[int i]
{
get { return GetIndex(i); }
set { SetIndex(i, (T)value); }
}
public IEnumerator<T> GetEnumerator()
{
var pointer = _head;
while (pointer != null)
{
yield return pointer.Data;
pointer = pointer.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddHead_Node_Should_Become_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddHead(45);
// Assert
Assert.Equal(45, myLinkedList.Head);
}
[Fact]
public void AddTail_Node_Should_Become_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddTail(7777);
// Assert
Assert.Equal(7777, myLinkedList.Tail);
}
[Fact]
public void RemoveHead_Next_Node_Should_Be_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveHead();
// Assert
Assert.Equal(2, myLinkedList.Head);
}
[Fact]
public void RemoveTail_Next_Node_Should_Be_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(4, myLinkedList.Tail);
}
[Fact]
public void Find_5_Should_Return_True()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isFound = myLinkedList.Find(5);
// Assert
Assert.True(isFound);
}
[Fact]
public void IsEmpty_Should_Return_False_Count_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.False(isEmpty);
}
[Fact]
public void IsEmpty_Should_Return_True_Count_Equal_0()
{
// Arrange
int myNums = { };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.True(isEmpty);
}
[Fact]
public void GetIndex_4_Should_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var index = myLinkedList.GetIndex(4);
// Assert
Assert.Equal(5, index);
}
[Fact]
public void SetIndex_2_10_Should_Set_Index_2_To_10()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.SetIndex(2, 10);
// Assert
Assert.Equal(10, myLinkedList[2]);
}
[Fact]
public void RemoveAll_Should_Delete_All_5s()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveAll(5);
// Assert
Assert.False(myLinkedList.Find(5));
}
[Fact]
public void Remove_1_Should_Return_True()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(1);
// Assert
Assert.True(isRemoved);
}
[Fact]
public void Remove_2_Should_Return_False()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(2);
// Assert
Assert.False(isRemoved);
}
[Fact]
public void AddHead_Should_Increment_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
// Assert
Assert.Equal(theCount + 5, myLinkedList.Count);
}
[Fact]
public void Remove_2_Should_Decrement_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(theCount - 1, myLinkedList.Count);
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string args)
{
RunLinkedList();
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(1);
myLinkedList.AddHead(2);
myLinkedList.AddHead(3);
myLinkedList.AddHead(4);
myLinkedList.AddHead(5);
myLinkedList.RemoveHead();
myLinkedList.RemoveTail();
myLinkedList.SetIndex(2, 10);
myLinkedList[2] = 2;
System.Console.WriteLine("Count = " + myLinkedList.Count);
System.Console.WriteLine("Is Empty = " + myLinkedList.IsEmpty);
PrintList<int>(myLinkedList);
}
static void PrintList<T>(LinkedList<T> myList)
{
if (myList.Head == null || myList.Tail == null) return;
var listText = "LinkedList[";
for (int i = 0; i < myList.Count; i++)
{
listText += myList[i];
if (i < myList.Count - 1)
{
listText += "<";
listText += "---";
listText += ">";
}
}
listText += "]";
System.Console.WriteLine(listText);
System.Console.WriteLine("Found Data = 66 -> " + myList.Find((T)(object)66));
System.Console.WriteLine("Found Data = 3 -> " + myList.Find((T)(object)3));
}
}
}
c# beginner linked-list unit-testing
New contributor
$endgroup$
add a comment |
$begingroup$
Here are the changes I've made thanks to suggestions made by @vnp, and @Henrik Hansen. Here is the link to the previous code review: Linked list implementation along with unit test [Round 2]
I've made some new additions that were not mentioned and added more unit tests :). I really feel like I'm improving!
Implementation
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T> : IEnumerable<T>
{
class Node
{
public T Data { get; set; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
private Node _head, _tail;
public T Head => _head == null ? throw new NullReferenceException() : _head.Data;
public T Tail => _tail == null ? throw new NullReferenceException() : _tail.Data;
public bool IsEmpty { get { return Count > 0 ? false : true; } }
public int Count { get; private set; } = 0;
public LinkedList() { }
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddHead(T item)
{
var node = new Node(item);
if (_head == null && _tail == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Next = _head;
_head.Previous = node;
Count += 1;
}
_head = node;
}
public void AddTail(T item)
{
var node = new Node(item);
if (_tail == null && _head == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Previous = _tail;
_tail.Next = node;
Count += 1;
}
_tail = node;
}
public T RemoveHead()
{
if (_head == null) return default;
else
{
var temp = _head.Next;
_head = _head.Next;
if (_head != null) _head.Previous = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public T RemoveTail()
{
if (_tail == null) return default;
else
{
var temp = _tail.Previous;
_tail = _tail.Previous;
if (_tail != null) _tail.Next = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public bool Find(T item)
{
if (_head == null || _tail == null) return false;
var node = _head;
while (node.Data.Equals(item) == false)
{
if (node.Next == null)
return false;
node = node.Next;
}
return true;
}
public bool Remove(int index)
{
if (_head == null || _tail == null) return false;
var node = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
node = node.Next;
}
// Remove the node
if (node == null) return false;
bool isRemoved = NodeAwareRemove(node);
return isRemoved;
}
private bool NodeAwareRemove(Node node)
{
if (node.Next != null && node.Previous != null)
{
// In between nodes
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
Count -= 1;
return true;
}
if (node.Next != null && node.Previous == null)
{
// Head node
RemoveHead();
return true;
}
if (node.Previous != null && node.Next == null)
{
// Tail node
RemoveTail();
return true;
}
if (node.Next == null && node.Previous == null)
{
// Only node
_head = null;
_tail = null;
Count -= 1;
return true;
}
return false;
}
public int RemoveAll(T item)
{
if (_head == null || _tail == null) return -1;
var node = _head;
int numberRemoved = 0;
while (node != null)
{
if (node.Data.Equals(item))
{
if (NodeAwareRemove(node)) numberRemoved += 1;
}
node = node.Next;
}
return numberRemoved;
}
public T GetIndex(int index)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) return _head.Data;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
return temp.Data;
}
public bool SetIndex(int index, T item)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) _head.Data = item;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
temp.Data = item;
return true;
}
public object this[int i]
{
get { return GetIndex(i); }
set { SetIndex(i, (T)value); }
}
public IEnumerator<T> GetEnumerator()
{
var pointer = _head;
while (pointer != null)
{
yield return pointer.Data;
pointer = pointer.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddHead_Node_Should_Become_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddHead(45);
// Assert
Assert.Equal(45, myLinkedList.Head);
}
[Fact]
public void AddTail_Node_Should_Become_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddTail(7777);
// Assert
Assert.Equal(7777, myLinkedList.Tail);
}
[Fact]
public void RemoveHead_Next_Node_Should_Be_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveHead();
// Assert
Assert.Equal(2, myLinkedList.Head);
}
[Fact]
public void RemoveTail_Next_Node_Should_Be_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(4, myLinkedList.Tail);
}
[Fact]
public void Find_5_Should_Return_True()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isFound = myLinkedList.Find(5);
// Assert
Assert.True(isFound);
}
[Fact]
public void IsEmpty_Should_Return_False_Count_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.False(isEmpty);
}
[Fact]
public void IsEmpty_Should_Return_True_Count_Equal_0()
{
// Arrange
int myNums = { };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.True(isEmpty);
}
[Fact]
public void GetIndex_4_Should_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var index = myLinkedList.GetIndex(4);
// Assert
Assert.Equal(5, index);
}
[Fact]
public void SetIndex_2_10_Should_Set_Index_2_To_10()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.SetIndex(2, 10);
// Assert
Assert.Equal(10, myLinkedList[2]);
}
[Fact]
public void RemoveAll_Should_Delete_All_5s()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveAll(5);
// Assert
Assert.False(myLinkedList.Find(5));
}
[Fact]
public void Remove_1_Should_Return_True()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(1);
// Assert
Assert.True(isRemoved);
}
[Fact]
public void Remove_2_Should_Return_False()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(2);
// Assert
Assert.False(isRemoved);
}
[Fact]
public void AddHead_Should_Increment_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
// Assert
Assert.Equal(theCount + 5, myLinkedList.Count);
}
[Fact]
public void Remove_2_Should_Decrement_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(theCount - 1, myLinkedList.Count);
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string args)
{
RunLinkedList();
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(1);
myLinkedList.AddHead(2);
myLinkedList.AddHead(3);
myLinkedList.AddHead(4);
myLinkedList.AddHead(5);
myLinkedList.RemoveHead();
myLinkedList.RemoveTail();
myLinkedList.SetIndex(2, 10);
myLinkedList[2] = 2;
System.Console.WriteLine("Count = " + myLinkedList.Count);
System.Console.WriteLine("Is Empty = " + myLinkedList.IsEmpty);
PrintList<int>(myLinkedList);
}
static void PrintList<T>(LinkedList<T> myList)
{
if (myList.Head == null || myList.Tail == null) return;
var listText = "LinkedList[";
for (int i = 0; i < myList.Count; i++)
{
listText += myList[i];
if (i < myList.Count - 1)
{
listText += "<";
listText += "---";
listText += ">";
}
}
listText += "]";
System.Console.WriteLine(listText);
System.Console.WriteLine("Found Data = 66 -> " + myList.Find((T)(object)66));
System.Console.WriteLine("Found Data = 3 -> " + myList.Find((T)(object)3));
}
}
}
c# beginner linked-list unit-testing
New contributor
$endgroup$
add a comment |
$begingroup$
Here are the changes I've made thanks to suggestions made by @vnp, and @Henrik Hansen. Here is the link to the previous code review: Linked list implementation along with unit test [Round 2]
I've made some new additions that were not mentioned and added more unit tests :). I really feel like I'm improving!
Implementation
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T> : IEnumerable<T>
{
class Node
{
public T Data { get; set; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
private Node _head, _tail;
public T Head => _head == null ? throw new NullReferenceException() : _head.Data;
public T Tail => _tail == null ? throw new NullReferenceException() : _tail.Data;
public bool IsEmpty { get { return Count > 0 ? false : true; } }
public int Count { get; private set; } = 0;
public LinkedList() { }
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddHead(T item)
{
var node = new Node(item);
if (_head == null && _tail == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Next = _head;
_head.Previous = node;
Count += 1;
}
_head = node;
}
public void AddTail(T item)
{
var node = new Node(item);
if (_tail == null && _head == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Previous = _tail;
_tail.Next = node;
Count += 1;
}
_tail = node;
}
public T RemoveHead()
{
if (_head == null) return default;
else
{
var temp = _head.Next;
_head = _head.Next;
if (_head != null) _head.Previous = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public T RemoveTail()
{
if (_tail == null) return default;
else
{
var temp = _tail.Previous;
_tail = _tail.Previous;
if (_tail != null) _tail.Next = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public bool Find(T item)
{
if (_head == null || _tail == null) return false;
var node = _head;
while (node.Data.Equals(item) == false)
{
if (node.Next == null)
return false;
node = node.Next;
}
return true;
}
public bool Remove(int index)
{
if (_head == null || _tail == null) return false;
var node = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
node = node.Next;
}
// Remove the node
if (node == null) return false;
bool isRemoved = NodeAwareRemove(node);
return isRemoved;
}
private bool NodeAwareRemove(Node node)
{
if (node.Next != null && node.Previous != null)
{
// In between nodes
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
Count -= 1;
return true;
}
if (node.Next != null && node.Previous == null)
{
// Head node
RemoveHead();
return true;
}
if (node.Previous != null && node.Next == null)
{
// Tail node
RemoveTail();
return true;
}
if (node.Next == null && node.Previous == null)
{
// Only node
_head = null;
_tail = null;
Count -= 1;
return true;
}
return false;
}
public int RemoveAll(T item)
{
if (_head == null || _tail == null) return -1;
var node = _head;
int numberRemoved = 0;
while (node != null)
{
if (node.Data.Equals(item))
{
if (NodeAwareRemove(node)) numberRemoved += 1;
}
node = node.Next;
}
return numberRemoved;
}
public T GetIndex(int index)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) return _head.Data;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
return temp.Data;
}
public bool SetIndex(int index, T item)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) _head.Data = item;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
temp.Data = item;
return true;
}
public object this[int i]
{
get { return GetIndex(i); }
set { SetIndex(i, (T)value); }
}
public IEnumerator<T> GetEnumerator()
{
var pointer = _head;
while (pointer != null)
{
yield return pointer.Data;
pointer = pointer.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddHead_Node_Should_Become_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddHead(45);
// Assert
Assert.Equal(45, myLinkedList.Head);
}
[Fact]
public void AddTail_Node_Should_Become_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddTail(7777);
// Assert
Assert.Equal(7777, myLinkedList.Tail);
}
[Fact]
public void RemoveHead_Next_Node_Should_Be_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveHead();
// Assert
Assert.Equal(2, myLinkedList.Head);
}
[Fact]
public void RemoveTail_Next_Node_Should_Be_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(4, myLinkedList.Tail);
}
[Fact]
public void Find_5_Should_Return_True()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isFound = myLinkedList.Find(5);
// Assert
Assert.True(isFound);
}
[Fact]
public void IsEmpty_Should_Return_False_Count_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.False(isEmpty);
}
[Fact]
public void IsEmpty_Should_Return_True_Count_Equal_0()
{
// Arrange
int myNums = { };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.True(isEmpty);
}
[Fact]
public void GetIndex_4_Should_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var index = myLinkedList.GetIndex(4);
// Assert
Assert.Equal(5, index);
}
[Fact]
public void SetIndex_2_10_Should_Set_Index_2_To_10()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.SetIndex(2, 10);
// Assert
Assert.Equal(10, myLinkedList[2]);
}
[Fact]
public void RemoveAll_Should_Delete_All_5s()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveAll(5);
// Assert
Assert.False(myLinkedList.Find(5));
}
[Fact]
public void Remove_1_Should_Return_True()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(1);
// Assert
Assert.True(isRemoved);
}
[Fact]
public void Remove_2_Should_Return_False()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(2);
// Assert
Assert.False(isRemoved);
}
[Fact]
public void AddHead_Should_Increment_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
// Assert
Assert.Equal(theCount + 5, myLinkedList.Count);
}
[Fact]
public void Remove_2_Should_Decrement_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(theCount - 1, myLinkedList.Count);
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string args)
{
RunLinkedList();
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(1);
myLinkedList.AddHead(2);
myLinkedList.AddHead(3);
myLinkedList.AddHead(4);
myLinkedList.AddHead(5);
myLinkedList.RemoveHead();
myLinkedList.RemoveTail();
myLinkedList.SetIndex(2, 10);
myLinkedList[2] = 2;
System.Console.WriteLine("Count = " + myLinkedList.Count);
System.Console.WriteLine("Is Empty = " + myLinkedList.IsEmpty);
PrintList<int>(myLinkedList);
}
static void PrintList<T>(LinkedList<T> myList)
{
if (myList.Head == null || myList.Tail == null) return;
var listText = "LinkedList[";
for (int i = 0; i < myList.Count; i++)
{
listText += myList[i];
if (i < myList.Count - 1)
{
listText += "<";
listText += "---";
listText += ">";
}
}
listText += "]";
System.Console.WriteLine(listText);
System.Console.WriteLine("Found Data = 66 -> " + myList.Find((T)(object)66));
System.Console.WriteLine("Found Data = 3 -> " + myList.Find((T)(object)3));
}
}
}
c# beginner linked-list unit-testing
New contributor
$endgroup$
Here are the changes I've made thanks to suggestions made by @vnp, and @Henrik Hansen. Here is the link to the previous code review: Linked list implementation along with unit test [Round 2]
I've made some new additions that were not mentioned and added more unit tests :). I really feel like I'm improving!
Implementation
using System;
using System.Collections;
using System.Collections.Generic;
namespace DataStructuresAndAlgorithms.DataStructures
{
public class LinkedList<T> : IEnumerable<T>
{
class Node
{
public T Data { get; set; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T data)
{
Data = data;
}
}
private Node _head, _tail;
public T Head => _head == null ? throw new NullReferenceException() : _head.Data;
public T Tail => _tail == null ? throw new NullReferenceException() : _tail.Data;
public bool IsEmpty { get { return Count > 0 ? false : true; } }
public int Count { get; private set; } = 0;
public LinkedList() { }
public LinkedList(IEnumerable<T> items)
{
foreach (var item in items)
{
AddTail(item);
}
}
public void AddHead(T item)
{
var node = new Node(item);
if (_head == null && _tail == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Next = _head;
_head.Previous = node;
Count += 1;
}
_head = node;
}
public void AddTail(T item)
{
var node = new Node(item);
if (_tail == null && _head == null)
{
_head = node;
_tail = node;
Count += 1;
}
else
{
node.Previous = _tail;
_tail.Next = node;
Count += 1;
}
_tail = node;
}
public T RemoveHead()
{
if (_head == null) return default;
else
{
var temp = _head.Next;
_head = _head.Next;
if (_head != null) _head.Previous = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public T RemoveTail()
{
if (_tail == null) return default;
else
{
var temp = _tail.Previous;
_tail = _tail.Previous;
if (_tail != null) _tail.Next = null;
Count -= 1;
if (temp == null) return default;
return temp.Data;
}
}
public bool Find(T item)
{
if (_head == null || _tail == null) return false;
var node = _head;
while (node.Data.Equals(item) == false)
{
if (node.Next == null)
return false;
node = node.Next;
}
return true;
}
public bool Remove(int index)
{
if (_head == null || _tail == null) return false;
var node = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
node = node.Next;
}
// Remove the node
if (node == null) return false;
bool isRemoved = NodeAwareRemove(node);
return isRemoved;
}
private bool NodeAwareRemove(Node node)
{
if (node.Next != null && node.Previous != null)
{
// In between nodes
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
Count -= 1;
return true;
}
if (node.Next != null && node.Previous == null)
{
// Head node
RemoveHead();
return true;
}
if (node.Previous != null && node.Next == null)
{
// Tail node
RemoveTail();
return true;
}
if (node.Next == null && node.Previous == null)
{
// Only node
_head = null;
_tail = null;
Count -= 1;
return true;
}
return false;
}
public int RemoveAll(T item)
{
if (_head == null || _tail == null) return -1;
var node = _head;
int numberRemoved = 0;
while (node != null)
{
if (node.Data.Equals(item))
{
if (NodeAwareRemove(node)) numberRemoved += 1;
}
node = node.Next;
}
return numberRemoved;
}
public T GetIndex(int index)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) return _head.Data;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
return temp.Data;
}
public bool SetIndex(int index, T item)
{
if (index < 0) throw new IndexOutOfRangeException();
if (index > Count) throw new IndexOutOfRangeException();
if (index == 0) _head.Data = item;
var temp = _head;
for (int i = 0; i < Count; i++)
{
if (i == index) break;
temp = temp.Next;
}
temp.Data = item;
return true;
}
public object this[int i]
{
get { return GetIndex(i); }
set { SetIndex(i, (T)value); }
}
public IEnumerator<T> GetEnumerator()
{
var pointer = _head;
while (pointer != null)
{
yield return pointer.Data;
pointer = pointer.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Unit Test
using System;
using Xunit;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.DataStructures.Tests
{
public class LinkedListTest
{
[Fact]
public void AddHead_Node_Should_Become_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddHead(45);
// Assert
Assert.Equal(45, myLinkedList.Head);
}
[Fact]
public void AddTail_Node_Should_Become_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.AddTail(7777);
// Assert
Assert.Equal(7777, myLinkedList.Tail);
}
[Fact]
public void RemoveHead_Next_Node_Should_Be_Head()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveHead();
// Assert
Assert.Equal(2, myLinkedList.Head);
}
[Fact]
public void RemoveTail_Next_Node_Should_Be_Tail()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(4, myLinkedList.Tail);
}
[Fact]
public void Find_5_Should_Return_True()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isFound = myLinkedList.Find(5);
// Assert
Assert.True(isFound);
}
[Fact]
public void IsEmpty_Should_Return_False_Count_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.False(isEmpty);
}
[Fact]
public void IsEmpty_Should_Return_True_Count_Equal_0()
{
// Arrange
int myNums = { };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var isEmpty = myLinkedList.IsEmpty;
// Assert
Assert.True(isEmpty);
}
[Fact]
public void GetIndex_4_Should_Equal_5()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
var index = myLinkedList.GetIndex(4);
// Assert
Assert.Equal(5, index);
}
[Fact]
public void SetIndex_2_10_Should_Set_Index_2_To_10()
{
// Arrange
int myNums = { 1, 2, 3, 4, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.SetIndex(2, 10);
// Assert
Assert.Equal(10, myLinkedList[2]);
}
[Fact]
public void RemoveAll_Should_Delete_All_5s()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
myLinkedList.RemoveAll(5);
// Assert
Assert.False(myLinkedList.Find(5));
}
[Fact]
public void Remove_1_Should_Return_True()
{
// Arrange
int myNums = { 5, 5, 5, 3, 2, 5 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(1);
// Assert
Assert.True(isRemoved);
}
[Fact]
public void Remove_2_Should_Return_False()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
// Act
bool isRemoved = myLinkedList.Remove(2);
// Assert
Assert.False(isRemoved);
}
[Fact]
public void AddHead_Should_Increment_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
myLinkedList.AddHead(7);
// Assert
Assert.Equal(theCount + 5, myLinkedList.Count);
}
[Fact]
public void Remove_2_Should_Decrement_Count()
{
// Arrange
int myNums = { 1 };
var myLinkedList = new LinkedList<int>(myNums);
var theCount = myLinkedList.Count;
// Act
myLinkedList.RemoveTail();
// Assert
Assert.Equal(theCount - 1, myLinkedList.Count);
}
}
}
Presentation
using System;
using System.Collections;
using DataStructuresAndAlgorithms.DataStructures;
namespace DataStructuresAndAlgorithms.Presentation.Console
{
class Program
{
static void Main(string args)
{
RunLinkedList();
}
static void RunLinkedList()
{
System.Console.WriteLine("Running the LinkedList class");
System.Console.WriteLine("----------------------------");
var myLinkedList = new LinkedList<int>();
myLinkedList.AddHead(1);
myLinkedList.AddHead(2);
myLinkedList.AddHead(3);
myLinkedList.AddHead(4);
myLinkedList.AddHead(5);
myLinkedList.RemoveHead();
myLinkedList.RemoveTail();
myLinkedList.SetIndex(2, 10);
myLinkedList[2] = 2;
System.Console.WriteLine("Count = " + myLinkedList.Count);
System.Console.WriteLine("Is Empty = " + myLinkedList.IsEmpty);
PrintList<int>(myLinkedList);
}
static void PrintList<T>(LinkedList<T> myList)
{
if (myList.Head == null || myList.Tail == null) return;
var listText = "LinkedList[";
for (int i = 0; i < myList.Count; i++)
{
listText += myList[i];
if (i < myList.Count - 1)
{
listText += "<";
listText += "---";
listText += ">";
}
}
listText += "]";
System.Console.WriteLine(listText);
System.Console.WriteLine("Found Data = 66 -> " + myList.Find((T)(object)66));
System.Console.WriteLine("Found Data = 3 -> " + myList.Find((T)(object)3));
}
}
}
c# beginner linked-list unit-testing
c# beginner linked-list unit-testing
New contributor
New contributor
edited 36 mins ago
feature_creep
New contributor
asked 1 hour ago
feature_creepfeature_creep
535
535
New contributor
New contributor
add a comment |
add a comment |
0
active
oldest
votes
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
});
}
});
feature_creep is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216758%2flinked-list-implementation-along-with-unit-test-round-3%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
feature_creep is a new contributor. Be nice, and check out our Code of Conduct.
feature_creep is a new contributor. Be nice, and check out our Code of Conduct.
feature_creep is a new contributor. Be nice, and check out our Code of Conduct.
feature_creep is a new contributor. Be nice, and check out our Code of Conduct.
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216758%2flinked-list-implementation-along-with-unit-test-round-3%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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