Identify an object in a container using object name? - c++

If there is the following vector1:
vector<string*> cont; // cont[0] == "0"
where pointers to strings are named either l or r; are sequentially added like so:
string r* = new string("1");
cont.emplace_back(r);
or:
string l* = new string("-1");
cont.emplace_back(l);
For example: if there is a direction to a node given like: "lrlrrr".
Is there a way to search through the vector using the string names, l and r, as "element id" rather than string content2?
Note: I've researched finding a vector element by native property, however, I'm interested if there is alternative way.
1. The vector stores sequentially (level by level) the nodes of a binary tree, where each left node's,l, value is: parent value - 1 and each right node's, r, value is: parent value + 1.
2. Comparing current and previous node values determines if current node left or right.

It is generally weird to use pointers to string in C++, since string internally contains a pointer to char giving a double indexation. But in this use case, it could make sense, if you store pointers to the same constant objects:
static string _r = "1";
static string _l = "-1";
const string * r = &_r;
const string * l = &_l;
then you could do
cont.emplace_back(r);
or
cont.emplace_back(l);
Because when iterating the vector of pointers you can do if (cont[i] == r) ...
If you really build new different objects on each step, storing pointers would only make sense if you need polymorphism, but it would be hard to test as identity if you do not have a know set of possible objects.

Is there a way to search through the vector using the string names?
No, because the names, l or r, are local variables1 that get destroyed after the string is stored in the vector. Once stored, the vector indexes become "names" of the stored strings.
1. l and r are rvalues and their addresses can not be obtained after the execution of the function that contains them.

Related

Hashing with separate chaining

Let's consider that for two different inputs("tomas", "peter") a hash function yields the same key (3).
Please correct my assumtion how it works under the hood with the separate chaining:
In a hash table, index 3 contains a pointer to a linked list header. The list contains two nodes implemented for example like this:
struct node{
char value_name[];
int value;
node* ptr_to_next_node;
};
The searching mechanism remembers the input name ("peter") and compares value_name in nodes. When it equals with "peter", the mechanism would return the value.
Is this correct? I've learned that ordinary linked list doesn't contain the name of the node so that I didn't know, how could I find the correspondind value in the list with nodes like this for different names ("tomas", "peter"):
struct node{
int value;
node* ptr_to_next_node;
};
Yes, its correct that this is a possible implementation of part of a hash table.
When you say an "ordinary linked list doesn't contain the name of the node", I'd be expecting a linked list to be generic if the implementation language allows that. In C++ it would be a template.
It would be a linked list of a certain type and each element would have an instance of or a handle to that type and a pointer to the next element as your second code snippet shows except substituting int with the type.
In this case the type would most likely be a key-value-pair
So the linked list in that case doesn't directly contain the name - it contains an object that contains the name (and the value)
This is just a possible implementation though. There are other options
Yes, basically: a table of structures, with the hash function limited to return a value between 0 and table size - 1, and that is used as an index into the table.
This gets you to the top of the list of chained elements, which will be greater than or equal to zero in number.
To save time and space, usually the table element is itself a chain list element. Since you specified strings as the data being stored in the hash table, usually the structure would be more like:
struct hash_table_element {
unsigned int length;
char *data_string;
struct hash_table_element *next;
}
and the string space allocated dynamically, maybe with one of the standard library functions. There are a number of ways to manage string tables that may optimize your particular use case, of course, and checking the length first can often times speed up the search if you use short cut evaluation:
if (length == element->length &&
memcmp(string, element->data_string, length))
{
found = TRUE
};
This will not waste time comparing the strings unless they are the same length.

Applying c++ "lower_bound" on an array of char strings

