We will be using the We will be using the **minimal blog** template.

- Login to Gatsby dashboard and click on "
**Add a site**"

- Go for "
**Start from a Template**" option.

- We will be using the
**minimal blog**template.

- Give a name to your project:

- A github repository will be created on your behalf.

Now clone/download the Github repo just created, to your local system and open the code in your code editor.

You can use the following command for cloning -

```
git clone <github_url>
```

Run the following commands -

```
npm install
```

```
npm run develop
```

The directory structure:

Note: If anything breaks due to the following changes, run `npm run develop`

before panicking :P.

For changing the site name, head over to `gatsby-config.js`

and add the following code ( change it with the name you want for your blog )

```
siteMetadata: {
siteTitleAlt: `Priyanka Yadav`,
siteTitle: `Priyanka Yadav`,
},
```

The code might break, just run `npm run develop`

to build and run it again.

To change the content of About Me page,

- head over to
`content/pages/about/index.mdx`

- write a new about me description.

```
---
title: About
slug: "/about"
---
Hi!
< About Me Description >
```

To change the hero text on the index page,

- create a new file at
`src\@lekoarts\gatsby-theme-minimal-blog\texts\hero.mdx`

- This file shadows the default hero text.

```
<Text sx={{ fontSize: [4, 5, 6], fontWeight: `bold`, color: `heading` }}>
Hi.
</Text>
I am Priyanka....................................
```

You might have to run `npm run develop`

to see the changes.

You can add, edit and modify your Social Media details from `gatsby-config.js`

.

