e computer notes - methods of linked list

21
ecomputernotes.com – Data Structures Lecture No. 04 _________________________________________________________ __________ Data Structures Lecture No. 04 Methods of Linked List In the previous lecture, we discussed the methods of linked list. These methods form the interface of the link list. For further elucidation of these techniques, we will talk about the start method that has the following code. // position currentNode and lastCurrentNode at first element void start() { lastCurrentNode = headNode; currentNode = headNode; }; There are two statements in this method. We assign the value of headNode to both lastCurrentNode and currentNode. These two pointers point at different nodes of the list. Here we have pointed both of these pointers at the start of the list. On calling some other method like next, these pointers will move forward. As we can move in the singly- linked list in one direction, these pointers cannot go behind headNode. We will now see how a node can be removed from the link list. We use the method remove for this purpose. void remove() { if( currentNode != NULL && currentNode != headNode) { Page 1 of 21

Upload: ecomputernotes

Post on 10-Jan-2017

175 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

Data Structures

Lecture No. 04

Methods of Linked ListIn the previous lecture, we discussed the methods of linked list. These methods form the interface of the link list. For further elucidation of these techniques, we will talk about the start method that has the following code.

// position currentNode and lastCurrentNode at first elementvoid start() {

lastCurrentNode = headNode;currentNode = headNode;

};

There are two statements in this method. We assign the value of headNode to both lastCurrentNode and currentNode. These two pointers point at different nodes of the list. Here we have pointed both of these pointers at the start of the list. On calling some other method like next, these pointers will move forward. As we can move in the singly-linked list in one direction, these pointers cannot go behind headNode.

We will now see how a node can be removed from the link list. We use the method remove for this purpose.

void remove() { if( currentNode != NULL && currentNode != headNode) {

(step 1) lastCurrentNode->setNext(currentNode->getNext());(step 2) delete currentNode;(step 3) currentNode = lastCurrentNode->getNext();(step 4) size--;

}};

Page 1 of 15

76 1

headNodecurrentNode

Size = 5

lastCurrentNode

2 8

Page 2: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

Suppose that the currentNode is pointing at the location that contains the value 6. A request for the removal of the node is made. Resultantly, the node pointed by currentNode should be removed. For this purpose, at first, the next pointer of the node with value 2 (the node pointed by the lastCurrentNode pointer), that is before the node with value 6, bypasses the node with value 6. It is, now pointing to the node with value 8. The code of the first step is as:

lastCurrentNode->setNext(currentNode->getNext());

What does the statement currentNode->getNext() do? The currentNode is pointing to the node with value 6 while the next of this node is pointing to the node with value 8. That is the next pointer of node with value 6 contains the address of the node with value 8. The statement lastCurrentNode->setNext(currentNode->getNext()) will set the next pointer of the node pointed by the lastCurrentNode to the node with value 8. So the next pointer of the node with value 2 is pointing to the node with value 8.

You see that the next pointer of the node having data element 2 contains the address of the node having data element 8. The node with value 6 has been disconnected from the chain while the node with value 2 is connected to the node with the value 8.

The code of the next step is:

delete currentNode;

You already know, in case of allocation of the memory with the help of the new keyword, the delete statement releases this memory which returns the memory to the system. Pictorially it can be represented as:

Page 2 of 15

76 1

headNode

currentNode

Size = 5

lastCurrentNode

2 8

Step1

Page 3: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

In the next step, we have moved the currentNode to point the next node. The code is:

currentNode = lastCurrentNode->getNext();

In the fourth step, the size of the list has been reduced by 1 after the deletion of one node i.e.

size--;

The next method is length() that simply returns the size of the list. The code is as follows:

// returns the size of the listint length() {

return size; };

The private data members of the list are:

private:int size; // contains the size of the listNode *headNode; // points to the first node of the listNode *currentNode, // current nodeNode *lastCurrentNode; // last current node

Page 3 of 15

7 1

headNode

currentNode

Size = 5

lastCurrentNode

2 8

Step1

Step2

7 1

headNode

currentNode

Size = 4

lastCurrentNode

2 8

Step1

Step2

Step3

Step4

Page 4: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

