I am trying to implement a singly linked list. What is the most optimal way of implementing a RemoveBefore(ListNode)
method?
I have done this:
- Check if node being removed is the head. If so, return.
- Check if there are two nodes and node being removed is the tail. Then set head and tail as the same. Old tail will be automatically disposed.
- If there are more than 2 nodes and the above 2 conditions are not satisfied track current node, child node and grandchild node.
- If grandchild node is the requested node the make current node point to grandchild node. Child node will be disposed.
namespace DataStructures.Lists
{
public interface ISinglyLinkedNode<T> where T : IComparable<T>
{
T Data { get; set; }
ISinglyLinkedNode<T> Next { get; set; }
}
public interface ISinglyLinkedList<T> where T : IComparable<T>
{
ISinglyLinkedNode<T> Head { get; }
ISinglyLinkedNode<T> Tail { get; }
void Add(ISinglyLinkedNode<T> Data);
void AddHead(ISinglyLinkedNode<T> Data);
void AddTail(ISinglyLinkedNode<T> Data);
void RemoveHead();
void RemoveTail();
void AddAt(int Index, ISinglyLinkedNode<T> Data);
void InsertAfter(ISinglyLinkedNode<T> Node, T Data);
void InsertBefore(ISinglyLinkedNode<T> Node, T Data);
ISinglyLinkedNode<T> GetAt(int Index);
void RemoveAt(int Index);
void RemoveAfter(ISinglyLinkedNode<T> Node);
void RemoveBefore(ISinglyLinkedNode<T> Node);
void Remove(ISinglyLinkedNode<T> Node);
void ReverseList();
}
public interface IPrintLinkedList
{
void PrintLinkedList();
}
/// <summary>
/// Definition of a Singly linked node. This node has a data slot and a single pointer slot pointing to the next
/// singly linked node.
/// </summary>
/// <typeparam name="T"></typeparam>
public class SinglyLinkedNode<T> : IDisposable, IComparable<SinglyLinkedNode<T>>, ISinglyLinkedNode<T> where T : IComparable<T>
{
private T _data;
private ISinglyLinkedNode<T> _next;
public SinglyLinkedNode()
{
_data = default(T);
_next = null;
}
public SinglyLinkedNode(T data)
{
_data = data;
_next = null;
}
public T Data { get { return _data; } set { _data = value; } }
public ISinglyLinkedNode<T> Next { get { return _next; } set { _next = value; } }
int IComparable<SinglyLinkedNode<T>>.CompareTo(SinglyLinkedNode<T> other)
{
if (other == null)
return -1;
return this.Data.CompareTo(other.Data);
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
IDisposable disposable = _data as IDisposable;
if (disposable != null)
disposable.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
/// <summary>
/// Implements ISinglyLinkedList and defines a singly linked list
/// </summary>
/// <typeparam name="T">Template type</typeparam>
public class SinglyLinkedList<T> : ISinglyLinkedList<T>, IPrintLinkedList, IEnumerable<T> where T : IComparable<T>
{
private ISinglyLinkedNode<T> _head;
private ISinglyLinkedNode<T> _tail;
public SinglyLinkedList()
{
_head = null;
_tail = null;
}
#region ISinglyLinkedList implementation
ISinglyLinkedNode<T> ISinglyLinkedList<T>.Head
{
get
{
return _head;
}
}
ISinglyLinkedNode<T> ISinglyLinkedList<T>.Tail
{
get
{
return _tail;
}
}
void ISinglyLinkedList<T>.Add(ISinglyLinkedNode<T> Data)
{
(this as ISinglyLinkedList<T>).AddHead(Data);
}
void ISinglyLinkedList<T>.AddAt(int Index, ISinglyLinkedNode<T> Data)
{
throw new NotImplementedException();
}
void ISinglyLinkedList<T>.AddHead(ISinglyLinkedNode<T> Data)
{
Data.Next = _head;
_head = Data;
}
void ISinglyLinkedList<T>.AddTail(ISinglyLinkedNode<T> Data)
{
_tail.Next = Data;
_tail = Data;
}
ISinglyLinkedNode<T> ISinglyLinkedList<T>.GetAt(int Index)
{
if (Index < 0)
return new SinglyLinkedNode<T>();
ISinglyLinkedNode<T> Temp = _head;
for (int i = 0; i < Index - 1; i++)
{
Temp = Temp.Next;
}
return Temp;
}
void ISinglyLinkedList<T>.Remove(ISinglyLinkedNode<T> Node)
{
//empty linked list
if (_head == null)
return;
for (ISinglyLinkedNode<T> current = _head, prev = null; current != null; prev = current, current = current.Next)
{
if (object.Equals(current.Data, Node.Data))
{
prev.Next = current.Next;
break;
}
}
}
void ISinglyLinkedList<T>.RemoveAfter(ISinglyLinkedNode<T> Node)
{
Node.Next = Node.Next.Next;
}
void ISinglyLinkedList<T>.RemoveAt(int Index)
{
(this as ISinglyLinkedList<T>).Remove((this as ISinglyLinkedList<T>).GetAt(Index));
}
void ISinglyLinkedList<T>.RemoveBefore(ISinglyLinkedNode<T> Node)
{
//cannot remove before head
if (object.Equals(Node.Data, _head.Data))
return;
//if we need to remove the node before tail then make head and tail the same
if (object.Equals(Node.Data, _tail.Data))
{
_head = _tail;
(_tail as IDisposable).Dispose();
}
for (ISinglyLinkedNode<T> currentnode = _head, child = null, grandchild = null; currentnode != null; currentnode = currentnode.Next)
{
child = currentnode.Next;
grandchild = child.Next;
if (object.Equals(Node.Data, grandchild.Data))
{
currentnode.Next = grandchild;
break;
}
}
}
void ISinglyLinkedList<T>.RemoveHead()
{
lock (_head)
{
lock (_head.Next)
{
_head = _head.Next;
}
}
}
void ISinglyLinkedList<T>.RemoveTail()
{
ISinglyLinkedNode<T> currentnode = _head;
//check if there is only one node. Remove head then
if (_head.Next == null)
{
_head = null;
return;
}
//if there are only two nodes set heads next to null to remove tail
if (_head.Next != null && _head.Next.Next == null)
{
_head.Next = null;
return;
}
for (ISinglyLinkedNode<T> current = _head, child = current.Next, grandchild = child.Next; current != null; current = current.Next)
{
}
}
#endregion
#region IEnumerable implementation
IEnumerator IEnumerable.GetEnumerator()
{
return new SinglyLinkedListEnumerator<T>();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new SinglyLinkedListEnumerator<T>();
}
#endregion
void IPrintLinkedList.PrintLinkedList()
{
PrintNode(_head);
}
void PrintNode(ISinglyLinkedNode<T> Node)
{
if (Node == null)
{
Debug.Write(" | " + "NULL" + " | " + "\n");
return;
}
Debug.Write(" | " + Node.Data + " | " + "-->");
PrintNode(Node.Next);
}
void ISinglyLinkedList<T>.InsertAfter(ISinglyLinkedNode<T> Node, T Data)
{
throw new NotImplementedException();
}
void ISinglyLinkedList<T>.InsertBefore(ISinglyLinkedNode<T> Node, T Data)
{
throw new NotImplementedException();
}
void ISinglyLinkedList<T>.ReverseList()
{
// < __ < __ < __ __: reversedPart: head
// (__)__ __ __
//head : current: > > >
ISinglyLinkedNode<T> reversedPart = null;
ISinglyLinkedNode<T> current = _head;
while (current != null)
{
ISinglyLinkedNode<T> next = current.Next;
current.Next = reversedPart;
reversedPart = current;
current = next;
}
_head = reversedPart;
}
internal class SinglyLinkedListEnumerator<T> : IEnumerator<T>
{
public T Current
{
get
{
throw new NotImplementedException();
}
}
object IEnumerator.Current
{
get
{
throw new NotImplementedException();
}
}
public void Dispose()
{
throw new NotImplementedException();
}
public bool MoveNext()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
}
}
}