Making adjacency list, weird bug? - c++

Edit: Original problem fixed.
New problem: While loop doesn't break for or statement:
while(m->next != NULL || m->val != n)
{
cout<<"Looking for main node. Comparing"<<n<<" to "<<m->val<<endl;
m = m->next;
}
It prints out all the comparisons, including the two that are exactly alike. Any reason why this wouldn't be breaking it?

m = NULL is assignment statement, m == NULL is the comparison statement to be used in your if statement
Note:
Checking m for NULL should be done before using it for even printing (in cout)
If you want to continue the while loop till the last element or till val equals n, then it should be like this
while(m != NULL && m->val != n)
{
cout<<"Looking for main node. Comparing"<<n<<" to "<<m->val<<endl;
m = m->next;
}

Related

Beginner difficulty with vectors and while-loops in C++

Update:
So it turns out there were two issues:
The first is that I checked the [k-1] index before I checked k == 0. This was a crash, although mostly fixable, and not the primary issue I posted about.
The primary issue is that the code seems to execute only after I press ctrl+z. Not sure why that would be.
Original:
So, learning from Stroustrup's text in C++ programming, I got to an example on vectors and tried implementing it myself. The gist is that the program user enters a bunch of words, and the program alphabetizes them, and then prints them without repeats. I managed to get working code using a for statement, but one of my initial attempts confuses me as to why this one doesn't work.
To be clear, I'm not asking to improve this code. I already have better, working code. I'm wondering here why the code below doesn't work.
The "error" I get is that the code compiles and runs fine, but when I input words, nothing happens and I'm prompted to input more.
I'm certain there's an obvious mistake, but I've been looking everywhere for the last 8 hours (no exaggeration) just devoted to finding the error on my own. But I can't.
int main() {
vector<string> warray; string wentry; int k = 0;
cout << "Enter words and I'll alphabetize and delete repeats:\n\n";
while (cin >> wentry) warray.push_back(wentry);
sort(warray.begin(), warray.end());
while (k < warray.size()) {
if (warray[k - 1] != warray[k] || k == 0) cout << warray[k] << "\n";
++k;
}
}
My reasoning for why this should work is this: I initialize my array of words, my word entry per input, and a variable to index word output.
Then I have a while statement so that every input is stacked at the end of the array.
Then I sort my array.
Then I use my index which starts at 0 to output the 0th item of the array.
Then so long as there are words in the array not yet reached by the index, the index will check that the word is not a repeat of the prior index position, and then print if not.
No matter what whappens, the index is incremented by one, and the check begins again.
Words are printed until the index runs through and checks all the words in the array.
Then we wait for new entries, although this gets kind of screwy with the above code, since the sorting is done before the checking. This is explicitly not my concern, however. I only intend for this to work once.
To end the cycle of input you need to insert EOF character which is ctrl+d. However, there are other problems in your code. You have k = 0 to start with so the moment you will try warray[k - 1] your code will crash.
At the point where you take
warray[k - 1]
for the first time, k is zero, so you want to get the warray value at index -1, which is not necessarily defined in memory (and even if, I wouldn't do this anyway). So as it compiles, I guess the address is defined in your case by accident.
I would try simply reversing the OR combination in your if-condition:
if (k == 0 || warray[k - 1] != warray[k])
thus for the first iteration (k == 0) it won't check the second condition because the first condition is then already fulfilled.
Does it work then?
You're stuck in the while loop because you don't have a way of breaking out of it. That being said, you can use Ctrl + d (or use Ctrl + z if executing on windows in the command prompt) to break out of the loop and continue executing the code.
As for while loop at the bottom which prints out the sorted vector of values, your program is going to crash as user902384 suggested because your program will first check for warray[k - 1].
Ideally, you want to change the last part of your program to:
while (k < warray.size())
{
if (k == 0 || warray[k - 1] != warray[k])
cout << warray[k] << "\n";
++k;
}
This way, the k == 0 check passes and your program will skip checking warray[k - 1] != warray[k] (which would equal warray[-1] != warray[0] when k=0).
You just needed to reverse:
if (warray[k - 1] != warray[k] || k == 0)
to
if (k == 0 || warray[k - 1] != warray[k] )
for terminating this condition if k = 0.
An alternative.
Although it can termed as a bit off topic, considering you want to work with std::vector<>, but std::set<> is an excellent container which satisfies your current two conditions:
Sort the strings in alphabetical order.
Delete all the repetitions.
Include <set> in your .cpp file, and create a set object, insert all the std::string and iterate through the set to get your ordered, duplicate-free strings!
The code:
int main() {
//Define a set container.
set<string> s;
//A temporary string variable.
string temp;
//Inserting strings into the set.
while (cin >> temp) s.insert(temp);
//Create a set<int> iterator.
set<string>::iterator it;
//Scanning the set
for(it = s.begin(); it != s.end(); ++it)
{
//To access the element pointed by the iterator,
//use *it.
cout<<*it<<endl;
}
return 0;
}
I just recommended this container, because you will study set in Stroustrup's text, and it is very easy and convenient instead of laboring over a vector.

Incorrect string comparison

I have a problem i cannot figure out at all!
in my program the user enters numbers to be sorted. i had to be able to sort infinity, negative infinity and the so called "Nullity" (these i defined early in the program)
if the user wants to enter infinity for example they have to enter "Pinf" into the string.
my issue is i store the users input in a std::string and then check if the string is "pinf" or "Pinf" even tho i have entered the number 3 so the string is "3", it still goes into the if statement, what have i done wrong?!
My code is below;
string Temp;
cin>> Temp;
if (Temp.find("Pinf")||Temp.find("pinf")) {
Num = Pinfinity;
}
It thinks the if statement is true everytime.
1.Error - you are using | instead of ||.
2.Error - findreturns
The position of the first character of the first match. If no matches
were found, the function returns string::npos.
You should change
if (Temp.find("Pinf")|Temp.find("pinf")) {
to
if ((Temp.find("Pinf") != string::npos) || (Temp.find("pinf") != string::npos)) {
If you are just searching for Pinf or pinf then you can use this. Note the logical or operator is ||.
if (Temp == "Pinf" || Temp == "pinf") {
| is a bitwise or operator. Use || in place of |
if ( Temp.find("Pinf") != npos || Temp.find("pinf") != npos )

binary tree traversal why need to check pre->right != current

In a binary tree traversal algorithm like below cited from this question, why do we need to check the second condition
pre->right != current? is this a loop condition? when would this happen?
pre = current->left;
while(pre->right != NULL && pre->right != current)
pre = pre->right;
Because the latter code makes a cycle (i.e. child pointing to a parent):
pre->right = current;
The cycle is deleted later, however, but the pre->right != current test tris to avoid following the cycle endlessly.
Consider the tree given below,
A
/ \
B C
/ \ /\
D E F G
The node A which is the root is initialized as current. Now the code given by you tries to find out the immediate predecessor of A in inoreder traversal. As we know the inorder traversal of the given tree is as follows,
D B E A F C G
So the code identifies E as the immediate predecessor of A.
[Pertaining to your Question-code]
Assume tree:
A
/ \
B C
It's In-order traversal = B,A,C
Now consider, B was already printed by
if(current->left == NULL)
{
printf(" %d ", current->data);
current = current->right;
}
So, The Condition:
pre->right != current
is required to break while loop (which may be cyclic at times), exactly when our aim is to print node A.
In this case, at the end of the while loop i.e. while(pre->right != NULL && pre->right != current), we'll have :
1) pre pointing to left node B - which is already printed
2) current pointing to middle node A - Next to be print, thus breaking cycle link we've created just for this. Following part takes care of this:
else
{
pre->right = NULL; // Break cyclic link we've created for printing 'A'
printf(" %d ",current->data);// prints 'A'
current = current->right; // Now, Aim for 'C'
}

Linear Search in Linked List [Language: C++ Compiler: Dev-Cpp 4.9.9.2]

I'm having a problem and can't seem to find the solution..
int linearSearch(nodeptr list,char search){
int pos =0;
if(list==NULL)
return -1;
while(list->info!=search && list!=NULL){
pos++;
list=list->next;
}
if(list==NULL)
return -1;
else
return pos;
}
I always get a runtime error.. :(
while(list->info!=search && list!=NULL)
should be:
while(list!=NULL && list->info!=search)
This is called as Short-circuit evaluation.
When you use && the first expression is guaranteed to be executed before the second for inbuilt primitive types[#1].
In your case the dereferencing happens before the NULLcheck, So when list == NULL, You will end up derefrencing the NULLand causing an Undefined Behavior and a crash.
In the sugeested solution:
if list == NULL then the second condition will not be evaluated.
Reference:
[#1]C++03 Standard 1.9.18:
In the evaluation of the following expressions
a && b
a || b
a ? b : c
a , b
using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).
you are not checking for the validity of list here:
while(list->info!=search && list!=NULL)
try checking list!=NULL before list->info.
Also, don use the name list, it is the name of a standard library container.
&& conditions are evaluated in the order they are specified, so in you case when list becomes NULL in the loop during the next iteration you are first trying to do list->info != search which results in access violation. You need to reverse the condition to list != NULL && list->info != search.

How to use the penultimate position of an iterator in c++

I have the following piece of code which helps me to write a bunch of values into a comma separated file format. My problem is, that I do not want a comma after the last element written to normcsv. How can I use beg in an If clause of the kind:
if(beg == penultimate element)
then.... bla bla...
Everything I tried out ended up with the iterator being mad invalid
ReadLine.erase(0,17);
int offsets[] = {8,8,8,8,8,8};
boost::offset_separator f(offsets, offsets+6);
boost::tokenizer<boost::offset_separator> RVBEARline(ReadLine,f);
boost::tokenizer<boost::offset_separator>::iterator beg;
for( beg=RVBEARline.begin(); beg!=RVBEARline.end();++beg )
{
copy=*beg;
boost::trim(copy);
if(copy.compare(0,1,".")==0)
{
copy.insert(0,"0");
}
normcsv << copy <<",";
}
Instead of printing the comma after the element except during the last iteration, print it before the element except during the first iteration. For that, you can use if(beg != RVBEARline.begin()).
An alternative to ruakh's "first plus rest" approach, you can do with one less local variable by using a loop-and-a-half construct:
{
auto it = x.begin(), end = x.end();
if (it != end)
{
for ( ; ; )
{
process(*it);
if (++it == end) break;
print_delimiter();
}
}
}
Here x.begin() and x.end() are only called once. There is one mandatory comparison per loop round, the minimum possible. The check for emptiness is hoisted outside.
Couldn't you just always remove the last character since you know it will be an extraneous comma?