0% found this document useful (0 votes)
8 views13 pages

Linked List

The document provides an overview of various data structures including linked lists, stacks, queues, deques, and trees, detailing their characteristics, types, and basic operations. It includes C implementations for each data structure, demonstrating how to manage elements and perform operations like insertion and deletion. Additionally, it covers specialized trees such as binary search trees and sparse matrices, emphasizing their unique properties and applications.

Uploaded by

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

Linked List

The document provides an overview of various data structures including linked lists, stacks, queues, deques, and trees, detailing their characteristics, types, and basic operations. It includes C implementations for each data structure, demonstrating how to manage elements and perform operations like insertion and deletion. Additionally, it covers specialized trees such as binary search trees and sparse matrices, emphasizing their unique properties and applications.

Uploaded by

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

Linked list

• A linked list is a data structure that is used to store and organize collections of data. It
consists of a series of nodes, where each node contains data and a reference (or pointer) to the
next node in the sequence. The nodes are connected in a linear fashion, forming a "linked"
chain.
• The elements in a linked list are linked using pointers.
• Unlike arrays, linked lists do not require contiguous memory locations, as each node can
be allocated dynamically in memory. This makes linked lists more flexible in terms of size, as
nodes can be added or removed at any point in the list without needing to reallocate the entire
list.
• Linked lists can be singly linked, where each node only has a reference to the next node,
or doubly linked, where each node has references to both the next and previous nodes. Doubly
linked lists provide more flexibility, but require additional memory for the previous node
references.
Implementation of Linked list in C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;

// display the list


void printList(){
struct node *p = head;
printf("\n[");

//start from the beginning


while(p != NULL) {
printf(" %d ",p->data);
p = p->next;
}
printf("]");
}

//insertion at the beginning


void insertatbegin(int data){

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


lk->data = data;
// point it to old first node
lk->next = head;

//point first to new first node


head = lk;
}

void insertatend(int data)


{
//create a link
struct node *lk = (struct node*) malloc(sizeof(struct node));
lk->data = data;
struct node *linkedlist = head;

while(linkedlist->next != NULL)
linkedlist = linkedlist->next;

linkedlist->next = lk;
}

Types of linked List


• Singly Linked List: In a singly linked list, each node has a data field and a
pointer/reference to the next node in the sequence. It allows traversal in only one direction, from
the head (the first node) to the tail (the last node).
// Define a node structure
struct Node {
int data; // Data of the node
struct Node* next; // Pointer to the next node
};
// Function to create a new node with given data
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return NULL;
}
newNode->data = data; // Set the data of the new node
newNode->next = NULL; // Set the next pointer to NULL
return newNode; // Return the newly created node
}
• Doubly Linked List: In a doubly linked list, each node has a data field and two
pointers/references: one to the next node and one to the previous node. This allows for traversal
in both forward and backward directions, providing more flexibility in certain operations.
// Define a node structure
struct Node {
int data; // Data of the node
struct Node* prev; // Pointer to the previous node
struct Node* next; // Pointer to the next node
};

// Function to create a new node with given data


struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return NULL;
}
newNode->data = data; // Set the data of the new node
newNode->prev = NULL; // Set the prev pointer to NULL
newNode->next = NULL; // Set the next pointer to NULL
return newNode; // Return the newly created node
}

• Circular Linked List: In a circular linked list, the last node's next pointer/reference points
back to the head, creating a circular structure. This allows for continuous traversal from the last
node to the first node, forming a loop.
struct Node {
int data; // Data of the node
struct Node* next; // Pointer to the next node
};
// Function to create a new node with given data
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
if (newNode == NULL) {
printf("Memory allocation failed\n");
return NULL;
}
newNode->data = data; // Set the data of the new node
newNode->next = NULL; // Set the next pointer to NULL
return newNode; // Return the newly created node
}
// Function to insert a new node at the beginning
void insertAtBeginning(struct Node** head, int data)
{
struct Node* newNode = createNode(data);
if (*head == NULL) {
newNode->next = newNode;
*head = newNode;
return;
}
struct Node* temp = *head;
while (temp->next != *head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = *head;
*head = newNode;
}

STACK
A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. Stack has
one end, whereas the Queue has two ends (front and rear). It contains only one pointer top
pointer pointing to the topmost element of the stack. Whenever an element is added in the
stack, it is added on the top of the stack, and the element can be deleted only from the stack. . It
can be implemented using an array or a linked list.
Standard Stack Operations
The following are some common operations implemented on the stack:
• push(): When we insert an element in a stack then the operation is known as a push. If
the stack is full then the overflow condition occurs.
• pop(): When we delete an element from the stack, the operation is known as a pop. If the
stack is empty means that no element exists in the stack, this state is known as an underflow
state.
• isEmpty(): It determines whether the stack is empty or not.
• isFull(): It determines whether the stack is full or not.'
• peek(): It returns the element at the given position.
• count(): It returns the total number of elements available in a stack.
Implementation of stack
#include <stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;

int isempty()
{
if(top == -1)
return 1;
else
return 0;
}

int isfull()
{
if(top == MAXSIZE)
return 1;
else
return 0;
}

int pop()
{
int data;
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Stack is empty.\n");
}
}

