Data Structure and Algorithm Analysis - 2024-2025
Data Structure and Algorithm Analysis - 2024-2025
GCyB - I
2
1. Why studying data structure ?
• The study of data structures helps us to understand the basic concepts involved in organizing and
storing data as well as the relationship among the data sets.
• Data structure provides a way to store and organize data in a manner that allows for efficient retrieval
and modification.
• Choosing the right data structure can significantly impact the performance of an application or
algorithm. This enable faster processing and reduced memory consumption (more details in Chapter
IV).
• Data structures are supported by the majority of programming languages, including C, C++, Java,
Python, and others.
• Java provides a rich set of built-in data structures through its libraries (Chapter II). 3
2. Goals of data structure
Correctness Efficiency
4
3. Classification of data structure
Depending on the organization of the elements, data structures are classified into two categories :
• Primitive data structure: Primitive data structures consist of the numbers and the characters which
are built in programs. These can be manipulated or operated directly by the machine level instructions.
Basic data types such as integer, real, character, and Boolean come under primitive data structures.
• Non-primitive data structure: Non-primitive data structures are those that are derived from primitive
data structures. These data structures cannot be operated or manipulated directly by the machine level
instructions. In java, non-primitive data structure further divided into:
• Linear data structures: Data elements are accessed in a sequential order but it is not compulsory
to store all elements sequentially (Ex: Array, Linked Lists, Stacks and Queues).
• Non-linear data structures: Data elements are not arranged in a sequential order. There is a
hierarchical relationship between individual data items (Ex: Trees and Graphs).
5
3. Classification of data structure
6
4. Abstract Data Type ?
• Abstract Data Types (ADT) is the combination of data structure with their operations.
7
2. Abstract Data Type
• The operations of an ADTs are separated from their implementation (The same operation or
functionality can result from different implementations).
• ADTs are language-independent representations of data types (Can be used to specify a new data type
that can then be implemented in various ways using different programming languages).
9
1. Arrays
• Array is a type of data structure that stores data elements of same data types in adjacent locations.
• The array’s length is set when the array is created, and it cannot be changed.
One-dimensional Array: It has only one row of elements. It is stored in ascending storage location.
Two-dimensional Array: It consists of multiple rows and columns of data elements. It is also called
as a matrix.
11
1. Arrays
• Example of a 2D array (3x3) of integers
int[][] Array2D = {
{7, 12, 31},
{14, 62, 49},
{10, 55, 75}
};
12
1. Arrays
• Example of a 3D array (2x3x4) of integers
int[][][] Array3D = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12} },
{
{13, 14, 15, 16},
{17, 18, 19, 20},
{21, 22, 23, 24}
}
};
• If an array is already full and we want to add more values to it than we need to create a new array,
which have sufficient space and then copy the old array to the new array.
• To avoid this manual reallocation and copy we can use ArrayList or Linked Lists to store data.
14
2. Linked List
• A linked list is a dynamic data structure in which memory is allocated at run time.
• A linked list is considered as a chain of records called nodes. Each node in the list contains two
items: the data and a reference to the next node
• A linked list has the following properties.
The number of nodes in a list is not fixed and can grow and shrink on demand.
The last node has a reference to null.
The entry point into a linked list is called the head (the reference to the first node) of the list.
If the linked list is empty then the head is a null reference.
15
2. Linked List
• Types of Linked List:
Singly Linked List: In a singly linked, each node has some data and a pointer to the next node in the list.
Doubly Linked List: In a doubly linked list each node contains two pointer: one points to the previous node and the
other points to next node. This allows easy traversal in both forward and backward direction.
Circular Linked List: In a circular linked list, the last node points to the first node. This implies that the list can be
traversed infinitely in a loop. Circular linked lists can be implemented using either singly linked nodes or doubly linked
nodes.
16
2. Linked List
import java.util.LinkedList;
LinkedList<Integer> LL = new LinkedList<>(); //Creating a linkedlist
LL.add(10); // Adding elements to the LinkedList
LL.add(20);
System.out.println("LinkedList elements: " + LL); // Displaying the elements of the
LinkedList
System.out.println("the first element: "+LL.getFirst()); //get the first element
System.out.println("the second element: "+LL.get(1)); //get the second element
LL.addFirst(5); // Inserting at the beginning
System.out.println("the first element: "+LL.getFirst());
LL.addLast(50); // Inserting at the end
System.out.println("After insertion: " + LL);
LL.removeFirst(); // Removing the first element
LL.removeLast(); // Removing the last element
System.out.println("After deletion: " + LL);
boolean contains30 = LL.contains(30); // Searching
System.out.println("Does the list contain '30'? " + contains30);
System.out.println("Elements of the LinkedList:"); // Traversal
for (int number : LL) {
System.out.println(number); 17
}
2. Linked List
Applications:
Implement dynamic memory management functions of operating system. They can be used to
maintain a list of free memory blocks, allowing the operating system to efficiently allocate memory to
processes as needed.
Linked lists can represent polynomials efficiently. Each node of the linked list can store a term of the
polynomial (e.g., coefficient and exponent), allowing for operations such as addition, subtraction,
multiplication, and division of polynomials.
18
2. Linked List
Advantages of Linked List:
Dynamic Data Structure: Linked List being a dynamic data structure can shrink and grow at the runtime by deallocating or
allocating memory, so there is no need for an initial size in linked list.
No Memory Wastage: As the size of a linked list can grow or shrink at runtime, so there is no memory wastage. Only the
required memory is allocated.
Implementation: data structures like queues and stacks can be easily implemented using a Linked List.
Insertion and Deletion Operation: In a Linked List, insertion and deletion operations are quite easy, as there is no need to
shift every element after insertion or deletion. Only the address present in the pointers needs to be updated.
19
2. Linked List
Disadvantages of Linked List:
Slower Access Time: Accessing elements in a linked list requires traversing the list from the beginning (or end) to the
desired position, which can result in slower access times.
Extra Space for Pointers: Linked lists require additional space for storing pointers/references to the next node, which
increases the overall space complexity of the data structure. This overhead can become significant, especially for large lists
or in scenarios where memory usage is critical.
Difficulty in Reversal and Traversal: Singly linked lists can be traversed in only one direction, doubly linked lists support
traversal in both directions but require more memory for storing additional pointers.
Potential for Fragmentation: Linked lists can suffer from memory fragmentation over time, especially in dynamic memory
allocation scenarios. As nodes are dynamically allocated and deallocated, memory fragmentation may occur, leading to
inefficient memory utilization and increased memory management overhead.
20
3. Stacks
• A stack is a linear data structure in which insertion and deletion of elements are done at only one
end, which is known as the top of the stack.
• Stack is called a last-in, first-out (LIFO) structure because the last element which is added to the
stack is the first element which is deleted from the stack.
21
3. Stacks
When an element is inserted in a stack, the concept is called push.
when an element is removed from the stack, the concept is called pop.
22
2. Stacks
import java.util.Stack;
public class StacksDemo
{
public static
void main(String[] args) {
Stack<Integer> ST = new Stack<Integer>();
// Pushing elements onto the stack
ST.push(1);
ST.push(2);
ST.push(3);
System.out.println("Stack: "+ST); ); // Displaying the elements of the Stacks
System.out.println("Stack size : "+ST.size()); //Returns the number of elements stored in
the stack
System.out.println("Stack top : "+ST.peek()); // Peeking the top element of the stack
System.out.println("Stack pop : "+ST.pop());//Remove the top element of the stack
System.out.println("Stack top : "+ST.peek());
System.out.println("Stack isEmpty : "+ST.isEmpty()); //Verify if the stack is emptyt
} 23
}
3. Stacks
Applications:
Depth-first search of trees and graphs traversal.
Backtracking Algorithms: The backtracking algorithm uses stacks to keep track of the states of the problem-solving
process. The current state is pushed onto the stack, and when the algorithm backtracks, the previous state is popped
from the stack.
UNDO and REDO operation: Undo/Redo operations: Each time an action is performed, it is pushed onto the stack.
To undo the action, the top element of the stack is popped.
Browser history: manage the history of visited pages in web browsers. Each time you visit a new page, the URL is
pushed onto the stack, and when you hit the back button, the previous URL is popped from the stack.
24
3. Stacks
Advantages of stacks:
Easy implementation: Stack data structure is easy to implement using arrays or linked lists, and its operations are simple to
understand and implement.
Efficient memory utilization: Stack uses a contiguous block of memory, making it more efficient in memory utilization as
compared to other data structures.
Fast access time: Stack data structure provides fast access time for adding and removing elements as the elements are
added and removed from the top of the stack.
25
3. Stacks
Disadvantages of stacks:
Limited capacity: Stack data structure has a limited capacity as it can only hold a fixed number of elements. If the stack
becomes full, adding new elements may result in stack overflow, leading to the loss of data.
No random access: Stack data structure does not allow for random access to its elements, and it only allows for adding and
removing elements from the top of the stack. To access an element in the middle of the stack, all the elements above it must
be removed.
Memory management: Stack data structure uses a contiguous block of memory, which can result in memory fragmentation
if elements are added and removed frequently.
Not suitable for certain applications: Stack data structure is not suitable for applications that require accessing elements
in the middle of the stack, like searching or sorting algorithms.
Stack overflow and underflow: Stack data structure can result in stack overflow if too many elements are pushed onto the
26
stack, and it can result in stack underflow if too many elements are popped from the stack.
4. Queue
• A queue is an ordered list in which the elements in a queue are added at one end called the “rear”
and removed from the other end called the “front”.
• The first element to be inserted is the first one to be deleted. Hence, it is called First in First out
(FIFO).
27
4. Queue
import java.util.ArrayDeque;
public class QueueDemo
{
public static
void main(String[] args) {
ArrayDeque<Integer> que = new ArrayDeque<Integer>();
que.add(1);
que.add(2);
que.add(3);
System.out.println("Queue "+que);
System.out.println("Queue size : "+que.size());
System.out.println("Queue peek : "+que.peek());
System.out.println("Queue remove : "+que.remove());
System.out.println("Queue isEmpty : "+que.isEmpty());
}
}
28
4. Queue
Applications:
Operating System Scheduling: In an operating system, queues are used to schedule processes and
allocate resources.
Computer Networks: Queues are also used in computer networks to manage network traffic.
Simulation and Modeling: Queues are commonly used in simulation and modeling to simulate real-
life scenarios. For example, a queue can be used to simulate the waiting time at a supermarket
checkout counter.
Traffic Management Systems: Queues are used in traffic management systems to manage traffic
flow and avoid congestion.
29
4. Queue
Advantages of queue:
They are efficient for storing and accessing elements in a specific order.
Queues are suitable for applications that require processing elements in a FIFO manner.
Disadvantages of queue:
Queues have a fixed size, which means they can’t accommodate more elements than their size.
Adding and removing elements from the middle of the queue is not efficient and requires shifting all the
elements.
30
5. Tree
• Tree is a hierarchical data structure. The top node of a
tree is called the root of the tree.
• A tree can contain no nodes or root node with zero or
more subtrees.
• Except the root node, every node in a tree has a parent
node, and zero or more child nodes.
• Every edge of the tree is directly or indirectly originated
from the root.
• Every child has only one parent, but one parent can
have many children.
• A leaf node is a node that has no children. It's at the end
of the tree branch.
31
5. Tree
• The depth of a node is the length of the path from the root to
the node (The depth of B is 2, P-Q-B).
• The height of a node is the length of the path from that node
to the deepest node (The height of R is 3, R-C-M-I).
• The height of a tree is the length of the path from the root to
the deepest node in the tree (The height of this tree is 4).
32
5-1. Binary Tree
A binary tree is a type of tree in which each node has at most two children (0, 1 or 2) which are referred as left child and
right child, binary tree also can divide into three category:
Strict Binary Tree: A binary tree is called strict binary tree if each node has exactly two children or no children.
Complete binary tree : A binary tree is called complete binary tree if all leaf nodes are at height h or h-1 (h is
height of the binary tree) and also without any missing number in the sequence.
Perfect Binary Tree: A binary tree is called perfect binary tree if each node has exactly two children and all
leaf nodes are at the same level.
33
5-1. Binary Tree
A binary search tree (BST) is a special type of binary tree in which the left child of a node contains a value smaller than
the node's value, and the right child contains a value greater than the node's value. This property enables efficient
searching, insertion, and deletion operations.
34
5. Tree
• Tree implementation in JAVA Collection
TreeSet: Implements the NavigableSet interface and import java.util.TreeSet;
public class TreeDemo {
is also based on a red-black tree. It represents a set public static
where elements are sorted in their natural order or void main(String[] args) {
// Create a tree set.
according to a specified comparator. TreeSet<String> ts = new TreeSet<String>();
// Add elements to the tree set.
ts.add("A");
TreeMap: Implements the NavigableMap interface ts.add("B");
and is based on a red-black tree. It provides a sorted ts.add("C");
System.out.println(ts);
key-value mapping, where keys are sorted in their }
natural order or according to a specified comparator. }
35
5. Tree
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String, Integer> tm = new TreeMap<String, Integer>(); // create a
tree map.
// Put elements into the map
tm.put("Adam", 55);
tm.put("Sara", 77);
tm.put("Ali",89);
tm.put("rim", 75);
System.out.println("Students count: " + tm.size());
for(String key : tm.keySet()){
System.out.println(key + " score marks:" + tm.get(key));
}
System.out.println("Adam score: " + tm.containsKey("Adam"));
tm.remove("sara");
System.out.println(tm.toString());
}
} 36
5 Tree
Application
The tree is the most useful data structure when we have hierarchical information to store/maintain:
• Implementing the hierarchical structures in computer systems like directory and file system.
• Implementing the navigation structure of a website.
• Decision making in gaming applications.
• Implementation of priority queues for priority-based OS scheduling functions
• Storing data keys for DBMS for indexing
• Spanning trees for routing decisions in computer and communications networks
• Path-finding algorithm to implement in AI, robotics and video games applications
37
5 Tree
Application
The tree is the most useful data structure when we have hierarchical information to store/maintain:
• Implementing the hierarchical structures in computer systems like directory and file system.
• Implementing the navigation structure of a website.
• Decision making in gaming applications.
• Implementation of priority queues for priority-based OS scheduling functions
• Storing data keys for DBMS for indexing
• Spanning trees for routing decisions in computer and communications networks
• Path-finding algorithm to implement in AI, robotics and video games applications
38
5 Tree
Advantages
• Hierarchical Structure: Trees represent hierarchical relationships among elements, making them suitable for
organizing and representing hierarchical data, such as file systems, organizational charts, and XML/HTML
documents.
• Efficient Search: Balanced trees (e.g., binary search trees, AVL trees, red-black trees) provide efficient search
operations with time complexity O(log n), where n is the number of elements in the tree. This makes them suitable for
applications requiring fast search operations.
• Ordered Data: Some trees, like binary search trees and B-trees, maintain elements in sorted order. This makes it
easy to retrieve elements in sorted order, which is useful in various applications like searching for nearest neighbors
or iterating through elements in sorted order.
• Dynamic Size: Trees can dynamically grow and shrink in size, allowing for efficient insertion and deletion operations
without requiring a fixed-size structure. 39
5 Tree
Disadvantages
• Complexity: Some types of trees, especially balanced trees, can be complex to implement and understand.
Managing balance conditions, rotations, and other operations can be challenging.
• Memory Overhead: Trees often have a higher memory overhead compared to simpler data structures like arrays or
linked lists. Each node in a tree typically requires additional memory for storing references to child nodes, leading to
increased memory consumption.
• Traversal Complexity: Traversing trees can sometimes be complex, especially in the case of unbalanced trees. In
worst-case scenarios, traversal operations can degrade to linear time complexity, making them less efficient than in
balanced trees.
• Insertion and Deletion Overhead: While balanced trees offer efficient insertion and deletion operations on average,
in some cases, these operations can involve complex restructuring of the tree, leading to increased overhead.
40
6. HashMap
• HashMap is a data structure that implements the Map interface provided by the Java Collections
Framework. It stores key-value pairs and allows rapid retrieval of values based on their associated keys.
• The HashMap class provides methods to add, remove, and retrieve elements from the map.
The put() method is used to add a key-value pair to the map,
The remove() method is used to remove a key-value pair,
The get() method is used to retrieve the value associated with a key.
• Hashing is used to provide fast access to the elements in the map. When a key-value pair is added to the
map, the key is hashed to generate an index into an array of buckets. Each bucket contains a linked list
of elements with the same hash code. When a key is used to retrieve a value, its hash code is used to
locate the appropriate bucket, and the linked list is searched for the key.
41
6. HashMap
import java.util.HashMap;
public class HashMapDemo {
public static void main(String[] args) {
// Create a new HashMap to store country-domain mappings
HashMap<String, String> countryTLD = new HashMap<>();
// Add country-domain mappings to the HashMap
countryTLD.put("Morocco", ".ma");
countryTLD.put("France", ".fr");
countryTLD.put("United Kingdom", ".co.uk");
// Print the TLD results
System.out.println(countryTLD.toString());
System.out.println(countryTLD.hashCode());
countryTLD.replace("Morocco",".ma",".ac.ma");
System.out.println(countryTLD.toString());
System.out.println(countryTLD.hashCode());
countryTLD.remove("France"); // Remove a country tld mapping
System.out.println("After removing France, size of country TLD: " +
countryTLD.size());
} 42
}
6. HashMap
Advantages
• Fast Retrieval: HashMap provides constant time O(1) performance for retrieving elements. This means that
regardless of the size of the map, the time to retrieve an element remains the same.
• Efficient Storage: HashMap uses a hash table data structure to store key-value pairs. This provides efficient storage
and retrieval of elements, as the hash function can map the key to the index of the array directly.
• Flexibility: HashMap can store any type of object as a key or value. This allows for a wide range of data to be stored
in the map.
• Dynamic Sizing: HashMap is dynamically sized, which means that the size of the map can be changed as elements
are added or removed. This allows the map to be optimized for memory usage and performance
43
6. HashMap
Disadvantages
• Unordered: The items in a HashMap are not stored in any particular order. This means that if you need to retrieve the
items in a specific order, you will need to sort the items yourself.
• Performance: In certain situations, the performance of a HashMap may not be optimal. This is because the hash
code function used to generate the keys must distribute the keys evenly to avoid collisions, which can lead to longer
lookup times.
• Thread safety: HashMaps are not thread-safe by default. This means that if multiple threads access the same
HashMap object concurrently, it can lead to data corruption or inconsistency. You can use synchronized or concurrent
HashMaps to overcome this issue, but this comes at the cost of performance.
• Memory usage: HashMaps can use a lot of memory, especially if the hash table needs to be resized. When the load
factor is exceeded, the HashMap needs to allocate a new, larger array and rehash all the elements. This can be a
costly operation in terms of time and memory usage. 44
II- Implementation of main data structures
45
1. Singly Linked List Implementation
• A Singly-linked list is a collection of nodes linked together in a sequential way where each node of the
singly linked list contains a data field and an address field that contains the reference of the next node.
• The structure of the node in the Singly Linked List is: public class LinkedList{
private Node head;
class Node { private int length;
int data; class Node {
Node next; int data;
Node(int data) { Node next;
this.data = data; Node(int data) {
} this.data = data;
} }
}
public LinkedList(int val){
Node newNode = new
Node(val);
head= newNode;
length=1;
46
}
}
1. Singly Linked List Implementation
• To display the data of linked list we must verify if the linked list is empty.
public void DisplayLinkedList() {
Node current = head;
System.out.print("head ==> ");
while (current != null) {
System.out.print(current.data + " =>
");
current = current.next;
}
System.out.println("Null"); 47
}
1. Singly Linked List Implementation
48
1-1. Insert element in Singly Linked List
49
1-1-1. Insertion at the start of Singly Linked List
• Analysis:
We need to create a new node with the value passed to the function as argument.
The next pointer of the new node will point to the head of the linked list or null in case when list is
empty.
The newly created node will become head of the linked list.
Time Complexity: O(1).
50
1-1-1. Insertion at the start of Singly Linked List
newNode.next = head;
head = newNode;
51
}
1-1-2. Insertion at the end of Singly Linked List
public void addEnd(int val) {
• Analysis:
New node is created and the value is stored inside it
Node newNode = new Node(val);
and store null value to its next pointer.
53
}
1-1-2. Insertion at the end of Singly Linked List
54
1-1-2. Insertion at the end of Singly Linked List
public void addEnd(int val) { public void addEnd(int val) {
} 55
}
1-1-3. Insertion at a position N
56
1-1-3. Insertion at a position N public boolean insert(int index, int value){
if(index<0 || index>length) return false;
58
1-2-1. Remove first element in a Singly Linked List
head = head.next;
temp.next=null;
length--;
return temp;
} 59
1-2-2. Remove last element in a Singly Linked List
public Node removeLast(){
if(head==null) return null;
while(temp.next!=null){
pre=temp;
temp=temp.next;
}
tail=pre;
tail.next=null;
length--;
return temp;
}
60
3. Doubly Linked List Implementation
public class DoublyLinkedList {
private class Node { private Node head;
int data; private Node tail;
Node next; private int length;
Node preview; public DoublyLinkedList(int val){
Node(int data) { Node newNode = new Node(val);
this.data = data; head= newNode;
} tail= newNode;
} length=1;
}
61
3. Doubly Linked List Implementation
62
3. Doubly Linked List Implementation
63
3. Doubly Linked List Implementation
public Node get(int index){ public boolean set(int index, int value){
if(index<0 || index>=length){
return null; Node temp = get(index);
}else{ if(temp!=null){
int m=length/2; temp.data=value;
if(index>m) { return true;
Node temp=tail;
for (int i = length-1; i > index; i--) { }
temp = temp.preview; return false;
} }
return temp;
}else {
Node temp=head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
return temp;
}
}
64
}
3. Doubly Linked List Implementation
public boolean insert(int index,int value){
if(index<0 || index>length) return false; public boolean remove(int index){
if(index==0){
if(index<0 || index>length) return false;
addFirst(value);
return true;
if(index==0){
} removeFirst();
if(index==length){ return true;
addEnd(value); }
return true; if(index==length-1){
} removeLast();
Node newNode=new Node(value); return true;
Node temp = get(index); }
newNode.next=temp; Node temp = get(index);
temp.preview.next=newNode; temp.preview.next=temp.next;
temp.preview=newNode;
temp.next.preview=temp.preview;
newNode.preview=temp.preview;
length++;
length--;
return true; if(length==0) {head=null;tail=null;}
} return true;
}
65
4. Binary Search Tree Implementation
• In a binary search tree (BST) the left child of a node contains a value smaller than the node's value, and
the right child contains a value greater than the node's value.
• The structure of a node in a BST can be implemented as:
66
4. Binary Search Tree Implementation
• To create a BST of one top node (root is the top node of the tree. ):
67
4-1. Insert method
null val
val<40 val>40
val=40
69
4-1. Insert method Node temp=root;
while(true ){
if(newNode.data<temp.data){
//insert at left
if(temp.left==null){
temp.left=newNode;
temp = temp.left;
}
else{
//insert at right
if(temp.right==null){
temp.right=newNode;
Insert the node at right. return true;
}
temp = temp.right;
}
70
}
4-1. Insert method
40
30 50
25 35 45 60
71
4-1. Insert method
public static void main(String[] args) {
• Let’s create the following BST
BinarySearchTree myBST = new BinarySearchTree();
myBST.insert(40);
myBST.insert(30);
myBST.insert(50);
myBST.insert(25);
myBST.insert(35);
myBST.insert(45);
myBST.insert(60);
72
4-1. Insert method
System.out.println(myBST.root.left.right.data);
System.out.println(myBST.root.right.right.data);
73
4-2. Search method
• How to verify if a node’s data/value exist in a BST. public boolean contains(int val){
There are many methodologies for this task, let’s start with Node temp = root;
while (temp!=null){
the iterative approach: if(val<temp.data){
Create a function contains(int value) temp=temp.left;
Loop through the BST starting from the root } else if (val>temp.data) {
If the search value is less then the current node’s temp=temp.right;
}else {
data, then move to the next node on the left. return true;
Otherwise, move to the next node on the right.
}
}
return false;
}
74
4-2. Search method
• How to verify if a node’s data/value exist in a BST.
System.out.println(myBST.contains(40));
System.out.println(myBST.contains(100));
}
75
5 . Heap Implementation
What is Heap?
• A heap is a complete binary tree, in which the node can have at most two children.
76
5 . Heap Implementation
What is Heap?
Max heap: The value of the parent node is greater than or equal to its children.
In a max heap, the node with maximum value will always be at the root node.
77
5-1 . Heap Implementation
• A Heap can be implemented using an array. Since the heap is a complete binary tree, there is no wastage of space.
• Let’s start the process of implementing a max heap
78
5-1 . Heap Implementation
79
import java.util.ArrayList;
import java.util.List;
private int leftChild(int index){
Left Child is at [2*i+1] if available. return 2*index+1;
}
private int parent(int index){
Parent Node is at [(i-1)/2] if available. return (index-1)/2;
}
}
80
5-1-1 . Insert method
Add the Element: Add the new element to the end of the
70 60
ArrayList.
81
5-1-1 . Insert method
90 90 99
?
70 60 99 60 90 60
?
50 99 50 70 50 70
82
5-1-1 . Insert method
public void insert(int value){
heap.add(value);
Add the Element: Add the new element to the
end of the ArrayList. int current = heap.size()-1;
Ensure that the heap property is
while(current>0 &&
heap.get(current)>heap.get(parent(current))){
maintained after insertion. swap(current,parent(current));
Do a Bubble Up: Comparing the newly
}
current = parent(current);
84
5-1-2 . Remove method
Replace the root element with the last element of the heap. 90 60
Ensure that the heap property is maintained after removing
by doing a Bubble down. 50 70 45
85
5-1-2 . Remove method
?
99 99 45
90 60 90 60
90 60
50 70 45 50 70 45
50 70
86
5-1-2. Remove method
87
5-1-2. Remove method
• Identify the indices of the left and right children of the current node (leftIndex(i)=2*i+1; rightIndex(i)=2*i+2)
• Compare the value of the current node with the values of its children.
If the value of the current node is less than the value of the selected child, swap the current node with the selected
child.
After the swap, update the index of the current node to be the index of the child with which it was swapped.
• Repeat Until Heap Property is Satisfied, where one of the following conditions is met:
The current node satisfies the heap property.
The current node becomes a leaf node.
88
5-1-2. Remove method
private void BubbleDown(int index){
int maxIndex=index;
while(true){
Bubble down function: int leftIndex = leftChild(index);
int rightIndex=rightChild(index);
if(leftIndex<heap.size() &&
heap.get(leftIndex)>heap.get(maxIndex)){
maxIndex=leftIndex;
}
if(rightIndex<heap.size() &&
heap.get(rightIndex)>heap.get(maxIndex)){
maxIndex=rightIndex;
}
if(maxIndex!=index){
swap(index,maxIndex);
index=maxIndex;
}else{
return;
}
89
}
5-1-1 . Remove method
myHeap.remove();
System.out.println(myHeap.getHeap());
}
90
6 . Hash Table Implementation
• A Hash table is a specific type of data structure, often referred to as an associative array, that is similar to arrays but is
not indexed by integers, but by other forms of data such as strings.
• In array, we store the element whose key is k at a position k of the array. That means, given a key k, we find the element
whose key is k by just looking in the kth position of the array. This is called direct addressing.
• Direct addressing is applicable when we can afford to allocate an array with one position for every possible key. But if
we do not have enough space to allocate a location for each possible key, then we need a mechanism to handle this
case.
91
6 . Hash Table Implementation
What is Hashing?
• Hashing in the context of hash tables involves using a hash function to convert keys into numerical indices within
an array (or hash table). This process allows for efficient storage and retrieval of key-value pairs.
• A hash function is a mathematical algorithm that takes an input key and generates a numerical value, known as a hash
code or hash value.
• The primary purpose of a hash function in a hash table is to efficiently map keys to indices within the underlying array
structure of the hash table.
92
6 . Hash Table Implementation
93
6 . Hash Table Implementation
{‘Tablet’,3500} 2
{‘Printer’,2500}
3
{‘HardDisk’,3000}
{‘USB’,100} 4
Hash code =1
94
6 . Hash Table Implementation
What is Collision ?
• In a hash table, a collision occurs when two or more distinct keys hash to the same index or position in the array. This
situation arises because the hash function used to map keys to indices is not perfect or because the array size is
limited compared to the number of possible keys.
• When a collision occurs, it means that there are multiple elements that are supposed to be stored at the same index
in the hash table. This can lead to data loss.
• The main methods to handle collisions when inserting elements into a hash table are:
Linear Probing: when a collision occurs, the algorithm searches for the next available slot in the hash table by
incrementing the index by a fixed amount (often 1) until an empty slot is found.
Separate chaining: Instead of storing all elements directly in the hash table's array, each slot in the array
contains a linked list to store multiple elements that hash to the same index.
95
6 . Hash Table Implementation
H(S) = σ𝑛−1 𝑖
𝑖=0 𝑆[𝑖] ∗ 𝑝 𝑚𝑜𝑑 𝐿
where:
■ S[i] represents the ASCII value of the i-th character of the string S.
■ p is a prime number chosen to reduce collisions.
■ L is the size of the hash table or the maximum value of the hash code.
96
6 . Hash Table Implementation
97
6 . Hash Table Implementation
98
6 . Hash Table Implementation
Implementation of Hash Table
102
7 . Graph Implementation
Introduction
• In the real world, many problems are represented in
terms of objects and connections between them.
• Graphs can be used to model a wide range of
relationships and structures, including social networks,
computer networks, transportation networks, molecular
structures, and more.
• They provide a powerful framework for analyzing and
solving problems related to connectivity, paths, flows,
and optimisation.
• Graphs can vary in complexity from simple structures
with a few nodes and edges to large, interconnected
networks with millions of nodes and edges.
103
7 . Graph Implementation
What is a Graph?
104
7 . Graph Implementation
What is a Graph?
Undirected graph
• A graph could be also directed (all the edges are directed) or undirected
(all the edges are undirected),
• When an edge connects two vertices, the vertices are said to be adjacent Directed graph
106
7 . Graph Implementation
Graph implementation
• There are several ways to represent graphs, each with its advantages and disadvantages.
107
7-1 . Implementation using Adjacency List
108
7-1 . Implementation using Adjacency List
} 109
7-1 . Implementation using Adjacency List
Example:
}
111
7-1 . Implementation using Adjacency List
114
7-2 . Implementation using Adjacency Matrix
115
7-3 . Implementation using Adjacency Matrix
116
7-2 . Implementation using Adjacency Matrix
118
7-2 . Implementation using Adjacency Matrix
119
7-3 . Implementation using Adjacency Matrix
public static void main(String[] args) {
WeightedGraph graph = new WeightedGraph(5);
Implementation of weighted graph
// Add vertices
graph.addVertex(0, "A");
graph.addVertex(1, "B");
graph.addVertex(2, "C");
graph.addVertex(3, "D");
graph.addVertex(4, "E");
// Add edges with weights
graph.addEdge(0, 1, 4); // A B
graph.addEdge(0, 2, 3); // A C
graph.addEdge(2, 3, 2); // C D
graph.addEdge(3, 1, 1); // D B
graph.addEdge(3, 4, 1); // D E
graph.addEdge(4, 0, 1); // E A
System.out.println("Adjacency Matrix:");
graph.printGraph();
}
120