Created
October 1, 2022 19:54
-
-
Save Macawls/3c16861ec269df07bdfefcd87ba99489 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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