Is linked list important in programming?

Operations on Linked Lists

We studied the fundamentals of linked lists in previous lesson. Linked lists are dynamic data structures where nodes can be added, deleted or updated with a minimal cost. Also linked lists do not require access to a large contiguous block of memory at compile time, but rather accessing memory as needed during runtime. This flexibility makes linked lists attractive data structures for many practical applications.

In this lesson, we will focus on some of the basic operations on linked lists such as adding, deleting and updating node elements. In an array, adding or deleting an entry requires shifting of the array to �fill� or �create� holes. Updating an entry in an array only requires accessing entry by its index and changing its value. One of the best features of the array data structure is its ability to access entries in a random access manner. That is, given the index of the entry we can easily find it.

Unlike arrays, the entry point into any linked list is the head of the list. Head of the list is not a node but a reference to the first node in the list. In other words, head can be considered a lvalue. In an empty list the value of head is equal to null. We also know that any linked list ends with null pointer [unless it is a circular linked list where last node is connected to the head node]. We must take great care in manipulating linked lists since any misguided link in the middle will make the entire list inaccessible. This is because the only way to navigate a list is by using a reference to the next node from the current node. Often referred as �memory leaks�, if a reference to a node is lost, then the entire list from that point on may not be accessible.

BASIC OPERATIONS

Some of the basic operations that can be performed on a linked list are

1. Traversing a linked list.

2. Appending a new node [to the end] of the list

3. Prepending a new node [to the beginning] of the list

4. Inserting a new node to a specific position on the list

5. Deleting a node from the list

6.��� Updating the data of a linked list node

Traversing a Linked List

A linked list is a linear data structure that needs to be traversed starting from the head node until the end of the list. Unlike arrays, where random access is possible, linked list requires access to its nodes through sequential traversal. Traversing a linked list is important in many applications. For example, we may want to print a list or search for a specific node in the list. Or we may want to perform an advanced operation on the list as we traverse the list. The algorithm for traversing a list is fairly trivial.

a. Start with the head of the list. Access the content of the head node if it is not null.

b. Then go to the next node[if exists] and access the node information

c. Continue until no more nodes [that is, you have reached the last node]

Appending a new Node to the end of the list

Sometimes we need to append [or insert to end] new nodes to the end of a list. Since we only have information about the head of the list, we need to traverse the list until we find the last node. Then we insert new node to the end of the list. In this case, it is important to consider special cases such as list being empty.

���������������

������� ���������head��������������������������� ����������last

Let us consider a method append that inserts nodes to the end of the list.

public void append[Node N ] {

�� Node ptr, prev;

��� ptr = prev = head;

��� while [ptr != null]�� ptr = ptr.next;� // assume next is a public field in the node class

��� prev.next = N;� N.next = null;

}

Question: Does this code always work? Can you find a case where the code fails to work?

Prepending a new Node to the beginning of the list

Let us try to prepend a new node to the beginning of a list or in other words insert a node to the beginning of the list. Prepending a node to a list is easy since there is no need to traverse the list and find the place to insert into the list. If list is empty, we make new node the head of the list. Otherwise, we connect new node to the current head of the list and make new node the head of the list.

������������

���������������� �New head� �����������Old� head����

public void prepend[Node N ] {

��� if [head == null]� head = N;

��� else { N.next = head; head = N;}

}

Question: Does this code always work? Can you find a case where the code fails to work [if any]?

Inserting a new Node to an arbitrary position in the list

Suppose we need to insert [to some specific location] a new node to a list. It is important that we traverse the list to find the place to insert the node. In the traversal process, we must maintain a reference to previous and next nodes of the list. Then we will insert a new node between previous and next.

����������������

����������������� prev ��������������������������������������ptr

public void insertInOrder[Node N ]{

����� Node prev, ptr;

����� prev = ptr = head;

����� while [ptr != null && N.compareTo[ptr] > 0] { prev = ptr; ptr = ptr.next;}

���� prev.next = N;� N.next = ptr;

}

Question: Are all cases covered in the above code?

We did use few methods like compareTo in the above code. Our assumption is that compareTo method is implemented by our Linked List class. We also assume that our linked list class has implemented the Comparable interface. compareTo method returns 0, 1 or -1 based on if the first node is equal, bigger or less than the second node.

Deleting a Node from the list

To delete a specific node from the list [if the node exists]. It is important that we traverse the list to find the node to delete. In the traversal process, we must maintain a reference to previous node of the list. Unlike in other programming languages [such as C] we don�t need to worry about deallocating memory associated with the deleted node, since Java garbage collector takes care of this.

���������������� ����

�������������������� prev��������������� �������������

Let us take a look at the code to delete a node.

public void delete[Node N ] {

���� Node prev, ptr;

���� while [ptr != null &&� ptr.compareTo[N] != 0]� { prev = ptr; ptr = ptr.next;}

���� if [ptr == null]� return;

���� prev.next = ptr.next;

}

Question: Does the above code covers all special cases of deleting a node? What if the node does not exists? What if the node to be deleted turns out to be the very first node? What if node to be deleted turns out to be the last node in the list?

Conclusion

In this lesson we learned how to traverse, append, prepend, insert and delete nodes from a linked list. These operations are quite useful in many practical applications. Suppose you are the programmer responsible for an application like Microsoft powerpoint. We can think of a powerpoint presentation as a list, whose nodes are the individual slides. In the process of creating and managing slides we can use the concepts such as inserting and deleting nodes learned in this lesson. Many other applications may require you to think of an abstraction like a list, where list can be easily maintained. In the next lesson we will learn more advanced list operations such as reversing a list, swapping nodes and sorting a list etc. Linked lists remain one of the widely used concepts in programming applications. More advanced linked list structures like an array of linked lists, or linked list of linked lists or multilinked lists can be used to implement applications that require complex data structures.

Video liên quan

Chủ Đề