Skip to content

Release #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions Headers/0003_Graph/0007_MinimumSpanningTreeKruskalAlgorithm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include<map>
#include<vector>
#include<list>
using namespace std;

namespace MinimumSpanningTreeKruskalAlgorithm
{
class Node
{
public:
int data;
Node* parent;
int rank;
Node(int data);
};

class Edge
{
public:
Node* nodeU;
Node* nodeV;
int weight;
Edge(Node* nodeU, Node* nodeV, int weight);
};

class Graph
{
private:
map<Node*, vector<Node*>> _adjlist;
map<int, Node*> _nodeMap;
vector<Edge*> _edgeList;
vector<pair<pair<int, int>, int>> _minimumSpanningTree;
Node* MakeOrFindNode(int data);
void MakeSet(Node* node);
void Union(Node* nodeU, Node* nodeV);
void Link(Node* nodeU, Node* nodeV);
Node* FindSet(Node* node);

public:
void PushUndirectedEdge(int valueU, int valueV, int weight);
void FindMinimumSpanningTreeKruskalAlgorithm();
vector<pair<pair<int, int>, int>> GetMinimumSpanningTree();
};
}
42 changes: 42 additions & 0 deletions Headers/0003_Graph/0008_MinimumSpanningTreePrimAlgorithm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# pragma once

#include<map>
#include<vector>
#include<set>
using namespace std;

namespace MinimumSpanningTreePrimAlgorithm
{
class Node
{
public:
int data;
Node* parent;
int key;
bool isInOperationalSet;
Node(int data);
};

class CompareNodeKey
{
public:
bool operator()(const Node* nodeU, const Node* nodeV) const
{
return nodeU->key < nodeV->key;
}
};

class Graph
{
private:
map<Node*, vector<pair<Node*, int>>> _adjlist;
map<int, Node*> _nodeMap;
vector<pair<pair<int, int>, int>> _minimumSpanningTree;
multiset<Node*, CompareNodeKey> _operationalSet;
Node* MakeOrFindNode(int data);
public:
void PushUndirectedEdge(int valueU, int valueV, int weight);
void FindMinimumSpanningTreePrimAlgorithm();
vector<pair<pair<int, int>, int>> GetMinimumSpanningTree();
};
}
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Data Structures and Algorithms

This repository contains a collection of **data structures and algorithms** implemented in **C++**. It is designed to provide efficient solutions to common algorithmic problems while adhering to clean coding practices and modular design.

### Features

- **Data Structures and Algorithms:** Implementations of data structures and algorithms based on the concepts from the book Introduction to Algorithms by Cormen, Leiserson, Rivest, and Stein (CLRS).
- **Modular Design:** Code is organized into manageable modules for better readability and reusability.
- **Testing:**
- Built with **CMake** as the build system for ease of compilation and dependency management.
- **Google Test** framework is integrated for comprehensive unit testing to ensure code correctness.

### Folder Structure

```plain text
datastructures-algorithms
├── Headers # Header Files
├── SourceCodes # Implementation of the solutions
├── Tests # Unit tests for implemented solutions
└── CMakeLists.txt # CMake configuration file
```
108 changes: 108 additions & 0 deletions SourceCodes/0003_Graph/0007_MinimumSpanningTreeKruskalAlgorithm.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "../Headers/0003_Graph/0007_MinimumSpanningTreeKruskalAlgorithm.h"
#include<climits>
#include<algorithm>
using namespace std;

namespace MinimumSpanningTreeKruskalAlgorithm
{
Node::Node(int data)
{
this->data = data;
this->parent = nullptr;
this->rank = INT_MAX;
}

Edge::Edge(Node* nodeU, Node* nodeV, int weight)
{
this->nodeU = nodeU;
this->nodeV = nodeV;
this->weight = weight;
}

// Graph Private Member Methods
Node* Graph::MakeOrFindNode(int data)
{
Node* node = nullptr;
if (this->_nodeMap.find(data) == this->_nodeMap.end())
{
node = new Node(data);
this->_nodeMap[data] = node;
}
else
{
node = this->_nodeMap[data];
}
return node;
}

void Graph::MakeSet(Node* node)
{
node->parent = node;
node->rank = 0;
}

void Graph::Union(Node* nodeU, Node* nodeV)
{
this->Link(this->FindSet(nodeU), this->FindSet(nodeV));
}

void Graph::Link(Node* nodeU, Node* nodeV)
{
if (nodeV->rank > nodeU->rank)
{
nodeU->parent = nodeV;
}
else
{
nodeV->parent = nodeU;
if (nodeU->rank == nodeV->rank)
{
nodeU->rank += 1;
}
}
}

Node* Graph::FindSet(Node* node)
{
if (node != node->parent)
{
node->parent = this->FindSet(node->parent);
}
return node->parent;
}

// Graph Public Member Methods
void Graph::PushUndirectedEdge(int dataU, int dataV, int weight)
{
Node* nodeU = this->MakeOrFindNode(dataU);
Node* nodeV = this->MakeOrFindNode(dataV);

this->_adjlist[nodeU].push_back(nodeV);
this->_adjlist[nodeV].push_back(nodeU);
this->_edgeList.push_back(new Edge(nodeU, nodeV, weight));
}

void Graph::FindMinimumSpanningTreeKruskalAlgorithm()
{
for (auto& iterator : this->_nodeMap)
{
this->MakeSet(iterator.second);
}

sort(this->_edgeList.begin(), this->_edgeList.end(), [](Edge* edgeX, Edge* edgeY) { return edgeX->weight < edgeY->weight; });

for (auto& edge : this->_edgeList)
{
if (this->FindSet(edge->nodeU) != this->FindSet(edge->nodeV))
{
this->Union(edge->nodeU, edge->nodeV);
this->_minimumSpanningTree.push_back({ {edge->nodeU->data, edge->nodeV->data}, edge->weight });
}
}
}

vector<pair<pair<int, int>, int>> Graph::GetMinimumSpanningTree()
{
return this->_minimumSpanningTree;
}
}
85 changes: 85 additions & 0 deletions SourceCodes/0003_Graph/0008_MinimumSpanningTreePrimAlgorithm.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "../Headers/0003_Graph/0008_MinimumSpanningTreePrimAlgorithm.h"
#include<climits>
using namespace std;


namespace MinimumSpanningTreePrimAlgorithm
{
Node::Node(int data)
{
this->data = data;
this->parent = nullptr;
this->key = INT_MAX;
this->isInOperationalSet = false;
}

// Graph Private Member Methods
Node* Graph::MakeOrFindNode(int data)
{
Node* node = nullptr;
if (this->_nodeMap.find(data) == this->_nodeMap.end())
{
node = new Node(data);
this->_nodeMap[data] = node;
}
else
{
node = this->_nodeMap[data];
}
return node;
}

// Graph Public Member Methods
void Graph::PushUndirectedEdge(int dataU, int dataV, int weight)
{
Node* nodeU = this->MakeOrFindNode(dataU);
Node* nodeV = this->MakeOrFindNode(dataV);

this->_adjlist[nodeU].push_back({nodeV, weight});
this->_adjlist[nodeV].push_back({nodeU, weight});
}

void Graph::FindMinimumSpanningTreePrimAlgorithm()
{
Node* root = this->_nodeMap.begin()->second;

root->key = 0;
for (auto& iterator : this->_nodeMap)
{
iterator.second->isInOperationalSet = true;
this->_operationalSet.insert(iterator.second);
}

while (!this->_operationalSet.empty())
{
Node* nodeU = *(this->_operationalSet.begin());
this->_operationalSet.erase(nodeU);
nodeU->isInOperationalSet = false;

for (auto& iterator : this->_adjlist[nodeU])
{
Node* nodeV = iterator.first;
int weight = iterator.second;

if (nodeV->isInOperationalSet && weight < nodeV->key)
{
this->_operationalSet.erase(nodeV);
nodeV->key = weight;
nodeV->parent = nodeU;
this->_operationalSet.insert(nodeV);

}
}

if (nodeU->parent != nullptr)
{
this->_minimumSpanningTree.push_back({ {nodeU->parent->data, nodeU->data}, nodeU->key });
}
}
}

vector<pair<pair<int, int>, int>> Graph::GetMinimumSpanningTree()
{
return this->_minimumSpanningTree;
}
}
3 changes: 3 additions & 0 deletions SourceCodes/0003_Graph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ set(0003GRAPH_SOURCES
0004_StronglyConnectedComponents.cc
0005_HamiltonianPathAndCycle.cc
0006_EulerianPathAndCircuit.cc
0007_MinimumSpanningTreeKruskalAlgorithm.cc
0008_MinimumSpanningTreePrimAlgorithm.cc

)

# Create a library target
Expand Down
22 changes: 22 additions & 0 deletions Tests/0000_CommonUtilities/UnitTestHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,26 @@ class UnitTestHelper
reverse(normalizedCycle2.begin() + 1, normalizedCycle2.end());
return (normalizedCycle1 == normalizedCycle2);
}

template<typename T>
vector<pair<pair<T, T>, T>> SortVectorOfPair(vector<pair<pair<T, T>, T>> data)
{
for (auto& iterator : data)
{
if (iterator.first.first > iterator.first.second)
{
swap(iterator.first.first, iterator.first.second);
}
}

sort(data.begin(), data.end(), [](const pair<pair<T, T>, T>& pairA, const pair<pair<T, T>, T>& pairB)
{
if (pairA.second == pairB.second)
{
return pairA.first.first < pairB.first.first;
}
return pairA.second < pairB.second;
});
return data;
}
};
45 changes: 45 additions & 0 deletions Tests/0003_Graph/0007_MinimumSpanningTreeKruskalAlgorithmTest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include<gtest/gtest.h>
#include "../Headers/0003_Graph/0007_MinimumSpanningTreeKruskalAlgorithm.h"
#include "../0000_CommonUtilities/UnitTestHelper.h"

namespace MinimumSpanningTreeKruskalAlgorithm
{
UnitTestHelper unitTestHelper;

TEST(MST, Kruskal)
{
Graph graph;

graph.PushUndirectedEdge(1, 2, 4);
graph.PushUndirectedEdge(1, 8, 8);
graph.PushUndirectedEdge(2, 8, 11);
graph.PushUndirectedEdge(2, 3, 8);
graph.PushUndirectedEdge(3, 4, 7);
graph.PushUndirectedEdge(3, 9, 2);
graph.PushUndirectedEdge(3, 6, 4);
graph.PushUndirectedEdge(4, 5, 9);
graph.PushUndirectedEdge(4, 6, 14);
graph.PushUndirectedEdge(5, 6, 10);
graph.PushUndirectedEdge(6, 7, 2);
graph.PushUndirectedEdge(7, 8, 1);
graph.PushUndirectedEdge(7, 9, 6);
graph.PushUndirectedEdge(8, 9, 7);

graph.FindMinimumSpanningTreeKruskalAlgorithm();

vector<pair<pair<int,int>, int>> actualMST = graph.GetMinimumSpanningTree();
vector<pair<pair<int, int>, int>> expectedMST =
{
{{7, 8}, 1},
{{3, 9}, 2},
{{6, 7}, 2},
{{2, 1}, 4},
{{3, 6}, 4},
{{3, 4}, 7},
{{8, 1}, 8},
{{4, 5}, 9}
};

ASSERT_EQ(unitTestHelper.SortVectorOfPair(actualMST), unitTestHelper.SortVectorOfPair(expectedMST));
}
}
Loading
Loading