0% found this document useful (0 votes)
18 views

Lecture 5 - Linked List

asd

Uploaded by

toprakcihalil0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

Lecture 5 - Linked List

asd

Uploaded by

toprakcihalil0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 58

SE 2005

DATA
STRUCTURES
INTRODUCTION
• Array: a linear collection of data elements in which the elements are stored in
consecutive memory locations.

• While declaring arrays, we have to specify the size of the array, which will restrict
the number of elements that the array can store.
– For example, if we declare an array as int marks[10], then the array can store a
maximum of 10 data elements but not more than that.
– But what if we are not sure of the number of elements in advance?

• Moreover, to make efficient use of memory, the elements must be stored


randomly at any location rather than in consecutive locations.
ARRAY VS LINKED LIST
• Like arrays,
– Linked List is a linear data structure.
– insertions and deletions can be done at any point in the list

• Unlike arrays, Linked lists


– are dynamic, so the length of a list can increase or decrease as necessary
– elements are not stored at a contiguous location.
– do not allow random access to data.
• Elements in a linked list can be accessed only in a sequential manner.
LINKED LIST
• A linked list is a set of dynamically allocated nodes, arranged in such a way that each node
contains one value (data) and one pointer (link or reference).
– The pointer always points to the next member of the list. If the pointer is NULL, then it is the last
node in the list

Since in a linked list, every node contains a pointer to another node which is of the same
type, it is also called a self-referential data type.

A head pointer is
used to track the
first element in the
linked list

Each node in the list is also called an element.


The programmer doesn’t have to guess the size of the linked list ahead of time.
If we need another node, we just get one and connect it to the list

Each node is allocated in the heap using malloc(), so the node memory
continues to exist until it is explicitly de-allocated using free().
MEMORY ALLOCATION PROCESS
• C programming language manages memory statically, automatically, or
dynamically.

Local Variables, Automatic


variables, Function Calls Stack

Free Memory
Heap

Global & Static Variables

Permanent
C Program Instructions Storage Area

Conceptual view of storage of a C program in memory


header

Std #1 Std #2 Std #3 Std #n


Memory heap

Std Std
2 n

header
Std
3 Std
Value of header=? 1

Value of header=2E450
list_

Linked List Object


ADVANTAGES/DISADVANTAGES
Advantages
• Dynamic size  There is no need to define an initial size
• Ease of insertion/deletion  Items can be added or removed from the middle
of the list
• Stacks and queues can be easily executed.

Disadvantages
• The memory is wasted as pointers require extra memory for storage.
• No element can be accessed randomly; it has to access each node sequentially.
• Reverse Traversing is difficult in linked list.
DECLARATION
• create a node of the linked list using a self-referential structure

// Declaring a Linked list


struct node { Info Next
int data; //stores the information
11
struct node* next; //pointer holds the address of the next node.
};

• declare a head pointer that always points to the first node of the list.
struct node* head;
DYNAMIC MEMORY ALLOCATION
• For example, the statement
newPtr = malloc( sizeof( struct node ) );

– evaluates sizeof(struct node) to determine the size in bytes of a structure


of type struct node,
– allocates a new area in memory of that number of bytes and stores a pointer
to the allocated memory in variable newPtr.

• The allocated memory is not initialized.


• If no memory is available, malloc returns NULL.
DYNAMIC MEMORY ALLOCATION (CONT.)
• Function free deallocates memory
– the memory is returned to the system so that it can be reallocated in the
future.
– free(newPtr);

• Memory Leak: Not returning dynamically allocated memory when it’s no longer
needed can cause system to run out of memory prematurely.
– Use free to return the memory to system.
TYPES OF LINKED LIST
– Singly Linked List

– Doubly Linked List

– Circular Linked List


• A circular linked list can be either singly linked or doubly linked.
BASIC LINKED LIST OPERATIONS

Insert Delete

Traverse Search
S I N G LY L I N K E D L I S T
INSERTION: IN SINGLY LINKED LIST AT BEGINNING
// Allocate the space for the new node malloc() is used to
struct node *ptr = (struct node *) malloc(sizeof(struct node *)); dynamically allocate a
// store data into the data part of the node single block of
memory in the heap,
ptr → data = data;
and and returns a
//make the link part of the newnode pointing to the existing first node of the list.
pointer to the new
ptr->next = head; block. It is available in
//make the new node as the first node of the list the header file
head = ptr; stdlib.h.

sizeof() is used to
determine size in
bytes of an element
in C. Here it is used
to determine size of
each node and sent
as a parameter to
malloc.
INSERTION: IN SINGLY LINKED LIST AT THE END
There are two scenarios
Scenario 1: (The list is Empty)  head == NULL
• .
// allocate the space for the created node
struct node *ptr = (struct node *) malloc(sizeof(struct node *));

//put the data in the related field


ptr->data = item;

//set the next pointer to NULL


ptr -> next = NULL;

//Since, ptr is the only node that will be inserted in the list, we need to make this node
pointed by the head pointer of the list
head = ptr
INSERTION: IN SINGLY LINKED LIST AT THE END
Scenario 2: The list contains at least one node  Head != NULL
// temporary pointer temp in order to traverse through the list.
// temp is made to point the first node of the list
temp = head
//traverse through the entire linked list to find the last node
//At the end of the loop, the temp will be pointing to the last node of the list.
while (temp→ next != NULL)
temp = temp → next;
//Assume we allocate the space for the new node (ptr) before, put the data in the related
field and set the next pointer to NULL.
//make the next part of the temp node (which is currently the last node of the list) point
to ptr
temp->next = ptr;
ptr->next = NULL;
INSERTION: IN SINGLY LINKED LIST AT THE END

temp = head

while (temp→ next != NULL)


temp = temp → next;

temp->next = ptr;
ptr->next = NULL;
INSERTION: IN SINGLY LINKED LIST AFTER
SPECIFIED NODE temp=head;

• we need to skip the desired number of elements for(i=0;i<loc;i++) {


in the list to move the pointer to the position temp = temp->next;
after which the node will be inserted.
if(temp == NULL)
return;
}

• Allocate the space for the new node and add the item to the data part of it.
ptr = (struct node *) malloc (sizeof(struct node));
ptr->data = item;
INSERTION: IN SINGLY LINKED LIST AFTER
SPECIFIED NODE

the next part of the new node


ptr must contain the address of
the next part of the temp

make the next part of the temp,


point to the new node ptr

The order is important to avoid losing the elements in right side.


SMALLISH QUESTION - 1
Assuming that we would like to
keep the list sorted, which of the
following list of commands
correctly inserts the new node into
the list

W: current->next = new
X: current= current->next
Y: new->next = current->next
Z: current = new A: X X X Y W
B: X X X X W Y
C: X X X W Y
D: X X X W Z Y
E: None of the above
SMALLISH QUESTION - 2
Consider the following linked list and
possible commands.Which correctly
orders the list?

A: c = c -‐> next
B: d = d -‐> next
C: c -‐> next = e
D: d -‐> next = c A: A A B E B B B F G:
B: A B B C E B F
E: e -‐> next = d
C: A C B B E B F
F: d -‐> next = NULL D: A B B C D G
G: e --‐> next = NULL E: none of the above
DELETION: IN SINGLY LINKED LIST AT BEGINNING

Since the first node of the list is to


be deleted, we should make the head,
free the pointer ptr which was point to the next node
pointing to the head node of
the list
DELETION: IN SINGLY LINKED LIST AT THE END
There are two scenarios

Senerio I: There is only one node in the list  head → next = NULL

ptr = head;
head = NULL;
free(ptr);
DELETION: IN SINGLY LINKED LIST AT THE END
Senerio 2: There are more than
one node in the list and the last
node of the list will be deleted
 head → next != NULL

ptr = head; //declare a temporary pointer (ptr)

// traverse the node in order to reach the last node of the list
//ptr1 will point to the second last node of the list
while(ptr->next != NULL) {
ptr1 = ptr;
ptr = ptr ->next;
}
ptr1->next = NULL;
free(ptr);
DELETION: IN SINGLY LINKED LIST AFTER THE
SPECIFIED NODE
• We need to keep track of the two nodes. The one which is to be deleted the other one
if the node which is present before that node. For this purpose, two pointers are used:
ptr and ptr1.
ptr=head;

for(i=0;i<loc;i++) {
ptr1 = ptr;
ptr = ptr->next;

if(ptr == NULL) {
printf("\nThere are less than %d elements in the list..",loc);
return;
}
}
DELETION: IN SINGLY LINKED LIST AFTER THE
SPECIFIED NODE
TRAVERSING IN
SINGLY LINKED LIST
• Traversing means visiting each node of the
list once in order to perform some
operation on that
• Traversing a list involves the following steps:
– Assign the address of start pointer to a temp
(here is ptr) pointer.
– Display the information from the data field of
each node
ptr = head;
while (ptr!=NULL)
{
ptr = ptr -> next;
}
SEARCHING IN
SINGLY LINKED LIST
• Searching any element in the list needs traversing
through the list and make the comparison of every
element of the list with the specified element.

• If the element is matched with any of the list


element then the location of the element is
returned from the function.
COUNTING THE NUMBER OF NODES
The following code will count the number of nodes exist in the list using recursion.

int countnode(node *st) {


if(st == NULL)
return 0;
else
return(1 + countnode(st -> next)); }
WHAT IS THE DISADVENTAGE OF SINGLY
LINKED LIST?

Do not look back!


D O U B LY L I N K E D L I S T
DOUBLY LINKED LIST (DLL)
• Doubly linked list consists of three parts:
– node data
– pointer to the next node in sequence (next pointer)
– pointer to the previous node (previous pointer)

struct node
{
int data;
struct node *prev; // Pointer to previous node in DLL
struct node *next; // Pointer to next node in DLL
}

struct node* head;


DOUBLY LINKED LIST
• The prev part of the first node and the next part of the last node will always contain
null indicating end in each direction.

• In a singly linked list, we could traverse only in one direction, because each
node contains address of the next node and it doesn't have any record of its previous
nodes. However, doubly linked list overcome this limitation of singly linked list.
MEMORY REPRESENTATION OF A DOUBLY
LINKED LIST
• In the image, the first element of the list
that is i.e. 13 stored at address 1. The head
pointer points to the starting address 1.
Since this is the first element being added
to the list therefore the prev of the
list contains null. The next node of the list
resides at address 4 therefore the first node
contains 4 in its next pointer.

• We can traverse the list in this way until we


find any node containing null or -1 in its
next part.
INSERTION: IN DOUBLY LINKED LIST IF THE
LIST IS EMPTY

//Allocate the space for the new node in the memory


ptr = (struct node *)malloc(sizeof(struct node));

ptr->data=item;
ptr->next = NULL;
ptr->prev=NULL;

head=ptr;
(ptr)
INSERTION: IN DOUBLY LINKED LIST AT BEGINNING

//Allocate the space for the new node in the memory


ptr = (struct node *)malloc(sizeof(struct node));
/* Given a reference (pointer to pointer) to the head of a list and an data, inserts a new node on the front
of the list. */

void push(struct Node** head_ref, int new_data)


{
/* 1. allocate node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));

/* 2. put in the data */


new_node->data = new_data;

/* 3. Make next of new node as head and previous as NULL */


new_node->next = (*head_ref);
new_node->prev = NULL;

/* 4. change prev of head node to new node */


if ((*head_ref) != NULL)
(*head_ref)->prev = new_node;
https://stackoverflow.com/questions/727164
/* 5. move the head to point to the new node */
7/what-is-the-reason-for-using-a-double-
(*head_ref) = new_node; pointer-when-adding-a-node-in-a-linked-lis
}
WHY WE USE DOUBLE POINTER?
// note that there's no return value: it's not needed
void push(struct node** head, int data) {
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=*head;
*head = newnode; // *head stores the newnode in the head
}

push(&head,1); // and call like this:

