0% found this document useful (0 votes)
10 views30 pages

Module 3

The document covers advanced data structures, specifically circular linked lists, skip lists, and XOR linked lists. It explains the properties, advantages, and operations of circular linked lists, including insertion methods in C, and introduces skip lists as a probabilistic structure for efficient data access. Additionally, it discusses XOR linked lists as a memory-efficient alternative to doubly linked lists, utilizing bitwise XOR for pointer storage.

Uploaded by

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

Module 3

The document covers advanced data structures, specifically circular linked lists, skip lists, and XOR linked lists. It explains the properties, advantages, and operations of circular linked lists, including insertion methods in C, and introduces skip lists as a probabilistic structure for efficient data access. Additionally, it discusses XOR linked lists as a memory-efficient alternative to doubly linked lists, utilizing bitwise XOR for pointer storage.

Uploaded by

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

Module 3: Advanced Linked list and arrays

CIRCULAR LINKED LISTS:


 Circular linked lists are a variation of the standard linked list data
structure. Here the last node points back to the first node, creating a
circular structure, they have no null references and can be traversed
starting from any node
 CLL have advantages like efficiency in handling cyclic data
representations, simplification of certain algorithms (e.g., round-robin
scheduling) and continuous iteration through the list, but there are few
cons like the risk of infinite loops if not handled carefully
 Common operations include creation, insertion and deletion

A circular linked list is a list in which the nodes are connected in a sequence,
where the last node always points to the head (first) node of the linked list.
Generally, the last node in a singly or doubly linked list contains NULL,
which means the end of the list. However, the circular linked lists do not
have any end as the last node always points to the first node of the linked list
which makes it circular.
We must be cautious when navigating circular linked lists to avoid endlessly
exploring the list. It should be noted that, unlike normally linked lists,
circularly linked lists do not have any nodes with a NULL pointer, every
node has a next node in a linear sequence.

Singly Circular Linked List in C


A node in a circular singly linked list contains a data block and a next block
to store the address of the next node. The last node's next block contains the
address of the first (head) node.
Syntax:

struct node{
<data__type> data;
struct node* next;
};

Doubly Circular Linked list in C


A node in a circular doubly linked list contains a data block, and two blocks
(prev and next) to store the addresses of the previous node and the next node.
The first (head) node contains the address of the last node in the prev block,
and the last node's next block contains the address of the first (head) node.

Syntax:

struct node{
<data__type> data;
struct node* next;
struct node* prev;
};

Memory Representation of circular linked list:


• The example below shows the memory representation of a circular linked
list containing marks of a student in 4 subjects. However, the image
shows a glimpse of how the circular list is being stored in the memory.
The start or head of the list is pointing to the element with the index 1 and
containing 13 marks in the data part and 4 in the next part. Which means
that it is linked with the node that is being stored at 4th index of the list.
• However, due to the fact that we are considering circular linked list in the
memory therefore the last node of the list contains the address of the first
node of the list.
Operations on Circular Singly linked list:

Programs for Different Operations on the Circular Linked List in C


Insertion of a Node at the Beginning
We can insert a node at the beginning of the circular linked list using the
below procedure:
 Create a new node and assign it to a temporary variable.
 If our list is empty (head is NULL), then assign the new node's
address in the head pointer and the new node's next pointer.
 If the list is not empty, assign the head node's address in a new current
variable to traverse the list. Assign the new node's address in the last
node (current).
 Update the new node's next block to point to the current first node by
assigning the head node's address, then update the head pointer to
point to the new node.
C Program:
#include<stdio.h>
#include<stdlib.h>

// creating a structure for the circular singly linked list


struct node
{
int data;
struct node *next;
};
// code for creating a new node
struct node* createNode(){
struct node *n;
n = (struct node*)malloc(sizeof(struct node));
return n;
}

void insertNodeAtBeginning(struct node** head, int data){


struct node* temp, *current;

// creating the new node


temp = createNode();
temp->data = data;
temp->next = NULL;

// if the list is empty


if(*head == NULL){
*head = temp;
temp->next = *head;
return;
}

// if the list already has more than 1 node


current = *head;

while(current->next != *head){
current = current->next;
}

current->next = temp;
temp->next = *head;
*head = temp;
return;
}

// code for displaying the list in the output


