Open In App

How to Implement Generic Singly LinkedList in C#?

Last Updated : 09 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Linked List linear collection of objects called nodes that are stored in the memory at random addresses. The first node is a special node named Head which stores the address of the first element. In the last node of the linked list, the node may point at null or another special node named Tail. 

Linked List Node Representation: 

A node is an object which contains two fields, one stores data, and the other address of the next node. 

Node

 

Linked List Visualization:

The first node is a special node named Head which stores the address of the first element. In the last node of the linked list, the node may point at null or another special node named Tail

Visualization of Linked List

 

Basic Operations in Linked List:

  • AddFirst() – Adds node at the start of the List 
  • AddLast() – Adds node at the start of the List 
  • AddAfter() – Adds node after a particular Node
  • Remove() – Removes a particular node 
  • RemoveFirst() – Removes the first node
  • RemoveLast() -Removes the last node
  • Clear() – Removes all the nodes from the linked list
  • Find() – Find a particular node in the linked list
  • ToString() – To display all the elements of the linked list
  • Count – It returns the number of nodes in the linked list

Generic:

In simple words generics allow users to work with any data type while writing a class or method. 

Example 1:

C#




using System;
using System.Text;
 
namespace LinkedList
{
    public interface INode<K>
    {
        K Value { get; set; }
    }
 
    public class LinkedList<T>
    {
        // Private class so that it cannot
        // be accessed outside of this class
        private class Node<K> : INode<K>
        {
            // Data field of the Node
            public K Value { get; set; }
 
            // Storing address of next node
            public Node<K> Next { get; set; }
 
            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="value"></param> 
            // Data at the node
            /// <param name="next"></param> 
            // Address of next node
            public Node(K value, Node<K> next)
            {
                Value = value;
                Next = next;
            }
 
            /// <summary>
            /// Print the node and the next value
            /// Output Format of the function
            // {(element)->next element}
            /// </summary>
            /// <returns></returns>
            public override string ToString()
            {
                StringBuilder s = new StringBuilder();     
                // Mutable string object
                s.Append("{");
                s.Append("(");
                s.Append(Value);   
                 
                // Printing Value
                s.Append(")->");   
                 
                // Arrow pointing towards next element
                s.Append(Next.Next == null ? "XXX" : Next.Value.ToString());   
                // If it is end of the list it will be signified by 'XXX'
                s.Append("}");
                return s.ToString();
            }
 
        }
 
        // Private property with read and write access
        private Node<T> Head { get; set; } 
         
        // Head of the linked list
        private Node<T> Tail { get; set; } 
         
        // Tail of the linked list
        // Number of elements in the list
        public int Count { get; private set; } = 0;
 
        /// <summary>
        /// Constructor
        /// </summary>
        public LinkedList()
        {
            Head = new Node<T>(default(T), null);  
            // Default value of T in generic instruction is stored
             
            Tail = new Node<T>(default(T), null);  
            // Default value of T in generic instruction is stored
             
            Head.Next = Tail;
        }
 
        /// <summary>
        /// Property returns first element of the list
        /// Read-Only property
        /// </summary>
        public INode<T> First
        {
            get
            {
                // Checks if the list is empty
                if (Count == 0) return null;
                // If the list is not empty it will return the first element
                else return Head.Next;
            }
        }
 
        /// <summary>
        /// Function return the next node of the node passed in the function
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public INode<T> After(INode<T> node)
        {
            // Checks if the node is null
            if (node == null) throw new NullReferenceException();
 
            // Converting INode<T> to Node<T> using 'as'
            Node<T> node_current = node as Node<T>;
 
            // Checks if the next of the node exists
            if (node_current.Next == null) throw new
            InvalidOperationException("The node referred as
            'after' is no longer in the list");
 
            // Checks if the next of node is equal to tail
            if (node_current.Next.Equals(Tail)) return null;
 
            // If all the above checks are passed the next node is returned
            else return node_current.Next;
        }
 
        /// <summary>
        /// Function to find a particular node
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public INode<T> Find(T value)
        {
            // Storing the first node
            Node<T> node = Head.Next;
 
            // Iterating until we get the element or
            // we have reached at the end of the linked list
            while (!node.Equals(Tail))
            {
                // Checks of the data stored in the node is equal to the value
                if (node.Value.Equals(value)) return node;
 
                // Storing the next node for the current node
                node = node.Next;
            }
 
            // Null is returned if the element is not found
            return null;
        }
 
 
        /// <summary>
        /// Function to print the entire linked list
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            // Checks if the list is empty
            if (Count == 0) return "[]";
 
 
            StringBuilder s = new StringBuilder();
 
            // Adding an opening bracket
            s.Append("[");
            int k = 0;
 
            // Storing the first node
            Node<T> node = Head.Next;
 
            // Iterating over the linked list
            while (!node.Equals(Tail))
            {
                // Adding the string output from ToString()
                // function to 's' string
                s.Append(node.ToString());
 
                // Next node of the current node
                node = node.Next;
 
                // If the current node is not the last node
                // then a coma will be added at the last
                if (k < Count - 1) s.Append(",");
 
                // Incrementing k
                k++;
            }
 
            // Adding a closing bracket
            s.Append("]");
 
            // Return the linked list in a string format
            return s.ToString();
        }
 
 
        /// <summary>
        /// Function to add elements at the starting of the list
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public INode<T> AddFirst(T value)
        {
            // Creating an instance of new node
            Node<T> new_node = new Node<T>(value, Head.Next);
            // Next of the head will be next of the new first node
 
            // Next of the Head will be our new node
            Head.Next = new_node;
 
            // Incrementing count by 1 as new element is added to the list
            Count++;
 
            // returning the new node
            return new_node;
        }
 
