using System; using System.Linq; using System.Text; using System.Threading.Tasks; using C_.Datastructures.Nodes; namespace C_.Datastructures { internal class DoublyLinkedList { internal DoublyLinkedListNode? Head { get; set; } = default; internal DoublyLinkedListNode? Tail { get; set; } = default; private int Count { get; set; } = 0; public static DoublyLinkedList Create() { //Create a new empty list return new DoublyLinkedList(); } public static DoublyLinkedList Create(T value) { //Create a new Class with a single item return new DoublyLinkedList() { Head = DoublyLinkedListNode.Create(value, default, default), Count = 1 }; } public static DoublyLinkedList Create(DoublyLinkedList list1, DoublyLinkedList list2) { //Create a new list from 2 separate lists DoublyLinkedList list; list = list1; if (list == default || list.Count == 0) return list2; //Find end of list and append fist item of next list if (list2 == default || list.Count == 0) return list; DoublyLinkedListNode? end = list.Traverse(); //Connect up pointers at ajoining section end!.Next = list2!.Head; end!.Next!.Prev = end; end = list2.Tail; list.Count += list2!.Count; return list; } public T? this[int i] { get { //Check Range if (i >= Count || i < 0) throw new System.Exception("Error! Index out of Bounds"); //Return Value DoublyLinkedListNode? node = Traverse(i); if (node != default) return node.Value; return default; } set { //Check Range if (i >= Count || i < 0) throw new System.Exception("Error! Index out of Bounds"); //Change Value DoublyLinkedListNode? node = Traverse(i); node!.Value = value; } } public void Append(T value) { Count++; //Set head to new item if list is empty if (Head == null) {//Append item to front of list (End as well) Head = DoublyLinkedListNode.Create(value, default, default); Tail = Head; return; } //Append item to the end of the list Tail!.Next = DoublyLinkedListNode.Create(value, default, Tail); Tail = Tail.Next; } public void Insert(int index, T value) { Count++; if (index > Count || index < 0) throw new System.Exception("Error! Index outside of Bounds"); //Set head to new item if list is empty if (index == 0 || Head == null) { Head = DoublyLinkedListNode.Create(value, Head, default); Tail = Head; return; } //Set tail to new item if index is the end if (index == Count - 1) { //Decrement count as it will be be re-incremented once appended Count--; Append(value); return; } //Fetch point in list and add new item DoublyLinkedListNode? node = Traverse(index - 1); node!.Next = DoublyLinkedListNode.Create(value, node.Next, node); //Create backlink in the list if(node.Next.Next != default) node.Next.Next.Prev = node.Next; } public void Delete(int index) { Count--; if (index > Count || index < 0) throw new System.Exception("Error! Index outside of Bounds"); //Check if we are trying to reference the first item if (index == 0 && Head != default) { Head = Head!.Next; if(Head != default) Head.Prev = default; return; } //Set tail to new item if index is the end if (index == Count && Tail != default) { Tail = Tail!.Prev; if(Tail != default) Tail.Next = default; return; } DoublyLinkedListNode? node = Traverse(index - 1); node!.Next = node.Next!.Next; //Connect item after to the the item before the node we are deleting if (node.Next != default) { node.Next.Prev = node; } } private DoublyLinkedListNode? Traverse() { //Return the final item in the list return Tail; } private DoublyLinkedListNode? Traverse(int i) { //Determine whether to start at the start or end of the list int direction = 1; DoublyLinkedListNode? node = Head; if (i > (Count/2)) { //reverse direction of search direction = -1; node = Tail; //i becomes the amount of hops left to reach the item i = Count - i - 1; } if (node != null) { //continue to given point in the list ('i' hops) for (int x = 0; x < i; x++) { if (direction == 1) {//Going forwards node = node!.Next; } else { node = node!.Prev; } } } return node; } private DoublyLinkedListNode? Next(DoublyLinkedListNode current) { if (current != default) return current.Next; return null; } private DoublyLinkedListNode? Prev(DoublyLinkedListNode current) { if (current != default) return current.Prev; return null; } } }