the search function will take in a key value which is a const string& and it will look in the hashtable to see if the key value item is found or not..
my code here works except for a few cases (for example when i pass in "ZZ0" in to the function).
not sure if its because i'm using == instead of strcmp
But i can't see why it would not work simply because of that. can someone please explain if i'm missing something here?
void HT::search(const string& item)
{
int index=hash(item);
bool found=false;
for(unsigned int i=0;i<hsize;i++)
{
if(hTable[(index+i)%hsize].key==item)
{
found=true;
cout<<"item found";
break;
}
}
if(!found)
{
cout<<" : Item not found!"<<endl;
}
cout<<endl;
}
I see you use open address for collision and I don't see any problem here. Are you sure that your string "ZZO" has been inserted into the hash table correctly? I suggest you do a unit test to check that. Just insert the string and iterate the hashtable see whether it exists.
BTW, I suggest you use Separate chaining to implement the hashtable because it's easy to implemented and generally more efficient(Well definitely depends on your hash function). And it could be further extended to be thread-safe.
Even without seeing your insert function code -- I suggest to you that your 'insert' function is the problem -- it most likely does not handle hash collisions and simply override some values/elements -- why don't you post your code for the insert function as well?
Related
The obvious way is to just write two functions, but then they are almost identical. What I'm doing now is a function template with the return type (either bool or vector<something>) as the argument
template<typename ReturnType>
ReturnType foo(...){
constexpr bool return_bool = std::is_same<ReturnType, bool>::value;
ResultType results; //hopefully, the compiler takes it out in the bool case
And the plan is to use if constexpr(return_bool) when needed. But then I get this reoccurring piece of code
ReturnType result = foo<ResultType>(...);
if constexpr(return_bool){
if(result) return true;
}else std::copy(result.begin(), result.end(), std::back_inserter(results));
The return statement makes it hard to use standard anti-repetition techniques. I could use macros but then perhaps the repetition is better. Getting either all solutions or just the information whether one exists seems like a fairly general problem, is there a better way to do it?
I should've added that the function is performance-critical in the "does a solution exist?" case. That's why I want to have another version there and also why I don't want any costly abstractions.
You want two opposite features :
Reusing one solution in the other to avoid replication
Having an optimized version for solutionExists() to avoid a full result search
You didn't specify what is the solution your function returns, so I will explain why you can't have both using a simple example : your function is returning the number of ocurences of 0 in a vector of integers.
The function returning all solutions would look like this :
int GetNumberOfOccurencesOf0(const vector<int>& data)
{
int occurences = 0;
for (int i : data)
{
if (i == 0)
++occurences;
}
return occurences;
}
If you are not concerned about performance, your function for returning if there is a solution can be :
bool AreThereOccurencesOf0(const vector<int>& data)
{
return (GetNumberOfOccurencesOf0(data) > 0);
}
Note that there is no code duplication but the solution is not optimal : the data vector is iterated entirely. If you want an optimized solution, it would look like this :
bool AreThereOccurencesOf0(const vector<int>& data)
{
for (int i : data)
{
if (i == 0)
return true;
}
return false;
}
If your problem requires an optimized version of solutionExists(), you should write it and it should not need to reuse code from the getAllSolutions() function.
I have a Server class that processes QJsonObject data and handles it according to a key set in the data.
At the moment, I use a big if-then-else statement to decide what to do like this:
const QString action = jsonObject.value(KEY_ACTION).toString();
if (action == SOME_ACTION) {
// do something
} else if (action == SOME_OTHER_ACTION) {
// do something else
}
and so on. Now, meanwhile, I have quite a lot of actions, and for each one, my server has to check all cases until it finds the correct one. I thus wondered if there was a nicer way to do this.
I thought about having the data processing in different functions and having a QHash with the respective function pointer to the respective function for each action like this:
In the constructor:
const QHash<QString, void(Server::*)(const QJsonObject &)> processFunctionsMap {
{ SOME_ACTION, &Server::processSomeAction },
{ SOME_OTHER_ACTION, &Server::processSomeOtherAction }
}
And the respective functions:
void Server::processSomeAction(const QJsonObject &data)
{
...
}
and then to invoke the matching function:
if (! processFunctionsMap.contains(action)) {
// Catch this case
}
(this->*processFunctionsMap.value(action))(jsonObject);
This seems to work, but I'm not a C++ pro, so my question is if this is the correct way to do it.
Your approach is reasonable, but you've changed the no-matches scenario from executing an else block (potentially doing nothing at all) to instant undefined behavior.
You need to separate the hash lookup from the call so you can insert a check for successful lookup in between. With C++ standard collections (std::map which is a red-black tree, std::unordered_map which is a hashtable), that'd be a call to find(key) which returns an iterator... you compare it to map.end() and make very sure not to dereference if they are equal. QHash, or any other non-standard hashtable, will surely provide something similar.
Understanding what QHash does when key not found
In my code I have an if-else block condition like this:
public String method (Info info) {
if (info.isSomeBooleanCondition) {
return "someString";
}
else if (info.isSomeOtherCondition) {
return "someOtherString";
}
else if (info.anotherCondition) {
return "anotherStringAgain";
}
else if (lastCondition) {
return "string ...";
}
else return "lastButNotLeastString";
}
Each conditional branch returns a String.
Since if-else statements are difficult to read, test and maintain, how can I replace?
I was thinking to use Chain Of Responsability Pattern, is it right in this case?
Is there any other elegant way that I can do that?
I am left to assume that your code does not exist in the Info class as it is passed in an referenced for all but that last condition. My first instinct would be to make String OtherClass.method(Info) into String Info.method() and have it return the appropriate string.
Next, I would take a look at the conditions. Are they really conditions or can they be mapped to a table. Whenever I see code performing a lookup, such as this, I tend to fall back on attempting to fit into a dictionary or map so I can perform a lookup for the value.
If you are left with conditions that must be checked then I would begin thinking about lambdas, delegates or custom interface. A series of if..then across the same type could easily be represented. Next, you would collect them and execute accordingly. IMO, this would make the if..then bunch much clearer. It is more code by is secondary at this point.
interface IInfoCheck
{
bool TryCheck(Info info, out string);
}
public OtherClass()
{
// Setup checks
CheckerCollection.add(new IInfoCheck{
public String check(out result) {
// check code
}
});
}
public String method(Info info) {
foreach (IInfoCheck ic in CheckerCollection)
{
String result = null;
if (ic.TryCheck(out result))
{
return result;
}
}
}
The problem statement does not fit into an ideal chain of responsibility scenario because it is either/or kind or conditions which look 'chained' but is actually 'not'. Reason - one processes all the chain-links in the chain of responsibility pattern irrespective of what happened in the previous links, i.e. no chain-links are skipped(although you can configure which chain links to process and which not - but still the execution of a chain-link is not dependent on the outcome of a previous chain-link). However, in this if-else-if* scenario - once an if statement condition matches, the further conditions are not evaluated.
I have thought of an alternative design which achieves the above without if-else, but it is lengthier but at the same time more flexible.
Lets say we have a FunctionalInterface IfElseReplacer which takes 'info' as input and gives 'String' output.
public Interface IfElseReplacer(){
public String executeCondition(Info);
}
Then the above conditions can be re-phrased as lambda expressions would look like -
"(Info info) -> info.someCondition ? someString"
"(Info info) -> info.anotherCondition ? someOtherString"
and so on...
Then we need a processConditons method to process these Lambdas- it could be a default method in ifElseReplacer -
default String processConditions(List<IfElseReplacer> ifElseReplacerList, Info info){
String strToReturn="lastButNotLeastString";
for(IfElseReplacer ifElseRep:ifElseReplacerList){
strToReturn=ifElseRep.executeCondition(info);
if(!"lastButNotLeastString".equals(strToReturn)){
break;//if strToReturn's value changes i.e. executeCondition returns a String valueother than "lastButNotLeastString" then exit the for loop
}
return strToReturn;
}
What remains now is to (I am skipping the code for this - please let me know if you need it then will write this also) -
From wherever the if-else conditions need to be checked there -
Create an array of lambda expressions as explained above assigning them to IfElseReplacer interfaces while adding them to a list of type IfElseReplacer.
Pass this list to the default method processConditions() along with an instance of Info.
Default method would return the String value which we would be same as the result of if-else-if* block given in the problem statement.
I'd simply factor out the returns:
return
info.isSomeBooleanCondition ? "someString" :
info.isSomeOtherCondition ? "someOtherString" :
info.anotherCondition ? "anotherStringAgain" :
lastCondition ? "string ..." :
"lastButNotLeastString"
;
From the limited information about the problem, and the code given, it looks like this a case of type-switching. The default solution would be to use a inheritance for that:
class Info {
public abstract String method();
};
class BooleanCondition extends Info {
public String method() {
return "something";
};
class SomeOther extends Info {
public String getString() {
return "somethingElse";
};
Patterns which are interesting in this case are Decorator, Strategy and Template Method. Chain of Responsibility has another focus. Each element in the chain implement logic to process some commands. When chained, an object forwards the command if it cannot process it. This implements a loosly coupled structure to process commands where no central dispatch is needed.
If computing the string on the conditions is an operation, and from the name of the class I am guessing that it is probably an expression tree, you should look at the Visitor pattern.
I'm working on a project that needs unique keys and values so I decided to use maps. Everything works expect for the case where someone may want to change the key value. I'm not sure why, but it causes a fragmentation fault. Can I not do this?
void Journal::set_id(int id){ // journal class
if(join.count(id)){ // join is: static map <int,string> join
cout<<"Journal ID is already being used. Try again."<<endl;
}
else {
join.erase (join.find(id));
join.insert(pair<int,string>(id,name));
}
}
Your logic is flawed.
void Journal::set_id(int id){
if(join.count(id)){
cout<<"Journal ID is already being used. Try again."<<endl;
}
else {
// When you hit this block of the code, there is nothing
// in the map corresponding to 'id'.
// join.find(id) returns the same iterator as join.end()
// Calling erase() with that iterator is causing you the
// problem.
// Don't call erase. Just insert the new item.
// join.erase (join.find(id));
join.insert(pair<int,string>(id,name));
}
}
You have just checked to make sure that id is not being used as a key in the map. If it is, you issue an error. So now you know that id is not in the map. If id is not in the map, join.find(id) will return join.end(), so you really didn't need to call find at all. But more importantly, you then call join.erase(join.end()), which is an error.
See documention for std::map::erase() in cppreference:
The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferencable) cannot be used as a value for pos.
Rather than check whether the key is present, and insert it only if not found, you can simplify the code by just inserting the item, and then checking the return value to see if the insertion succeeded (which it won't if that key was already present).
void Journal::set_id(int id){
if (!(join.insert(std::make_pair(id, name)).second))
cout<<"Journal ID is already being used. Try again."<<endl;
}
This should also improve speed, since it only searches the tree once whereas code doing a count then an insert has to search it twice.
I'm currently learning C++ and practicing my Knowledge by implementing an simple AddressBook Application. I started with an Entry class and an AddressBook class which implements a STL Map to access the entries by the last names of the persons. Now I arrived at the following code:
Entry AddressBook::get_by_last_name(string last_name){
if(this->addr_map.count(last_name) != 0){
//What can I do here?
} else {
return addr_map[last_name];
}
In Scripting Languages I would just return something like -1, Error Message(A List in Python) to indicate that the Function failed. I don't want throw an exception, because it's part of the application logic. The Calling Class should be able to react to the request by printing something on the console or opening a Message Box. Now I thought about implementing the Scripting Languae Approach in C++ by introducing some kind of an Invalid State to the Class Entry. But isn't that bad practice in C++? Could it be that my whole class design is just not appropriate? I appreciate any help. Please keep in mind that I'm still learning C++.
Some quick notes about your code:
if(this->addr_map.count(last_name) != 0){
//What can I do here?
You probably wanted it the other way:
if(this->addr_map.count(last_name) == 0){
//handle error
But your real problem lies here:
return addr_map[last_name];
Two things to note here:
The operator[] for map can do 2 things: If the element exists, it returns it; If the element doesn't exist, it creaets a new (key,value) pair with the specified key and value's default constructor. Probably not what you wanted. However, if your if statement from before would have been the right way, then the latter would never happen because we would knowthe key exists before hand.
In calling count() before, you effectively tell map to try and find the element. By calling operator[], you are telling map to find it again. So, you're doing twice the work to retrieve a single value.
A better (faster) way to do this involves iterators, and the find method:
YourMap::iterator it = addr_map.find(last_name); //find the element (once)
if (it == addr_map.end()) //element not found
{
//handle error
}
return *it.second; //return element
Now, back to the problem at hand. What to do if last_name is not found?
As other answers noted:
Simplest solution would be to return a pointer (NULL if not found)
Use boost::optional.
Simply return the YourMap::iterator but it seems that you are trying to "hide" the map from the user of AddressBook so that's probably a bad idea.
throw an exception. But wait, now you'll have to first check that calling this method is 'safe' (or handle the exception when appropriate). This check requires a boolean method like lastNameExists which would have to be called before calling get_by_last_name. Of course then we'er back to square 1. We're performing 2 find operations to retrieve a single value. It's safe, but if you're doing A LOT of calls to get_by_last_name then this is potentially a good place to optimize with a different solution (besides, arguably the exception is not very constructive: What's wrong with searching for something that isn't there, huh?).
Create a dummy member for Entryindicating that is not a real Entry but that is very poor design (unmanageable, counter intuitive, wasteful - you name it).
As you can see, the first 2 solutions are by far preferable.
One dead-simple option is to change the return type to Entry* (or const Entry*) and then return either the address of the Entry if found, or NULL if not.
If you use Boost, you could return a boost::optional<Entry>, in which case your success code would be the same, but on not-found you'd say return boost::none. This is fancier, but does about the same thing as using a pointer return type.
Throwing an exception is definitely the 'correct' C++ thing to do, based on your function return type.
You might want a function like this to help you, though:
bool AddressBook::lastNameExists(const string &last_name)
{
return addr_map.count(last_name) > 0;
}
Note that your current code returns the entry 'by value' so modifying the returned entry won't update the map. Not sure if this is by accident or design...
Other answers have given various approaches, most of them valid. I didn't see this one yet:
You could add a second parameter with a default value:
Entry AddressBook::get_by_last_name(string last_name, const Entry& default_value){
if(this->addr_map.count(last_name) == 0){
return default_value;
} else {
return addr_map[last_name];
}
In this particular instance, there might not be a sensible default value for a non-existing last name, but in many situations there is.
In C++ you have several ways of signalling that an issue happened in your function.
You can return a special value which the calling code will recognize as an invalid value. This can be a NULL pointer if the function should return a pointer, or a negative value if your function returns an index in an array, or, in the case of a custom class (e.g. your Entry class) you can define a special Entry::invalid value or something similar that can be detected by the calling function.
Your calling code could look like
if ( entryInstance->get_by_last_name("foobar") != Entry::invalid)
{
// here goes the code for the case where the name is valid
} else {
// here goes the code for the case where the name is invalid
}
On the other hand you can use the C++ exceptions mechanism and make your function throw an exception. For this youcan create your own exception class (or use one defined in the standard library, deriving from std::exception). Your function will throw the exception and your calling code will have to catch it with a try...catch statement.
try
{
entryInstance->get_by_last_name("foobar")
}
catch (Exception e)
{
// here goes the code for the case where the name is invalid
}
// here goes the code for the case where the name is valid
Apart from the fact that you could have more than one entry per surname.
Eliminate the getter, and you've solved the problem, or at least shifted it elsewhere.
Tell the AddressBook to display people with given surnames. If there aren't any it can do nothing.
AddressBookRenderer renderer;
AddressBook contacts;
contacts.renderSurnames("smith", renderer);
contacts.renderCompletions("sm", renderer);
//etc
You can do what std::map (and the other containers do).
You return an iterator from your search function.
If the search does not find a value that is useful return an iterator to end().
class AddressBook
{
typedef <Your Container Type> Container;
public:
typedef Container::iterator iterator;
iterator get_by_last_name(std::string const& lastName) {return addr_map.find[lastName];}
iterator end() {return addr_map.end();}
};
Your address book is a container like object.
Not finding an item in a search is likely to happen but it does not have enough context to incorporate error handling code (As the address book could be used from lots of places and each place would have different error handling ideas).
So you must move the test for not found state out of your address book.
just like "Python" we return a marker. In C++ this is usually an iterator to end() which the calling code can check and take the appropriate action.
AddressBook& ab = getAddressBookRef();
AddressBook::iterator find = ab.get_by_last_name("cpp_hobbyist");
if (find != ab.end())
{
Entity& person *find; // Here you have a reference to your entity.
// you can now manipulate as you want.
}
else
{
// Display appropriate error message
}