struct node* push(struct node* head, int data) {


struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=head;
return newnode;
If you don't do this assignment }
when calling this function, you will
be leaking the nodes you allocate //note the assignment of the result to the head pointer
with malloc, and the head pointer head = push(head,1);
will always point to the same node.
INSERTION: IN DOUBLY LINKED LIST AT THE END

we have to traverse the whole list


in order to reach the last node of
the list.

temp = head;

while (temp != NULL)


{
temp = temp → next;
}
/* Given a reference (pointer to pointer) to the head of a DLL and an int, /* 6. Change the next of last node */
appends a new node at the end */ last->next = new_node;
void append(struct Node** head_ref, int new_data) {
/* 1. allocate node */ /* 7. Make last node as previous of new node
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); */
new_node->prev = last;
struct Node* last = *head_ref; /* used in step 5*/
return;
/* 2. put in the data */ }
new_node->data = new_data;

/* 3. This new node is going to be the last node, so make next of it as


NULL*/
new_node->next = NULL;

/* 4. If the Linked List is empty, then make the new node as head */
if (*head_ref == NULL) {
new_node->prev = NULL;
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
INSERTION: IN DOUBLY LINKED LIST AFTER
SPECIFIED NODE
• In order to insert a node after the specified node in the list, we need to skip the required
number of nodes in order to reach the mentioned node and then make the pointer
adjustments as required.

– Allocate the memory for the new node ptr = (struct node *)malloc(sizeof(struct node));

– Traverse the list by using the


temp=head;
pointer temp to skip the required
number of nodes in order to reach the for(i=0;i<loc;i++) {
specified node. temp = temp->next;
}
The temp would point to the
specified node at the end of
the for loop.
INSERTION: IN DOUBLY LINKED LIST AFTER
SPECIFIED NODE
/* Given a node as prev_node, insert a new node after the given
node */

void insertAfter(struct Node* prev_node, int new_data) {


/*1. check if the given prev_node is NULL */
if (prev_node == NULL) {
printf("the given previous node cannot be NULL");
return;
}

/* 2. allocate new node */


struct Node* new_node = (struct Node*)malloc(sizeof(struct
Node));

/* 3. put in the data */


new_node->data = new_data;

/* 4. Make next of new node as next of prev_node */


new_node->next = prev_node->next;

/* 5. Make the next of prev_node as new_node */


prev_node->next = new_node; /* 7. Change previous of new_node's next node */
if (new_node->next != NULL)
/* 6. Make prev_node as previous of new_node */ new_node->next->prev = new_node;
new_node->prev = prev_node; }
DELETION : IN DOUBLY LINKED LIST AT BEGINNING
DELETION : IN DOUBLY LINKED LIST AT END
• Need traversing the list in order to reach the last node of the list and then make
pointer adjustments at that position.

• If there is only one node in the list then


– we just need to assign the head of the list to NULL and free head in order to
completely delete the list.

• Otherwise, just traverse the list to reach the last node of the list.

ptr = head;

if(ptr->next != NULL) {
ptr = ptr -> next;
}
DELETION: IN DOUBLY LINKED LIST AT END

(ptr)
DELETION: IN DOUBLY LINKED LIST AFTER THE
SPECIFIED NODE

• Copy the head pointer into a temporary pointer temp. temp = head

• Traverse the list until we find the desired data value. while(temp -> data != val)
temp = temp -> next;

• Check if this is the last node of the list. If it is so then we


can't perform deletion. if(temp -> next == NULL)
{
return;
}
DELETION
DELETION IN DOUBLY LINKED LIST AFTER THE SPECIFIED
NODE

• Check if the node which is to be deleted, is the last node of the list, if it so then we have to
make the next pointer of this node point to null so that it can be the new last node of the list.

if(temp -> next -> next == NULL)


{
temp ->next = NULL;
}

• Otherwise, make the pointer ptr point to the node which is to be deleted. Make the next of
temp point to the next of ptr. Make the previous of next node of ptr point to temp. free the ptr.
ptr = temp -> next;
temp -> next = ptr -> next;
ptr -> next -> prev = temp;
free(ptr);

You might also like