Skip to content

Instantly share code, notes, and snippets.

@Macawls
Created October 1, 2022 19:54
Show Gist options
  • Save Macawls/3c16861ec269df07bdfefcd87ba99489 to your computer and use it in GitHub Desktop.
Save Macawls/3c16861ec269df07bdfefcd87ba99489 to your computer and use it in GitHub Desktop.
using System;
using System.Text;
using ADT.Node;
namespace ADT.LinkedList
{
public class CustomLinkedList<T>
{
public Node<T> Head { get; private set; }
public Node<T> Tail { get; private set; }
public int Count { get; private set; }
/// <summary>
/// Creates an empty linked list
/// </summary>
public CustomLinkedList() {
}
/// <summary>
/// Creates a linked list and uses the data specified as the head
/// </summary>
public CustomLinkedList(T data)
{
AddFront(data);
}
/// <summary>
/// Creates a linked list and inserts every element in the array in the same order
/// </summary>
public CustomLinkedList(T[] array)
{
Array.ForEach(array, e => AddEnd(e));
}
public bool IsEmpty()
{
return Head == null;
}
/// <summary>
/// Returns a string representation of the list
/// </summary>
public string Display
{
get
{
Node<T> current;
try {
current = Head;
}
catch (NullReferenceException)
{
return "List has not been initialized";
}
var sb = new StringBuilder();
while (current != null)
{
sb.Append(current);
current = current.Next;
}
return sb.ToString();
}
}
/// <summary>
/// Empties the list
/// </summary>
public void Empty()
{
Head = Tail = null;
}
/// <summary>
/// Perform an action on every element's data in the linked list
/// </summary>
public void ForEach(Action<T> action)
{
var current = Head;
while (current != null)
{
action(current.Data);
current = current.Next;
}
}
/// <returns>
/// Returns the reverse of the linked list
/// </returns>
public CustomLinkedList<T> Reverse()
{
var reversed = new CustomLinkedList<T>();
ForEach(e => reversed.AddFront(e));
return reversed;
}
/// <returns>
/// Returns true if any element in the list matches the predicate.
/// </returns>
public bool Any(Func<T, bool> func)
{
var current = Head;
while (current != null)
{
if (func(current.Data)) return true;
current = current.Next;
}
return false;
}
/// <returns>
/// Returns first element in the list where the data matches the predicate.
/// </returns>
public Node<T>SelectFirst(Func<T, bool> func)
{
var current = Head;
while (current != null)
{
if (func(current.Data)) return current;
current = current.Next;
}
return null;
}
/// <returns>
/// Returns all the elements that match the predicate in the form of a linked list
/// </returns>
public CustomLinkedList<T>SelectMany(Func<T, bool> func)
{
var newList = new CustomLinkedList<T>();
var current = Head;
while (current != null)
{
if (func(current.Data)) newList.AddEnd(current.Data);
current = current.Next;
}
return newList;
}
/// <summary>
/// Inserts an element as the head, the added element will point to the previous head
/// </summary>
public void AddFront(T data)
{
var node = new Node<T>(data) {
Next = Head
};
Head = node;
Count++;
if (Count == 1)
{
Tail = Head;
}
}
/// <summary>
/// Inserts an element as the tail
/// </summary>
public void AddEnd(T data)
{
if (IsEmpty())
{
AddFront(data);
return;
}
var node = new Node<T>(data);
Tail.Next = node;
Tail = node;
Count++;
}
/// <summary>
/// Removes the head of the linked list
/// </summary>
public void RemoveFront()
{
Head = Head.Next;
Count--;
}
/// <summary>
/// Removes the tail of the linked list
/// </summary>
public void RemoveEnd()
{
if (Count == 1)
{
RemoveFront();
return;
}
var currentNode = Head;
while (currentNode.Next.Next != null)
{
currentNode = currentNode.Next;
}
currentNode.Next = null;
Tail = currentNode;
Count--;
}
/// <summary>
/// Get the first node element that matches the data
/// </summary>
/// <returns>
/// Returns null if no match was found or the list was empty, otherwise returns the node.
/// </returns>
public Node<T> GetFirst(T data)
{
if (IsEmpty()) return null;
var current = Head;
while (current.Next != null)
{
if (current.Data.Equals(data)) return current;
current = current.Next;
}
return current;
}
/// <summary>
/// Worst: O(n)
/// <returns>
/// The node that matches the index
/// </returns>
/// </summary>
public Node<T> GetByIndex(int index)
{
if (index == -1) return Tail;
var current = Head;
int count = 0;
while (current != null)
{
if (count == index) return current;
current = current.Next;
count++;
}
return null;
}
/// <summary>
/// Counts all the nodes that match the data
/// </summary>
public int CountAll(T data)
{
if (Count == 1) return 1;
var current = Head;
int total = 0;
while (current != null)
{
if (current.Data.Equals(data)) total++;
current = current.Next;
}
return total;
}
/// <summary>
/// Deletes all occurrences of the data and mutates the list
/// </summary>
public void DeleteAll(T data)
{
if (Head == null) return;
if (Head.Data.Equals(data)) RemoveFront();
var current = Head;
while (current.Next != null)
{
if (current.Next.Data.Equals(data))
{
current.Next = current.Next.Next;
Count--;
}
else
{
current = current.Next;
}
}
}
/// <summary>
/// Deletes all nodes where the data matches the predicate and mutates the list
/// </summary>
public void DeleteAll(Func<T, bool> func)
{
if (Head == null) return;
if (func(Head.Data)) RemoveFront();
var current = Head;
while (current.Next != null)
{
if (func(current.Next.Data))
{
current.Next = current.Next.Next;
Count--;
}
else
{
current = current.Next;
}
}
}
/// <summary>
/// Gets all the indexes of nodes matching the data specified.
/// </summary>
/// <returns>
/// The indexes of all the duplicates as an array. If the list is empty, it will return an empty array.
/// </returns>
public int[] GetAllDuplicates(T data)
{
if (IsEmpty()) return new int[0];
if (Head.Data.Equals(data) && Count == 1) return new[] {0};
var indexes = new CustomLinkedList<int>();
int index = 0;
var current = Head;
while (current != null)
{
if (current.Data.Equals(data)) indexes.AddEnd(index);
index++;
current = current.Next;
}
int[] dupes = new int[indexes.Count];
int count = 0;
indexes.ForEach(e =>
{
dupes[count] = e;
count++;
});
return dupes;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment