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

Unit 1

The document provides an overview of data structures, focusing on arrays, their types, and operations such as search, insert, and delete. It also covers concepts of recursion, time complexity, and asymptotic analysis, including Big O and Omega notations. Additionally, it explains how to calculate memory addresses in row-major and column-major orders.

Uploaded by

crystal2moon2004
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Unit 1

The document provides an overview of data structures, focusing on arrays, their types, and operations such as search, insert, and delete. It also covers concepts of recursion, time complexity, and asymptotic analysis, including Big O and Omega notations. Additionally, it explains how to calculate memory addresses in row-major and column-major orders.

Uploaded by

crystal2moon2004
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 86

Unit 1

What is Data Structure?


• Data Structure is a particular way of storing and
organizing data in the memory of the computer so that
these data can easily be retrieved and efficiently
utilized in the future when required. The data can be
managed in various ways, like the logical or
mathematical model for a specific organization of data
is known as a data structure.
Arrays
• An array is a collection of items of the same variable type that are stored at
contiguous memory locations.

Types of Array
1.One-Dimensional Array: An Array with only one row of data elements is
known as a One-Dimensional Array. It is stored in ascending storage location.
2.Two-Dimensional Array: An Array consisting of multiple rows and columns
of data elements is called a Two-Dimensional Array. It is also known as a
Matrix.
3.Multidimensional Array: We can define Multidimensional Array as an Array
of Arrays. Multidimensional Arrays are not bounded to two indices or two
dimensions as they can include as many indices are per the need.
Array Operations
• Search
• Insert
• Delete

• Search Operation:
• In an unsorted array, the search operation can be
performed by linear traversal from the first element to
the last element
• Time Complexity: O(N)
• // C++ program to implement linear • int arr[] = { 12, 34, 10, 6, 40 };
• // search in unsorted array • int n = sizeof(arr) / sizeof(arr[0]);
• #include <bits/stdc++.h>
• using namespace std; • // Using a last element as search element
• int key = 40;
• // Function to implement search operation
• int findElement(int arr[], int n, int key) • // Function call
• { • int position = findElement(arr, n, key);
• int i;
• for (i = 0; i < n; i++) • if (position == -1)
• if (arr[i] == key) • cout << "Element not found";
• return i; • else
• • cout << "Element Found at Position: "
• // If the key is not found • << position + 1;
• return -1;
• } • return 0;
• }
• int main()
• {
Insert Operation:
• 1. Insert at the end:
• In an unsorted array, the insert operation is faster as
compared to a sorted array because we don’t have to
care about the position at which the element is to be
placed.
• #include <iostream> • int arr[20] = { 12, 16, 20, 40, 50, 70 };
• using namespace std; • int capacity = sizeof(arr) / sizeof(arr[0]);
• int n = 6;
• // Inserts a key in arr[] of given capacity. • int i, key = 26;
• // n is the current size of arr[]. This
• // function returns n + 1 if insertion • cout << "Before Insertion: ";
• // is successful, else n. • for (i = 0; i < n; i++)
• int insertSorted(int arr[], int n, int key, int capacity) • cout << arr[i] << " ";
• {
• // Cannot insert more elements if n is • // Inserting key
• // already more than or equal to capacity • n = insertSorted(arr, n, key, capacity);
• if (n >= capacity)
• return n; • cout << "\nAfter Insertion: ";
• for (i = 0; i < n; i++)
• arr[n] = key; • cout << arr[i] << " ";
• return (n + 1);
• } • return 0;
• }
• int main()
• {
• 2. Insert at any position
• Insert operation in an array at any position can be
performed by shifting elements to the right, which are
on the right side of the required position
• // C++ Program to Insert an element • int n = 5;
• // at a specific position in an Array
• cout<<"Before insertion : ";
• #include <bits/stdc++.h> • for (int i = 0; i < n; i++)
• using namespace std; • cout<<arr[i]<<" ";

• // Function to insert element • cout<<endl;


• // at a specific position
• void insertElement(int arr[], int n, int x, int pos) • int x = 10, pos = 2;
• {
• // shift elements to the right • // Function call
• // which are on the right side of pos • insertElement(arr, n, x, pos);
• for (int i = n - 1; i >= pos; i--) • n++;
• arr[i + 1] = arr[i];
• cout<<"After insertion : ";
• arr[pos] = x; • for (int i = 0; i < n; i++)
• } • cout<<arr[i]<<" ";

• int main() • return 0;


• { • }
• int arr[15] = { 2, 4, 1, 8, 5 };
• Delete Operation:
• In the delete operation, the element to be deleted is
searched using the linear search, and then the delete
operation is performed followed by shifting the
elements.
• #include <iostream> • return -1;
• using namespace std; • }
• int findElement(int arr[], int n, int key); • int main()
• int deleteElement(int arr[], int n, int key) • {
• { • int i;
• // Find position of element to be deleted • int arr[] = { 10, 50, 30, 40, 20 };
• int pos = findElement(arr, n, key);
• if (pos == -1) { • int n = sizeof(arr) / sizeof(arr[0]);
• cout << "Element not found"; • int key = 30;
• return n;
• } • cout << "Array before deletion\n";
• int i; • for (i = 0; i < n; i++)
• for (i = pos; i < n - 1; i++) • cout << arr[i] << " ";
• arr[i] = arr[i + 1]; •
• return n - 1; • // Function call
• } • n = deleteElement(arr, n, key);
• int findElement(int arr[], int n, int key)
• { • cout << "\n\nArray after deletion\n";
• int i; • for (i = 0; i < n; i++)
• for (i = 0; i < n; i++) • cout << arr[i] << " ";
• if (arr[i] == key)
• return i; • return 0;
• }
Row Major Order

• Address of A[I][J] = B + W * ((I – LR) * N + (J – LC))

• I = Row Subset of an element whose address to be


found,
J = Column Subset of an element whose address to be
found,
B = Base address,
W = Storage size of one element store in an array(in
byte),
LR = Lower Limit of row/start row index of the matrix(If
not given assume it as zero),
LC = Lower Limit of column/start column index of the
• Given an array, arr[1………10][1………15] with base
value 100 and the size of each element is 1 Byte in
memory. Find the address of arr[8][6] with the help of
row-major order.
• Formula:
• Address of A[I][J] = B + W * ((I – LR) * N + (J – LC))

• Solution:
• Address of A[8][6] = 100 + 1 * ((8 – 1) * 15 + (6 – 1))
• = 100 + 1 * ((7) * 15 + (5))
• = 100 + 1 * (110)
• Address of A[I][J] = 210
• Column Major Order
• Address of A[I][J] = B + W * ((J – LC) * M + (I – LR))
• I = Row Subset of an element whose address to be found,
J = Column Subset of an element whose address to be found,
B = Base address,
W = Storage size of one element store in any array(in byte),
LR = Lower Limit of row/start row index of matrix(If not given
assume it as zero),
LC = Lower Limit of column/start column index of matrix(If not
given assume it as zero),
M = Number of rows given in the matrix.
• Given an array arr[1………10][1………15] with a base
value of 100 and the size of each element is 1 Byte in
memory find the address of arr[8][6] with the help of
column-major order.
• Formula: used
Address of A[I][J] = B + W * ((J – LC) * M + (I – LR))
Address of A[8][6] = 100 + 1 * ((6 – 1) * 10 + (8 – 1))
= 100 + 1 * ((5) * 10 + (7))
= 100 + 1 * (57)
Address of A[I][J] = 157
• Given an array, arr[1………10][1………15] with base
value 1048 and the size of each element is 1 Byte in
memory. Find the address of arr[2][5] with the help of
row-major order and column-major order.
• Given an array, arr[-6………10][+4………15] with base
value 1048 and the size of each element is 1 Byte in
memory. Find the address of arr[2][5] with the help of
row-major order and column-major order.
Recursion
• The process in which a function calls itself directly or indirectly is
called recursion and the corresponding function is called a recursive
function. Using a recursive algorithm, certain problems can be solved
quite easily. Examples of such problems are Towers of Hanoi (TOH),
Inorder/Preorder/Postorder Tree Traversals, DFS of Graph, etc.
Properties of Recursion:
• Performing the same operations multiple times with
different inputs.
• In every step, we try smaller inputs to make the
problem smaller.
• Base condition is needed to stop the recursion
otherwise infinite loop will occur.
• int fact(int n)
•{
• if (n < = 1) // base case
• return 1;
• else
• return n*fact(n-1);
•}
• // An example of direct recursion • // An example of indirect recursion
• void directRecFun() • void indirectRecFun1()
• { • {
• // Some code.... • // Some code...

• directRecFun(); • indirectRecFun2();

• // Some code... • // Some code...


• } • }
• void indirectRecFun2()
• {
• // Some code...

• indirectRecFun1();

• // Some code...
• }
• // C++ code to implement Fibonacci series • }
• #include <bits/stdc++.h>
• using namespace std; • int main()
• // Function for fibonacci • {
• int fib(int n) • // Initialize variable n.
• { • int n = 5;
• // Stop condition • cout<<"Fibonacci series of 5 numbers is:
• if (n == 0) ";
• return 0;
• // for loop to print the fibonacci series.
• // Stop condition • for (int i = 0; i < n; i++)
• if (n == 1 || n == 2) • {
• return 1; • cout<<fib(i)<<" ";
• }
• // Recursion function • return 0;
• else • }
• return (fib(n - 1) + fib(n - 2));
Time complexity and space
complexity
• Upper bound, Lower bound, and Average case
• O(n2), n-?
Time complexity
• Sum =0;
• for(i=1; i<=n; i++)
•{
• Sum = Sum + 1;
•}
• Sum =0;
• for(i=1; i<=n; i = i+2)
•{
• Sum = Sum + 1;
•}
• Sum =0;
• for(i=1; i<=n, i = i*2)
•{
• Sum = Sum + 1;
•}
• Sum =0;
• for(i=1; i<=n, i++)
•{
• for(j=1; j<=n, j++)
• {
• Sum = Sum + j;
• }
•}
Asymptotic Analysis
• Worst case: It defines the input for which the
algorithm takes a huge time.
• Average case: It takes average time for the program
execution.
• Best case: It defines the input for which the algorithm
takes the lowest time
Asymptotic Notations
• The commonly used asymptotic notations used for
calculating the running time complexity of an algorithm
is given below:
• Big oh Notation (O)
• Omega Notation (Ω)
• Theta Notation (θ)
Big oh Notation (O)
• Big O notation is an asymptotic notation that measures
the performance of an algorithm by simply providing
the order of growth of the function.
• This notation provides an upper bound on a function
which ensures that the function never grows faster than
the upper bound. So, it gives the least upper bound on a
function so that the function never grows faster than
this upper bound.
• If f(n) and g(n) are the two functions defined for positive integers,
• then f(n) = O(g(n)) as f(n) is big oh of g(n) or f(n) is on the order of
g(n)) if there exists constants c and no such that:
• f(n)≤c.g(n) for all n≥no and c>0
• This implies that f(n) does not grow faster than g(n), or g(n) is an
upper bound on the function f(n). In this case, we are calculating the
growth rate of the function which eventually calculates the worst time
complexity of a function, i.e., how worst an algorithm can perform.
• Example 1: f(n)=2n+3 , g(n)=n
• Now, we have to find Is f(n)=O(g(n))?
• To check f(n)=O(g(n)), it must satisfy the given condition:
• f(n)<=c.g(n)
• First, we will replace f(n) by 2n+3 and g(n) by n.
• 2n+3 <= c.n
• Let's assume c=5, n=1 then
• 2*1+3<=5*1
• 5<=5
• For n=1, the above condition is true.
• If n=2
• 2*2+3<=5*2
• 7<=10
• For n=2, the above condition is true.
Omega Notation (Ω)
• It basically describes the best-case scenario which is
opposite to the big O notation.
• It is the formal way to represent the lower bound of an
algorithm's running time. It measures the best amount
of time an algorithm can possibly take to complete or
the best-case time complexity.
• It determines what is the fastest time that an algorithm
can run.
• If f(n) and g(n) are the two functions defined for
positive integers,
• then f(n) = Ω (g(n)) as f(n) is Omega of g(n) or f(n)
is on the order of g(n)) if there exists constants c and no
such that:
• f(n)>=c.g(n) for all n≥no and c>0
• If f(n) = 2n+3, g(n) = n,
• Is f(n)= Ω (g(n))?
• It must satisfy the condition:
• f(n)>=c.g(n)
• To check the above condition, we first replace f(n) by 2n+3 and
g(n) by n.
• 2n+3>=c*n
• Suppose c=1
• 2n+3>=n (This equation will be true for any value of n starting
from 1).
• Therefore, it is proved that g(n) is big omega of 2n+3 function.
Theta Notation (θ)
• The theta notation mainly describes the average case
scenarios.
• It represents the realistic time complexity of an
algorithm. Every time, an algorithm does not perform
worst or best, in real-world problems, algorithms mainly
fluctuate between the worst-case and best-case, and
this gives us the average case of the algorithm.
• Big theta is mainly used when the value of worst-case
and the best-case is same.
• It is the formal way to express both the upper bound
and lower bound of an algorithm running time.
• Let f(n) and g(n) be the functions of n where n is the steps required to execute
the program then:
• f(n)= θg(n)
• The above condition is satisfied only if when
• c1.g(n)<=f(n)<=c2.g(n)
• where the function is bounded by two limits, i.e., upper and lower limit, and
f(n) comes in between. The condition f(n)= θg(n) will be true if and only if
c1.g(n) is less than or equal to f(n) and c2.g(n) is greater than or equal to f(n).
• Let's consider the same example where
f(n)=2n+3
g(n)=n

• As c1.g(n) should be less than f(n) so c1 has to be 1 whereas c2.g(n) should be


greater than f(n) so c2 is equal to 5. The c1.g(n) is the lower limit of the of the f(n)
while c2.g(n) is the upper limit of the f(n).
• c1.g(n)<=f(n)<=c2.g(n)
• Replace g(n) by n and f(n) by 2n+3
• c1.n <=2n+3<=c2.n
• if c1=1, c2=2, n=1
• 1*1 <=2*1+3 <=2*1
• 1 <= 5 <= 2 // for n=1, it satisfies the condition c1.g(n)<=f(n)<=c2.g(n)
• If n=2
• 1*2<=2*2+3<=2*2
• 2<=7<=4 // for n=2, it satisfies the condition c1.g(n)<=f(n)<=c2.g(n)
• Therefore, we can say that for any value of n, it satisfies the condition
c1.g(n)<=f(n)<=c2.g(n). Hence, it is proved that f(n) is big theta of g(n). So, this is
the average-case scenario which provides the realistic time complexity.
Linked List
• A linked list is a linear data structure that consists of a
series of nodes connected by pointers. Each node
contains data and a reference to the next node in the
list. Unlike arrays, linked lists allow for
efficient insertion or removal of elements from any
position in the list, as the nodes are not stored
contiguously in memory.
Linked Lists vs Arrays

Linked List:
• Data Structure: Non-contiguous
• Memory Allocation: Dynamic
• Insertion/Deletion: Efficient
• Access: Sequential

Array:
• Data Structure: Contiguous
• Memory Allocation: Static
• Insertion/Deletion: Inefficient
• Access: Random
Operations of Linked Lists:
Insertion in Linked List
• At the front of the linked list
• After a given node.
• At the end of the linked list.
Insert a Node at the Front/Beginning
of Linked List
To insert a node at the start/beginning/front of a Linked
List, we need to:
• Make the first node of Linked List linked to the new node
• Remove the head from the original first node of Linked
List
• Make the new node as the Head of the Linked List.
• #include <bits/stdc++.h> • while (node != NULL) {
• using namespace std; • cout << " " << node->data;
• class Node { • node = node->next;
• public: • }
• int data; • cout << "\n";
• Node* next; • }
• }; • int main()
• {
• void insertAtFront(Node** head_ref, int new_data) •
• { • Node* head = NULL;
• // 1. allocate node • insertAtFront(&head, 1);
• Node* new_node = new Node(); • insertAtFront(&head, 2);
• // 2. put in the data • insertAtFront(&head, 3);
• new_node->data = new_data; • insertAtFront(&head, 4);
• // 3. Make next of new node as head • insertAtFront(&head, 5);
• new_node->next = (*head_ref); • insertAtFront(&head, 6);
• // 4. move the head to point • cout << "After inserting Nodes at their front: ";
• // to the new node • // The nodes will be : 6 5 4 3 2 1
• (*head_ref) = new_node; • printList(head);
• }
• return 0;
• void printList(Node* node) • }
• {
Insert Node at the End of a
Linked List
• #include <bits/stdc++.h>
• using namespace std; • // Set the next pointer of the new
• class Node { node as NULL since it
• public: • // will be the last node
• int data; • new_node->next = NULL;
• Node* next;
• }; • // If the Linked List is empty, make
the new node as the
• void append(Node** head_ref, int
new_data) • // head and return
• { • if (*head_ref == NULL) {
• // Create a new node • *head_ref = new_node;
• Node* new_node = new Node(); • return;
• new_node->data = new_data; • }

• // Store the head reference in a • // Else traverse till the last node
temporary variable • while (last->next != NULL) {
• Node* last = *head_ref; • last = last->next;
• } • insertAtFront(&head, 5);
• insertAtFront(&head, 4);
• last->next = new_node; • insertAtFront(&head, 3);
• } • insertAtFront(&head, 2);
• void printList(Node* node)
• { • cout << "Created Linked list is: ";
• while (node != NULL) { • printList(head);
• cout << " " << node->data; • // Insert 1 at the end
• node = node->next; • append(&head, 1);
• } • cout << "\nAfter inserting 1 at the
• } end: ";
• int main() • printList(head);
• {
• Node* head = NULL; • return 0;
• insertAtFront(&head, 6); • }
Insert a Node after a given Node
in Linked List
• // C++ program to show inserting a node • return;
• // after a given node in given Linked List • }
• #include <bits/stdc++.h>
• using namespace std; • // 2. allocate new node
• Node* new_node = new Node();
• // A linked list node
• class Node { • // 3. put in the data
• public: • new_node->data = new_data;
• int data;
• Node* next; • // 4. Make next of new node
• }; • // as next of prev_node
• new_node->next = prev_node->next;
• // Given a node prev_node, insert a new
• // node after the given prev_node • // 5. move the next of prev_node
• void insertAfter(Node* prev_node, int new_data) • // as new_node
• { • prev_node->next = new_node;
• // 1. check if the given prev_node • }
• // is NULL
• if (prev_node == NULL) { • // Function to insert element in LL
• cout << "The given previous node cannot be • void push(Node** head_ref, int new_data)
NULL"; • {
• Node* new_node = new Node(); • Node* head = NULL;
• new_node->data = new_data;
• new_node->next = (*head_ref); • push(&head, 6);
• (*head_ref) = new_node; • push(&head, 5);
• } • push(&head, 4);
• push(&head, 3);
• // This function prints contents of • push(&head, 2);
• // linked list starting from head
• void printList(Node* node) • cout << "Created Linked list is: ";
• { • printList(head);
• while (node != NULL) {
• cout << " " << node->data; • // Insert 1 at the beginning.
• node = node->next; • insertAfter(head, 1);
• }
• cout << "\n"; • cout << "After inserting 1 after 2: ";
• } • printList(head);

• // Driver code • return 0;


• int main() • }
• {
• // Start with the empty list
Search an element in a Linked List
• #include <bits/stdc++.h> • {
• using namespace std; • Node* current = head; // Initialize current
• class Node { • while (current != NULL) {
• public: • if (current->data == x)
• int data; • return true;
• Node* next; • current = current->next;
• }; • }
• void push(Node** head_ref, int new_key) • return false;
• { • }
• /* allocate node */ • int main()
• Node* new_node = new Node(); • {
• Node* head = NULL;
• /* put in the key */ • int x = 21;
• new_node->key = new_key; • push(&head, 10);
• push(&head, 30);
• /* link the old list of the new node */ • push(&head, 11);
• new_node->next = (*head_ref); • push(&head, 21);
• push(&head, 14);
• /* move the head to point to the new node */
• (*head_ref) = new_node; • // Function call
• } • search(head, x) ? cout << "Yes" : cout << "No";
Deletion in Linked List
• Delete from a Linked List:-
• You can delete an element in a list from:
• Beginning
• End
• Middle
Delete from Beginning:
• // CPP program to remove first node of
• // linked list. • // Move the head pointer to the next node
• #include <iostream> • Node* temp = head;
• using namespace std; • head = head->next;

• /* Link list node */ • delete temp;


• struct Node {
• int data; • return head;
• struct Node* next; • }
• };
• // Function to push node at head
• /* Function to remove the first node
• of the linked list */
• Node* removeFirstNode(struct Node* head)
• {
• if (head == NULL)
• return NULL;
• void push(struct Node** head_ref, int new_data) • push(&head, 29);
• { • push(&head, 11);
• struct Node* new_node = new Node; • push(&head, 23);
• new_node->data = new_data; • push(&head, 8);
• new_node->next = (*head_ref);
• (*head_ref) = new_node; • head = removeFirstNode(head);
• } • for (Node* temp = head; temp != NULL;
temp = temp->next)
• cout << temp->data << " ";
• // Driver code
• int main()
• return 0;
• {
• }
• /* Start with the empty list */
• Node* head = NULL;

• /* Use push() function to construct


• the below list 8 -> 23 -> 11 -> 29 -> 12 */
• push(&head, 12);
Delete from End:
• // CPP program to remove last node of
• // linked list. • if (head->next == NULL) {
• #include <iostream> • delete head;
• using namespace std; • return NULL;
• }
• /* Link list node */
• struct Node { • // Find the second last node
• int data; • Node* second_last = head;
• struct Node* next; • while (second_last->next->next != NULL)
• }; • second_last = second_last->next;

• /* Function to remove the last node • // Delete last node


• of the linked list */ • delete (second_last->next);
• Node* removeLastNode(struct Node* head)
• { • // Change next of second last
• if (head == NULL) • second_last->next = NULL;
• return NULL;
• Node* head = NULL;
• return head;
• } • /* Use push() function to construct
• the below list 8 -> 23 -> 11 -> 29 -> 12 */
• // Function to push node at head • push(&head, 12);
• void push(struct Node** head_ref, int new_data) • push(&head, 29);
• { • push(&head, 11);
• struct Node* new_node = new Node; • push(&head, 23);
• new_node->data = new_data; • push(&head, 8);
• new_node->next = (*head_ref);
• (*head_ref) = new_node; • head = removeLastNode(head);
• } • for (Node* temp = head; temp != NULL;
temp = temp->next)
• // Driver code • cout << temp->data << " ";
• int main()
• { • return 0;
• }
• /* Start with the empty list */
Delete from Middle:
• // A complete working C++ program to delete • // the node at the given position
• // a node in a linked list at a given position • void deleteNode(Node** head_ref, int position)
• #include <iostream> • {
• using namespace std;
• // If linked list is empty
• // A linked list node • if (*head_ref == NULL)
• class Node { • return;
• public:
• int data; • // Store head node
• Node* next; • Node* temp = *head_ref;
• };
• // If head needs to be removed
• // Given a reference (pointer to pointer) to • if (position == 0) {
• // the head of a list and an int inserts a
• // new node on the front of the list. • // Change head
• void push(Node** head_ref, int new_data) • *head_ref = temp->next;
• {
• Node* new_node = new Node(); • // Free old head
• new_node->data = new_data; • free(temp);
• new_node->next = (*head_ref); • return;
• (*head_ref) = new_node; • }
• } • // Find previous node of the node to be deleted
• // Given a reference (pointer to pointer) to • for (int i = 0; temp != NULL && i < position - 1; i++)
• // the head of a list and a position, deletes temp = temp->next;
• • }
• // If position is more than number of nodes
• if (temp == NULL || temp->next == NULL) • // Driver code
• return; • int main()
• {
• // Node temp->next is the node to be deleted
• // Store pointer to the next of node to be deleted • // Start with the empty list
• Node* next = temp->next->next; • Node* head = NULL;

• // Unlink the node from linked list • push(&head, 7);


• free(temp->next); // Free memory • push(&head, 1);
• push(&head, 3);
• // Unlink the deleted node from list • push(&head, 2);
• temp->next = next; • push(&head, 8);
• }
• cout << "Created Linked List: ";
• // This function prints contents of linked • printList(head);
• // list starting from the given node • deleteNode(&head, 4);
• void printList(Node* node) • cout << "\nLinked List after Deletion at position 4: ";
• { • printList(head);
• while (node != NULL) { • return 0;
• cout << node->data << " "; • }
• node = node->next;
• }
Doubly Linked List
• A doubly linked list is a data structure that consists of
a set of nodes, each of which contains a value and two
pointers, one pointing to the previous node in the list
and one pointing to the next node in the list. This
allows for efficient traversal of the list in both
directions, making it suitable for applications where
frequent insertions and deletions are required.
Traversal in Doubly Linked List:
• #include <iostream> • while (current != NULL) {
• using namespace std; • // Output data of the current node
• cout << current->data << " ";
• // Define the Node structure
• struct Node { • // Move to the next node
• int data; // Data stored in the node • current = current->next;
• Node* next; // Pointer to the next node in the list • }
• Node* prev; // Pointer to the previous node in the list
• // Print newline after traversal
• // Constructor to initialize Node with data • cout << endl;
• Node(int data) : data(data), next(NULL), prev(NULL) {} • }
• };
• // Function to traverse the doubly linked list in backward
• // Function to traverse the doubly linked list in forward direction
direction • void backwardTraversal(Node* tail) {
• void forwardTraversal(Node* head) { • // Start traversal from the tail of the list
• // Start traversal from the head of the list • Node* current = tail;
• Node* current = head;
• // Continue until current node is not null (end of list)
• // Continue until current node is not null (end of list)
• while (current != NULL) { • head->next = second;
• // Output data of the current node • second->prev = head;
• cout << current->data << " "; • second->next = third;
• third->prev = second;
• // Move to the previous node
• current = current->prev; • cout << "Forward Traversal:" << endl;
• } • forwardTraversal(head);

• // Print newline after traversal • cout << "Backward Traversal:" << endl;
• cout << endl; • backwardTraversal(third);
• }
• // Free memory allocated for nodes
• int main() { • delete head;
• // Sample usage of the doubly linked list and • delete second;
traversal functions • delete third;
• Node* head = new Node(1);
• Node* second = new Node(2); • return 0;
• Node* third = new Node(3); • }
Finding Length of Doubly Linked
List:
•?
Insertion at the Beginning in
Doubly Linked List:
• // Define the structure for a node in the value) {
doubly linked list • // Create a new node
• struct Node { • Node* newNode = new Node;
• int data; // Data stored in the node
• Node* next; // Pointer to the next node • // Assign the value to the new node
• Node* prev; // Pointer to the previous • newNode->data = value;
node
• };
• // Since it's the first node, the previous
pointer is NULL
• // Function to insert a node at the • newNode->prev = NULL;
beginning of the list
• void insertBeginning(Node*& head, int
• // If the list is empty, make the new node the • newNode->next = head;
head
• if (head == NULL) { • // Update the previous pointer of the
• // Since it's the only node, the next pointer current head to point to the new node
is NULL • head->prev = newNode;
• newNode->next = NULL;
• // Update the head pointer to point to the
• // Update the head pointer to point to the new node
new node • head = newNode;
• head = newNode; • }
• } else { • }
• // Point the new node's next pointer to the
current head
Insertion at the End of Doubly
Linked List
• #include <iostream> • newNode->next = NULL;

• // Define the structure for a node in the doubly linked • // Check if the list is empty
list • if (head == NULL) {
• struct Node { • // If the list is empty, make the new node the
• int data; // Data stored in the node head
• Node* next; // Pointer to the next node • newNode->prev = NULL;
• Node* prev; // Pointer to the previous node
• }; • // Update the head pointer to point to the new
node
• // Function to insert a node at the end of the list • head = newNode;
• void insertEnd(Node*& head, int value) { • } else {
• // Create a new node • // Start from the head of the list
• Node* newNode = new Node; • Node* current = head;

• // Assign the value to the new node • // Traverse to the end of the list
• newNode->data = value; • while (current->next != NULL) {
• current = current->next;
• // Initialize the next pointer to NULL • }
• insertEnd(head, 3);
• // Adjust pointers to insert the new node at the
end • // Print the list
• // Set the next pointer of the last node to point to • Node* current = head;
• // the new node • while (current != NULL) {
• current->next = newNode; • std::cout << current->data << " ";
• current = current->next;
• // Set the previous pointer of the new node to • }
point
• // to the last node
• // Delete dynamically allocated memory
• newNode->prev = current;
• while (head != NULL) {
• }
• Node* temp = head;
• }
• head = head->next;
• delete temp;
• int main() {
• }
• // Test the insertEnd function
• Node* head = NULL;
• return 0;
• insertEnd(head, 1);
• }
• insertEnd(head, 2);
Insertion at a Specific Position
of Doubly Linked List
•?
Deletion at the Beginning of
doubly linked list
Deletion at the End on doubly linked list:
Deletion at a Specific Position in
doubly linked list
Circular Linked List
• The circular linked list is a linked list where all nodes
are connected to form a circle. In a circular linked list,
the first node and the last node are connected to each
other which forms a circle. There is no NULL at the end.

You might also like