I am using a C++ STL set with a custom comparator to store an Edge data structure as shown below. I defined the Edge to be essentially a key-value pair. Index is the key and I want to iterate through the collection by value (maxlength) from largest to smallest. At any given time, I usually only care about the edges with the 3 largest values. There will only be a relatively small number of edges in the collection ranging from around 7 to 64. When I insert an edge, the values of the two adjacent edges will need to be adjusted. To do this, I will add the new edge to the set, then remove the two adjacent edges and re-add them with their new values. Can anyone share a more efficient data structure for this purpose?
#include <iostream>
#include <iomanip>
#include <sstream>
#include <set>
using namespace std;
struct Edge {
int maxlength;
int index;
Edge(int index, int maxlength) {
this->maxlength = maxlength;
this->index = index;
}
bool operator<(Edge other) const {
return maxlength < other.maxlength;
}
};
void run() {
set<Edge> edges;
edges.insert(Edge(25, 3));
edges.insert(Edge(21, 4));
edges.insert(Edge(28, 2));
cout << "First Edge: " << edges.begin()->maxlength << endl;
edges.erase(Edge(28, 2));
cout << "First Edge: " << edges.begin()->maxlength << endl;
edges.insert(Edge(39, 1));
cout << "First Edge: " << edges.begin()->maxlength << endl;
cout << "Last Edge: " << (--edges.end())->maxlength << endl;
}
int main() {
run();
return 1;
}
Related
How can the unordered_set can hold both (0, 1) and (1, 0) if they have the same hash value?
#include <iostream>
#include <unordered_set>
#include <utility>
using namespace std;
struct PairHash
{
template <class T1, class T2>
size_t operator()(pair<T1, T2> const &p) const
{
size_t hash_first = hash<T1>{}(p.first);
size_t hash_second = hash<T2>{}(p.second);
size_t hash_combined = hash_first ^ hash_second;
cout << hash_first << ", " << hash_second << ", " << hash_combined << endl;
return hash_combined;
}
};
int main()
{
unordered_set<pair<int, int>, PairHash> map;
map.insert({0, 1});
map.insert({1, 0});
cout << map.size() << endl;
for (auto& entry : map) {
cout << entry.first << ", " << entry.second << endl;
}
return 0;
}
Output:
0, 1, 1
1, 0, 1
2
1, 0
0, 1
Link to onlinegdb.
unordered_set can hold one instance of any unique data-value; it is not limited to only holding data-values with unique hash-values. In particular, when two data-values are different (according to their == operator) but both hash to the same hash-value, the unordered_set will make arrangements to hold both of them regardless, usually at a slightly reduced efficiency (since any hash-based lookups for either of them will internally hash to a data structure that holds both of them, which the unordered_set's lookup-code will have to iterate over until it finds the one it is looking for)
i try to implement freq unordered map but it has weird behavior , why when i use unordered_map it gives me keys with negative numbers and when i use map it will give my the correct keys values.
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int maxOperations(vector<int>& nums, int k) {
unordered_map <int,int> mp;
for(auto i:nums){
mp[i]++;
}
int count=0;
// for(auto i:mp)
// cout << i.first << " " << i.second << endl;
for(auto i:mp){
int target= k-i.first;
cout << i.first << " " << i.second << " "<< mp[target] << endl;
if(i.second>0 && mp[target]>0){
if(i.first!=target){
count += min(i.second,mp[target]);
mp[target]=0;
//i.second=0;
mp[i.first]=0;
}else
{
cout << count << endl;
count += floor(i.second/2);
mp[target]=0;
}
}
}
return count;}
int main()
{
vector<int> vec= {29,26,81,70,75,4,48,38,22,10,51,62,17,50,7,7,24,61,54,44,30,29,66,83,6,45,24,49,42,31,10,6,88,48,34,10,54,56,80,41,19};
int k =12 ;
cout << maxOperations(vec,k);
return 0;
}
When you use an ordered map, you traverse the keys in order. Thus, target is never negative. When you traverse an unordered map, it is unordered. Therefore, target is sometimes negative.
If the negative values are not correct, then you need to traverse the map in order and so you should not use an unordered map.
Another problem with traversing out of order is that when modifying the map while traversing it, you will create entries that may or may not be included in your traversal. That will cause unpredictable behavior. You may prefer to create new entries in a separate container and merge them into the original container only when you're finished traversing.
#include<bits/stdc++.h>
using namespace std;
int main() {
map<int, int> nums_map;
cout << nums_map.count(0) << endl;
int a = nums_map[0];
cout << nums_map.count(0) << endl;
cout << nums_map[0];
return 0;
}
OUTPUT:
0
1
0
It makes no sense to me at least, why the line:
int a = nums_map[0];
is increasing the value of count by 1, also the nums_map.empty() = 0 at the same time.
Because std::map::operator[] works in a slightly weird way. From the documentation on std::map::operator[]:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
So if the key doesn't exist, it creates a new pair. That's exactly what's happening here.
#include <iostream>
#include <map>
int main() {
using namespace std;
map<int, int> nums_map; // nums_map == {}
cout << nums_map.count(0) << endl; // 0, because the map is empty
int a = nums_map[0]; /* a new key/value pair of {0, 0} is
created and a is set to nums_map[0],
which is 0 */
cout << nums_map.count(0) << endl; // Since there is one key 0 now, this shows 1
cout << nums_map[0]; // As shown previously, nums_map[0] is 0
return 0;
}
I am creating a scrabble game and i need to have a basic score to words on the dictionary.
I used make_tuple and stored it inside my tuple. Is there a way to access elements in a tuple as if it was in a vector?
#include <iostream>
#include <tuple>
#include <string>
#include <fstream>
void parseTextFile()
{
std::ifstream words_file("scrabble_words.txt"); //File containing the words in the dictionary (english) with words that do not exist
std::ofstream new_words_file("test.txt"); //File where only existing words will be saved
std::string word_input;
std::tuple<std::string, int> tupleList;
unsigned int check_integrity;
int counter = 0;
while(words_file >> word_input)
{
check_integrity = 0;
for (unsigned int i = 0; i < word_input.length(); i++)
{
if((int)word_input[i] >= 97 && (int)word_input[i] <= 123) //if the letter of the word belongs to the alphabet
{
check_integrity++;
}
}
if(word_input.length() == check_integrity)
{
new_words_file << word_input << std::endl; //add the word to the new file
tupleList = std::make_tuple(word_input, getScore(word_input)); //make tuple with the basic score and the word
counter++; //to check if the amount of words in the new file are correct
std::cout << std::get<0>(tupleList) << ": " << std::get<1>(tupleList) << std::endl;
}
}
std::cout << counter << std::endl;
}
One would generally use a tuple when there are more than two values of different types to store. For just two values a pair is a better choice.
In your case what you want to achieve seems to be a list of word-value pairs. You can store them in a container like a vector but you can also store them as key-value pairs in a map. As you can see when following the link, an std::map is literally a collection of std::pair object and tuples are a generalization of pairs.
For completeness, if my understanding of your code purpose is correct, these are additions to your code for storing each tuple in a vector - declarations,
std::tuple<std::string, int> correct_word = {};
std::vector<std::tuple<std::string, int>> existing_words = {};
changes in the loop that saves existing words - here you want to add each word-value tuple to the vector,
if(word_input.length() == check_integrity)
{
// ...
correct_word = std::make_tuple(word_input, getScore(word_input));
existing_words.push_back(correct_word);
// ...
}
..and finally example of usage outside the construction loop:
for (size_t iv=0; iv<existing_words.size(); ++iv)
{
correct_word = existing_words[iv];
std::cout << std::get<0>(correct_word) << ": " << std::get<1>(correct_word) << std::endl;
}
std::cout << counter << std::endl;
The same code with a map would look like:
The only declaration would be a map from strings to values (instead of a tuple and vector of tuples),
std::map<std::string, int> existing_words = {};
In the construction loop you would be creating the map pair in a single line like this,
if(word_input.length() == check_integrity)
{
// ...
existing_words[word_input] = getScore(word_input);
// ...
}
While after constructing you would be accessing map elements using .first for the word and .second for the counter. Below is a printing example that also uses a for auto loop:
for (const auto& correct_word : existing_words)
std::cout << correct_word.first << ": " << correct_word.second << std::endl;
std::cout << counter << std::endl;
Notice that maps are by default alphabetically ordered, you can provide your own ordering rules and also use an unordered map if you don't want any ordering/sorting.
My first C++ class coming from a basic Java class. This class is a more advanced C++ programming class about Data Structures. I don't know the basics of C++, only a little basics of Java.
Assignment is to :
-get 3 user inputs of states and their population (done).
-Get the most populated (biggest of three) and post it. (1/2)
I am able to get the highest number... but I'm not sure on the syntax on how to post it with the corresponding string (state).
I know this is some kind of array using struct, but I dont know how to post st.title
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct states_t {
string statename;
int population;
} state[3];
int main()
{
string mystr;
int n;
for (n = 0; n<3; n++)
{
cout << "Enter state name: ";
getline(cin, state[n].statename);
cout << "Enter population: ";
getline(cin, mystr);
stringstream(mystr) >> state[n].population;
}
cout << "\nYou have entered these movies:\n";
for (n = 0; n < 3; n++)
cout << state[n].statename << "\n" << state[n].population << "\n";
return 0;
}
==== UPDATED CODE WITH LARGEST POPULATION ====
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct states_t {
string statename;
int population;
} state[3];
int main()
{
string mystr;
int n;
for (n = 0; n<3; n++)
{
cout << "Enter state name: ";
getline(cin, state[n].statename);
cout << "Enter population: ";
getline(cin, mystr);
stringstream(mystr) >> state[n].population;
}
cout << "\nYou have entered these states:\n";
for (n = 0; n < 3; n++)
cout << state[n].statename << " " << state[n].population << "\n" << "\n";
if ((state[0].population >= state[1].population) && (state[0].population >= state[2].population))
cout << "The most populous state you entered is: " << state[0].statename << " with a population of " << state[0].population << "\n";
else if ((state[1].population >= state[0].population) && (state[1].population >= state[2].population))
cout << "The most populous state you entered is: " << state[1].statename << " with a population of " << state[1].population << "\n";
else
cout << "The most populous state you entered is: " << state[2].statename << " with a population of " << state[2].population << "\n";
return 0;
}
The first step is to store the name of each state with its population. It will help if you change title to name to make it more clear what the variable is for. If you do this correctly, you will quickly see that you no longer need mystr. (Note that you should always use meaningful variable names. A generic name like mystr often means that you do not know the purpose of the variable. Keep thinking about what the variable is for in order to make a more useful name.)
Now once you have the state data input into the array correclty, you should keep track of the data for the least and most populous state, rather than just its population. Instead of
int mn, mx;
declare
state_t mn, mx;
Then in your if statement do
mn = st[n];
and similarly for mx.
You will have to change your if condition to access the value in the struct. Then you can print the values directly from mn and mx.
Your code is designed to find the highest (and lowest) population of all states. You could also have tried to find out what the index-number is of the state with the highest population and use that number to index the state array to get what you need from there.
Here's how I would do it:
I would first make two int arrays, one corresponding to the index values of the array of struct states_t, and then one corresponding to the population values, like such:
int index[3];
int pop[3];
for (int i = 0; i < 3; i++)
{
index[i] = i;
pop[i] = st[i].population;
}
Next, perform a bubble sort algorithm on the population, and move the indices of the objects around according to the actions of the sort algorithm like such:
int n = 3;
for (int i = 0 ; i < ( n - 1 ); i++)
{
for (int j = 0 ; j < n - i - 1; j++)
{
//if the population of the next element
//is higher than the current element, swap it
//perform the same operation for state indices
if (array[j] > array[j+1])
{
int swap = pop[j];
int swap2 = index[j];
pop[j] = pop[j+1];
index[j] = index[j+1];
pop[j+1] = swap;
index[j+1] = swap2;
}
}
}
All that's left to do now is to call the first object in the list with the index array like such:
st[index[0]].title; //state with highest population
Coolest part about this method is that you can make this work for any number of States by changing the value of int n.
While there is nothing that prevents you from using a standard array-of-struct as you would in C, embracing the C++ std::vector can take a bulk of the tedium out of it. While using the array-of-struct, you get the benefit of protecting your array bounds manually indexing and manually handling storage, C++ has long sought to help alleviate or ease the manual aspects of handling collections of "things" (for lack of better words)
The std::vector container is tailor made to allow you to add to a collection of things using the simple push_back modifier. Basically you define your struct (say s_state_t) holding your name and pop, much as you have, and then declare and create an instance of a vector of type <s_state_t> (say state). Then to add a state (say s) to the vector you simply state.push_back(s) and let std::vector handle the storage and indexing. (vector also provides many other helpful member functions and modifiers to help get information about your collection)
Then the C++ way to approach managing a collection of states is to create either an additional struct or class to manipulate your collections of states, to add to, check and keep track of the max/min populations, etc. In a very simple form, you could create a class, that provides member functions that do just that, add a new state, check the max/min and then provide a way to output the contents of your collection. For example, you could do something like:
#include <vector>
#include <string>
#include <iomanip>
#include <limits>
typedef struct { /* struct holding state name and population */
std::string name;
int pop;
} s_state_t;
class country { /* class country - a collection of states */
std::vector<s_state_t> state; /* declare vector for states */
s_state_t mx = { "", 0 }, /* declare structs for max min */
mn = { "", std::numeric_limits<int>::max() };
void chkmxmn (s_state_t s) { /* function to set max/min */
if (s.pop < mn.pop)
mn = s;
if (s.pop > mx.pop)
mx = s;
}
public:
void addstate (std::string name, int pop) { /* add a state */
s_state_t s = { name, pop }; /* struct for new state */
chkmxmn (s); /* update max and min */
state.push_back (s); /* push_back to vector */
}
void prnstates() { /* output saved states, max/min */
for (auto& i : state) /* loop over vector */
std::cout << std::setw(16) << std::left << i.name <<
std::setw(10) << std::right << i.pop << "\n";
std::cout << "\nminimum and maximum populations:\n" <<
std::setw(16) << std::left << mn.name <<
std::setw(10) << std::right << mn.pop << "\n" <<
std::setw(16) << std::left << mx.name <<
std::setw(10) << std::right << mx.pop << "\n";
}
};
int main (void) {
country us; /* instance of country */
us.addstate ("Texas", 25000000); /* add names/pops */
us.addstate ("Louisiana", 12000000);
us.addstate ("California", 50000000);
us.prnstates(); /* output results */
return 0;
}
(note: you should add additional validations to check the name is not NULL or empty and pop is a reasonable number -- that is left to you)
Example Use/Output
$ ./bin/vector_states
Texas 25000000
Louisiana 12000000
California 50000000
minimum and maximum populations:
Louisiana 12000000
California 50000000
note: you can also create a typedef to your new vector type to cut down on the typing associated with specifying instances and parameters of the type with something similar to:
typedef std::vector<s_state_t> state_t; /* typedef to cut down typing */
which then allows you to declare new instances or parameters as simply, e.g.:
state_t state; /* declare vector for states */
Look things over. Neither method is more "right or wrong", but if you are going to learn C++ instead of C, you might as well go ahead and use the nice parts of it.