int push(int data)


{
if(!isfull()) {
top = top + 1;
stack[top] = data;
} else {
printf(" Stack is full.\n");
}
}

Queue
A queue is a data structure that represents a collection of elements arranged in a linear order,
where elements are added to the rear (enqueue) and removed from the front (dequeue)
according to the First-In-First-Out (FIFO) principle. In other words, the first element that is added
to the queue is the first one to be removed, and new elements are always added to the rear of
the queue.
The basic operations of a queue include enqueue, which adds an element to the rear of the
queue; dequeue, which removes the front element from the queue; peek, which retrieves the
front element without removing it; and isEmpty, which checks if the queue is empty.
Implementation of queue
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX 6

int intArray[MAX];
int front = 0;
int rear = -1;
int itemCount = 0;
bool isFull(){
return itemCount == MAX;
}
bool isEmpty()
{
return itemCount == 0;
}

int removeData(){
int data = intArray[front++];
if(front == MAX) {
front = 0;
}
itemCount--;
return data;
}
void insert(int data){
if(!isFull()) {
if(rear == MAX-1) {
rear = -1;
}
intArray[++rear] = data;
itemCount++;
}
}
Basic Operations
The basic operations that can be performed on a queue are:
• Enqueue: Also known as "insert" or "push", this operation adds an element to the rear
(end) of the queue. The element becomes the last element in the queue.
• Dequeue: Also known as "remove" or "pop", this operation removes the front (first)
element from the queue. The element that was added first is the one to be removed, following
the First-In-First-Out (FIFO) principle.
• Peek: This operation retrieves the front element from the queue without removing it. It
allows you to inspect the element at the front of the queue without modifying the queue.
• IsEmpty: This operation checks if the queue is empty or not. It returns a boolean value,
typically "true" if the queue is empty and "false" if it contains one or more elements.
Dequeue
The deque stands for Double Ended Queue. Deque is a linear data structure where the insertion
and deletion operations are performed from both ends. We can say that deque is a generalized
version of the queue.
Though the insertion and deletion in a deque can be performed on both ends, it does not follow
the FIFO rule. The representation of a deque is given as follows -

Operations performed on deque


There are the following operations that can be applied on a deque -
1. Insertion at front 2. Insertion at rear 3. Deletion at front 4. Deletion at rear
Implementation of Dequeue

#include <stdio.h>
#define size 5
int deque[size];
int f = -1, r = -1;
// insert_front will insert the value from the front
void insert_front(int x)
{
if((f==0 && r==size-1) || (f==r+1))
printf("Overflow");
else if((f==-1) && (r==-1))
{
f=r=0;
deque[f]=x;
}
else if(f==0)
{
f=size-1;
deque[f]=x;
}
else
{
f=f-1;
deque[f]=x;
}
}

// insert_rear will insert the value from the rear