The list class completed just now, can be termed as list factory. We have included all the required methods in it. We may employ more methods if required. A programmer can get the size of the list, add or remove nodes in it besides moving the pointers.

Example of list usage

Now let’s see how we use the link list. Here is an example showing the use of list:

/* A simple example showing the use of link list */

#include <iostream>#include <stdlib.h>#include "List.cpp" // This contains the definition of List class

// main methodint main(int argc, char *argv[]){

List list; // creating a list object

// adding values to the listlist.add(5); list.add(13); list.add(4);list.add(8); list.add(24); list.add(48); list.add(12);

// calling the start method of the listlist.start();

// printing all the elements of the listwhile (list.next())

cout << "List Element: "<< list.get()<<endl;}

The output of the program is:

List Element: 5List Element: 13List Element: 4List Element: 8List Element: 24List Element: 48List Element: 12

Let’s discuss the code of the above program. We have included the standard libraries besides having the “List.cpp” file. Usually we do not include .cpp files. Rather, the .h

Page 4 of 15

Page 5: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

files are included. Whenever you write a class, two files will be created i.e. .h (header file containing the interface of the class) and .cpp (implementation file). Here for the sake of explanation, we have combined the two files into “List.cpp” file. At the start of the main method, we have created a list object as:

List list;

Here the default constructor will be called. If you understand the concept of factory, then it is not difficult to know that we have asked the List factory to create a List object and named it as list. After creating the object, nodes have been added to it. We have added the elements with data values 5, 13, 4, 8, 24, 48 and 12. Later, the start() method of list is called that will position the currentNode and lastCurrentNode at the start of the list. Now there is no need to worry about the implementation of the List. Rather, we will use the interface of the List. So the start method will take us to the start of the list and internally, it may be array or link list or some other implementation. Then there is a while loop that calls the next() method of the List. It moves the pointer ahead and returns a boolean value i.e. true or false. When we reach at the end of the list, the next() method will return false. In the while loop we have a cout statement that prints the value of the list elements, employing the get() method. The loop will continue till the next() method returns true. When the pointers reach at the end of the list the next() will return false. Here the loop will come to an end.

Please keep in mind that list is a very important data structure that will be used in the entire programming courses.

Analysis of Link ListAs stated earlier, we will be going to analyze each data structure. We will see whether it is useful or not. We will see its cost and benefit with respect to time and memory. Let us analyze the link list which we have created with the dynamic memory allocation in a chain form.

addFor the addition purposes, we simply insert the new node after the current node. So ‘add’ is a one-step operation. We insert a new node after the current node in the chain. For this, we have to change two or three pointers while changing the values of some pointer variables. However, there is no need of traversing too much in the list. In case of an array, if we have to add an element in the centre of the array, the space for it is created at first. For this, all the elements that are after the current pointer in the array, should be shifted one place to the right. Suppose if we have to insert the element in the start of the array, all the elements to the right one spot are shifted. However, for the link list, it is not something relevant. In link lists, we can create a new node very easily where the current pointer is pointing. We have to adjust two or three pointers. Its cost, in terms of CPU time or computing time, is not much as compared to the one with the use of arrays.

remove

Remove is also a one-step operation. The node before and after the node to be removed is connected to each other. Update the current pointer. Then the node to

Page 5 of 15

Page 6: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

be removed is deleted. As a result, the node to be removed is deleted. Very little work is needed in this case. If you compare it with arrays, for the deletion of an element from the array, space is created. To fill this space, all the right elements are shifted one spot left. If the array size is two thousand or three thousand, we need to run a loop for all these elements to shift them to left.

findThe worst-case in find is that we may have to search the entire list. In find, we have to search some particular element say x. If found, the currentNode pointer is moved at that node. As there is no order in the list, we have to start search from the beginning of the list. We have to check the value of each node and compare it with x (value to be searched). If found, it returns true and points the currentNode pointer at that node otherwise return false. Suppose that x is not in the list, in this case, we have to search the list from start to end and return false. This is the worst case scenario. Though time gets wasted, yet we find the answer that x is not in the list. If we compare this with array, it will be the same. We don’t know whether x is in the array or not. So we have to search the complete array. In case of finding it, we will remember that position and will return true. What is the average case? x can be found at the first position , in the middle or at the end of the list. So on average, we have to search half of the list.

