error in iterating maps to get input - c++

In chess, each type of coin has some weight. Given the name of the coin and weight for the coin, write a C++ code to print the name of the coins in ascending order of their weight. Assume that weight of each coin is unique.
I want to use map
My codes is here
#include <iostream>
#include <map>
using namespace std;
int main(){
int n,i=0;
char name;
int weight;
cin>>n;
class std::map<char,int> coins;
while(i<n)
{
i++;
cin>>name;
cin>>weight;
coins[name]=weight;
}
coins.sort(coins.begin(),coins.end(),weight);
while(i<n){
i++;
cout<<coins;
}

You cannot sort a map. The elements are already sorted in an
order defined by the key of each element.
If it is guaranteed that every piece will have a unique weight,
none the same as any other,
then you can use weight instead of name as your key
in a map of type std::map<int,char>.
Then simply iterating through the map will give you the elements
in order of increasing weight.
But if you do that
and if it ever happens that someone specifies two pieces that have
the same weight in the input to your program, one of the pieces
will be lost and will not appear at all in the output list.
For the reason just mentioned, using a map this way has a bad
"code smell" and I would be reluctant to use it in real life.
I would also be hesitant to give this as an answer to an
exercise in a programming course.
If you use multimap instead of map, however, you can have
multiple elements with the same key, still sorted according to the
order of their keys.
That seems like a much better idea.

No need to sort . Only list needs to be sorted . Maps by default keep the data in sorted format

Related

Hashing Function/Code

so I'm just learning (or trying to) a bit about hashing. I'm attempting to make a hashing function, however I'm confused where I save the data to. I'm trying to calculate the number of collisions and print that out. I have made 3 different files, one with 10,000 words, 20,000 words and 30,000 words. Each word is just 10 random numbers/letters.
long hash(char* s]){
long h;
for(int i = 0; i < 10; i++){
h = h + (int)s[i];
}
//A lot of examples then mod h by the table size
//I'm a bit confused what this table is... Is it an array of
//10,000 (or however many words)?
//h % TABLE_SIZE
return h
}
int main (int argc, char* argv[]){
fstream input(argv[1]);
char* nextWord;
while(!input.eof()){
input >> nextWord;
hash(nextWord);
}
}
So that's what I currently have, but I can't figure out what the table is exactly, as I said in the comments above... Is it a predefined array in my main with the number of words in it? For example, if I have a file of 10 words, do I make an array a of size 10 in my main? Then if/when I return h, lets say the order goes: 3, 7, 2, 3
The 4th word is a collision, correct? When that happens, I add 1 to collision and then add 1 to then check if slot 4 is also full?
Thanks for the help!
The point of hashing is to have a constant time access to every element you store. I'll try to explain on simple example bellow.
First, you need to know how much data you'd have to store. If for example you want to store numbers and you know, that you won't store numbers greater than 10. Simpliest solution is to create an array with 10 elements. That array is your "table", where you store your numbers. So how do I achieve that amazing constant time access? Hashing function! It's point is to return you an index to your array. Let's create a simple one: If you'd like to store 7, you just save it to array on position 7. Every time, you'd like to look, for element 7, you just pass it to your hasning funcion and bzaah! You got an position to your element in constant time! But what if you'd like to store more elements with value 7? Your simple hashing function is returning 7 for every element and now its position i already occupied! How to solve that? Well, there is not many solution, the simpliest are:
1: Chaining - you simply save element on first free position. This has significant draw back. Imagine, you want to delete some element ... (this is the method, you describing in question)
2: Linked list - if you create an array of pointers on some linked lists, you can easilly add your new element at the end of linked list, that is on position 7!
Both of this simple solutions has its drawbacks and cons. I guess you can see them. As #rwols has said, you don't have to use array. You can also use a tree or be a real C++ master and use unordered_map and unordered_set with custom hash function, which is quite cool. Also there is structure named trie, which is usefull, when you'd like to create some sort of dictionary (where is really hard to know, how many words you will need to store)
To sum it up. You has to know, how many things, you wan't to store and then, create ideal hashing function, that covers up array of apropriate size and in perfect world, it has to have uniform index distribution, with no colisions. (Achiving this is pretty hard and in the real world, I guess, this is impossible, so the less colisions, the better.)
Your hash function, is pretty bad. It will have lot of colisions (like strings "ab" and "ba") and also, you need to mod m it with m being the size of you array (aka. table), so you can save it to some array and you can profit of it. The modus is a way of simplyfiing the has function, because has function has to "fit" in table, that you specified in beginning, because you can't save element on position 11, 12, ... if you have array of 10.
How should good hashing function look like? Well, there is better sources than me. Some example (Alert! It's in Java)
To your example: You simply can't save 10k or even more words into table of size 10. That'll create a lot of collisions and you loose the main benefit of hashing function - constant access to elements you saved.
And how would your code look? Something like this:
int main (int argc, char* argv[]){
fstream input(argv[1]);
char* nextWord;
TypeOfElement table[size_of_table];
while(!input.eof()){
input >> nextWord;
table[hash(nextWord)] = // desired element which you want to save
}
}
But I guess, your goal isn't to save something somewhere, but to count number of colisions. Also note that code above doesn't solve colisions. If you'd like to count colisions, create array table of ints and initialize it to zero. Than, just increment the value, which is stored on index, which is returned by your hash funcion, like this:
table[hash(nextWord)]++;
I hope I helped. Please specify, what else you want to know.
If a hash table is required then as others have stated std::unordered_map will work in most cases. Now if you need something more powerful because of a large entry base, then I would suggest looking into tries. Tries combine the concepts of (Vector-Array) insertion, (Hashing) & Linked Lists. The run time is close to O(M) where M is the amount of characters in a string if you are hashing a string. It helps to remove the chance of collisions. And the more you add to a trie structure the less work has to be done as certain nodes are opened and created. The one draw back is that tries require more memory. Here is a diagram
Now your trie may vary on the size of the array due to what you are storing, but the overall concept and construction of one is the same. If you was doing a word - definition look up then you may want an array of 26 or a few more for each possible hashing character.
To count a number of words which have same hash, we should know hashes of all previous words. When you count a hash of some word, you should write it down, for example in some array. So you need an array with size equal to the number of words.
Then you should compare the new hash with all previous ones. Method of counting depends on what you need - number of pair of collisions or number off same elements.
Hash function should not be responsible for storing data. Normally you would have a container that uses hash function internally.
From what you wrote I understood that you want to create hashtable. One way you could do that (probably not the most efficient one, but should give you an idea):
#include <fstream>
#include <vector>
#include <string>
#include <map>
#include <memory>
using namespace std;
namespace example {
long hash(char* s){
long h;
for(int i = 0; i < 10; i++){
h = h + (int)s[i];
}
return h;
}
}
int main (int argc, char* argv[]){
fstream input(argv[1]);
char* nextWord;
std::map<long, std::unique_ptr<std::vector<std::string>>> hashtable;
while(!input.eof()){
input >> nextWord;
long newHash = example::hash(nextWord);
auto it = hashtable.find(newHash);
// Collision detected?
if (it == hashtable.end()) {
hashtable.insert(std::make_pair(newHash, std::unique_ptr<std::vector<std::string>>(new std::vector<std::string> { nextWord } )));
}
else {
it->second->push_back(nextWord);
}
}
}
I used some C++ 11 features to write an example faster.
I am not sure that I understand what you do not understand. The explanations below might help you.
A hash table is a kind of associative array. It is used to map keys to values in a similar manner an array is used to map indexes (keys) to values. For instance, an array of three numbers, { 11, -22, 33 }, associates index 0 to 11, index 1 to -22 and index 2 to 33.
Now, let us assume that we would like to associate 1 to 11, 2 to -22 and 3 to 33. The solution is simple: we keep the same array, only we transform the key by subtracting one from it, thus obtaining the original index
This is fine until we realize that this is just a particular case. What if the keys are not so “predictable”? A solution would be to put the associations in a list of {key, value} pairs and when someone is asking for a key, just search the list: { 123, 11}, {3, -22}, {0, 33} If the value associated to 3 is asked, we simply search the keys in list for a match and find -22. That’s fine, but if the list is large we’re in trouble. We could speed the search if we sort the array by keys and use binary search, but still the search may take some time if the list is large.
The search speed may be further enhanced if we break the list in sub-lists (or buckets) made of related pairs. This is what a hash function does: puts together pairs by related keys (an ideal hash function would associate one key to one value).
A hash table is a two columns table (an array):
The first column is the hash key (the index computed by a hash function). The size of the hash table is given by the maximum value of the hash function. If, for instance, the last step in computing the hash function is modulo 10, the size of the table will be 10; the pairs list will be broken into 10 sub-lists.
The second column is a list (bucket) of key/values pairs (the sub-list I was taking about).

Creating indexes of highest value in struct for top 5

Lets say i have a struct below
struct info
{
string firstname;
string lastname;
double kids;
double income;
double cars;
int index;
};
Lets say i have 500 people in this struct, each containing the information first, last name, kids, income and cars.
I created a int called index so that i can sort who has the most income from highest to least.
What method would you use or how would you go about finding the top 5 people with the most income, and giving them an index as 1,2,3,4,5 etc. So that i can tell who the top 5 are if i wished to print their names out.
I am looking for a simple method as im still learning about trees and such.
Thanks!
vector of structs. Supply a specialized function for comparison that gets called during sort.
the specialized compare function shall compare based on income (descending order)
the first top 5 elements from sorted vector should give your answer
If you just want the top 5 (and don't need them in order) you can use std::nth_element to find them. This is normally faster than sorting.
If you do want the top 5 in order, you could use std::partial_sort to do the job, something like this:
std::partial_sort(x.begin(), x.begin() + 5, x.end(),
[](auto a, auto b) { return b.income < a.income; });
Note that I've swapped the two parameters when comparing them to get it to sort in descending order instead of ascending.
I don't see a very good way to use the index field you've put into the structure. To work very well, you'd want the index separate from the data you're sorting, and you'd do an indirect sort on the indexes (that is, you'd sort the indexes based on the income for the item at that index).

Simple and effective way to store data that can be accessed though key or ordinal c++

I need to create a data structure that can access elements by a string key, or by their ordinal.
the class currently uses an array of nodes that contain the string key and a pointer to whatever element. This allows for O(n) looping through, or O(1) getting an element by ordinal, however the only way I've found to find an element by key is doing an O(n) loop and comparing keys until I find what I want, which is SLOW when there are 1000+ elements. is there a way to use the key to reference the pointer, or am I out of luck?
EDIT: the by ordinal is not so much important as the O(n) looping. This is going to be used as a base structure that will be inherited for use in other ways, for instance, if it was a structure of draw able objects, i'd want to be able to draw all of them in a single loop
You can use std::map for O(log n) searching speed. View this branch for more details. In this branch exactly your situation (fast retrieving values by string or/and ordinal key) is discussed.
Small example (ordinal keys are used, you can do similiar things with strings):
#include <map>
#include <string>
using std::map;
using std::string;
struct dummy {
unsigned ordinal_key;
string dummy_body;
};
int main()
{
map<unsigned, dummy> lookup_map;
dummy d1;
d1.ordinal_key = 10;
lookup_map[d1.ordinal_key] = d1;
// ...
unsigned some_key = 20;
//determing if element with desired key is presented in map
if (lookup_map.find(some_key) != lookup_map.end())
//do stuff
}
If you seldom modify your array you can just keep it sorted and use binary_search on it to find the element by key in O(logn) time (technically O(klogn) since you're using strings [where k is the average length of a key string]).
Of course this (just like using a map or unordered_map) will mess up your ordinal retrieval since the elements are going to be stored in sorted order not insertion order.
Use vector and map:
std::vector<your_struct> elements;
std::map<std::string, int> index;
Map allows you to retrieve the key's index in O(lg n) time, whereas the vector allows O(1) element access by index.
Use a hashmap

Does hash_map automatically sort [C++]?

In the below code, hash_map is automatically sorting or maybe inserting elements in a sorted order. Any ideas why it does this?? Suggestions Please??
This is NOT a homework problem, trying to solve an interview question posted on glassdoor dot com.
#include <iostream>
#include <vector>
#include <ext/hash_map>
#include <map>
#include <string.h>
#include <sstream>
using namespace __gnu_cxx;
using namespace std;
struct eqstr
{
bool operator()(int i, int j) const
{
return i==j;
}
};
typedef hash_map<int, int, hash<int>, eqstr> myHash;
int main()
{
myHash array;
int inputArr[20] = {1,43,4,5,6,17,12,163,15,16,7,18,19,20,122,124,125,126,128,100};
for(int i=0;i<20;i++){
array[inputArr[i]] = inputArr[i]; //save value
}
myHash::iterator it = array.begin();
int data;
for (; it != array.end(); ++it) {
data = it->first;
cout << ":: " << data;
}
}
//!Output ::: 1:: 4:: 5:: 6:: 7:: 12:: 15:: 16:: 17:: 18:: 19:: 20:: 43:: 100:: 122:: 124:: 125:: 126:: 128:: 163
Hash map will not automatically sort your data. In fact the order is unspecified, depending on your hash function and input order. It is just that in your case the numbers turns out are sorted.
You may want to read about hash table for how this container stores the data.
A clear counter example can be created by replacing that 100 with 999999999. The result is
:: 1:: 4:: 5:: 6:: 7:: 12:: 15:: 16:: 17:: 18:: 19:: 20:: 999999999:: 43:: 122:: 124:: 125:: 126:: 128:: 163
(The actual reason is the hash_map's bucket_count is 193 and the hash function of int is an identity function, so any numbers below 193 will appear sorted.)
A hash map may appear to be sorted based on a few factors:
The hash function returns values that are in the same order as the input, for the range of input that you are providing.
There are no hash collisions.
There are no guarantees that the results will be sorted, it's only a coincidence if they come out that way.
Think about how the hash function operates. A hash is always a function f:input->output that maps the input set I into a (usually smaller) output set O so that the input set is approximately uniformly distributed across the output set.
There is no requirement that order should be preserved; in fact, it's unusual that it would be preserved, because (since the output set is smaller) there will be values *i,j*that have the same hash. This is called a collision.
On the other hand, there's no reason it shouldn't. IN fact, it can be proven that there will always exist at least one sequence that will preserve the order.
But there's another possibility: if ALL the values collide, then they get stored in some other kind of data structure, like a list. It may be that these all collidge, and the other structure imposes order.
Three possibilities: hash_map happens to sort that particular sequence, or hash_map is actually implimented as an array, or the values collidge and the implementation stores collisions in a way that gives a sorted order.

Order like a list but access by a key?

I used list to place cities into a trip. Then I iterate over
the list to display the trip itinerary. I would like to access
the cities by the name rather than by the trip order. So, I
thought I could use a map rather than a list but the key determines
the order. I would still like to control the order of the sequence
but be able to access the entries by a key.
Can these features be combined? Is there some standard way to address
this?
#include <list>
#include <iostream>
struct City{
City(std::string a_n, int a_d):name(a_n), duration(a_d){}
std::string name;
int duration;
};
int main(){
std::list<City*> trip;
trip.push_back(new City("NY", 5));
trip.push_back(new City("LA", 2));
for (std::list<City*>::iterator ii=trip.begin(); ii!=trip.end(); ++ii)
std::cout << (*ii)->name << " for " << (*ii)->duration << " days." <<std::endl;
}
Often times you will need to compose multiple lists and maps. The common way is to store a pointer to the Cities in your by city lookup map from the pointers in your list. Or you can use a class like Boost.MultiIndex to do what you want in what I would say is much cleaner. It also scales much better and there is a lot less boiler plate code if you want to add new indexes. It is also usually more space and time efficient
typedef multi_index_container<
City,
indexed_by<
sequenced<>, //gives you a list like interface
ordered_unique<City, std::string, &City::name> //gives you a lookup by name like map
>
> city_set;
Create a map<string,int> m;, where the values are indexes to a vector<City>, for example m["NY"] == 0 and m["LA"] == 1.
Use two collections:
A list to store the actual objects in the order you are interested in.
A map to map names to the objects.
The best solution is to use Boost.MultiIndex, though that's slightly more involved. Unfortunately, I don't have time now to provide sample code; sorry.