        /// <summary>
        /// Function to add at the end of the list
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public INode<T> AddLast(T value)
        {
 
            Node<T> node = Head;
 
            // Iterating through the linked list
            // Findin the previous node of the last node
            while (!node.Next.Next.Equals(Tail))
            {
                node = node.Next;
            }
 
            // Creating a new Node
            Node<T> new_node = new Node<T>(value, Tail);
            // The next of the new last node will be tail
 
 
            node.Next.Next = new_node;
 
            // Incrementing count by 1 as new element is added to the list
            Count++;
 
            // returning the new node
            return new_node;
        }
 
        /// <summary>
        /// Function to add element after a particular node
        /// </summary>
        /// <param name="after"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public INode<T> AddAfter(INode<T> after, T value)
        {
            // Node after which we want to add new node
            Node<T> current_node = after as Node<T>;
            Node<T> new_node = new Node<T>(value, current_node.Next);
            //Setting new node next of current node
            current_node.Next = new_node;
 
            // Incrementing count by 1 as new element is added to the list
            Count++;
 
            // Returning the new node
            return new_node;
        }
 
        /// <summary>
        /// Function to remove all the elements of the list
        /// </summary>
        public void Clear()
        {
            INode<T> node = First;
 
            // Iterates throught the entire list and romove a node one by one
            for (int i = 0; i < Count; i++)
            {
                // Removing the node
                Remove(node);
 
                // Setting the next node which is to be removed
                node = After(node);
            }
 
            // Setting the count to 0 as all the nodes are removed
            Count = 0;
        }
 
        /// <summary>
        /// Function to remove a particular node
        /// </summary>
        /// <param name="node"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="InvalidOperationException"></exception>
        public void Remove(INode<T> node)
        {
            // Checking if the node is null
            if (node == null) throw new ArgumentNullException();
 
            // Check if the node exist in the linked list
            if (Find(node.Value) == null) throw new InvalidOperationException();
            Node<T> remove = node as Node<T>;
            Node<T> current_node = Head;
 
            // Iterating through the linked list
            while (!current_node.Next.Next.Equals(remove.Next))
            {
                // Changing the linkes
                current_node = current_node.Next;
            }
 
            // Changing the links
            current_node.Next = remove.Next;
 
            // Decrementing Count by 1 as one node is removed
            Count--;
        }
 
        /// <summary>
        /// Function to romove first node
        /// </summary>
        /// <exception cref="InvalidOperationException"></exception>
        public void RemoveFirst()
        {
            // Checking if the Linked List is empty
            if (Count == 0) throw new InvalidOperationException();
 
            // Removing the first node
            Remove(First);
        }
 
        /// <summary>
        /// Function to remove last node
        /// </summary>
        public void RemoveLast()
        {
            // Checking if the Linked List is empty
            if (Count == 0) throw new InvalidOperationException();
 
            Node<T> current_node = Head;
 
            // Iterating through the linked list
            while (!current_node.Next.Next.Equals(Tail))
            {
                // Changing the links
                current_node = current_node.Next;
            }
 
            // Changing the links
            current_node.Next = Tail;
 
            // Decrementing Count by 1 as one node is removed
            Count--;
        }
    }
 
    public class GFG
    {
        static void Main(string[] args)
        {
            LinkedList<int> list = new LinkedList<int>();
 
            list.AddFirst(1);
            list.AddFirst(2);
            list.AddFirst(3);
            list.AddFirst(4);
            list.AddFirst(5);
            Console.Write("List: ");
            Console.WriteLine(list.ToString());
            list.AddAfter(list.Find(4), 7);
            Console.Write("List after adding 7: ");
            Console.WriteLine(list.ToString());
            list.AddLast(6);
            Console.Write("List: ");
            Console.WriteLine(list.ToString());
 
            Console.Write("After 4: ");
            Console.WriteLine(list.After(list.Find(4)));
 
            list.Remove(list.Find(7));
            Console.Write("List after removing 7: ");
            Console.WriteLine(list.ToString());
 
            Console.WriteLine();
 
            LinkedList<string> cities
                = new LinkedList<string>();
 
            cities.AddFirst("Ludhiana");
            cities.AddFirst("Jalandhar");
 
            Console.Write("Cities: ");
            Console.WriteLine(cities.ToString());
 
            cities.AddLast("Amritsar");
 
            Console.Write("Cities: ");
            Console.WriteLine(cities.ToString());
        }
    }
}


Output:

 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads