I have a really basic problem that I can't figure out. I'm using chaining with hash tables to store nodes that collide with each other. I used a do while loop to print the first node at least once, and continue to print the chained nodes if they exist. However, in order to traverse the chained list, I need to change the address of the node for the next loop. Any way I try writing this, I find myself repeating code, which I was trying to avoid by using this loop. Please help
do {
cout << "Bid id: " << table.at(i)->bidId << " title: " << table.at(i)->title <<
" fund: " << table.at(i)->fund << " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next!=nullptr){//check if first node has next node
table.at(i) = table.at(i)->next; //change address to the next pointer
}// how do I avoid repeating my condition below?
}
while (table.at(i)->next!=nullptr);
This code will replicate the functionality in your loop without duplicating the check against NULL.
while(true)
{
cout << /* stuff */ endl;
auto next = table.at(i)->next;
if(next)
table.at(i) = next;
else
break;
}
From the description though, are you sure you want to reassign the values inside your hash map while looping over them? I suspect that this code may suit your intent/needs better:
auto current = table.at(i);
while(current)
{
cout << /* stuff */ endl;
current = current->next;
}
When you find yourself in a situation like this one, it's a good idea to question your premise. In this case, I am talking about your assumption that you need a do while loop.
If there is a chance that your data won't be there or that your container is empty, then a do while won't do the job because it will loop at least once.
Generally, for iterating through a collection of data you'll want to use a for or while loop.
If I understand the code correctly, you need a precondition loop and not a postcondition one, as you have right now. For example:
while (table.at(i)) {
cout << "Bunch of stuff";
table.at(i) = table.at(i)->next;
}
You could try doing:
for(auto node = table.at(i)->next;node!=nullptr;node=node->next)
cout << "Bid id: " << node->bidId << " title: " << node->title;
Where you may need to replace node = table.at(i)->next with an appropriate way of getting a link to the first entry.
You can use C++11's range based for loop here. All you want to know is that value->next is not a nullptr before doing the assignment. Rest all is taken care by the simple and modern range based for loop
for(auto const& value: table) {
if (value->next != nullptr) {
value = value->next;
}
}
Its even faster and safer this way
If really you want to be able to get last element after the loop, you may do:
do {
cout << "Bid id: " << table.at(i)->bidId
<< " title: " << table.at(i)->title
<< " fund: " << table.at(i)->fund
<< " amount: " << table.at(i)->amount << endl;
if (table.at(i)->next == nullptr){
break;
}
table.at(i) = table.at(i)->next;
} while (true);
// table.at(i) != nullptr && table.at(i)->next == nullptr
Related
I have a recursive display function, meant to go through the values of array b and print the details. My function is successful in looping the correct amount of times, but only prints out the value at index 0. For example, if I have 3 books, it prints out the first book 3 times and is not going to the other values. I am a beginner programmer and I believe I am missing something very simple or obvious, but any help is appreciated.
void displayBooks(int n)
{
// Write the code below
if (n >= currentCount) {
return;
}
else {
cout << "Name: " << b->getName() << "\n";
cout << "Name of Book Author: " << b->getAuthor() << "\n";
cout << "Publication Year: " << b->getYearOfPublication() << "\n";
cout << "ID: " << b->getID() << "\n";
displayBooks(n + 1);
}
}
This is the function itself, however I can't show the complete program since it is a lot of code with multiple files. When the function is first called as displayBooks(0) in a switch case.
I believe that you are not printing out each index of the "b" variable you need to access the index of each one. You need to have b as an array of pointers then access the index of that variable like b[n]->someProperty();
You can create the array like this:
Obj* b[HOWMANY];
Here is some code that I have made that should copy all the nodes in a linked data type correctly, but it is not working. I have checked my logic and wrote it on paper many times, yet it still isn't working. Am I doing something wrong on this part of the code? Is my use of pointers to copy nodes accurate? The part of my Constructor test that goes haywire is the part that starts to print out what's in the queue.
void LinkedQueue<ItemType>::CopyNodesFrom(const LinkedQueue& a_queue)
{
Node<ItemType>* orig_chain_ptr = a_queue.front_ptr_; // Points to nodes in original chain
if (orig_chain_ptr == nullptr) {
front_ptr_ = nullptr; // Original queue is empty
back_ptr_ = nullptr;
return;
}
// Copy first node
front_ptr_ = new Node<ItemType>();
front_ptr_->SetItem(orig_chain_ptr->GetItem());
// Advance original-chain pointer
orig_chain_ptr = orig_chain_ptr->GetNext();
// Copy remaining nodes
Node<ItemType>* new_chain_ptr = front_ptr_; // Points to last node in new chain
Node<ItemType>* temp_ptr;
while (orig_chain_ptr != nullptr) {
temp_ptr = new Node<ItemType>(orig_chain_ptr->GetItem() );
new_chain_ptr->SetNext(temp_ptr);
orig_chain_ptr = orig_chain_ptr->GetNext(); //Advance Our original pointer
new_chain_ptr = new_chain_ptr->GetNext(); //Advance our new chain pointer
} // end while
new_chain_ptr->SetNext(nullptr);
back_ptr_ = new_chain_ptr;
} // end copy constructor
#include <iostream>
#include <string>
#include "LinkedQueue.h" // ADT Queue operations
using namespace std;
void CopyConstructorAndAssignmentTester() {
LinkedQueue<string> queue;
string items[] = {"zero", "one", "two", "three", "four", "five"};
for (int i = 0; i < 6; i++) {
cout << "Adding " << items[i] << endl;
bool success = queue.Enqueue(items[i]);
if (!success)
cout << "Failed to add " << items[i] << " to the queue." << endl;
}
cout << "Queue contains, from front to back, zero one two three four five." << endl;
cout << "Checking Copy Constructor tester " << endl;
LinkedQueue<string> copy_of_queue(queue);
cout << "Copy of queue contains, from front to back, ";
for (int i = 0; i < 6; i++)
{
cout << " " << copy_of_queue.PeekFront();
copy_of_queue.Dequeue();
}
cout << "." << endl;
/*
cout << "Checking Assignment Operator tester " << endl;
LinkedQueue<string> assigned_queue;
assigned_queue.Enqueue("ha");
assigned_queue.Enqueue("ba");
assigned_queue = queue;
cout << assigned_queue << endl;*/
/* cout << "Assigned queue contains, from front to back, ";
for (int i = 0; i < 6; i++)
{
cout << " " << assigned_queue.PeekFront();
assigned_queue.Dequeue();
}
cout << "." << endl;
cout << "Original queue contains, from front to back,";
for (int i = 0; i < 6; i++) {
cout << " " << queue.PeekFront();
queue.Dequeue();
}
cout << "." << endl << endl; */
} // end copyConstructorTester
int main()
{
CopyConstructorAndAssignmentTester();
char a;
cin >> a;
//ConcatenateTester();
//return 0;
} // end main
EDIT: Oh crap, this stumps more people than I thought. XD. I thought I made a blatantly obvious mistake.
This may not be the answer you are looking for, and I'm finding it difficult to spot mistakes in your code lacking the full information of the states being manipulated.
The linked list logic looks all right: nothing jumps out at me as being faulty there in terms of the logic used to copy. Put in a distilled form:
first_node = last_node = new Node(other.first_node->data);
for (Node* other_node = other.first_node->next; other_node; other_node = other_node->next)
{
Node* new_node = new Node(other_node->data);
last_node->next = new_node;
last_node = new_node;
}
last_node->next = nullptr;
I believe this is what you have and it should be correct in terms of the overall logic. Any problems will probably be found elsewhere. Nevertheless, it should make your life easier to reduce the number of states you're working with. This 'new_chain_ptr' is unnecessary and you can just write out the results to 'back_ptr_' directly.
However, I have a different suggestion. You have the rest of the Queue working correctly, yes, including these methods like 'Enqueue'? If so, your copy constructor can be more trivially implemented just using what works already. Start with the state for an empty queue, and then read the elements from the other queue and 'Enqueue' those elements into your copy. Now you can avoid getting yourself tangled up in the low-level linked list logic by utilizing the parts you already know are functioning like so:
// Create empty queue.
first_node = last_node = nullptr;
// Enqueue elements from other queue.
for (Node* other_node = other.first_node; other_node; other_node = other_node->next)
Enqueue(other_node->data);
It might cost you an additional branch or so per iteration but remember that correctness always precedes efficiency, and you can come back and optimize once you have it working. Remember to handle self-assignment if the logic cannot work properly in those cases.
And yes, a debugger will give you a massive edge in accelerating the understanding of the nature of your code in addition to spotting mistakes more quickly.
I have created a program that will read a text file and put the words as strings into a linked list, along with their frequency count throughout the text file. It only prints one occurrence of each word with the total times it appeared.
My program also loads a blacklist, in which it is supposed to compare the blacklist linked list to the word cloud (or word frequency) linked list, and then remove the blacklisted words from the word frequency list.
I have tried doing this several ways. The following is my 3rd version. What I am wanting to do is add a Boolean value to each node, and when one node is equal to a word in the blacklist, the Boolean value will be true. However, I am not getting it to print right with the following code. I have searched, and I can't seem to find the correct syntax to add a Boolean value to a node in linked list.
EDIT #3:
void wordCloud::compareWith(wordCloud& wordList, wordCloud& badList){
wordNode *wordListTemp, *blacklistTemp, *temp = NULL;
unsigned int counter = 0;
for (blacklistTemp = badList.head; blacklistTemp; blacklistTemp = blacklistTemp->next){
cout << blacklistTemp->myWord << "\n";
for (wordListTemp = wordList.head; wordListTemp; wordListTemp = wordListTemp->next){
if (wordListTemp->myWord != blacklistTemp->myWord){
wordListTemp->blacklist = false;
if (wordListTemp->blacklist = false){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
}
}
else if (wordListTemp->myWord == blacklistTemp->myWord){
cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
wordListTemp->blacklist = true;
if (wordListTemp->blacklist = true)
cout << wordListTemp->myWord << "\n";
}
}
//counter++;
cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
}
system("pause");
}
This is not complete, but it is as far as I have gotten. The problem is it only prints the true if, and will not print any false if. Even if I switch the values, it will still only print the true if's. So I am assuming that I am going about this wrong. What would be the correct way to "flag" a node true and "flag" a node false? All the cout's are for debugging purposes. I will remove or comment those out later.
First of all, you could always debug step-by-step to see just which portion of the code freezes up your comp. The better way to detect memory leaks would be to use Valgrind.
On a side note, I would implement that comparison function as a comparison operator, and implement a comparison operator for their Nodes as well (for convenience). Doing so divides the code a bit and helps, later on, understand where your problem is. It is also a better way to do it (more readable, OOP-y, etc).
Finally!!
With a lot of old fashion debugging and cout statements, I finally got what I wanted. I know this might have been easy for some, but with not being very familiar with linked lists, this was quite the process for me.
Before I was trying to delete words that were seen in the blacklist linked list out of the wordList linked list. I decided later to just try to add a boolean value of true to the nodes in wordList, and then adjust my print function to not print nodes with the value of true. I also had to tweak a few things in insertWord(), and my freqSort() functions, but all that really consisted of was adding a pointer to the boolean value when a new node was being created.
My member function is void wordCloud::compareWith(wordCloud& wordList, wordCloud& badList), and is part of my wordCloud class. Here is the following definition:
void wordCloud::compareWith(const wordCloud& wordList, const wordCloud& badList){
wordNode *wordListTemp, *blacklistTemp;
unsigned int counter = 0;
//loop that advances wordListTemp
for (wordListTemp = wordList.head; wordListTemp; wordListTemp = wordListTemp->next){
blacklistTemp = badList.head;
//loop advances blacklistTemp - compares links in wordList to badList(blacklist)
//and sets the node to true if myWord equals any word in the blacklist
while (blacklistTemp){
if (wordListTemp->myWord == blacklistTemp->myWord){
wordListTemp->blacklist = true;
counter++;
}
blacklistTemp = blacklistTemp->next;
}
//for debugging
//cout << blacklistTemp->myWord << " " << wordListTemp->myWord << "\n";
}
/********************* All for debugging ***************************************
cout << "True:\n\n";
wordListTemp = wordList.head; //reset wordListTemp to head
while (wordListTemp){ //print blacklisted words from wordList
if (wordListTemp->blacklist == true){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
}
wordListTemp = wordListTemp->next;
}
//prints total words blacklisted
cout << "There are " << counter << " blacklisted words.";
cout << "\n\nFalse:\n\n";
wordListTemp = wordList.head; //reset wordListTemp to head
counter = 0;
while (wordListTemp){ //print non-blacklisted words from wordList
if (wordListTemp->blacklist == false){
cout << wordListTemp->myWord << " <"
<< wordListTemp->freq_count << ">\n";
counter++;
}
wordListTemp = wordListTemp->next;
}
//prints total words not blacklisted
cout << "There are " << counter << " words that are not blacklisted.\n";
system("pause");
******************** End debugging *******************************************/
}
So basically this is a comparison function that flags nodes that are found in another list. Works well and tested with all other options.
I have a Playlist class that has a vector with Tracks and each Track has a multimap<long, Note> as datamember.
class Track {
private:
multimap<long, Note> noteList;
}
Using an iterator to acces the tracks is no problem, so this part here is working fine:
vector<Track>::iterator trackIT;
try{
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}catch (int e){
cout << "exception #" << e << endl;
}
What I want to do next is iterate the Notes of each Track. But starting from this part all output is stopped. So I only get to see the first tracks name. Any cout's after that are not shown and the compiler isn't giving me any errors. Even the cout inside the try catch block isn't working..
vector<Track>::iterator trackIT;
multimap<long, Note>::iterator noteIT;
for(trackIT = this->playlist.getTracklist().begin(); trackIT < this->playlist.getTracklist().end(); trackIT++){
cout << trackIT->getTrackName() << endl;
for(noteIT = trackIT->getNoteList().begin(); noteIT != trackIT->getNoteList().end(); noteIT++){
cout << "---" << noteIT->second.getName() << endl;
}
}
cout << "random cout that is NOT shown" << endl; // this part doesn't show up in console either
Also, the method in my Track class that I'm using to add the Note objects looks like this:
void Track::addNote(Note ¬e) {
long key = 1000009;
this->noteList.insert(make_pair(key, note));
}
// I'm adding the notes to the track like this:
Note note1(440, 100, 8, 1, 1);
note1.setName("note1");
synthTrack.addNote(note1);
Any ideas why the iterator won't work?
Change
noteIT < trackIT->getNoteList().end()
To
noteIT != trackIT->getNoteList().end()
Not all iterators support less than / greater than comparisons.
If you have c++11 you can use a range-based for loop:
for (Note& note : trackIT->getNoteList())
Or you can use BOOST_FOREACH
BOOST_FOREACH (Note& note, trackIT->getNoteList())
You haven't shown the definitions of getTrackList or getNoteList, but there's a common mistake people make - if you return a copy of the container instead of a reference to it, the iterators will be pointing to different containers making comparisons impossible. Not only that but since the containers are temporary any use of the iterators results in undefined behavior.
If you are really hardcoding the track key, then there will only ever be one track in the map because std::map stores unique keys...
long key = 1000009; //If yo are really doing this, this key is already inserted so it will fail to insert more.
Also, if you would like a more elegant approach you could use function object.
struct print_track
{
void operator()(const Track& track)
{
cout << track.getTrackName() << endl;
std::for_each(track.getNoteList().begin(), track.getNoteList().end(), print_track_name());
}
};
struct print_note_name
{
void operator()(const std::pair<long,Note>& note_pair)
{
cout << "---" << note_pair.second.getName() << endl;
}
};
//In use...
std::for_each(playlist.getTracklist().begin(), playlist.getTracklist.end(), print_track());
I have a map storing a "job" as a key and a "name" as the value it stores.
map<string, string>dutyAndJob;
map<string,string>::iterator it;
I'm basically trying to look through this map for a particular "name".
If the name isn't there, it shouldn't enter this loop, however, for some unknown reason, it always enters this loop:
string name = "Bob";
it = dutyAndJob.find(name);
if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
For some reason, it would still enter this loop even though there isn't a Bob stored in the map.
Any help would be greatly appreciated!
if (it == dutyAndJob.end())
{
cout << "Testing : " << name << endl;
}
should be:
if (it != dutyAndJob.end()) // Does it refer to a valid association
{
cout << "Testing : " << name << endl;
}
Notice the change from == to != indicating that the key was found in the map. The iterator it is only equal to dutyAndJob.end() if the key was not found.
Just realized that Job is the key, and Name is the data. The way you have it structured, you can only use find on the Job that will retrieve the Name.
string job = "Cashier";
it = dutyAndJob.find(job);
if (it == dutyAndJob.end())
{
cout << "Testing : " << job<< endl;
}
If you actually wanted to search by Name, maybe the Name should be the key, and the Job should be the data?