Here are some things that may help you improve your program. ## Clarify your specification In the text, you describe the desired quantity of nodes as "half the amount of coordinates" but what the code actually does is choose half the number of unique edges. There could well be a difference if, say, we had a thousand coordinate pairs that each referred to the same two edges. ## Understand standard structures There is a much simpler way to create your `unordered_map` that doesn't require any helper function. Because each value is initialized to zero, we can rely on this and simplify the code considerably: std::unordered_map<int, int> node_degree; for (const auto &coord : coordinates) { ++node_degree[coord.x]; ++node_degree[coord.y]; } ## Use appropriate data structures Your use of an `unordered_map` is a sound idea, but I'm not so sure about the conversion to a `std::vector`. It seems to me that a `std::priority_queue` more directly matches what you're trying to accomplish. Here's the equivalent to your `select_coordinates_highest_occurrence` (which I find a bit wordy): void popularEdges(const std::vector<Coordinate> & coordinates) { std::unordered_map<int, int> m; for (const auto &coord : coordinates) { ++m[coord.x]; ++m[coord.y]; } std::priority_queue<std::pair<int, int>> pq; for (const auto &node : m) { pq.emplace(node.second, node.first); } for (auto n=pq.size()/2; n; --n) { std::cout << pq.top().second << '\n'; pq.pop(); } } In my testing on my computer, this version is 25% faster than the original. ## Separate I/O from processing It may depend on your particular needs, but I'd suggest that passing back a vector would be much more generally useful than simply printing from within the function. Similarly, the `read_coordinates_into_vector` prints the file name back to the user. I'd expect instead that it would be silent. The caller can just as easily print that string if needed. ## Make return variables return variables The `read_coordinates_into_vector` currently requires the user to pass in a vector, but what would likely make more sense would be to have the code return a newly created vector instead. ## Don't use spurious `typedef` C++ is not C. The `typedef` here is not needed: typedef struct Coordinate { /*...*/ }; because in C++, `Coordinate` is a proper type without the additional keyword. ## Prefer `std::istream` to file names The current code for `read_coordinates_into_vector` is only capable of handing a named file and not, say, a `std::stringstream`. It could be made more generic and, I think, more durable, if the function prototype were this: std::vector<Coordinate> read_coordinates_into_vector(std::istream &in); ## Use a `friend` function and custom inserter Use a friend function and custom inserter to simplify reading coordinates from a file: struct Coordinate { int x; int y; friend std::istream &operator>>(std::istream &in, Coordinate &c) { return in >> c.x >> c.y; } }; std::vector<Coordinate> read(std::istream &in) { std::vector<Coordinate> v; Coordinate pair; while (in >> pair) { v.push_back(edge); } return v; }