I am working on a Polynomial class which uses the STL linked list. One of the functions requires me to add two Polynomial's together. For some reason, the += operator seems to be duplicating the node, as opposed to merely modifying the contents.
Here is the class declaration:
class Polynomial
{
public:
Polynomial(pair<double,int>); //Specified constructor
void add(const Polynomial&);
void print();
private:
Polynomial(); //Default constructor
list<pair<double,int> > terms;
};
This is the add member function:
void Polynomial::add(const Polynomial& rhs)
{
list<pair<double,int> >::const_iterator r;
list<pair<double,int> >::iterator l;
for(r=rhs.terms.begin(); r!=rhs.terms.end(); r++)
{
bool match=0;
//Check to see if we have an existing nth order node
for(l=terms.begin(); l!=terms.end(); l++)
{
//If we do, just add the coefficients together
if(l->second == r->second)
{
l->first += r->first;
match = 1;
}
}
//If there was no matching existing node, we need to find out
//where to insert it into the list.
if(!match)
{
l=terms.begin();
bool inserted=0; //Sentinel for the loop
while(l!=terms.end() && !inserted)
{
//If there's only one term in the list
//Just compare and stick it in front or behind the existing node
if(terms.size()==1)
{
int this_exp = l->second;
int exp_to_ins = r->second;
if(exp_to_ins > this_exp) terms.push_back((*r));
if(exp_to_ins < this_exp) terms.push_front((*r));
inserted = 1;
}
//If there's more than one node, we need to traverse the list
if(terms.size()>1)
{
if(l!=terms.begin())
{
int this_exp = l->second;
l++;
int next_exp = l->second;
int exp_to_ins = r->second;
//If the new node value is between the current and next node
//Insert between them.
if((this_exp < exp_to_ins) && (exp_to_ins < next_exp))
{
terms.insert(l,(*r));
inserted = 1;
}
}
else if(l==terms.begin())
{
int this_exp = l->second;
int exp_to_ins = r->second;
//This will be the smallest order node
//Put it in the top spot
if(this_exp > exp_to_ins)
{
terms.push_front((*r));
inserted = 1;
}
l++;
}
}
}
//If we've traversed the list and can't find the right place
//this must be the greatest order node in the list
//so just tack it on the end.
if(!inserted) terms.push_back((*r));
}
}
}
Works fine with ordering the nodes in the correct order, but we have an existing nth order node, rather than just adding the coefficients together, it keeps the original node but seems to make a second node with the coefficients added together, and I have no idea why.
If I run the print function, for what should be F(x) = -2x^7 + 3x^6 - 11x^5 - 2x^4, instead I get F(x) = -2x^7 + 3x^6 - 11x^5 - 10x^5. If I call the size() function on the list, I get 4. But if I run the following code to print out the info from the nodes in the list:
stringstream test;
for(i=terms.end(); i!=terms.begin(); i--)
{
test << "Coefficient: " << i->first << " ";
test << "Exp: " << i->second << endl;
}
cout << "Size: " << terms.size() << endl;
cout << test.str();
The following is output:
Coefficient: -10 Exp: 5
Coefficient: -2 Exp: 7
Coefficient: 3 Exp: 6
Coefficient: -11 Exp: 5
Any help greatly appreciated.
EDIT: This is the test program.
Polynomial p(pair<double, int>(-10, 5));
p.add(Polynomial(pair<double,int> (-2,4)));
p.add(Polynomial(pair<double,int> (3,6)));
p.add(Polynomial(pair<double,int> (-2,7)));
p.add(Polynomial(pair<double, int> (-1,5)));
Your add() function seems to be correct except the print:
for(i=terms.end(); i!=terms.begin(); i--)
{
test << "Coefficient: " << i->first << " ";
test << "Exp: " << i->second << endl;
}
This is completely wrong, and invokes undefined behavior. i is initially terms.end() and you've dereferencing it? items.end() returns past-the-end iterator. Even if I assume it correct for a while, the condition i!=terms.begin() means the first element is never printed!
So the fix is this:
for(list<pair<double,int> >::iterator i=terms.begin(); i!=terms.end(); i++)
{
test << "Coefficient: " << i->first << " ";
test << "Exp: " << i->second << endl;
}
And it prints expected output:
Size: 4
Coefficient: -2 Exp: 4
Coefficient: -11 Exp: 5
Coefficient: 3 Exp: 6
Coefficient: -2 Exp: 7
Is it not correct?
See the output yourself here also : http://www.ideone.com/p8mwJ
By the way, instead of add, you could make it operator+= instead, as:
const Polynomial& operator+=(const Polynomial& rhs)
{
//same code as before
return *this;
}
If you write so, then you can add polynomials as:
Polynomial p(pair<double, int>(-10, 5));
p += Polynomial(pair<double,int> (-2,4));
p += Polynomial(pair<double,int> (3,6));
p += Polynomial(pair<double,int> (-2,7));
p += Polynomial(pair<double, int> (-1,5));
Demo : http://www.ideone.com/aA1zF
I just read your comment, and came to know that you want to print it in reverse order, in that case, you could use rbegin() and rend() instead of begin() and end() as:
for(list<pair<double,int> >::const_reverse_iterator i=terms.rbegin();
i!=terms.rend();
i++)
{
test << "Coefficient: " << i->first << " ";
test << "Exp: " << i->second << endl;
}
I would also advice you to make print a const function as :
void print() const
//^^^^ this makes the function const!
Better yet overload operator<< .
Anyway reverse order printing demo : http://www.ideone.com/Vk6XB
Your test loop (the one printing in the stringstream) is incorrect: it's undefined behavior to dereference the end () iterator. Probably your "std::list" is implemented in a circular way (i.e. with begin == end+1) so dereferencing "end" gives you *begin in your test loop.
Use reverse iterators to print the list in reverse order:
for (i = list.rbegin (); i != list.rend (); ++i)
{
test << "Coefficient: " << i->first ; // etc.
}
Besides the problem pointed out by #Nawaz, there is also a problem in the Polynomial::add function.
If the if(terms.size()==1) block is executed, a new item is inserted in the list. But that increases the size of the list by one, so the if(terms.size()>1) block will also be executed. And this can insert the same node once more.
A bit further in the while loop, you increment l, and proceed using the next node, without checking whether it's valid (ie. without comparing to terms.end()).
There might be more such mistakes, but these came up after a cursory glance.
Related
I'm trying to populate a tree as below.
m is the number of inputs and s is the data for the head node.
c is the head node and the inputs that follow are parent-child nodes. Each node has a list of children.
Now, calling addNode to always start from the top of the tree is slow for what I'm doing. Instead, I make addNode return a reference to the to node that it adds to the tree. I maintain a map iNode of to - TreeN so that I can pass a reference to the from node to addNode instead of passing it the head node.
I think what happens is when a TreeN's vector resizes, the objects in it are copied to a new vector in memory and the reference to the nodes I had in iNode are to now deallocated memory. I'm not sure though, fairly new to Cpp.
How would I get this to work the way I want it to?
class TreeN {
public:
int d;
vector<TreeN> chld;
bool operator==(const TreeN &o) {
return o.d == d;
}
};
TreeN& addNode(TreeN &root, int &from, int &to) {
cout << "f: " << from << " t: " << to << " p: " << root.d << endl;
if (root.d == from) {
root.chld.push_back(TreeN{to});
return root.chld[root.chld.size() - 1];
}
else {
for(auto &c : root.chld) {
return addNode(c, from, to);
}
}
}
int main(int argc, const char** argv) {
int m, s;
cin >> m >> s;
TreeN c = {s, vector<TreeN>{}};
map<int, TreeN&> iNode;
iNode.insert(pair<int, TreeN&>(c.d, c));
while (m--) {
int a, b;
cin >> a >> b;
map<int, TreeN&>::iterator itA = iNode.find(a);
map<int, TreeN&>::iterator itB = iNode.find(b);
if (itA != iNode.end()) {
cout << "here " << itA->first << endl;
TreeN &n = addNode(itA->second, a, b);
cout << n.d << endl;
if (itB == iNode.end()) iNode.insert(pair<int, TreeN&>(b, n));
} else {
iNode.insert(pair<int, TreeN&>(b, addNode(c, a, b)));
}
}
printTree(c);
}
Input:
4 1
1 2
1 3
2 3
3 2
This code fails and gives the following output:
here 1
f: 1 t: 2 p: 1
2
here 1
f: 1 t: 3 p: 1
3
here 2
f: 2 t: 3 p: 0 (should say 2)
Segmentation fault (core dumped)
I will not try understood what your code does and how.
By using references in strange places you made it hard to read and understand. In this code it is hard to track if lifetime of variable exceeds lifetime of reference which is points to that variable.
If you are beginner use references only as a function argument.
Anyway I see undefined behavior here:
TreeN& addNode(TreeN &root, int &from, int &to) {
cout << "f: " << from << " t: " << to << " p: " << root.d << endl;
if (root.d == from) { // consider this false
root.chld.push_back(TreeN{to});
return root.chld[root.chld.size() - 1];
}
else {
for(auto &c : root.chld) {// root.chld is empty
return addNode(c, from, to); // this is weird and wrong - but not a source of crash
}
}
// then you can reach this place and there is no return statement
// leading to UB
// I'm pretty sure compilers warns you about this problem.
}
Also this last loop has no sense. First iteration will terminate loop execution. This defensively wasn't intended.
I think what happens is when a TreeN's vector resizes, the objects in it are copied to a new vector in memory and the reference to the nodes I had in iNode are to now deallocated memory. I'm not sure though, fairly new to Cpp.
It is possible. Vector allocates some reserve (see its capacity) and when size is becomes larger then capacity new memory is allocated and values are copied/moved to new buffer. This can make references to items on vector invalid.
BUT: form what I see you are not storing those references for longer then next possible resize so this is not the issue.
I need to find the range of the first elements of a vector pair. I need this range for a map, which counts the duplicate entries in this vector.
Here is a code snipped and how I managed it. Maybe there is another, better solution?
unordered_map<int, int> frequency;
vector<pair<unsigned int,Point>> Roi_Num_Koord;
vector<int> Roi_first_Element;
int main()
{
// Part1: fill the Vector pair
Roi_Num_Koord.emplace_back(make_pair(0,Point(3.6));
Roi_Num_Koord.emplace_back(make_pair(1,Point(4,8));
Roi_Num_Koord.emplace_back(make_pair(2,Point(8.3));
Roi_Num_Koord.emplace_back(make_pair(3,Point(4,6));
// Part 2: now copy the first element to another vector
for (int i = 0; i < Roi_Num_Koord.size(); i++)
{
Roi_first_Element.emplace_back(Roi_Num_Koord[i].first);
}
// Part 3: now do the duplicate search (Code was taken out of the internet)
for (int i : Roi_first_Element)
{
++frequency[i];
cout << "freque "<<frequency[i] << endl;
}
for (const auto& e : frequency)
{
if (e.second == 5)
{
std::cout << "Roi " << e.first << " encountered " << e.second << " times\n";
}
}
}
So is there a possibility to remove Part 2 and find out the range of the first Element of Roi_Num_Koord?, so that I don't have to copy the first elements of this vector to the other vector (Roi_first_Element)
Yes the second step is completely redundant. You just iterate through the container and whenever you need first element of the pair you say it explicitly pretty much like you do in Step 2.
for(const pair<unsigned int,Point>& element : Roi_Num_Koord)
{
++frequency[element.first];
cout << "freque " << frequency[element.first] << endl;
}
I wrote a program that takes in N test cases of integers representing skill levels of students and attempts to find the total number of the smallest group possible if the only restriction is that there can be no to skill levels that are equal on a team and there is no skill gap greater than 1. So the following test case:
4 5 2 3 -4 -3 -5
would output:
3
Because the teams possible are {-4,-3,-5} and {4,5,2,3}, since the first group is only three members the output is 3.
I decided to use a linked list and a recursive function to solve the problem. One recursive function would go left and right of an integer looking for an integer that was higher by one size, is one is found then the element is removed from the list and 1 is returned. The same is done with another function looking for an integer smaller by 1. This should result in the sum of a group and I could compare the different sums to find the smallest. Unfortunately when I tried to implement this not only do I get a segmentation fault but the number that comes out after a few iterations are not even a part of the list and really large.
#include <cmath>
#include <cstdio>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int findHigherSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel + 1)) {
//cout << "test3" << endl;
skillLevel++;
list.erase(*it);
*it = list.begin();
//cout << "Iterator in the higher skill level function if it finds a skill level higher by 1: " << **it << endl;
//cout << "The skill level is: " << skillLevel << endl;
return 1 + findHigherSkillLevel(skillLevel, it, list);
} else {
//cout << "Iterator in the higher skill level function if it doesn't find one: " << **it << endl;
return findHigherSkillLevel(skillLevel, ++it, list);
}
return 0;
}
int findLowerSkillLevel(int skillLevel, list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
if (**it == (skillLevel - 1)) {
skillLevel--;
list.erase(*it);
*it = list.begin();
return 1 + findLowerSkillLevel(skillLevel, ++it, list);
} else {
//cout << "test2" << endl;
return findLowerSkillLevel(skillLevel, ++it, list);
}
return 0;
}
int findGroupsSizes(list<int>::iterator *it, list<int> &list) {
if (it == NULL) return 0;
int groupSize = 1;
int skillLevel = **it;
*it = list.erase(*it);
//cout << "Iterator value in the first function: " << **it << endl;
groupSize += findHigherSkillLevel(skillLevel, it, list) + findLowerSkillLevel(skillLevel, it, list);
return groupSize;
}
If I were to use the test case mentioned then it would iterate through 4, then 5, then 2, and then some weird numbers pop out and finally a seg fault. Is it impossible to use iterators on recursive functions if you pop them from the list in those recursions?
main() actually takes in t total test cases followed by t lines of N separated integers. I used the following as a test case:
4
7 4 5 2 3 -4 -3 -5
1 -4
4 3 2 3 1
7 1 -2 -3 -4 2 0 -1
Here is main if it matters:
int main() {
int t; // the number of test cases
cin >> t;
vector<list<int> > skillLevels(t, list<int>());
// input for each test case
for (int i = 0; i < t; i++) {
int n; // number of students for this test case
cin >> n;
// initialize the list for this test case
for (int j = 0; j < n; j++) {
int skillLevel;
cin >> skillLevel;
skillLevels[i].push_back(skillLevel);
}
}
// recursively scan lists for smallest teams
for (int i = 0; i < t; i++) {
int minGroupNumber = skillLevels[i].size();
list<int>::iterator iterator = skillLevels[i].begin();
int skillLevel = skillLevels[i].front();
while (!skillLevels[i].empty()) {
iterator = skillLevels[i].begin();
int currentGroupSize = findGroupsSizes(&iterator, skillLevels[i]);
cout << currentGroupSize << endl;
if (currentGroupSize < minGroupNumber)
minGroupNumber = currentGroupSize;
//cout << minGroupNumber << endl;
if (!skillLevels[i].empty()) skillLevels[i].pop_front();
}
cout << minGroupNumber << endl;
}
return 0;
}
++it is incrementing the pointer (which makes it invalid) not the iterator. You probably want ++*it.
But that might also take you beyond the end of the list.
My remove_if seems to be overwriting the elements that are not filtered out with values of filtered out elements. The purpose of these code is to allow user to filter and display only teacher from a certain category. (Not deleting any element)
Here are some of the code
static string compare;
static string debug;
bool filter_Cat (Teacher &t)
{
return (t.getCat() != compare);
}
void filterCat (vector<Teacher> &t)
{
vector<Teacher>::iterator i;
vector<Teacher>::iterator newedited = remove_if(t.begin(), t.end(), filter_Cat);
for (i = t.begin(); i != newedited; ++i)
{
Teacher& te = *i;
te.getName();
cout << "\t";
te.getCategory();
cout << "\t";
te.getLocation();
}
}
void filterTutorCat(vector<Teacher> &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
if(choice <= 3 && choice > 0)
{
if (choice == 1)
{
compare = "English";
filterCat(t);
}
if (choice == 2)
{
compare = "Math";
filterCat(t);
}
if (choice == 3)
{
compare = "Science";
filterCat(t);
}
}
else
{
cout << "Invalid Option" << endl;
}
}
remove_if shifts elements, for which the compare function returns false, from right to left; which in other words means, it overwrites the elements, for which compare returns true, with elements, for which compare returns false. The size of the vector doesn't change, however.
This reads,
Removes all elements satisfying specific criteria from the range [first, last). The first version removes all elements that are equal to value, the second version removes all elements for which predicate p returns true.
Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten. The elements between the old and the new ends of the range have unspecified values. Iterator to the new end of the range is returned. Relative order of the elements that remain is preserved.
So what you want to do should be expressed as:
void filterCat (vector<Teacher> &v)
{
for (vector<Teacher>::iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter_Cat(*i))
{
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
It seems in your code, getName() prints the name which ideally it should not do, instead it should return name. So I would suggest you to change it to make it return name. And do the same for getCategory as well. Choose your name correctly. If it is getName(), you should get you name by returning it; if it is printName(), then it should print name.
Also, the code which you've written isn't good:
You should avoid global variables.
You should avoid if-else as much as possible. Learn better ways.
You should learn about function objects (or functor)
You should learn about const member function.
You should understand the difference between iterator and const_iterator, and their usage.
You should understand the difference between const reference, and non-const reference. And try using them appropriately.
So I would write your code as:
//this is functor, not a function
struct filter_cat
{
std::string m_cat; //use member data, avoid global variable
filter_cat(std::string const & cat) : m_cat(cat) {}
bool operator()(Teacher const & t) const //const member function
{
return (t.getCat() != m_cat); //getCat should be const member function
}
};
//pass vector by const reference
void filterCat (vector<Teacher> const & v, filter_cat filter)
{
//use const_iterator here, instead of iterator
for (vector<Teacher>::const_iterator it = v.begin(); it != v.end() ; ++it)
{
if (!filter(*i))
{
//getName and getCategory should be const member function
std::cout << i->getName() <<"\t" << i->getCategory() << std::endl;
}
}
}
void filterTutorCat(vector<Teacher> const &t)
{
int choice;
cout << "No\tCategory" << endl
<< "1\tEnglish" << endl
<< "2\tMath" << endl
<< "3\tScience" << endl
<< "Choose the category you wish to filter :";
cin >> choice;
getline(cin, debug);
//avoid if-else as much as possible, learn better ways!
std::string cats[] = {"English", "Math", "Science"};
if(choice <= 3 && choice > 0)
{
filterCat(v, filter_cat(cats[choice-1]));
}
else
{
cout << "Invalid Option" << endl;
}
}
As noted in the comments: getCat, getName and getCategory should be const member functions. In fact, if getCategory returns category, then getCat isn't even needed.
Solved my issue.
remove_if collects the values for which filter_Cat returns false at the start of the container. While it doesn't reduce the number of elements in the container it neither does make any guarantees about the values of the elements beyond the returned range. So you are loosing values when using remove_if.
I am implementing a tree which is a Binary Expression Tree. The leaf nodes are numbers, non-leaf nodes are math operators. Succesfully implemented printInorder,PostOrder, PreOrder, evaluate. But stucked with the printLevel().
Here is my int main ()
int main()
{
EXTree myTree;
string tests[] = {"2.1*3.1+4.2", "(2.0+1.3)/1.4", "2.*(1.3+1.4)","1.2*(1.3+1.4/0.5)","1.2*(1.3+1.4/0.5)-4.4", "1.2*(1.3+1.4/0.5)- (9/3)"};
for (int i=0; i < 6; i++)
{
myTree.build (tests[i]);
myTree.printInorder();
myTree.printPreorder();
myTree.printPostorder();
myTree.printLevel(); //Starting from level = 0
cout << "Evaulating myTree = " << format(myTree.evaluate(),2) << endl;
myTree.removeAll(); // removes all the nodes
}
}
printLevel(); only prints the level of the tree given above and its initally 0.
and here is my printLevel function.
void EXTree:: printLevel()
{
queue<Node*> levelq;
levelq.push(root);
cout << "Current Level is: ";
while( levelq.size() > 0 )
{
Node *cur = levelq.front();
cout << cur->Root << " ";
levelq.pop();
if (cur->Left) levelq.push(cur->Left);
if (cur->Right) levelq.push(cur->Right);
}
cout << endl;
}
But I really didnt understand how to implement the printLevel. Appreciate for any help to clarify it.
I just implemented the inOrder algorith to my printLevel and tried to change it but still didnt get it.
Since you have no problem with recursion, this would work without queue:
void EXTree:: printLevel()
{
int currentLevel = 0;
if (root)
{
cout << "Current Level is: ";
printLevelHelper(root,currentLevel);
}
else
cout << "This BST is Empty\n";
}
// Declare a private method:
void EXTree:: printLevelHelper(Node* &n, int ¤tLevel)
{
cout << currentLevel << ' ';
if (n->Left)
{
currentLevel++;
printLevelHelper(n->Left,currentLevel);
currentLevel--;
}
if (n->Right)
{
currentLevel++;
printLevelHelper(n->Right,currentLevel);
currentLevel--;
}
}
When using Breadth First Search to print the nodes on one level immediately adjacent to each other, you'd just observe when the leftmost child of the leftmost node on the current level pops out of the queue: this must be the start of the next level. I could easily write the code but I'd guess it would incomprehensible for you and this homework is for you (I think you want to label your post appropriately as homework, BTW). Most of your implementation looks like a straight forward implementation. The only thing missing is detecting that the next level is reached.