Unit 1
Unit 1
Types of analysis:-
Worst-case − The maximum number of steps taken on any instance of size a.
Best-case − The minimum number of steps taken on any instance of size a.
Average case − An average number of steps taken on any instance of size a.
Amortized − A sequence of operations applied to the input of size a averaged over
time.
Importance of Algorithm Analysis:-
In the analysis of the algorithm, it generally focused on CPU (time) usage, Memory
usage, Disk usage, and Network usage. All are important, but the most concern is about the
CPU time. Be careful to differentiate between:
Performance: How much time/memory/disk/etc. is used when a program is run.
Thisdepends on the machine, compiler, etc. as well as the code we write.
Complexity: How do the resource requirements of a program or algorithm scale, i.e.
whathappens as the size of the problem being solved by the code gets larger.
Role of Algorithms in Computing:-
Algorithms play a crucial role in computing by providing a set of instructions for a
computer to perform a specific task. They are used to solve problems and carry out tasks in
computer systems, such as sorting data, searching for information, image processing, and
much more. An algorithm defines the steps necessary to produce the desired outcome, and
the computer follows the instructions to complete the task efficiently and accurately. The
development of efficient algorithms is a central area of computer science and has significant
impacts in various fields, from cryptography and finance to machine learning and robotics.
Algorithms are widely used in various industrial areas to improve efficiency, accuracy,
anddecision-making. Some of the key applications include:
1. Manufacturing: Algorithms are used to optimize production processes and supply
chainmanagement, reducing waste and increasing efficiency.
2. Finance: Algorithms are used to analyze financial data and make predictions, enabling
tradersand investors to make informed decisions.
3. Healthcare: Algorithms are used to process and analyze medical images, assist in
diagnosing diseases, and optimize treatment plans.4Retail: Algorithms are used for customer
relationship management, personalized product recommendations, and pricing optimization.
4. Transportation: Algorithms are used to optimize routes for delivery and transportation,
reducing fuel consumption and increasing delivery speed.
6. Security: Algorithms are used to detect and prevent security threats, such as hacking, fraud,
and cyber-attacks.
In these and many other industries, algorithms play a crucial role in automating tasks,
improving decision-making, and enhancing overall performance and efficiency. Algorithms
are fundamental to computing and play a crucial role in many aspects of the field. Some of
the key needs and applications of algorithms in computing include:
1. Data processing: Algorithms are used to process and analyze large amounts of data, such
as sorting and searching algorithms.
3. Computer graphics: Algorithms are used to create and process images and graphics, such
as image compression algorithms and computer-generated graphics algorithms.
5. Database management: Algorithms are used to manage and organize large amounts of
data indatabases, such as indexing algorithms and query optimization algorithms.
6. Network communication: Algorithms are used for efficient communication and data
transfer in networks, such as routing algorithms and error correction algorithms.
7. Operating systems: Algorithms are used in operating systems for tasks such as process
scheduling, memory management, and disk management.
Algorithm of Efficiency:-
There are some circumstances where the space/memory used must be analyzed. Forexample, for
large quantities of data or for embedded systems programming.
Clearly the more quickly a program/function accomplishes its task the better.
Omega (Ω) notation specifies the asymptotic lower bound for a function f(n). For a given function
g(n), Ω(g(n)) is denoted by:
Ω (g(n)) = {f(n): there exist positive constants c and n0 such that 0 ≤ c*g(n) ≤ f(n) for all n ≥ n0}.
This means that, f(n) = Ω(g(n)), If there are positive constants n0 and c such that, to the right of n0
the f(n) always lies on or above c*g(n).
This means that, f(n) = Θ(g(n)), If there are positive constants n0 and c such that, to the right of n0
the f(n) always lies on or above c1*g(n) and below c2*g(n).
Big – O Notation:
Big – O (O) notation specifies the asymptotic upper bound for a function f(n). For a given function
g(n), O(g(n)) is denoted by:
O (g(n)) = {f(n): there exist positive constants c and n0 such that f(n) ≤ c*g(n) for all n ≥ n0}.
This means that, f(n) = O(g(n)), If there are positive constants n0 and c such that, to the right of n0
the f(n) always lies on or below c*g(n).
The difference between the heights of the left subtree and the right subtree for any node is known as
the balance factor of the node.
The AVL tree is named after its inventors, Georgy Adelson-Velsky and Evgenii Landis, who
published it in their 1962 paper “An algorithm for the organization of information”.
Example of AVL Trees:
The above tree is AVL because the differences between the heights of left and right subtrees for
every node are less than or equal to 1.
Operations on an AVL Tree:
1. Insertion
2. Deletion
3. Searching [It is similar to performing a search in BST]
Rotating the subtrees in an AVL Tree:
An AVL tree may rotate in one of the following four ways to keep itself balanced:
Left Rotation:
When a node is added into the right subtree of the right subtree, if the tree gets out of
balance, we do a single left rotation.
// Calculate height
int height(struct Node *N) {
if (N == NULL)
return 0;
return N->height;
}
int max(int a, int b) {
return (a > b) ? a : b;
}
// Create a node
struct Node *newNode(int key) {
struct Node *node = (struct Node *)
malloc(sizeof(struct Node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1;
return (node);
}
// Right rotate
struct Node *rightRotate(struct Node *y) {
struct Node *x = y->left;
struct Node *T2 = x->right;
x->right = y;
y->left = T2;
y->height = max(height(y->left), height(y->right)) + 1;
x->height = max(height(x->left), height(x->right)) + 1;
return x;
}
// Left rotate
struct Node *leftRotate(struct Node *x) {
struct Node *y = x->right;
struct Node *T2 = y->left;
y->left = x;
x->right = T2;
x->height = max(height(x->left), height(x->right)) + 1;
y->height = max(height(y->left), height(y->right)) + 1;
return y;
}
// Delete a nodes
struct Node *deleteNode(struct Node *root, int key) {
// Find the node and delete it
if (root == NULL)
return root;
if (key < root->key)
root->left = deleteNode(root->left, key);
else if (key > root->key)
root->right = deleteNode(root->right, key);
else {
if ((root->left == NULL) || (root->right == NULL)) {
struct Node *temp = root->left ? root->left : root->right;
if (temp == NULL) {
temp = root;
root = NULL;
} else
*root = *temp;
free(temp);
} else {
struct Node *temp = minValueNode(root->right);
root->key = temp->key;
root->right = deleteNode(root->right, temp->key);
}
}
if (root == NULL)
return root;
// Update the balance factor of each node and
// balance the tree
root->height = 1 + max(height(root->left),
height(root->right));
return root;
}
B-Tree
The B-tree is a self-balancing ordered structured data that stores data in a set of pages and
also allows efficient searching, insertion, and deletion operations. It has its origin in a generic form
of binary search trees developed by Rudolf Bayer and Edward M. McCreight in 1972. It is capable
of processing large datasets efficiently. Among database systems and file systems, B-trees are quite
often employed. This is so because they have a well-balanced structure, which allows for high speed
performance, and they can handle a great number of elements.
Representation of B-Tree in C
A B-tree is organized as a balanced tree with the following properties-
1. Each node of the data structure can contain several keys with pointers to their child nodes.
2. Balancing of nodes is done by applying limits key constraints on the maximum and
minimum number of keys a node can carry.
3. Each leaf is comparable to the next, thereby eliminating any queue or wait time.
Basic Operations on B-Tree
Search: Move down the tree repeatedly in a recursive way until a key is found.
Insertion: Put the key into a bunch of leaf nodes and split the nodes if it is necessary.
Deletion: Take away the leaves from the tree, join or split the nodes, if needed.
Time and Space Complexity:
1. Search: O(logN)
2. Insertion: O(logN)
3. Deletion: O(logN)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct BTreeNode {
int num_keys; // Number of keys currently in the node
int keys[M-1]; // Array of keys
struct BTreeNode *children[M]; // Array of child pointers
bool is_leaf; // True if node is a leaf
};
newNode->num_keys = M/2 - 1;
child->num_keys = M/2 - 1;
parent->children[index + 1] = newNode;
// Shift parent's keys to insert the middle key from the child
for (int i = parent->num_keys - 1; i >= index; i--) {
parent->keys[i + 1] = parent->keys[i];
}
if (node->is_leaf) {
// Insert key into the sorted order
while (i >= 0 && node->keys[i] > key) {
node->keys[i + 1] = node->keys[i];
i--;
}
node->keys[i + 1] = key;
node->num_keys++;
} else {
// Find the child to insert the key
while (i >= 0 && node->keys[i] > key) {
i--;
}
i++;
if (node->children[i]->num_keys == M - 1) {
// Split child if it's full
splitChild(node, i);
if (node == NULL) {
// Create a new root node
*root = createNode(true);
(*root)->keys[0] = key;
(*root)->num_keys = 1;
} else {
if (node->num_keys == M - 1) {
// Split the root if it's full
struct BTreeNode *new_root = createNode(false);
new_root->children[0] = node;
splitChild(new_root, 0);
*root = new_root;
}
insertNonFull(*root, key);
}
}
insert(&root, 10);
insert(&root, 20);
insert(&root, 5);
insert(&root, 6);
insert(&root, 12);
insert(&root, 30);
return 0;
}
Output:
In-order traversal of the B-tree: 5 6 10 12 20 30
Applications of B-Tree
Here are some applications of B-Tree-
1. Database indexing.
2. Filesystem management.
3. Metadata storage.
4. Caching mechanisms.
5. Multilevel indexing.