void insert_rear(int x)
{
if((f==0 && r==size-1) || (f==r+1))
printf("Overflow");
else if((f==-1) && (r==-1))
{
r=0;
deque[r]=x;
}
else if(r==size-1)
{
r=0;
deque[r]=x;
}
else
{
r++;
deque[r]=x;
}

Tree
A tree is a non-linear data structure. Tree data structure is a hierarchical structure that is used to
represent and organize data in a way that is easy to navigate and search. It is a collection of
nodes that are connected by edges and has a hierarchical relationship between the nodes.
The topmost node of the tree is called the root, and the nodes below it are called the child
nodes. Each node can have multiple child nodes, and these child nodes can also have their own
child nodes, forming a recursive structure. Each node can have zero or more child nodes
connected to it. Nodes with no children are called leaf nodes.
Implementation
struct Node
{
int data;
struct Node *left_child;
struct Node *right_child;
};
Types of Tree
1. Binary Tree: A binary tree is a tree structure where each node has at most two child
nodes. The left child node contains a smaller value than the parent node, and the right child
node contains a greater value. Binary trees are used for fast searching, insertion, and deletion
of items, and are the foundation of many other types of trees.
2. AVL Tree: An AVL tree is a self-balancing binary search tree where the difference in
height between the left and right subtrees of any node is at most one. When a node is inserted
or deleted, the tree may need to be rebalanced to maintain this property. AVL trees are used for
fast searching, insertion, and deletion operations, and are particularly efficient for large datasets.
3. Red-Black Tree: A red-black tree is a self-balancing binary search tree that uses colored
nodes to ensure balance. Each node is either red or black, and the tree is balanced in such a
way that the longest path from the root to any leaf is no more than twice as long as the shortest
path. Red-black trees are used for efficient searching, insertion, and deletion operations, and
are particularly efficient for large datasets.
4. B-Tree: A B-tree is a tree structure that is designed for efficient external storage and
retrieval of data. B-trees are used in databases and file systems to store large amounts of data
on disk, and are designed to minimize the number of disk accesses needed to retrieve data.
5. Trie: A trie is a tree-like data structure used to store and retrieve associative data. Tries
are particularly useful for storing strings and other text-based data, and are commonly used in
spell-checking and autocomplete applications.
6. Heap: A heap is a tree-like data structure used for efficient priority queue operations.
Heaps are used in many applications that require prioritization of data, such as scheduling
algorithms and graph algorithms. The most common type of heap is a binary heap, where the
parent node is always greater (or less) than its child nodes.

Binary Search Tree


A binary search tree (BST) is a type of tree where each node has at most two child nodes, and
the values of the nodes in the left subtree are always less than the value of the parent node,
while the values of the nodes in the right subtree are always greater. This ordering property
allows for efficient searching, insertion, and deletion of nodes. The search algorithm compares
the value with the root node of the tree and navigates to the correct subtree based on the
comparison. Insertion and deletion operations are also efficient, as the tree can be easily
modified based on the value of the new node or the node to be deleted.
• The left subtree of a node contains only nodes with keys lesser than the node’s key.
• The right subtree of a node contains only nodes with keys greater than the node’s key.
• The left and right subtree each must also be a binary search tree.
Types of BST traversal
1. Inorder traversal: This type of traversal visits the nodes in ascending order. The
algorithm visits the left subtree first, then the root node, and then the right subtree. In simple
terms, it first visits the leftmost node, then its parent, then the right child of the parent, and so on
until it reaches the rightmost node. Inorder traversal is commonly used to produce a sorted list
of the nodes in the tree.
2. Preorder traversal: This type of traversal visits the root node first, then the left subtree,
and then the right subtree. In simple terms, it first visits the root node, then its left child, then the
left child of the left child, and so on until it reaches the leftmost node. After visiting all the nodes
in the left subtree, it visits the right subtree in a similar fashion. Preorder traversal is commonly
used to create a copy of the tree.
3. Postorder traversal: This type of traversal visits the nodes in a "bottom-up" fashion. The
algorithm visits the left subtree first, then the right subtree, and then the root node. In simple
terms, it first visits the leftmost node, then its right sibling, then its parent, and so on until it
reaches the root node. Postorder traversal is commonly used to delete the tree or to evaluate an
expression tree where the operators are stored in the internal nodes and the operands are
stored in the leaf nodes.
Sparse Matrix
A sparse matrix is a matrix that has a large number of zero values compared to non-zero
values. In data structure, a sparse matrix is typically represented using a compressed data
structure that only stores the non-zero elements of the matrix, thus saving memory space.
One common way to represent a sparse matrix is the compressed sparse row (CSR) format. In
this format, three arrays are used to store the matrix data: the values array contains the
non-zero values of the matrix in row-major order, the column index array contains the column
indices of the corresponding non-zero values in the values array, and the row pointer array
contains the indices into the values and column index arrays where each row of the matrix
starts.

BFS Traversal
• Breadth-first search (BFS) is an algorithm that helps you traverse or visit all the nodes in
a graph, starting from a specified node, by visiting all the neighbors of that node before moving
on to the neighbors of its neighbors
• In other words, BFS visits all nodes at the same distance or depth from the starting node
before moving on to nodes at a greater depth. This makes it useful for finding the shortest path
between two nodes in an unweighted graph or for performing topological sorting.
• BFS can be implemented using a queue data structure. The algorithm starts by
enqueuing the starting node and marking it as visited. Then, it dequeues the first node from the
queue and visits all of its unvisited neighbors, adding them to the queue and marking them as
visited. This process continues until all nodes have been visited.
The steps of the BFS algorithm:
1. Enqueue the root node into a queue data structure.
2. Mark the root node as visited.
3. While the queue is not empty, dequeue a node from the front of the queue.
4. For each unvisited neighbor of the dequeued node, mark it as visited and enqueue it into
the queue.
5. Process the dequeued node (for example, print its value or add it to a result list).
DFS Traversal
Depth-first search (DFS) is an algorithm that helps you traverse or visit all the nodes in a graph
by exploring as far as possible along each branch before backtracking. DFS can be
implemented using recursion or a stack data structure.
DFS starts from a source node and recursively applies DFS on each unvisited neighbor of the
current node. If there are no unvisited neighbors, it backtracks to the previous node and repeats
the process. DFS is useful for finding cycles, paths, or connected components in a graph, but
may not find the shortest path between two nodes.
DFS can be implemented recursively or using a stack data structure. In recursive
implementation, the algorithm applies DFS on each unvisited neighbor of the current node. In
stack implementation, it starts by pushing the source node onto the stack and repeatedly pops
the top node and pushes its unvisited neighbors onto the stack.
The steps of the DFS algorithm:
1. Start at a source node and mark it as visited.
2. For each unvisited neighbor of the current node, recursively apply DFS on that neighbor.
3. If all neighbors of the current node have been visited or there are no neighbors,
backtrack to the previous node.
4. Repeat steps 2-3 until all nodes have been visited.

Linear Data Structures


• Data structure where data elements are arranged sequentially or linearly where each
and every element is attached to its previous and next adjacent is called a linear data structure.
• In linear data structure, data elements are sequentially connected and each element is
traversable through a single run.
• In linear data structure, all data elements are present at a single level.
• Linear data structures are easier to implement.
• Linear data structures can be traversed completely in a single run.
• Linear data structures are not very memory friendly and are not utilizing memory
efficiently.
• Time complexity of linear data structure often increases with increase in size.
• Array, List, Queue, Stack.
Non-linear Data Structures
• Data structure where data elements are arranged sequentially or linearly where each
and every element is attached to its previous and next adjacent is called a linear data structure.
• In non-linear data structure, data elements are hierarchically connected and are present
at various levels.
• In non-linear data structure, data elements are present at multiple levels.
• Non-linear data structures are difficult to understand and implement as compared to
linear data structures.
• Non-linear data structures are not easy to traverse and needs multiple runs to be
traversed completely.
• Non-linear data structures uses memory very efficiently.
• Time complexity of non-linear data structure often remain with increase in size.
• Graph, Map, Tree.
ADT (Abstract Data Type)
• Abstract Data Types (ADTs) are high-level descriptions of how data can be stored and
manipulated in a computer program, without specifying the implementation details.
• ADTs define specific types of data structures, and each ADT has its own set of
operations that can be performed on the data.
• It provides a blueprint for how data can be organized and operated upon, without
specifying the implementation details.
• ADTs serve as a way to abstract the complexities of data structures and algorithms,
making them easier to understand and use.
• ADTs are like predefined templates for specific types of data structures, such as stacks,
queues, lists, dictionaries, and sets. They define how these data structures can be used and
what operations can be performed on them, making it easier to work with data in programs.
Array
• An array is a data structure used in programming to store a collection of items of the
same data type.
• Arrays are allocated as contiguous blocks of memory and consist of elements or slots
that can store values.
• Elements in an array are accessed using an index or position, starting from 0 for the first
element.
• Arrays have a fixed size or length, determined by the number of elements they can hold.
• Arrays can be one-dimensional (vectors/lists), multi-dimensional (matrices/tables), or
jagged (arrays of arrays).
• Arrays are widely used for tasks such as storing and retrieving collections of data,
performing operations on large sets of data, and iterating over elements in a systematic way.
• Arrays are a fundamental data structure in many programming languages and are used
in various applications, including software development, scientific computing, data analysis, and
more.
String
• A string is a sequence of characters or text in a programming language. It is a data type
that represents a collection of characters, such as letters, digits, symbols, and spaces, arranged
in a specific order. In most programming languages, strings are used to represent textual data,
such as words, sentences, or paragraphs.
• Strings are used to represent textual data, such as words, sentences, or paragraphs.
• Strings are typically enclosed in quotation marks (' ' or " ") in most programming
languages.
• Strings are immutable in many programming languages, meaning their contents cannot
be changed once created.
• String operations include concatenation (joining strings), substring extraction (retrieving
a portion of a string), and string formatting (inserting values into a string).
• Strings are widely used in programming for tasks such as text representation,
input/output processing, file handling, and more.
• String manipulation is a fundamental skill for many programmers and is supported by
built-in string functions and libraries in most programming languages.
• Common string-related tasks include searching, replacing, converting case, trimming
whitespace, and comparing strings.
• String encoding and decoding are important considerations when working with
non-ASCII characters or when handling data in different character encodings.
• String handling is an essential aspect of web development, data processing, text
processing, and other applications involving textual data.
AVL tree
• An AVL tree is a special type of binary tree that is used to store data in a way that allows
for fast searching, inserting, and deleting of items. The tree is "self-balancing," which means that
it automatically adjusts its structure to keep it balanced and efficient.
• An AVL tree is named after its inventors, Adelson-Velsky and Landis.
• Each node in an AVL tree has at most two child nodes, and the values in the left subtree
are always less than the value in the parent node, while the values in the right subtree are
always greater.
• The balancing property of an AVL tree means that the difference in height between the
left and right subtrees of any node is at most one.

You might also like