```
externalLinks: [
{
name: `Twitter`,
url: `https://twitter.com/<username>`,
},
{
name: `LinkedIn`,
url: `https://www.linkedin.com/in/<username>/`,
},
{
name: `Github`,
url: `https://github.com/<username>`,
},
],
```

From the documentation

New blog posts will be shown on the index page (the three most recent ones) of this theme and on the blog overview page. They can be added by creating MDX files inside content/posts. General setup:

- Create a new folder inside
`content/posts`

- Create a new
`index.mdx`

file, and add the frontmatter - Add images to the created folder (from step 1) you want to reference in your blog post.
- Reference an image as your
`banner`

in the frontmatter - Write your content below the frontmatter
- Add a slug to the frontmatter to use a custom slug, e.g. slug: "/my-slug" (Optional)
- You can also add
`tags`

to your blog.

Frontmatter reference:

```
title: Introduction to "Defence against the Dark Arts"
date: 2019-11-07
description: Defence Against the Dark Arts (abbreviated as DADA) is a subject taught at Hogwarts School of Witchcraft and Wizardry and Ilvermorny School of Witchcraft and Wizardry.
tags:
- Tutorial
- Dark Arts
banner: ./defence-against-the-dark-arts.jpg
canonicalUrl: https://random-blog-about-curses.com/curses-counter-curses-and-more
```

You can refer to this blog folder to get an idea.

To edit the projects part below “Latest posts” on the index page, create a file at `src/@lekoarts/gatsby-theme-minimal-blog/texts/bottom.mdx`

to edit the contents.

Since I do not want the Projects section, I created this file and left it empty.

Now, to remove the dummy blogs in the website, just delete the corresponding folders from `content/posts`

.

Generate favicons and banner for your site using favicon generator and canva.

Place the newly generated favicons and banner under

`static`

folder .And make the following changes in

`gatsby-config.js`

```
resolve: `gatsby-plugin-manifest`,
options: {
name: `Priyanka's Blog`,
short_name: `Priyanka's Blog`,
description: `Priyanka Yadav's blog`,
start_url: `/`,
background_color: `#fff`,
display: `standalone`,
icon: `./static/favicon-16x16.png`,
theme_color_in_head: false,
},
},
```

Now run `npm run develop`

to ensure nothing breaks and your website is working fine.

Now you can commit all the changes to Github. Use the following commands -

```
git status
git add .
git commit -m "<commit_message>"
// optional : git checkout -b <branch_name>
git push origin <branch_name>
```

Head over to Netlify and Login.

Click on the option "

**New Site from Git**"

- Choose "
**Github**" for continuous deployment.

- Find your repository and select it

- Select your branch name

- Enter the build command and go ahead.

It will take sometime for the site to build and get deployed.

After the site is deployed, you can change the site name from "

**Domain Settings**" option.

And there you are, you have successfully created your blog and even deployed it 🥳. Feel free to put your queries in the comments! :)

]]>Have you ever created multiple folders like `v1`

, `v2`

, `v3`

, `v4-final`

, `v5-final-final`

, `v7-last-final`

, `v7-updated-last-final`

for your project and ended up deleting and updating wrong files every other time?

Well, I have, and it was seriously horrible.

But what were we trying to do in the first place?

Trying to mess up? Come On, No!

We were trying to keep track of different versions of our project, with utmost honesty and creativity.

And if this interests you, Version Control Systems would be good to know about.

**VERSION CONTROL** is nothing but **CONTROLLING THE VERSIONS** of something.

Okay, imagine playing a game of chess with your friend. You both are in the middle of a game, but due to some reasons, you need to leave. Now, what's something you would do to continue the game in the future?

Take a picture right?

You would just capture the chessboard, come back later, set up the pieces, and continue with the game again, with no hassle.

So, what did you just do by capturing that image?

Made sure your friend doesn't cheat? Well yes, why not!

But you also ensured that your game was safe and you could come back to it later, whenever needed.

And that's what a VCS does too, **it records the changes in your files over time so you can recall previous versions later on.**

Every change is recorded by VCS, along with the metadata, such as who changed it, why they changed it, what was the issue, etc. Just like that chessboard image on your phone, it has all the metadata too, like when the picture taken, what's the size of the image, etc.

Now, the files need not be Source Code files only, they can vary from graphic design images, web design layouts, text documents, or any piece of information.

**A VCS gives you the independence of going back to a file, see who did the change and why, the exact timestamp of when the change was made, to easily recover if you messed up with the current version.
**

We will learn about 3 kinds of VCS -

- Local Version Control System
- Centralized Version Control System
- Distributed Version Control System

In earlier times, when there were no systems such as Git, developers used to track versions by copying files into multiple directories. Yes, just like `v1`

, `v2`

, `v3`

, and so on.

Whenever they wanted to make a change, they used to copy all the old files in a new directory, update the files there, and updated the version number accordingly.

The **advantage **is that it is really simple.

But the **disadvantages** are

- that it is absolutely
**error-prone**, and we have no clue about the reason behind creating these versions, the functionality that was added, etc. - there's always a risk of losing all the data if there's no continuous backup.

Centralized VCS was introduced to make developers work in a collaborative way.

- In CVCS, there is a
**single server and multiple clients**. - The server is a master repository that consists of all the versions of the project.
- Now, if a client needs to work on that project, he/she communicates with the server and pulls/copies the current version of the project in their local system.
- If there are any changes in a file or a new version is to be created, the client directly commits them into the main repository.

Two actions are required to make your changes visible to others

**You commit**the changes to the main repository.**Others update**their working copy to see the changes.

Some famous Centralized VCS are **Subversion** and **Perforce**.

The **advantages **of CVCS

- Developers can collaborate.
- They can be aware of the work done by others.
- Server administrators can control the privileges given to the clients.

However, the biggest **disadvantages **of CVCS is

**Single Point of Failure (SPOF)**:- What if the centralized repository goes down? It hampers the development process, and versioned changes could not be saved or updated.
- What if the centralized repository gets corrupted and there's no proper backup? This may lead to the loss of the complete project.

This disadvantage was the reason that Distributed VCS was developed.

In DVCS, the client doesn't just pull/checkout the latest version of the code but mirrors the entire repository, including its full history.

This prevents the fear of SPOF since anytime the server dies, any of the client's repositories could be used to recover it.

Actions required to make your changes visible to others

**You commit**the changes to your local repository.**You push**these changes to the main repository.**Others pull**your changes in their local repositories.**They update**their working copy to see the changes.

Some famous Distributed VCS are **Git **and **Mercurial**.

**Advantages **of DVCS

- Makes collaboration easier
- Prevents the SPOF problem.

There aren't any **disadvantages **to using a DVCS as compared to CVCS honestly. But in general

- If the project has large binary files, a lot of space would be needed to store these files and their versions.
- If your project has a very long history, downloading the entire history could be somewhat impractical and may also take up large disk space.

**Enforces Discipline:**VCS enforces discipline since it controls the entire development process.**Archive versions:**It also allows you to archive versions, so you can store subsequent versions of the project.**Maintain metadata:**Apart from storing the project files, you can also store metadata or historical information about the current and past versions of the project.**Enable Collaboration:**The existence of a central repository helps the developers in working together in a collaborative way.**Recovery from accidents:**Helps you to cover the mess :P

If you liked the write-up, leave your feedback and suggestions :)

]]>So here's my effort of bringing up the concept of Traditional Procedural Programming vs Object-Oriented Programming in the form of a story.

There were 2 associates - Harvey and Louis( Yes, I have been watching Suits these days :P)

And Jessica, their managing partner, gave them the following problem to solve-

```
There are 2 kinds of Associates in the Firm -
FirstYearAssociates and SecondYearAssociates
Both of them have the following functions to perform -
- minor research
- prepare documents
```

Jessica asked Harvey and Louis to solve this problem in an efficient way, and the solution that's most efficient and scalable will be sent over to the client.

Now, Louis decided to go on with the **Procedural programming approach**, and Harvey insisted on following the **Object-Oriented programming**.

Louis divided the work to be done in the form of procedures/functions. He created two functions - `minorResearch()`

and `prepareDocuments()`

and wrote the following code for the problem-

```
void minorResearch(string associate) {
//
//
}
void prepareDocuments(string associate) {
//
//
}
```

Now, Harvey wanted to come up with something that would solve the problem in an efficient and scalable way.

He was aware that OOPs is best whenever we need to code real-life situations, so he created two classes - `FirstYearAssociates`

and `SecondYearAssociates`

and defined functions for both of them.

```
class FirstYearAssociates {
void research() {
// DO MINOR RESEARCH
}
void prepareDocuments() {
//
//
}
}
```

```
class SecondYearAssociates {
void research() {
// DO MINOR RESEARCH
}
void prepareDocuments() {
//
//
}
}
```

Both of them went to Jessica and pitched their solutions. Louis pointed out that he solved the problem faster and with fewer lines of code. However, Harvey justified that his approach is scalable and can handle future problems as well.

So Jessica came up with the updated problem statement

```
The firm now has ThirdYearAssociates as well,
and they perform the following functions -
- major research
- prepare documents
- assist Senior Associates
```

Now, Louis got tensed and thought he was going to lose. He had to make changes in his existing code, which made it quite messy, but he was eventually able to come up with the following solution-

```
void research(string associate) {
if associate == "FirstYearAssociate" || associate == "SecondYearAssociate":
// do minor research
if associate == "ThirdYearAssociate":
// do major research
}
void prepareDocuments() {
//
//
}
void assistSeniorAssociates() {
//
//
}
```

While all Harvey did, was just adding one more class for Third Year Associates-

```
class ThirdYearAssociates {
void research() {
// DO MAJOR RESEARCH
}
void prepareDocuments() {
//
//
}
void assistSeniorAssociates() {
//
//
}
}
```

Now to note, Louis had to make changes in his original code and will have to do that every time in case the specification changes. While Harvey just wrote a new class without making any changes in the previous code.

So do you think Louis gave up? No, he argued that Harvey has written useless and duplicated code which was not even required, and he simply did it to get that promotion.

Jessica asks Harvey to explain the allegation thrown upon him.
He then explains that he is well aware of the fact that the code is repeated and the classes have a lot in common, so he has already created a **base class for all the associates** with their common features -

```
class Associate {
void research() {
//
}
void prepareDocuments() {
//
}
}
```

Harvey emphasized on the fact that in the end, all of them are `Associates`

, and all of them do research and prepare documents, so he abstracted out the common features.

And derived the classes - `FirstYearAssociate`

, `SecondYearAssociate`

, and `ThirdYearAssociate`

from the base class `Associate`

itself.

Even further, if any class needs to implement any special behaviors, then it can simply **override **these methods, just like we have been doing for the `research`

method all this time:

```
void research() {
// DO MINOR RESEARCH
}
```

```
void research() {
// DO MAJOR RESEARCH
}
```

Well !!! Who do you think won? ;)

But now to sum it up in a generalized way.

In procedural programming, the program is divided into small parts called

**functions**. In object-oriented programming, the program is divided into small parts called**objects ( instance of a class).**Adding new data and function is

**not easy**in procedural programming, while it is**comparatively easier**in OOPS.In procedural programming,

**overriding is not possible**, while it is**possible**for OOPS.Procedural programming is based on the

**unreal world**, while OOPS is made for the**real-world**.**C**is an example of procedural programming, whereas**C++ and Java**are Object-Oriented Languages.

If you liked the write-up, leave your feedback and suggestions :)

]]>They are basically used to represent a **network **- this network could refer to an intra-city network of roads or a connection network on social media.

Graphs are data structures that constitute of 2 things - vertices and edges. Vertices are also known as nodes, and edges are also known as links or connections. Edges are what connect the nodes together.

Edges can be of two types based on direction -

**Undirected Edges**: An undirected edge basically means a bidirectional edge, so if an edge connects A and B, it means A is connected to B, and B is connected to A.**Directed Edges**: A directed edge has a single direction, and has a particular orientation. So A->B means A is connected to B but not vice versa.

Edges can be of two types based on weights-

**Weighted Edge**: If the edge/link carries some weight, it is known as a weighted edge. The weight refers to the cost it will take to travel through that edge, just like a tollway.**Unweighted Edge**: If the edge/link does not carry any weight, it is known as an unweighted edge. It can be compared to a freeway, where it costs nothing to travel through that edge. Such edges are used to show if a connection exists or not.

Since we already know about the kind of edges, the types of graphs are easy to understand.

**Undirected graphs**: A graph that consists of undirected edges is known as an undirected graph.**Bidirectional graphs**: A graph that consists of directed edges is known as a directed graph.**Weighted graphs**: A graph that consists of weighted edges is known as a weighted graph.**Unweighted graphs**: A graph that consists of unweighted edges is known as an unweighted graph.

There exist 2 ways of representing a graph:

- Adjacency List
- Adjacency Matrix

Adjacency list as the name suggests is a list of all the vertices, where each vertex stores all of its adjacent or neighboring vertices in the form of a list.

```
#include<iostream >
#include < vector >
using namespace std;
vector < int > adj[10];
int main() {
int x, y, nodes, edges;
cin >> nodes;
cin >> edges;
for (int i = 0; i < edges; ++i) {
cin >> x >> y;
adj[x].push_back(y);
}
return 0;
}
```

**Space Complexity:**`O(V+E)`

**Time Complexity to find if two nodes are connected to each other:**`O(V)`

The time complexity is of the worst-case scenario such as a complete graph, where every vertex is connected to each other.

**Pros of Adjacency List:**

- Complete graphs rarely exist in real life, hence the adjacency list is more efficient in terms of space.

**Cons of Adjacency List:**

- The access time to check whether an edge exists between 2 vertices is linear. This could be a huge disadvantage for the problems that require frequent lookups for edge connectivity.

An adjacency matrix is a 2-dimensional matrix of dimensions `V*V`

where V=vertices.

Each cell in the matrix, say `graph[a][b]`

represents if vertex a is connected to b.

- For
**unweighted graphs**, the value of a cell is either`1(connected)`

or`0(not connected)`

. - For
**weighted graphs**, the value of a cell is either`0(not connected)`

or`w(weight of the edge)`

.

```
#include <iostream>
using namespace std;
int A[10][10];
int main() {
int x, y, nodes, edges;
cin >> nodes;
cin >> edges;
for (int i = 0; i < nodes; ++i) {
for (int j = 0; j < nodes; ++j) {
A[i][j] = 0;
}
}
for (int i = 0; i < edges; ++i) {
cin >> x >> y;
A[x][y] = 1; //Mark the edges from vertex x to vertex y
}
}
```

**Space Complexity: O(V*V)****Time Complexity to find if two nodes are connected to each other: O(1)**

**Pros of Adjacency Matrix:**

- Time Complexity to check if an edge exists between 2 vertices is O(1).

**Cons of Adjacency Matrix:**

- Can cause memory wastage, in the case of graphs where there are many vertices but few edges, since most of the cells would be filled by zero. Such graphs are known as
**Sparse Graphs**.

Both of these representations have their own pros and cons and the decision to move forward with either of them depends upon the given problem and the given graph.

To traverse a graph, you need to choose a vertex as a **root/source/starting node**. This vertex is from where we start our traversal.

BFS as the name stands means traversing a graph breadth by breadth. Breadth can also be thought of as a layer. We traverse the graph, layer by layer, or in a breadthwise manner.

For instance,

Now, a graph might contain a cycle, so we maintain a visited array to make sure we don't visit the same vertex again.

In simple words, this is what we do in BFS :

- We start from a vertex A, the source node, the node at Level 0.
- All the nodes directly connected to A, are at Level 1.
- Now you have a list of vertices at Level 1, we use them to find the vertices directly connected to them, the resulting vertices will be at Level 2.
- And we keep repeating this until we run out of the graph.

**BFS implementation using Queue :**

```
void BFS(int source) {
// Mark all the vertices as not visited
bool * visited = new bool[vertices];
for (int i = 0; i < vertices; i++)
visited[i] = false;
// Create a queue for BFS
queue < int > q;
// Mark the current node as visited and push it in the queue
visited[source] = true;
q.push(source);
// Eplore till we visit all the vertices
while (!q.empty()) {
// Pop a vertex from queue and print it
int temp = q.front();
cout << temp << " ";
q.pop();
// Get all adjacent vertices of the popped
// vertex temp.
// If a adjacent has not been visited,
// then mark it visited and push it in the queue
for (auto i = graph[temp].begin(); i != graph[temp].end(); ++i) {
if (!visited[ * i]) {
visited[ * i] = true;
q.push( * i);
}
}
}
}
```

**Space Complexity: O(B)**, for the queue where B is the maximum breadth/width of the graph.**Time Complexity: O(V)**, where V=Vertices since we visit each vertex once.

To traverse a graph, you need to choose a vertex as a **root/source/starting node**. This vertex is from where we start our traversal.

DFS as the name stands means traversing a graph in depth.

In DFS, we start from a source node, go deep as far as we can through a given path, and then backtrack to find an unexplored path, and then explore it in a depthwise fashion again. We keep doing this until the entire graph has been explored.

DFS implementation using Recursion:

```
void DFS(int sourceVertex, bool visited[]) {
// mark the current source vertex as visited
visited[sourceVertex] = true;
cout << v << " ";
// Recur for all the vertices adjacent to the current source vertex
for (auto i = graph[sourceVertex].begin(); i != graph[sourceVertex].end(); ++i) {
if (!visited[ * i]) {
DFS( * i, visited);
}
}
}
```

**Space Complexity: O(D)**, for the recursion stack where D is the maximum depth of the graph.**Time Complexity: O(V)**, where V=Vertices since we visit each vertex once.

Breadth-First Search can be implemented only using a queue, while Depth First Search can be implemented using Recursion or stack.

Do leave your feedback and suggestions :)

]]>In C++ Standard template library, we have `priority_queue`

which can be directly used to implement binary heap. This saves us the time and effort of implementing a heap from scratch. However, it is good to know both of these ways.

A `priority_queue`

is very similar to a stack, it has the following major operations :

`push`

: Inserts the element in max/min-heap.`pop`

: Extracts the root of the max/min-heap.`top`

: Returns the value of the root of max/min-heap.

We need not worry about heapifying or looking after the violating operations. `priority_queue`

takes care of it. It always keeps the root of the heap on the top, even after you push or pop an element.

**Syntax for creating Max Heap of integers** :

```
priority_queue<int> maxHeap;
```

**Syntax for creating Min Heap of integers** :

```
priority_queue<int, vector<int>, greater<int>> minHeap;
```

If using a user-defined type, `greater<int>`

can be replaced by a comparator function that takes 2 arguments and returns a bool value.

**Creating a max heap **:

```
int main()
{
// defining max heap
priority_queue <int> pq;
// insert nodes in the heap
/*the greatest number will always be at the top of the priority_queue, denoting the root of max heap*/
pq.push(2); // pq.top() = 2
pq.push(4); // pq.top() = 4
pq.push(7); // pq.top() = 7
pq.push(1); // pq.top() = 7
pq.push(9); // pq.top() = 9
// Extracting elements from max-heap
while(pq.empty()==false)
{
cout<<pq.top()<<" ";
pq.pop();
}
}
```

Explanation :

Output :

```
9 7 4 2 1
```

**Creating a min-heap **:

```
int main ()
{
// defining min heap
priority_queue <int, vector<int>, greater<int> > pq;
// insert nodes in the heap
/*the smallest number will always be at the top of the priority_queue, denoting the
root of min heap*/
pq.push(2); // pq.top() = 2
pq.push(4); // pq.top() = 2
pq.push(7); // pq.top() = 2
pq.push(1); // pq.top() = 1
pq.push(9); // pq.top() = 1
// One by one extract items from min heap
while (pq.empty() == false)
{
cout << pq.top() << " ";
pq.pop();
}
return 0;
}
```

Explanation :

Output:

```
1 2 4 7 9
```

Most of the questions related to heap are of the pattern `Top K elements`

.
They can be of following variations

- Top K smallest/largest numbers.
- Top K frequent numbers.
- Frequency Sort.
- Top K closest numbers etc.

Now, let us understand how can we solve such questions using a heap.

Consider a max heap, if you insert N elements in it, the time complexity is `O(N*log N)`

.
But if you insert K elements in the heap, the time complexity becomes `O(N*log K)`

.

`Question: Find Top 3 largest numbers in the given array`

Consider the array as `[1, 5, 6, 9, 2, 3, 10]`

**Brute-force method **:

- Sort the array and then traverse =>
`O(n*log n)`

**Solution using heap**:

- Let us insert all these elements in the min-heap.

Inserting all these elements took `O(n*log n)`

time.

But what if we create a heap of `size=k`

.

- We first insert the first k elements in the array =>
`O(k*log k)`

- We check for each of the rest n-k elements, if the element is greater than the top of the heap, pop the top element from the heap, and insert the current element =>
`O((n-k)*log k)`

And `O(k*log k) + O((n-k)*log k)`

= `O(n * log k)`

and this is much better than `O(n*log n)`

.

```
void findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> pq;
// Push k elements in the heap
for(int i=0;i<k;i++)
{
pq.push(nums[i]);
}
// Check for each of the n-k elements
for(int i=k;i<nums.size();i++){
if(nums[i]>pq.top())
{
pq.pop();
pq.push(nums[i]);
}
}
cout<<" The top k elements are :"<<endl;
while(!pq.empty()){
cout<<pq.top()<<" ";
pq.pop();
}
}
```

Hence, we can conclude for further similar questions :

This could be understood by the following image :

Please leave your feedback and suggestions :)

References

https://www.geeksforgeeks.org/implement-min-heap-using-stl/

https://www.educative.io/edpresso/find-the-kth-smallest-element-from-an-array-using-a-min-heap

]]>*( A complete binary tree is a tree in which every other node other than the leaves have two children )*
The 2 main characteristics of Heaps are

- It should be a
**complete binary tree**. - Nodes must be according to the
**Heap order property**.

The 2 heap order priorities are

**Max heap property**- In a max-heap, the value of the root node should be the greatest among all the value of all of its children. The same property should be recursively true for all the sub-trees.**Min heap property**- In a min-heap, the value of the root node should be the smallest among all the values of all of its children. The same property should be recursively true for all the sub-trees.

- Heap Sort uses Binary Heap to sort an array in
`O(N log N)`

time. - Heaps are also used to implement Priority Queues.
- Priority queues, in turn, are used to solve graph algorithms and array related questions.

A binary heap is generally represented using an array, by level order traversal. The root element is always the first element of the array.

or a node, present at index i -

- Its
`parent`

can be found at -`heap[(i-1)/2]`

- Its
`left child node`

can be found at -`heap[(2*i)+1]`

- Its
`right child node`

can be found at -`heap[(2*i)+2]`

`heapify()`

- heapify operation is called when the binary heap violates the heap property. heapify rearranges the heap in such a way, that it becomes valid again. This takes`O(log N)`

time.`getMin()`

or`getMax()`

- Returning the root node value of a min/max heap in`O(1)`

time.`extractMin()`

or`extractMax()`

- Removing the root node of a min/max heap. This takes`O(log N)`

time because heapify operation is called, to maintain the heap property, after removing the root node.`insert()`

: Inserting a new key takes`O(log N)`

time. We add the new key at the end of the max/min-heap. If the key violates the heap property, we traverse up and fix the tree.`decreaseKey()`

: Decreases the value of a key in a heap. If the decreased value violates the heap property, we traverse up and fix the tree. This takes`O(log N)`

time.`increaseKey()`

: Increases the value of a key in a heap. If the increased value violates the heap property, we traverse up and fix the tree. This takes`O(log N)`

time.`delete()`

: Deleting a key also takes`O(log N)`

time.

For min-heap, replace the value to be deleted with -INFINITY. Doing so, the value at the root node will now become -INFINITY. Then call `extractMin()`

.

For max-heap, replace the value to be deleted with +INFINITY. Doing so, the value at the root node will now become +INFINITY. Then call `extractMax()`

.

First we define a class for the heap.

```
class MinHeap
{
int *mh; // pointer to the array of heap elements
int maximum_size; // maximum size of the array or maximum number of heap nodes
int current_size; // current size of the array or current number of heap nodes
}
```

Constructor to initialize the heap - we would only be needing the maximum_size of the array as a parameter

```
MinHeap::MinHeap(int size)
{
current_size = 0;
maximum_size = size;
mh = new int[size];
}
```

Functions to return the parent, left, and right child node.

```
int parent(int i) { return (i-1)/2; }
int left(int i) { return (2*i + 1); }
int right(int i) { return (2*i + 2); }
```

Now, to insert a new key -

- First insert the new key at the end.
- Traverse up to fix the violated min-heap property if any.

```
void MinHeap::insertKey(int k)
{
if (current_size == maximum_size)
{
cout << "Overflow : Cannot insert more nodes";
return;
}
// First insert the new key at the end
current_size++;
int i = current_size - 1;
mh[i] = k;
// Traverse up & fix the min heap property if it is violated
while (i != 0 && mh[parent(i)] > mh[i])
{
swap(&mh[i], &mh[parent(i)]);
i = parent(i);
}
}
```

Now to decrease key.

- Decrease the key
- Traverse up & fix the min-heap property if it is violated

```
void MinHeap::decreaseKey(int i, int new_val)
{
// Decrease the key
mh[i] = new_val;
// Traverse up & fix the min-heap property if it is violated
while (i != 0 && mh[parent(i)] > mh[i])
{
swap(&mh[i], &mh[parent(i)]);
i = parent(i);
}
}
```

Now, `heapify`

method - To heapify a subtree with the root at given index i. The method assumes that the subtrees are already heapified.

```
void MinHeap::MinHeapify(int i)
{
int l = left(i);
int r = right(i);
int smallest = i;
if (l < current_size && mh[l] < mh[i])
smallest = l;
if (r < current_size && mh[r] < mh[smallest])
smallest = r;
if (smallest != i)
{
swap(&mh[i], &mh[smallest]);
MinHeapify(smallest);
}
}
```

Now, to extract the minimum/root node.

- Remove the root node.
- Replace the root node value with the last node value.
- Heapify the tree from the root.

```
int MinHeap::extractMin()
{
if (current_size <= 0)
return INT_MAX;
if (current_size == 1)
{
current_size--;
return mh[0];
}
// Remove the root node.
int root = mh[0];
// Replace the root node value with the last node value.
mh[0] = mh[current_size-1];
current_size--;
// Heapify the tree from the root.
MinHeapify(0);
return root;
}
```

Now, to delete a key.

- Replace the value of the key with INT_MIN.
- Extract the min/root node.

```
void MinHeap::deleteKey(int i)
{
decreaseKey(i, INT_MIN);
extractMin();
}
```

You can find the entire code here.

Subscribe to the newsletter to read more blogs on data structures and algorithms!

References -

https://www.educative.io/edpresso/what-is-a-heap

https://www.geeksforgeeks.org/heap-data-structure/

]]>