Linked List Chnoor M. Rahman Spring 2023 Outline • What is linked list (Singly and Doubly) • Adding and deleting elements • Displaying elements • Difference between singly linked list and doubly linked list Linked List • A linked list, in its simplest form, is a collection of nodes that together form a linear ordering. • It can be used in many cases in which you use an array, unless you need frequent random access to individual items using an index. • LinkedList acts as a dynamic array, we do not have to specify the size while creating it. • Size of the list automatically increases when we dynamically add and remove items. Linked List • Java LinkedList class can contain duplicate elements. • In Java LinkedList class, manipulation (insertion and deletion) is fast because no shifting needs to occur. How the Linked List Works • The LinkedList stores its items in "containers“. The list has a link to the first container and each container has a link to the next container in the list. To add an element to the list, the element is placed into a new container and that container is linked to one of the other containers in the list. • It is a class inside the java.util Import java.util.LinkedList; • Defining a linked list (String elements) : LinkedList<String> cars = new LinkedList<>(); The most common methods provided by the LinkedList class are: Method Description boolean add(E e) Appends specified value to the end of the list E get(int index) Returns the element at the specified position in this list void clear() Removes all of the elements from this list. The list will be empty after this call returns. boolean contains(Object o) Returns true if this list contains the specified element. o is the element whose presence in this list is to be tested. E remove() Retrieves and removes the head (first element) of this list. boolean isEmpty() Returns true if this collection contains no elements. int size() Returns the number of elements in this list. The most common methods provided by the LinkedList class are: Node • In a linked list, each data item is embedded in a node. • A node is made of two parts, namely data and pointer. • A node is an object of a class called something like Node. • A separate class is used for Nodes, distinct from the linked list itself. • Each Node object contains a reference (usually called next) to the next node in the list. • The last node in the list is the tail, and it points to NULL. Following is a singly linked list whose elements are characters. The next pointers of each node are shown as arrows. tail Length = 4 Linked List • The next reference inside a node can be viewed as a link or pointer to another node. • Moving from one node to another by following a next reference is known as link hopping or pointer hopping. • The first and last node of a linked list usually are called the head and tail of the list, respectively. • We can link hop through the list starting at the head and ending at the tail. • We can identify the tail as the node having a null next reference, which indicates the end of the list. • A linked list defined in this way is known as a singly linked list. Links in a list Order of elements • Like an array, a singly linked list keeps its elements in a certain order. This order is determined by the chain of next links going from each node to its successor in the list. Array and LinkedList • One of the major ways in which linked lists differ from arrays is that: In an array each item occupies a particular position. This position can be directly accessed using an index number. In a list the only way to find a particular element is to follow along the chain of elements. • Hence, you can’t access a data item directly; you must use relationships between the items to locate it. Insertion in a Singly LinkedList 1. Insertion of an element at the head: The main idea is that we create a new node, set its next link to refer to the same object as head, and then set head to point to the new node. We should set the next pointer for the new node before we make variable head point to the new node. Algorithm – addFirst(v) v.setNext(head) head v sizeList sizeList +1 // Make v point to the old head node // make variable head point to new node // increment the size of the list Insertion in a Singly LinkedList -- cont 2. Insertion of an element at the tail: In this case, we create a new node, assign its next reference to point to the null object, set the next reference of the tail to point to this new object, and then assign the tail reference itself to this new node. Note that we set the next link for the tail we assign the tail variable to point to the new node. Algorithm – addLast(v) v.setNext(null) tail.setNext(v) tail v sizeList sizeList+1 // make new node v point to null object // make old tail node point to new node // make variable tail point to new node //increment the size of the list Removing element in a singly linkedList • The reverse operation of inserting a new element at the head of a linked list is to remove an element at the head. • To delete the tail node We must be able to access the node before the last node in order to remove the last node. The only way to access this node is to start from the head of the list and search all the way through the list. • Removing any node other than the head is time consuming in a singly linked list. However, we can do it: • We can remove the target node at the given position and change the necessary links. Implementing a Singly Linked List • To implement a singly linked list, there should be a Node class, which specifies the type of objects stored at the nodes of the list. • Given the Node class, we can define a class, SLinkedList to defining the actual linked list. This class keeps a reference to the head node and a variable counting the total number of nodes. Algorithm • Create a class Node which has two attributes: data and next. Next is a pointer to the next node. • Create another class which has two attributes: head and tail. • addNode() will add a new node to the list: Create a new node. It first checks, whether the head is equal to null which means the list is empty. If the list is empty, both head and tail will point to the newly added node. If the list is not empty, the new node will be added to end of the list such that tail's next will point to the newly added node. This new node will become the new tail of the list. Algorithm Cont.. • a. display() will display the nodes present in the list: Define a node current which initially points to the head of the list. Traverse through the list till current points to null. Display each node by making current to point to node next to it in each iteration. class Node //Represent a node of the singly linked list 1. class Node{ 2. int data; 3. Node next; 4. 5. public Node(int data) { 6. this.data = data; 7. this.next = null; 8. } 9. } public class SinglyLinkedList { 1. public Node head = null; //Represent the head and tail of the singly li nked list 2. public Node tail = null; 3. public void addAtLast(int data) { //addNode() will add a new node to the list 4. Node newNode = new Node(data); //Create a new node 5. if(head == null) { //Checks if the list is empty 6. head = newNode;//If list is empty, both head and tail will point to ne w node 7. tail = newNode; 8. } 9. else { //add after tail such that tail's next will point to newNode 10. tail.next = newNode; 11. tail = newNode; //newNode will become new tail of the list Functions you should know • Add element to a list - First and Last. • Add element to a specific position. • Remove element - First and Last. • Remove an element in a specific position. • Remove all elements. Doubly Linked Lists Doubly Linked Lists • The type of linked list that allows us to go in both directions - forward and reverse – is a doubly linked list. • Doubly linked list allows for a great variety of quick update operations, including insertion and removal at both ends, and in the middle. • A node in a doubly linked list stores two references—a next link which points to the next node in the list, and a prev link, which points to the previous node in the list. Doubly linked list - Algorithm • Define a Node class that represents a node in the linked list. It should have 3 properties i.e. previous node, data, and the next node • Define another class to create a Doubly Linked List with two nodes i.e head and tail. Initially, these values will be null. • Create a function for adding nodes in the linked list, Doubly linked list – Algorithm Cont.. • It will first check whether the head is null and then insert the node as the head. • Both head and tail will then point to the new node. • If the tail is not null, the new node will be inserted at the list end in such a way that the pointer of the new node will point to the tail. • Thus, the new node will become a new tail. Node – Doubly linked list class Node { public int data; public Node prev; public Node next; public Node(int data) { this.data = data; } } Adding Data public void addNode(int data) { Node newNode = new Node(data); if(headNode == null) { headNode = tailNode = newNode; headNode.prevNode = null; tailNode.nextNode = null; } else { tailNode.nextNode = newNode; newNode.prevNode = tailNode; tailNode = newNode; tailNode.nextNode = null; } } Display Method public void displayNode() { Node currentNode = headNode; if(headNode == null) { System.out.println("Doubly Linked List is empty"); return; } System.out.println("Nodes in Doubly Linked List: "); while(currentNode != null) { System.out.print(currentNode.data + " "); currentNode = currentNode.nextNode; } } Add element to the Middle of a Doubly Linked List • Doubly linked lists also are convenient for maintaining a list of elements while allowing for insertion and removal in the middle of the list. • we can easily insert a new node z immediately after v. Let w be the node following v. We execute the following steps: 1. make z's prev 2. make z's next 3. make w's prev 4. make v's next link refer to v link refer to w link refer to z link refer to z Delete - beginning public void deleteInitialNode() { if(headNode == null) { System.out.println("Doubly Linked List is empty"); return; }else { if(headNode != tailNode) { headNode = headNode.nextNode; } else { headNode = tailNode = null; } } } Delete from the Middle of a Doubly Linked List • Likewise, it is easy to remove a node v in the middle of a doubly linked list. • We access the nodes u and w on either side of v using v’s specific methods to access the prev and the next nodes. • To remove node v, we simply have u and w point to each other instead of to v. • We refer to this operation as the linking out of v. • We also null out v's prev and next pointers so as not to retain old references into the list. Delete - Middle of a Doubly Linked List List: u v w List after removing v: u w Deference between singly linked list and doubly linked list Singly Linked List Doubly Linked List the complexity of insertion and deletion for a known index is O(n) the complexity of insertion and deletion for a known index is O(1) It has two segments: data and link It has three segments. First is data, second and third are the pointers. It permits traversal components only in one way It permits two way traversal. We mostly prefer a singly linked list for the execution of stacks We can use a doubly linked list to execute binary trees, heaps and stacks. When we want to save memory and do not need to perform searching, we prefer a singly linked list. In case of better implementation, while searching, we prefer a doubly linked list. A singly linked list consumes less memory as compared to the doubly linked list. The doubly linked list consumes more memory as compared to the singly linked list. References • https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html • https://www.softwaretestinghelp.com/linked-list-in-java/ • https://www.javaguides.net/2018/09/singly-linked-list-implementation-injava.html • https://www.simplilearn.com/tutorials/java-tutorial/linked-list-injava#:~:text=A%20linear%20data%20structure%20used,part%20and%20the%20a ddress%20part. • https://www.educba.com/java-doubly-linked-list/ • Data Structure and Algorithms – 2nd Edition – Chapter 5