backIn the back method, we move the current pointer one position back. Moving the current pointer back, one requires traversing the list from the start until the node whose next pointer points to current node. Our link list is singly linked list i.e. we can move in one direction from start towards end. Suppose our currentNode pointer and lastCurrentNode are somewhere in the middle of the list. Now we want to move one node back. If we have the pointer of lastCurrentNode, it will be easy. We will assign the value of lastCurrentNode to currentNode. But how can we move the lastCurrentNode one step back. We don’t have the pointer of previous node. So the solution for this is to go at the start of the list and traverse the list till the time you reach the node before the lastCurrentNode is pointing. That will be the node whose next pointer contains the value lastCurrentNode. If the currentNode and the lastCurrentNode are at the end of the list, we have to traverse the whole list. Therefore back operation is not a one step operation. We not only need a loop here but also require time.

Doubly-linked ListIf you look at single link list, the chain is seen formed in a way that every node has a field next that point to the next node. This continues till the last node where we set the next to NULL i.e. the end of the list. There is a headNode pointer that points to the start of the list. We have seen that moving forward is easy in single link list but going back is difficult. For moving backward, we have to go at the start of the list and begin from there. Do you need a list in which one has to move back or forward or at the start or in the end very often? If so, we have to use double link list.

In doubly-link list, a programmer uses two pointers in the node, i.e. one to point to next node and the other to point to the previous node. Now our node factory will

Page 6 of 15

Page 7: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

create a node with three parts.

First part is prev i.e. the pointer pointing to the previous node, second part is element, containing the data to be inserted in the list. The third part is next pointer that points to the next node of the list. The objective of prev is to store the address of the previous node.

Let’s discuss the code of the node of the doubly-link list. This node factory will create nodes, each having two pointers. The interface methods are same as used in singly link list. The additional methods are getPrev and setPrev. The method getPrev returns the address of the previous node. Thus its return type is Node*. The setPrev method sets the prev pointer. If we have to assign some address to prev pointer, we will call this method. Following is the code of the doubly-linked list node.

/* this is the doubly-linked list class, it uses the next and prev pointers */

class Node {public:

int get() { return object; }; // returns the value of the elementvoid set(int object) { this->object = object; }; // set the value of the element

Node* getNext() { return nextNode; }; // get the address of the next nodevoid setNext(Node* nextNode) // set the address of the next node

{ this->nextNode = nextNode; };

Node* getPrev() { return prevNode; }; // get the address of the prev nodevoid setPrev(Node* prevNode) // set the address of the prev node

{ this->prevNode = prevNode; };private:

int object; // it stores the actual value of the elementNode* nextNode; // this points to the next nodeNode* prevNode; // this points to the previous node

};

Most of the methods are same as those in singly linked list. A new pointer prevNode is added and the methods to get and set its value i.e. getPrev and setPrev. Now we will use this node factory to create nodes.

You have to be very cautious while adding or removing a node in a doubly linked list. The order in which pointers are reorganized is important. Let’s have a pictorial view of doubly-link list. The diagram can help us understand where the prevNode and nextNode are pointing.

Page 7 of 15

element nextprev

Page 8: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

This is a doubly link list. The arrows pointing towards right side are representing nextNode while those pointing towards left side are representing prevNode. Suppose we are at the last node i.e. the node with value 1. In case of going back, we usually take the help of prevNode pointer. So we can go to the previous node i.e. the node with value 7 and then to the node with value 8 and so on. In this way, we can traverse the list from the end to start. We can move forward or backward in doubly-link list very easily. We have developed this facility for the users to move in the list easily.

Let’s discuss other methods of the doubly-linked list. Suppose we have created a new node from the factory with value 9. We will request the node factory to create a new object using new keyword. The newly created node contains three fields i.e. object, prevNode and nextNode. We will store 9 into object and connect this new node in the chain. Let’s see how the pointers are manipulated to do that. Consider the above diagram, the current is pointing at the node with value 6. The new node will be inserted between the node with value 6 and the one with value 8.