void viewList(struct node** head){
struct node *temp;

// if the list is empty


if(*head == NULL){
printf("List is empty.\n");
return;
}else{ // if the list has one or more nodes.
temp = *head;
printf("List: ");
do{
printf("%d ", temp->data);
temp = temp->next;
}
while(temp != *head);
}
}
int main(){

struct node* head = NULL;

// inserting different values in the list,


// 10 will be the first and 60 will be the last node
insertNodeAtBeginning(&head, 60);
insertNodeAtBeginning(&head, 50);
insertNodeAtBeginning(&head, 40);
insertNodeAtBeginning(&head, 30);
insertNodeAtBeginning(&head, 20);
insertNodeAtBeginning(&head, 10);

// viewing the list


viewList(&head);

return 0;
}

Output:
List: 10 20 30 40 50 60

In the above C program, we have created a structure for the circular


singly linked list. Using this structure, we have implemented a
createNode() function to create new nodes using the dynamic memory
allocation function malloc(). We have also created an
insertNodeAtBeginning() function to insert the nodes in the circular
linked list. It takes two arguments, first the address of the head node and
second the data for the new node. Also, the viewList() function can be
used to view the entire list.

Insertion of a Node at the End


We can insert a node at the end of the circular linked list using the below
procedure:

 Create a new node and assign it to a temporary variable.


 If our list is empty (head is NULL), then assign the new node's
address in the head pointer and the new node's next pointer.
 If the list is not empty, assign the head node address in a new
current variable to traverse the list. Assign the new node's address
in the last node (current).
 Update the new node's next block to point to the current first node
by assigning the head node's address.

C Program
#include<stdio.h>
#include<stdlib.h>
// creating a structure for the circular singly linked list
struct node
{
int data;
struct node *next;
};

// code for creating a new node


struct node* createNode(){
struct node *n;
n = (struct node*)malloc(sizeof(struct node));
return n;
}

void insertNodeAtEnd(struct node** head, int data){


struct node* temp, *current;

// creating the new node


temp = createNode();
temp->data = data;
temp->next = NULL;

// if the list is empty, we assign the new node to the head pointer
if(*head == NULL){
*head = temp;
temp->next = *head;
return;
}

// if the list has one or more than one node already


current = *head;

while(current->next != *head){
current = current->next;
}

current->next = temp;
temp->next = *head;
}

// code for displaying the list in the output


void viewList(struct node** head){
struct node *temp;

// if the list is empty


if(*head == NULL){
printf("List is empty.\n");
return;
}else{ // if the list has one or more nodes.
temp = *head;
printf("List: ");
do{
printf("%d ", temp->data);
temp = temp->next;
}
while(temp != *head);
}
}

int main(){

struct node* head = NULL;

// inserting different values in the list,


// 3 will be the first node and 18 will be the last node
insertNodeAtEnd(&head, 10);
insertNodeAtEnd(&head, 20);
insertNodeAtEnd(&head, 30);
insertNodeAtEnd(&head, 40);
insertNodeAtEnd(&head, 50);

// viewing the list


viewList(&head);

return 0;
}

Output:
List: 10 20 30 40 50
Similar to the first C program, we have created a structure for the
circular singly linked list. We have created
an insertNodeAtEnd() function to insert new nodes at the end of the
list. It takes two arguments, first the address of the head pointer and
second the data for the new node. We can view the entire list using
the viewList() function.

Insertion of a Node After a Specific Element


We can insert a node after a specific element in the circular linked list
using the below procedure:
 Create a new node and assign it to a new node variable.
 Assign the head node address in a new temp variable, and traverse the list
till the next node contains the specified value.
 Assign the next node's address in the new node variable.
 Update the current node's next block address to point to the new node.

C Program:
#include<stdio.h>
#include<stdlib.h>

// creating a structure for the circular singly linked list


struct node
{
int data;
struct node *next;
};

// code for creating a new node


struct node* createNode(){
struct node *n;
n = (struct node*)malloc(sizeof(struct node));
return n;
}

void insertNodeAtEnd(struct node** head, int data){


struct node* temp, *current;

// creating the new node


temp = createNode();
temp->data = data;
temp->next = NULL;

// if the list is empty


if(*head == NULL){
*head = temp;
temp->next = *head;
return;
}

// if the list already has more than 1 node


current = *head;

while(current->next != *head){
current = current->next;
}

current->next = temp;
temp->next = *head;
return;
}