I am trying the lower_bound function in C++.
Used it multiple times for 1 d datatypes.
Now, I am trying it on a sorted array dict[5000][20] to find strings of size <=20.
The string to be matched is in str.
bool recurseSerialNum(char *name,int s,int l,char (*keypad)[3],string str,char (*dict)[20],int
dictlen)
{
char (*idx)[20]= lower_bound(&dict[0],&dict[0]+dictlen,str.c_str());
int tmp=idx-dict;
if(tmp!=dictlen)
printf("%s\n",*idx);
}
As per http://www.cplusplus.com/reference/algorithm/lower_bound/?kw=lower_bound , this function is supposed to return the index of 'last'(beyond end) in case no match is found i.e. tmp should be equal dictlen.
In my case, it always returns the beginning index i.e. I get tmp equal to 0 both 1. When passed a string that is there in the dict and 2. When passed a string that is not there in the dict.
I think the issue is in handling and passing of the pointer. The default comparator should be available for this case as is available in case of vector. I also tried passing an explicit one, to no avail.
I tried this comparator -
bool compStr(const char *a, const char *b){
return strcmp(a,b)<0;
}
I know the ALTERNATE is to used vector ,etc, but I would like to know the issue in this one.
Searched on this over google as well as SO, but did not find anything similar.
There are two misunderstandings here, I believe.
std::lower_bound does not check if an element is part of a sorted range. Instead it finds the leftmost place where an element could be inserted without breaking the ordering.
You're not comparing the contents of the strings but their memory addresses.
It is true that dict in your case is a sorted range in that the sense that the memory addresses of the inner arrays are ascending. Where in relation to this str.c_str() lies is, of course, undefined. In practice, dict is a stack object, you will often find that the memory range for the heap (where str.c_str() invariably lies) is below that of the stack, in which case lower_bound quite correctly tells you that if you wanted to insert this address into the sorted range of addresses as which you interpret dict, you'd have to do so at the beginning.
For a solution, since there is an operator<(char const *, std::string const &), you could simply write
char (*idx)[20] = lower_bound(&dict[0], &dict[0] + dictlen, str);
...but are you perhaps really looking for std::find?

3D Hash with no collisions on close values

I need a hash function for 3D vectors with no collisions between close key values.
The key is a 3d vector of integers. I want no collisions within roughly a 64 * 64 * 64 "area" or larger.
Does anyone know of any hashing functions suited for this purpose, or even better, how would you go about designing a hash for this?
If it's necessary to know, I will be implementing it in C++.
Why not create a Map<int,Map<int,Map<int,Object>>> for your objects? Where each int is x,y,z or whatever you're labeling your axis.
Here's an example of how you could use it.
int x,y,z;
map<int,map<int,map<int,string>>> Vectors = map<int,map<int,map<int,string>>>();
/*give x, y and z a real value*/
Vectors[x][y][z] = "value";
/*more code*/
string ValueAtXYZ = Vectors[x][y][z];
Just to explain because its not super obvious.
The Vectors[x] returns a map<int,map<int,string>>.
I then immediately use that maps [] operator with [y].
That then returns (you guessed it) a map<int,string>.
I immediately use that maps [] operator with [z] and can now set the string.
Note: Just be sure to loop through it using iterates and not a for(int x = 0; /*bad code*/;x++) loop because [] adds an element at every location it's used to look up. Here's an example of a loop and Here's and example of an unexpected add.
Edit:
If you want to make sure that you're not overriding an existing value you could do this.
string saveOldValue;
if(Vectors[x][y][z] != ""/*this is the default value of a string*/)
{
/*There was a string in that vector so store the old Value*/
saveOldValue = Vectors[x][y][z];
}
Vectors[x][y][z] = "Value";
If you use [] on a key that isn't in the map the map creates a default object there. For strings this would be the empty string "".
Or
if( Vectors.find(x)!=Vectors.end()
&& Vectors[x].find(y)!=Vectors[x].end()
&& Vectors[x][y].find(z)!=Vectors[x][y].end())
{
/* Vectors[x][y][z] has something in it*/
}else
{
/*Theres nothing at Vectors[x][y][z] so go for it*/
Vectors[x][y][z] ="value";
}
This uses the find(value) function which returns an iterator to the location of the key "value" OR and iterator that points to map::end() if that key is not int the current map.
If you don't have a default value for your thing being stored then use the second check to do your inserts. This greatly increases the useability of this answer and unclutters your code.
The insert function has it's place but in this example it would be very hard to use.