In the first step, we assign the address of the node with value 8 to the nextNode of the new node.

newNode->setNext( current->getNext() );

In the next step, a programmer points the prevNode of the newNode to the node with value 6.

newNode->setprev( current );

Page 8 of 15

size=52 6 8 7 1head

current

size=52 6 8 7head

current

1

9newNode 1

Page 9: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

In the third step, we will set the previous node with value 8 to point to the newNode.

(current->getNext())->setPrev(newNode);

Now the prevNode of the node with value 8 is pointing to the node with value 9. In the fourth step, the nextNode of the node with value 6 is pointing to the newNode i.e. the node with value 9. Point the current to the newNode and add one to the size of the list.

current->setNext( newNode );current = newNode;size++;

Now the newNode has been inserted between node with value 6 and node with value 8.

Page 9 of 15

size=52 6 8 7head

current

1

9newNode 1

2

9 1

size=52 6 8 7head

current

1

newNode

2 3

size=62 6 8 7head

current

1

9newNode 1

2 34

Page 10: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

Circularly-linked listsLet’s talk about circularly linked list. The next field in the last node in a singly-linked list is set to NULL. The same is the case in the doubly-linked list. Moving along a

singly-linked list has to be done in a watchful manner. Doubly-linked lists have two NULL pointers i.e. prev in the first node and next in the last node. A way around this potential hazard is to link the last node with the first node in the list to create a circularly-linked list.

The next method in the singly-linked list or doubly-linked list moves the current pointer to the next node and every time it checks whether the next pointer is NULL or not. Similarly the back method in the double-linked list has to be employed carefully if the current is pointing the first node. In this case, the prev pointer is pointing to NULL. If we do not take care of this, the current will be pointing to NULL. So if we try to access the NULL pointer, it will result in an error. To avoid this, we can make a circularly linked list.

We have a list with five elements. We have connected the last node with the first node. It means that the next of the last node is pointing towards the first node.

The same list has been shown in a circular shape.

You have noticed that there is no such node whose next field is NULL. What is the benefit of this? If you use the next or back methods that move the current pointer, it

Page 10 of 15

2 6 8 7 1head

current

size=5

2

8

7

1

head

current

size=5

6

Page 11: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

will never point to NULL. It may be the case that you keep on circulating in the list. To avoid this, we get help from the head node. If we move the head node in the circularly linked list, it will not be certain to say where it was pointing in the start. Its advantages depend on its use. If we do not have to move too much in the list and have no problem checking the NULL, there is little need a circularly-linked list. But this facility is available to us.

In this example, we made a circular linked list from a singly link list. In a singly link list we move in one direction. We point the next pointer of the last node to the first node. We can do the same with the doubly-linked list. The prev pointer of the first node will point to the last node and the next pointer of the last node will point to the first node. If you arrange all the nodes in a circle, one of the pointers (i.e. next pointer) will move in clockwise direction while the prev pointers in anti-clockwise direction. With the help of these pointers, you can move in the clockwise direction or anti-clockwise direction. Head node pointer will remain at its position. You don’t need to change it. If there is a need to remove the node pointed by head node than you have to move the head pointer to other node. Now we don’t have any NULL pointer in the doubly-linked list. We will not get any exception due to NULL pointers.

Josephus ProblemNow we will see an example where circular link list is very useful. This is Josephus Problem. Consider there are 10 persons. They would like to choose a leader. The way they decide is that all 10 sit in a circle. They start a count with person 1 and go in clockwise direction and skip 3. Person 4 reached is eliminated. The count starts with the fifth and the next person to go is the fourth in count. Eventually, a single person remains.

You might ask why someone has to choose a leader in this way. There are some historical stories attached to it. This problem is also studied in mathematics. Let’s see its pictorial view.

We have ten numbers representing the ten persons who are in a circle. The value of M shows the count. As the value of M is three, the count will be three. N represents the number of persons. Now we start counting clockwise. After counting up to three, we have the number four. The number four is eliminated and put in the eliminated

Page 11 of 15

N=10, M=34

5

6

7

8910

1

2

3

Page 12: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

column.