// code to insert a new node after a specific value node in the list
void insertAfterSpecificNode(struct node** head, int data, int value){
struct node* temp, *newNode;

// creating a new node


newNode = createNode();
newNode->data = data;
newNode->next = NULL;

// traversing the list till the value is found


temp = *head;
while(temp->data != value){
temp = temp->next;
}

// adding the newNode b/w the "value" data node and next node.
newNode->next = temp->next;
temp->next = newNode;
return;
}

// code for displaying the list in the output


void viewList(struct node** head){
struct node *temp;

// if the list is empty


if(*head == NULL){
printf("List is empty.\n");
return;
}else{ // if the list has one or more nodes.
temp = *head;
printf("List: ");
do{
printf("%d ", temp->data);
temp = temp->next;
}
while(temp != *head);
}
printf("\n");
}

int main(){

struct node* head = NULL;

// inserting different values in the list,


// 3 will be the first and 18 will be the last node
insertNodeAtEnd(&head, 3);
insertNodeAtEnd(&head, 6);
insertNodeAtEnd(&head, 9);
insertNodeAtEnd(&head, 12);
insertNodeAtEnd(&head, 18);
insertNodeAtEnd(&head, 21);

// viewing the list


viewList(&head);

// inserting the node after node containing 12 data values.


// parameters (head, newNodedata, valueAfterTheNodeIsInserted)
insertAfterSpecificNode(&head, 15, 12);

viewList(&head);

return 0;
}

Output:
List: 3 6 9 12 18 21
List: 3 6 9 12 15 18 21

Similar to the above C programs, we have created a circular singly linked


list. To insert a node after a specific node, we have created
an insertAfterSpecificNode() function. It takes three arguments, first the
address of the head pointer, second the data for the new node, and third the
data of the node after we have to add the new node. We can view the entire
list to check the list after the operation using the viewList() function.

Create a simple circular linked list


struct node *last; /* Initialize nodes */
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
one = malloc(sizeof(struct node)); /* Allocate memory */
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
one->data = 1; /* Assign data values */
two->data = 2;
three->data = 3;
one->next = two; /* Connect nodes */
two->next = three;
three->next = one;
last = three; /* Save address of third node in last */
SKIP LISTS:
 The skip list is a probabilisitc data structure that is built upon the general
idea of a linked list. The skip list uses probability to build subsequent
layers of linked lists upon an original linked list. Each additional layer of
links contains fewer elements, but no new elements.
 You can think about the skip list like a subway system. There's one train
that stops at every single stop. However, there is also an express train.
This train doesn't visit any unique stops, but it will stop at fewer stops.
This makes the express train an attractive option if you know where it
stops.
 Skip lists are very useful when you need to be able to concurrently access
your data structure.
 In a skip list, elements are organized in layers, with each layer having a
smaller number of elements than the one below it.
 The bottom layer is a regular linked list, while the layers above it contain
“skipping” links that allow for fast navigation to elements that are far
apart in the bottom layer.
 The idea behind this is to allow for quick traversal to the desired element,
reducing the average number of steps needed to reach it.

 A skip list SS has a few important properties that are referenced in its
analysis. It has a height of h which is the number of linked lists in it. It
has a number of distinct elements, n. And it has a probability p, which is
usually 12.21.
 The highest element (one that appears in the most lists) will appear in
log⁡1p(n)logp1(n) lists, on average. This, if we use p=12p=21, there are
log⁡2(n)log2(n) lists. This is the average value of h. Another way of saying
"Every element in a linked list is in the linked list below it" is "Every
element in level Si+1Si+1 exists in level Si."
 Each element in the skip list has four pointers. It points to the node to its
left, its right, its top, and its bottom. These quad-nodes will allow us to
efficiently search through the skip list.

XOR Linked List – A Memory Efficient Doubly Linked List


XOR linked lists are used to reduce the memory requirements of doubly-linked
lists.
We know that each node in a doubly-linked list has two pointer fields which
contain the addresses of the previous and next node. On the other hand, each
node of the XOR linked list requires only a single pointer field, which doesn’t
store the actual memory addresses but stores the bitwise XOR of addresses for
its previous and next node.

