I feel like this is a simple problem that I have overcomplicated. Any tips or different approach would be greatly appreciated.
Problem and goal
Given a list of coordinates (each line represents an 'edge' containing 'nodes') my goal is to obtain (half of the amount of the total) nodes that occur the most. I hope my example would clarify this problem:
Input file
Each line represents a 'coordinate' (in reality an 'Edge'), that consists of 2 nodes (integers).
20 1
7 15
7 1
7 20
7 4
7 19
Desired output
Preferably a vector that contains: [7,20,1]
Why 7,20,1? Because 7, 20 and 1 occur the most if you look at the input file. This is also half (3) of the total amount (6) of coordinates. Note: the output vector doesn't have to be sorted.
My goal is to increase the performance of my current approach (any other approach however is very appreciated (but please check my constraints in the next section). The current performance seems to be slow for 1 million edges (lines). An example of such a large coordinates file can be obtained from here (8 MB file).
Constraints
- The input file is being read and the results are added as a vector of struct with type
Coordinate
(as my code will show). Please note that I can not change this (due to constraints that are beyond the scope of my question). In other words, the input parameter to my function is avector<Coordinate>
. - I would like to obtain an array/vector as an output of the highest occurrences.
My current approach and code
Essentially, I am 'looping' through my coordinates in the select_coordinates_highest_occurrence
function and add each coordinate (along with its first and second element) to a map (function add_node_to_node_degree_map
) that keeps track of the amount of the occurrences. If I do a simple benchmark, this seems to also be the main bottleneck of the code.
I then proceed by converting the map to a vector, since I am unable to sort the vector by the value.
After I have done that, I sort the vector (ascending) and 'cut' it in half so that I obtain the highest amount of coordinates.
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
#include <string>
#include <unordered_map>
#include <algorithm>
typedef struct Coordinate {
int x;
int y;
} Coordinate;
void add_node_to_node_degree_map(std::unordered_map<int, int>& node_degree, int node) {
if (!node_degree.count(node)) {
node_degree[node] = 1;
}
else {
node_degree[node] = node_degree[node] + 1;
}
}
void select_coordinates_highest_occurrence(std::vector<Coordinate>& coordinates) {
// Map all vertices onto a map along with their degree
std::unordered_map<int, int> node_degree;
for (auto &edge : coordinates) {
add_node_to_node_degree_map(node_degree, edge.x);
add_node_to_node_degree_map(node_degree, edge.y);
}
// Convert the map to a vector
std::vector<std::pair<int, int>> node_degree_vect;
for (auto it = node_degree.cbegin(); it != node_degree.cend(); ++it)
{
node_degree_vect.push_back(std::make_pair(it->first, it->second));
}
// Sort the vector (ascending, high degree nodes are on top)
std::sort(node_degree_vect.begin(), node_degree_vect.end(), [](const std::pair<int, int> &left, const std::pair<int, int> &right) {
return left.second > right.second;
});
// Only collect the high occurrences (delete the 'other' half of the vector with lower occurrences)
std::vector<int> high_occurrences;
for (int i = 0; i < node_degree_vect.size() / 2; i++) {
high_occurrences.push_back(node_degree_vect[i].first);
}
for (int i = 0; i < high_occurrences.size(); i++) {
printf("\n%d", high_occurrences[i]);
}
}
/*
This method can be ignored and is only added to load a graph in case you want to test it on your system.
*/
void read_coordinates_into_vector(std::vector<Coordinate>& coordinates, std::string file_path) {
std::ifstream infile(file_path);
std::cout << file_path;
int vertex_source;
int vertex_destination;
while (infile >> vertex_source >> vertex_destination) {
Coordinate edge;
edge.x = vertex_source;
edge.y = vertex_destination;
coordinates.push_back(edge);
}
infile.close();
}
int main() {
std::vector<Coordinate> coordinates;
std::string file_path = "C:\\Users\\USERNAMEHERE\\Desktop\\coordinates_list.txt";
read_coordinates_into_vector(coordinates,file_path);
select_coordinates_highest_occurrence(coordinates);
return 0;
}
I really feel like I overcomplicated this solution.
2 1
and not2 0 1
. Is this desired or did I break something? \$\endgroup\$2 0 1
for me too. \$\endgroup\$2 0 1
for me, but the 1 might be a little bit harder to see since it is next to the 'Press any key to continue' message to exit the command line terminal (on Windows at least) \$\endgroup\$0
. Apologies. \$\endgroup\$