no suitable conversion from "std::string" to "char" exists

I'm working on a project for school and I am running into a bit of a problem (error is in the title).
Here is the line of code that runs into the error:
kruskalS[n].nodeList[m].push_back(tempFirstCity);
kruskalS is a struct and nodeList is a vector of type string within the struct and I'm trying to insert tempFirstCity (also a string) into that array.
I could easily be making a basic mistake since I haven't done any programming since April. Any kind of help would be appreciated and I'm willing to post a bit more information from the program if needed.
A std::string is (sort of) a container of chars. A push_back function is used to add one element to the end of a container. So when you call kruskalS[n].nodeList[m].push_back(tempFirstCity);, you say you are trying to add one element to the end of the string called kruskalS[n].nodeList[m]. So the compiler expects that one element to be a char.
If you know that tempFirstCity is not empty and you want to add the first char from tempFirstCity to the end of kruskalS[n].nodeList[m] (including the case where you know tempFirstCity.size() == 1), you can do
kruskalS[n].nodeList[m].push_back(tempFirstCity[0]);
If you want to add the entire string after any current contents, you can do
kruskalS[n].nodeList[m] += tempFirstCity;
If you expect there are no current contents and/or you want to just replace anything already there with the tempFirstCity string, you can do
kruskalS[n].nodeList[m] = tempFirstCity;
You can use:
std::string::c_str()
It returns a const char *.
You say nodeList is an array of type string. i.e. std::string nodeList[x] where x is a constant.
Then assigning a new element to that array where m < x is as follows:
kruskalS[n].nodeList[m] = tempFirstCity;
Based on comments:
For appending to end of vector you don't need the index m:
kruskalS[n].nodeList.push_back(tempFirstCity);
For inserting at index m:
vector<string>::iterator itr = nodeList.begin();
for (int i = 0; i < m; i++)
itr++;
nodeList.insert(itr, tempFirstCity);
In C++, you can use string::c_str() to convert a string to C programming char array..

c++ NULL terminated array segfault

I am writing a program that splits graphs, I got a class
Graph and an Algorithm class. I compute the partitioning in my Algorithm class and split the graph with a method in the Graph class according to the partitioning.
My code looks like this:
In my GraphClass:
void bisectGraph(int *iPartitioning, Graph **Subgraphs, Edge **Separator){
...
// Store separators in an array
Separator = new Edge*[Separators.size()+1]; //Separators is a vector containing the separating edges
if(Separator == NULL)
writeErrorMsg("Error assigning memory.", "Graph::bisectGraph");
for(i=0, SepIter = Separators.begin(); SepIter != Separators.end(); i++, SepIter++)
Separator[i] = *SepIter;
Separator[Separators.size()] = NULL;
}
In my Algorithm clas I call it like this:
Edge** separators;
Graph** subgraphs;
int somePartitioning;
g->bisectGraph(somePartitioning, subgraphs, separators);
Works fine so far, but when I want to work on my separators array like this for instance:
for(int i=0; separators[i]!=NULL, i++){
...
}
I always get a segmentation fault. ddd tells me that at the end of bisectGraph separators contains some content. Since I can't find any other mistake I think i got some concept wrong?
The new value of Separator is not being propagated to the separators variable outside the function call. Even though it has type Edge ** you're assigning to it inside the function, but that only assigns to the function's copy of the variable. Remember that C++ is pass-by-value unless otherwise specified.
You could change the signature to Edge **&, but it'd be more sensible to use a vector, and take a parameter of type vector<Edge *> &.