In a doubly linked list, you store two pointers per node: prev and next. In an
XOR linked list, you store one 'pointer' per node, which is the XOR of prev and
next (or if one of them is absent, just the other (the same as XORing with 0)).
The reason why you can still traverse an XOR linked list in both directions
relies on the properties of XOR and the redundancy of information inherent in a
double linked list.
XOR List; Pro’s and Con’s
 While an XOR linked list has the advantage of smaller memory usage, it
has disadvantages — it will confuse the compiler, debugging and static
analysis tools as your XOR of two pointers will not be correctly
recognized by a pointer by anything except your code.
 It also slows down pointer access to have to do the XOR operation to
recover the true pointer first.
 It also can't be used in managed code — XOR obfuscated pointers won't
be recognized by the garbage collector.

Example on XOR List


Let us consider the following XOR list
A->B->C->D
suppose you created nodes in this format below
Key|Link|
A|0^addr(B)| -> B|addr(A)^addr(C)| -> C|addr(B)^addr(D)| -> D|addr(C)^0|
CASE #1:[Forward Traversal] Now Suppose you are in B (current_node=>B)
want visit C , so you need Address of C . How you will get ?
Addressof(Next_node) = addressof(Prev_node) ^ Current_node(Link)
addr(A)^ ( addr(A)^ addr(C) ) =>(addr(A) ^ addr(A)) ^ addr(C) => 0 ^ addr(C)
=>addr(C)
CASE #2: [Backward traversal] Now Suppose you are in C (current_node=>
C) want visit B , so you need Address of B . How you will get ?
Addressof(Prev_node) = addressof(Next_node) ^ Current_node(Link)
addr(D) ^ ((addr(B) ^ addr(D)) => (addr(D)^ addr(D)) ^ addr(B) => 0^addr(B)
=> addr(B)

DYNAMIC ARRAYS
• A dynamic array is an array whose size can be changed during runtime.
Unlike static arrays, which have a fixed size that is determined at
compile time, dynamic arrays can be resized as needed. It allows for more
flexibility and better memory management, as the size of the array can be
adjusted to fit the amount of data being stored.
• Dynamic arrays are implemented using pointers and memory allocation
functions. In C, the most commonly used memory allocation functions
are malloc(), calloc(), and realloc(). These functions allow for the
allocation and deallocation of memory during runtime, which is necessary
for creating and manipulating dynamic arrays.

Creating Dynamic Arrays in C


To create a dynamic array in C, we must use memory allocation functions to
allocate memory for the array. The most commonly used memory allocation
functions in C are malloc(), calloc(), and realloc(). Here is an example of how
to create a dynamic array using malloc():
int *arr;
int size = 10;
arr = (int*) malloc(size * sizeof(int));

In this example, we declare a pointer to an integer array called arr. We also


declare an integer variable called size, which represents the size of the array we
want to create. After that, we use the malloc() function to allocate memory for
the array. The malloc() function takes the size of the array (in bytes) as its
argument, so we multiply the size of the array by the size of an integer (which is
4 bytes on most systems) to get the total size in bytes.

Adding Elements to a Dynamic Array


#include <stdio.h>
#include <stdlib.h>
int main() {
int size = 5;
int *arr = (int*) malloc(size * sizeof(int));
int i;
for(i = 0; i< size; i++) {
arr[i] = i;
}
// Add a new element to the array
size++;
arr = (int*) realloc(arr, size * sizeof(int));
arr[size-1] = i;
for(i = 0; i< size; i++) {
printf("%d ", arr[i]);
}
free(arr);
return 0;
}

Output:
012345

Resizing a Dynamic Array


#include <stdio.h>
#include <stdlib.h>
int main() {
int size = 5;
int *arr = (int*) malloc(size * sizeof(int));
int i;
for(i = 0; i< size; i++) {
arr[i] = i;
}
// Resize the array
size = 10;
arr = (int*) realloc(arr, size * sizeof(int));
for(i = 5; i< size; i++) {
arr[i] = i; }
for(i = 0; i< size; i++) {
printf("%d ", arr[i]);
}
free(arr);
return 0;
}
Output:
0123456789

MULTI-DIMENSIONAL ARRAY
 C allows arrays of three or more dimensions. The exact limit is
determined by the compiler. The general form of a multi-dimensional
array is
 type array_name[s1][s2][s3]....[sm];
 where si is the size of the ith dimension. Some example are:
 int survey[3][5][12];
 float table[5][4][5][3];
 survey is a three-dimensional array declared to contain 180 integer type
elements. Similarly table is a 4D array containing 300 elements of
floating point type.
 The array survey may represent a survey data of rainfall during the last 3
years from January to December in 5 cities.
 If the 1st index denotes year, 2nd city and the 3rd month, then the element
survey[2][3][10]
 denotes the rainfall in the month of October during the second year in
city-3.
3D array representation

Remember that a three-dimensional array can be represented as a series of two-


dimensional arrays as shown below:

APPLICATIONS OF MULTI DIMENSIONAL ARRAY


1. Matrix operations: 2D arrays are often used to represent matrices for
mathematical computations
2. Image processing: 2D arrays can store pixel values of images
3. Game development: 2D or 3D arrays can represent game boards or game
worlds.
4. Scientific simulations: Multidimensional arrays can model physical
phenomena in multiple dimensions.
5. Data tables: 2D arrays can store tabular data with rows and columns.
6. 3D graphics: 3D arrays can represent voxel data or color information in
3D space.
7. Financial modeling: Multidimensional arrays can store historical data
across multiple variables.
8. Machine learning: Arrays can represent feature vectors or weight matrices
in neural networks.
SPARSE ARRAY
A sparse array or sparse matrix is an array in which most of the elements are
zero.
Characteristics of Sparse array:
 The sparse array is an array in which most of the elements have the same
value(the default value is zero or null).
 Sparse matrices are those array that has the majority of their elements
equal to zero.
 A sparse array is an array in which elements do not have contiguous
indexes starting at zero.
 Sparse arrays are used over arrays when there are lesser non-zero
elements. Sparse arrays require lesser memory to store the elements and
the computation time can be saved.

Examples of Sparse array


Why sparse array is required over simple arrays to store the elements
• Storage: When there is the maximum number of zero elements and the
minimum number of non-zero elements then we use a sparse array over a
simple array as it requires less memory to store the elements. In the
sparse array, we only store the non-zero elements.
• Computation Time: In the sparse array we only store non-zero elements
and hence, traversing only non-zero elements takes less computation
time.
Representation of Sparse Array
Sparse arrays can be represented in two ways:
• Array Representation
• Linked List Representation

Array Representation of Sparse Array


To represent a sparse array 2-D array is used with three rows namely: Row,
Column, and Value.
 Row: Index of the row where non-zero elements are present.
 Column: Index of the column where the non-zero element is present.
 Value: The non-zero value which is present in (Row, Column) index.
Linked list representation of Sparse Array
To represent a sparse array using linked lists, each node has four fields namely:
Row, Column, Value, and Next node.
Row: Index of the row where non-zero elements are present.

Column: Index of the column where the non-zero element is present.

Value: The non-zero value which is present in (Row, Column) index.

Next node: It stores the address of the next node.


Sample questions:
Certainly! Here are 15 sample questions on advanced linked list and array
concepts using C:

1. Implement a function to reverse a doubly linked list in-place.


2. Write a function to detect and remove a cycle in a singly linked list.
3. Implement a skip list data structure with basic operations (insert, delete,
search).

4. Create a function to merge two sorted linked lists into a single sorted linked
list without using extra space.
5. Implement a circular buffer using an array. Include functions for enqueue,
dequeue, and checking if the buffer is full or empty.
6. Write a function to find the intersection point of two singly linked lists.
7. Implement a sparse matrix using a linked list of linked lists. Include functions
for matrix addition and multiplication.
8. Create a function to rotate a linked list to the right by k nodes.
9. Implement a memory-efficient doubly linked list using XOR of addresses
(XOR linked list).
10. Write a function to flatten a multilevel doubly linked list.
11. Implement a function to perform in-place merge sort on a singly linked list.
12. Create a self-organizing list that moves frequently accessed elements to the
front (using move-to-front heuristic).
13. Implement a function to rearrange a linked list in such a way that all even
position nodes are before odd position nodes.
14. Write a function to clone a linked list with random pointers.
15. Implement a persistent data structure for a singly linked list that allows
access to previous versions after modifications.

You might also like