Newer
Older
TheVengeance-Project-IADE-Unity2D / Assets / Scripts / DataStructures / LinkedLists / LinkedList.cs
using System.Collections.Generic;
using System.Collections;
using UnityEngine;
using System.Transactions;

namespace MyCollections.Generic
{
    public class LinkedList<T>
    {
        private ListNode<T> head;

        public ListNode<T> Head
        {
            get => head;
            set => head = value;
        }

        public int Count
        {
            get => CounElements();
        }

        //Constructors
        public LinkedList() => head = null;
        public LinkedList(ListNode<T> node) => head = node;

        //Inserts at the beginning
        public void InsertAtBegin(T item)
        {
            ListNode<T> newNode = new ListNode<T>(item);
            newNode.Next = head;
            head = newNode;
        }

        public void InsertAfter(T after, T item)
        {
            ListNode<T> afterNode = LinearSearch(after);

            if (afterNode != null)
            {
                ListNode<T> newNode = new ListNode<T>(item);
                ListNode<T> temp = afterNode.Next;
                afterNode.Next = newNode;
                newNode.Next = temp;
            }
        }

        //Inserts at the end of the LinkedList
        public void InsertAtEnd(T item)
        {
            ListNode<T> newNode = new ListNode<T>(item);

            if (head == null)
            {
                newNode.Next = head;
                head = newNode;
            }

            else
            {
                ListNode<T> current = head;

                while (current != null)
                {
                    current = current.Next;
                }

                current.Next = newNode;
            }
        }

        public void Remove(T data)
        {
            ListNode<T> current = head;
            ListNode<T> previous = null;

            //search and keep both current and previous pointers
            while ((current != null) && (!current.Data.Equals(data))) 
            {
                previous = current;
                current = current.Next;
            }

            if (current != null)
            {
                //remove from the beginning
                if (previous == null) head = current.Next;

                //remove from any other place  
                else previous.Next = current.Next;
            }
        }

        public void Remove(ListNode<T> node)
        {
            if (IsEmpty())
            {
                Debug.LogWarning($"The list is empty");
                return;
            }

            if (node == head)
            {
                head = head.Next;
                return;
            }

            ListNode<T> current = head;
            ListNode<T> previous = null;

            while (current != null && current != node)
            {
                previous = current;
                current = current.Next;
            }

            if (current == node) previous.Next = current.Next;
        }

        public ListNode<T> LinearSearch(T data)
        {
            ListNode<T> current = head;

            while (current != null)
            {
                if (current.Data.Equals(data))
                {
                    return current;
                }
                current = current.Next;
            }

            return null;
        }

        //Reverse a LinkedList
        public void Reverse() => Reverse(this);

        //Reverse a LinkedList
        public static void Reverse(LinkedList<T> list)
        {

            if (IsEmpty(list))
            {
                Debug.LogWarning($"List is empty!");
                return;
            }

            else
            {
                ListNode<T> previous = null;
                ListNode<T> current = list.head;
                ListNode<T> next = null;

                while (current != null)
                {
                    //Store the next node
                    next = current.Next;

                    //Reverse the current node's pointer
                    current.Next = previous;

                    //Move pointers one position ahead
                    previous = current;
                    current = next;
                }

                //Set the new head of the list
                list.head = previous;
            }

        }

        //Checks if the LinkedList is empty
        public bool IsEmpty() => IsEmpty(this);

        public static bool IsEmpty(LinkedList<T> list) => list.head == null;
        
        //Allow iteration with foreach
        public IEnumerator<T> GetEnumerator()
        {
            ListNode<T> current = head;

            while (current != null)
            {
                yield return current.Data;
                current = current.Next;
            }
        }

        public void AddArray(T[] array) => AddArray(this, array);

        //Adds an array to LinkedList 
        public static void AddArray(LinkedList<T> list, T[] array)
        {
            for (int i = 0; i < array.Length; i++)
            {
                list.InsertAtEnd(array[i]);
            }
        }

        //Converts an array to a LinkedList
        public static LinkedList<T> ArrayToLinkedList(T[] array)
        {
            LinkedList<T> list = new LinkedList<T>(null);

            if (array != null && array.Length > 0)
            {

                for (int i = 0; i < array.Length; i++)
                {
                    list.InsertAtEnd(array[i]);
                }
            }

            return list;
        }

        private int CounElements()
        {
            ListNode<T> current = head;
            int count = 0;

            while (current != null)
            {
                count++;
                current = current.Next;
            }

            return count;
        }
    }
}