After eliminating the number four, we will start our counting from number five. Counting up to three, we have number eight which is eliminated and so on.

In the end, only number five will remain intact.

Page 12 of 15

N=10, M=34

5

6

7

8910

1

2

3

N=10, M=34

5

6

7

8

910

1

2

3

Eliminated

Eliminated

Page 13: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

If we have ten persons (N = 10) in a circle and eliminate after counting up to three (M = 3). If we start our count from one, who will be the leader? We have studied this earlier and know that the person who is sitting at the fifth position will become the leader.

Suppose if the value of N is 300 or 400 and the value of M is 5 or 10. Now who will be the leader? This is a mathematical problem where we can change the values of N and M. There is a formula where the values of N, M are allotted. You can calculate who should become the leader. Here we will not solve it mathematically. Rather, it will be tackled as a computer problem. If you analyze the pictures shown above, it gets clear that this can be solved with the circular link list. We arrange these numbers in a circularly-linked list, point the head pointer at the starting number and after calling the next method for three times, we will reach the node which is to be removed. We will use the remove method to remove the node. Then the next method is called thrice from there and the node is removed. We will continue this till we have only one node.

We are not concerned with the NULL pointers, internal to link list. However, if you want to solve this problem and choose the best data structure, then circular link list is the best option. We can also use the list to solve this.

Let’s see the code of the program by which we can solve this problem. The code is as under:

/*This program solves the Josephus Problem */

#include <iostream.h>#include "CList.cpp" //contains the circularly-linked list definition

Page 13 of 15

N=10, M=34

5

6

7

8

9

10

1

2

3

Eliminated

Page 14: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

// The main methodvoid main(int argc, char *argv[]){

CList list; // creating an object of listint i, N=10, M=3;for(i=1; i <= N; i++ ) list.add(i); // initializing the list with values

list.start(); // pointing the pointers at the start of the list

// counting upto M times and removing the elementwhile( list.length() > 1 ) { for(i=1; i <= M; i++ ) list.next();

cout << "remove: " << list.get() << endl; list.remove();

}

cout << "leader is: " << list.get() << endl; //displaying the remaining node}

We have included the “CList.cpp”. It means that we are using the circularly-linked list. In the main method, CList factory is called to create a circular link list as CList list; After this, we assign the values to N and M. We have used for loop to add the nodes in the list. When this loop finishes, we have ten nodes in the list having values from 1 to 10. But here a programmer may not pay attention to the internal details of the list. We have created a list and stored ten numbers in it. Then we moved the pointers of the list at the start of the list using the start method. It means that the pointers are pointing at the position from where we want to start the counting of the list.

There is a while loop that will continue executing until only one node is left in the list. Inside this loop, we have a for loop. It will execute from 1 to M. It has only one statement i.e. list.next(). This will move the pointer forward three times (as the value of M is 3). Now the current pointer is at the 4 th node. We called the remove method. Before removing the node, we display its value on the screen using cout. Again we come into the while loop, now the length of the list is 9. The ‘for loop’ will be executed. Now the list.next() is not starting from the start. It will start from the position where the current pointer is pointing. The current pointer is pointing at the next node to the node deleted. The count will start again. The list.next() will be called for three times. The current pointer will point at the 8 th node. Again the remove method will be called and the current pointer moved to the next node and so on. The nodes will be deleted one by one until the length of the list is greater than one. When the length of the list is one, the while loop will be terminated. Now only one node is left in the list i.e. the leader. We will display its value using the get method.

We can change the values of M and N. Similarly, these values can be read from the file or can use the command line arguments to get values. There are many variations of this problem. One variation is that the value of M keeps on changing. Sometimes, it

Page 14 of 15

Page 15: e computer notes - Methods of linked list

ecomputernotes.com – Data Structures Lecture No. 04___________________________________________________________________

is 3, sometimes 4 or 5 and so on. Due to this, it will become difficult to think that who will become leader. Make a picture in your mind that ten persons are sitting in a circle. Every time the value of M is incremented by one. Now try to ascertain which position you should sit to get chosen as a leader. You may like to write a program to solve this or use the mathematical formula.

Page 15 of 15