Linked List and inserting a string in alphabetical order - c++

I'm writing a program that allows a user to insert, delete, search, and print books. The books must print out in alphabetical order. When I'm inserting books, it works just fine but it does not put them in the right order and it will crash. Here is my code for the insert function.
void BookList::Insert(Book* nBook)
{
string name;
int quant;
double p;
cout << "Enter the title of the book." << endl;
cin.ignore();
getline(cin, name);
cout << "Enter the number of quanities of this book." << endl;
cin >> quant;
cout << "Enter the price of this book." << endl;
cin.ignore();
cin >> p;
nBook->title = name;
nBook->quantity = quant;
nBook->price = p;
nBook->next = nullptr;
//cout << "test" << endl;
//If the current book is lexicographically smallest.
if (first == nullptr) {
first = nBook;
cout << first->title << endl;
}
else if (nBook->title <= first->title)
{
cout << "new first" << endl;
nBook->next = first;
first = nBook;
}
else
{
cout << first->title << endl;
//if current book is lexicographically small between two books.
Book* prevPtr = first;
while (prevPtr != nullptr)
{
cout << "Looking at: " << prevPtr->title << endl;
if (prevPtr->title > nBook->title)
{
break;
}
else
{
prevPtr = prevPtr->next;
}
}
nBook->next = prevPtr->next;
prevPtr->next = nBook;
}
}
P.S. This is in C++
Thank you

Just because something doesn't show an error at compile doesn't mean it works fine.
Why are you using cin.ignore() with no parameters? What is the single character you are trying to ignore? You realize cin >> (someint or somedouble) already ignores whitespace and return characters, right?
More of your code is needed for context, but it seems like you're trying to fill the information for the new book into a "nBook" node before you actually initialize a new "nBook" node.
Also, I suggest not putting that output at the end in the method. If your method is for adding a new book to your linklist, just use it to add it. Put those outputs in a separate method, or in the calling method. (or maybe you just put those in for debugging purposes, in which case nvm)
Just my 0.02

Related

Queue linked list not printing it's contents

I am trying to get input of a queue with the linked list implementation. The issue is that the contents of the queue aren't being printed. I tried debugging but it says that in the function displayCar that pointer p is null regardless. I can't tell what's wrong with why pointer p is NULL. Is there a missing reference when I am trying to push from the carInput function?
#include <iostream>
#include <queue>
using namespace std;
class record
{
public:
string ownerID, plateNumber;
record* next;
};
void push(string ownerID1, string plateNumber1, record **head, record **tail) {
record *n = new record();
n->ownerID = ownerID1;
n->plateNumber = plateNumber1;
n->next = NULL;
if (*head == NULL) {
*head =*tail= n;
}
else {
(*tail)->next = n;
*tail = n;
}
}
void pop(record** head, record** tail) {
record* p = *head;
while (*head != NULL) {
*head = (*head)->next;
free(p);
p = *head;
}
if (*head == NULL)
{
*tail = NULL;
}
}
void carInput(record *head, record *tail) {
char choice = 'Y';
string ownTemp, plateTemp;
while (choice == 'Y') {
cout << "Enter Owner Name: ";
cin >> ownTemp;
cout << "Enter Plate Number: ";
cin >> plateTemp;
push(ownTemp,plateTemp,&head,&tail);
cout << "Press [Y] for next input: ";
cin >> choice;
}
}
void displayCar(record* head, record *tail) {
record* p = head;
cout << "List Of Cars: \n";
int i = 1;
while (p!= NULL) {
cout << i << ". Owner Name: " << p->ownerID << endl;
cout << i << ". Plate Number: " << p->plateNumber<< endl;
pop(&head,&tail);
i++;
}
}
void serviceCar(record *head,record*tail) {
record* p = head;
string plateTemp;
int i = 0, time = 0;
char choice = 'Y';
cout << "Enter Plate Number:";
cin >> plateTemp;
while (p!= NULL) {
if (p->plateNumber == plateTemp) {
cout << "There is [" << i << "] car in queue before your turn. Estimated time in queue: " << time;
}
else {
i++;
time = time + 45;
}
pop(&head,&tail);
}
}
int main() {
record* head = NULL;
record*tail = NULL;
cout << ":: Car Record::\n\n";
carInput(head,tail);
displayCar(head,tail);
serviceCar(head, tail);
}
I don't know why you are punishing yourself with code like this when you are in C++ and there are plenty easier ways to do the same, but I'll try to help anyway by underlining the main problems:
1). The main reason that you must be struggling is that in the first push, even after *head =*tail= n;, the *head->next is still NULL and later when you'll try to iterate from the head, as you do in pop, *head = (*head)->next; you will get nothing.
2). if you want to do pop, you should delete one element for each call, not the whole collection - so you need if instead of while.
You have while where you using pop for each iteration and in the pop you also have the while, so think about it.
Also, you should be returning the value to display it easily - or change the way you trying to cout p in displayCar.
3). When you want to display the collection you just have to iterate through the collection instead of deleting all the elements, which will leave you empty collection after one display. You just need to iterate and display them, not to delete, something like that:
record* p = *head;
int i = 0;
while (p != NULL) {
cout << i << ". Owner Name: " << p->ownerID << endl;
cout << i << ". Plate Number: " << p->plateNumber<< endl;
p = p->next;
i++;
}
There are some other points that should be mentioned, but I think that's enough to get the code right direction - anyway, my advice would be to try to take a good look for simple linked-list how it's done and then try Queue linked-list, or just check already written examples and then try it by yourself. GeeksForGeeks
Your carInput receives pointers by value, and modifying those pointers has no effect on the pointers you pass to it.
Thus, main's head and tail are always null.
(You solved this with the pushing and popping functions, but failed to apply the same principle here.)
void carInput(record **head, record **tail) {
char choice = 'Y';
string owner, plate;
while (choice == 'Y') {
cout << "Enter Owner Name: ";
cin >> owner;
cout << "Enter Plate Number: ";
cin >> plate;
push(owner, plate, head, tail);
cout << "Press [Y] for next input: ";
cin >> choice;
}
}
You need to combine this fix with the fixes pointed out in the comments.

Merging 3 lists in one big list

So I have a few lists(HeadFirstCl, HeadNoSm, HeadSm) that I want to connect and make a big list (HeadByPlace) while the pointers for the others still remain. My question is why does my ConnectLists function not work?
#include <iostream>
#include <string>
using namespace std;
struct Item {
string naprav;
string chasizl;
string chaskac;
int termizl;
int termkac;
char fime[5];
int mqsto;
Item *NextByPlace;
};
typedef Item *Point;
Point HeadByPlace, HeadFirstCl, HeadNoSm, HeadSm;
void ConnectLists(Point &P, Point A) {
while (A) {
if (P->NextByPlace == NULL)
P->NextByPlace = A;
P = P->NextByPlace;
}
}
void PrintOut(Point P) {
while (P) {
cout << P->fime<<endl;
cout << P->chasizl << endl;
cout << P->chaskac << endl;
cout << P->mqsto << endl;
cout << P->naprav << endl;
cout << P->termizl << endl;
cout << P->termkac << endl;
P = P->NextByPlace;
}
}
void Create(Point &Head, int i) {
Point Last, P;
Last = NULL;
P = new Item;
P->mqsto = i;
cout << "Enter destination" << endl;
cin >> P->naprav;
cout << "Enter departure HOUR" << endl;
cin >> P->chasizl;
cout << "Enter arrival HOUR" << endl;
cin >> P->chaskac;
cout << "Enter # of leaving terminal" << endl;
cin >> P->termizl;
cout << "Enter # of entering terminal" << endl;
cin >> P->termkac;
cout << "Last name of traveler" << endl;
cin >> P->fime;
P->NextByPlace = NULL;
if (Head == NULL) {
Head = P;
} else {
Last->NextByPlace = P;
}
Last = P;
}
void Delete(char name[], Point &Head) {
Point Pprev, P;
P = new Item;
Pprev = new Item;
cin >> name;
while (Head) {
if (strcmp(Head->fime, name) == 1) {
Pprev = P->NextByPlace;
*P = *Pprev;
delete Pprev;
}
}
}
void main() {
char ch;
HeadByPlace = NULL;
HeadFirstCl = NULL;
HeadNoSm = NULL;
HeadSm = NULL;
int i;
cout << "New element? (Y/N)? : ";
cin >> ch;
while (ch == 'Y' || ch == 'y') {
cout << "Enter seat #: ";
cin >> i;
if (i < 7) Create(HeadFirstCl,i);
else if (i > 7 && i < 25) Create(HeadNoSm,i);
else if (i > 25) Create(HeadSm,i);
cout << " New element? (Y/N) ?: ";
cin >> ch;
}
ConnectLists(HeadByPlace, HeadFirstCl);
ConnectLists(HeadByPlace, HeadNoSm);
ConnectLists(HeadByPlace, HeadSm);
PrintOut(HeadByPlace);
system("pause");
}
I think I found some of your problems. Your connect list function has one main issue, your while loop never terminates. In C++, the implicit conversion from a pointer to a bool returns true if the pointer is not null, and false if the pointer is null. Your loop checks infinitely to see if A is null or not. Obviously, if you give the function a null pointer, it won't do anything, but if you give it a valid pointer for A, it will loop forever because A isn't being changed in the function. Here's a simple function that will actually combine your lists without this issue:
void ConnectLists(Point P, Point A) {
while (P->NextByPlace != nullptr) {
P = P->NextByPlace;
}
P->NextByPlace = A;
}
This function loops until the end of the list, then adds A to the end. Note that it doesn't do any error handling for situations where A or P are null. If you replace your function with this one, it will do what you asked.
There are also very fundamental problems with the code you provided. Your create function segfaults if you make more than one entry of the same type. Also, your test case is flawed. You are passing the connectLists function the pointer HeadByPlace for P each time it is called. HeadByPlace is null so attempting to access any of it's values, such as nextByPlace, results in a segmentation fault. If you want to make sure the code for the connectLists function I provided works, initialize one of each of your list types (HeadFirstCl, HeadNoSM, and HeadSM) and try to connect those, or simply allocate memory for HeadByPlace.
Also, I have one piece of unsolicited advice. You may want to take a look at the C++ STL containers: http://www.cplusplus.com/reference/stl/. I think some of these data structures, such as the vector or list, may be useful to you for this project.

can't make strstr() work

I have a homwework assignment that I can't get to work correctly at all in one area, specifically where I'm trying to compare strings.
Here is the assignment:
You will write a program that prompts the user for student names, ages, gpas, and graduation dates. Your program will then read in all the student information and store them into a linked list. The program will then print the names of the students. Next, the program will prompt the user for a string. The program will print the complete information for each student containing the string in the name.
Here's what I have:
#include <iostream>
#include <cstring>
using namespace std;
const char NAME_SIZE = 50;
struct StudentInfo
{
char studentName[NAME_SIZE];
int age;
double gpa;
char graduationSemester[3];
StudentInfo *next;
};
void displayStudentNames(StudentInfo *top);
void displayStudentInfo(StudentInfo *top);
int main(){
StudentInfo *top = 0;
cout << "Please enter the students. Enter the name, age, gpa, and semester of graduation (e.g. F13)." << endl;
cout << "Enter an empty name to stop." << endl << endl;
bool done = false;
while(!done){
char nameBuffer[NAME_SIZE];
char graduationBuffer[3];
cin.getline(nameBuffer, NAME_SIZE);
if(nameBuffer[0] != 0){
StudentInfo *temp = new StudentInfo;
strcpy(temp->studentName, nameBuffer);
cin >> temp->age;
cin >> temp->gpa;
cin.getline(graduationBuffer, 3);
strcpy(temp->graduationSemester, graduationBuffer);
cin.ignore(80, '\n');
temp->next = top;
top = temp;
}else{
displayStudentNames(top);
displayStudentInfo(top);
done = true;
}
}
}
void displayStudentNames(StudentInfo *top){
cout << "Here are the students that you entered: " << endl << endl;
while(top){
cout << top->studentName << endl;
top = top->next;
}
cout << endl;
}
void displayStudentInfo(StudentInfo *top){
char name[NAME_SIZE];
do{
cout << "Which students do you want? ";
cin.getline(name, NAME_SIZE);
const char *str = top->studentName;
const char *substr = name;
const char *index = str;
while((index = strstr(index,substr)) != NULL){
cout << "Name: " << top->studentName << ", Age: " << top->age << ", GPA: " << top->gpa << ", Graduations Date: " << top->graduationSemester;
index++;
}
}while(name[0] != 0);
}
My problem is happening in the displayStudentInfo function, I just can't make it work properly. I've tried many different things and this is just the latest thing I've tried. But after creating the linked list earlier in the program, we are supposed to enter a string ranging from a letter to a full name and find it anywhere in the list, then print out the information for that particular name.
eta: I'm also having a problem with my linked list storing the structures backwards? It also either isn't storing my graduation dates, or something's going wrong when I try to print them, because they print blank.
Your code problem is obvious. You are just checking head of list and not traversing into the list.
Here is a part that has problem(Assuming each function call should return info for 1 student):
void displayStudentInfo(StudentInfo *top){
char name[NAME_SIZE];
//Addes 'node' variable for simplicity, you can use 'top' itself
StudentInfo *node = top;
cout << "Which students do you want? ";
cin.getline(name, NAME_SIZE);
do{
// Check if name is correct
// "Entered name should be at start of field"
// You should use == not =
if(node->studentName == strstr(node->studentName, name){
cout << "Name: " << top->studentName << ", Age: " << top->age << ", GPA: " << top->gpa << ", Graduations Date: " << top->graduationSemester;
}
// Traverse in list
node = node->next;
// Until reach end of list
}while(node != NULL);
}
You need to add top = top->next somewhere inside displayStudentInfo, similarly to how you have done in displayStudentNames. Currently your loop does not iterate through the linked-list without this.
I won't post any code to avoid doing your homework, but feel free to ask me more questions or for clarification.

Issues With Displaying Queue Contents

First off I will explain the classes and their purposes: ClinicQueue(Queue class, designed to create queues of patients), ClinicNode(typical node class, necessary for Queue), ClinicPatient(stores data about the patients in the queues), and ClinicDriver(used to construct the main application). What I need to do is to display the queue's contents - each node has a data member "info" which is an instance of ClinicPatient and contains a patient's data. In my current code I can only get one patient to print and I know there's is something wrong with my logic, but after 3 hours of the same issue and various attempts at working around it I just can't see what that problem is. How can I fix my code, or write new code to perform the necessary task? Below is the display function as well as the function intended to grab information about patients.
ClinicPatient ClinicQueue::getInfo(int pos) //get information on patients
{
ClinicNode* Current = front;
for(int i = 0; i < pos; i++)//for pos +/- 1 only outputs
//"patient 1: "(a cout in driver)
{
Current = Current -> next;
}
return Current -> info; //blows up
}
And the display function:
void ClinicDriver::Peekaboo() //breaks with more than one patient, skips last patient
{
bool cont = true;
int QueueChoice;
while (cont == true)
{
string temp;
cout << "Select a Doctor by number." << endl;
cin >> QueueChoice;
if (status[QueueChoice - 1] == true)
{
cout << "Queue is open." << endl;
string OutputS = "";
for (int a = 1; a <= Clinic[QueueChoice - 1].getSize(); a++)
{
cout << "Patient " << a << " : " << endl; //new, debugging
OutputS += Clinic[QueueChoice - 1].getInfo(a-1).tostring();//breaks here, works on 1 patient
OutputS += "\n";
}
cout << OutputS << endl;
}
else
{
cout << "Queue is empty." << endl;
}
cout << "Do you wish to continue?" << endl;
cin >> temp;
if (temp == "Yes" || temp == "yes")
{
cont = true;
}
else
{
cont = false;
}
}
}
Any and all help is greatly appreciated.

On finding vowels and capitals char in the beginning of a string?

I've been making a little memory game as an exercise from a textbook I'm doing. It's called Grandma's trunk and it works by in one turn you found an item in the trunk and the next turn you say you found the previous item and the newest item on this turn...I think.
Mostly it's an exercise on using functions, which I think I've gotten down pretty well. But my output is completely wrong. I've believe I've located the problem in one function where I'm supposed to analyze the first character and decided if it needs an AN or A or THE before the string. There might be a problem with the random function I'm using to throw in predefined items from a small database. The int main() function is supposed to be relatively complete, this is just an exercise to master functions...which I, sorta? Would rather call it novice experience.
I thought that perhaps I was running into the getline bug where it couts a blank line, and from my understanding, is fixed by cin.ignore(); but all that did was force me to press enter twice when I enter data. Which...I sort of like. Perhaps I'm using gizmos like isupper and .at() wrong? I tried using find_first_of but it didn't really change anything.
output calling the storage trunk and the owner grandma and just using word1 word2 word3... wordn....as items found leaves me with the output.
In grandma trunk you've found a
and an ord3 word1.
it completely muddles up the output. I'm starting to think that the int main() body I was given wasn't exactly stellar. But I can't be 100% confident in my article function. Any help would just be incredible. I've been struggling using this among many books and advice from a buddy to teach myself a little about programming. It's been a rather huge headache.
program itself
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
using namespace std;
string CorrectArticle(string phrase);
string GetPhrase(void);
bool Continue(void);
string UpperCase(string);
string RandomItem(void);
const string PUNCTUATION = ".";
int main(){
//Variables
int turn;
bool flag;
string phrase,
article,
story, item,
storage, owner;
srand(time(NULL));
cout << "Welcome to Grandmother's Trunk 9000" << endl;
cout << "This is a memory game. Each turn a player" << endl;
cout << "Says an item to place inside a trunk. " << endl;
cout << "And the next player has to say what the " << endl;
cout << "previous player said plus his/her own item." << endl;
cout << "This will go around in revolving turns." << endl;
cout << endl << endl;
cout << "But Grandma's Trunk is a little dry..." << endl;
cout << "Let's change what the storage is and " << endl;
cout << "Who owns it." << endl << endl;
//define storage variable
cout << "What exactly is this storage?" << endl;
getline (cin, storage);
cout << "So the items are stored in " << storage << endl;
cout << endl;
//define owner
cout << "Who owns this " << storage << " ?" << endl;
getline (cin, owner);
cout << "The owner is " << owner << endl;
story = "In "+ owner + " " + storage + " you've found ";
turn = 0;
flag = Continue();
//While flag is true
while (flag) {
if (turn %2 == 0) {
item = GetPhrase();
} else {
item = RandomItem();
}
//set corrected item to article
article = CorrectArticle(item);
//advance the story every item
story = story + "\n and " + article + " " + item;
cout << story << PUNCTUATION << endl;
turn++;
flag = Continue();
}
return (0);
}
//Gives A, AN, and THE to correct words
// An if phrase starts with i,e,i,o,u or y
// A if phrase starts with other lower case letters
// The for phrases that start with an uppercase letter
string CorrectArticle(string phrase){
int i=0;
string correctedString;
string stringAn;
string stringA;
string stringThe;
stringAn= " an ";
stringA = " a ";
stringThe= "The ";
if (GetPhrase().at(i) = "a" or "e" or "i" or "u"){
correctedString = stringAn + GetPhrase();
}else if (isupper(GetPhrase().at(i))){
correctedString = stringThe + GetPhrase();
}else{
correctedString = stringA + GetPhrase();
}
return correctedString;
}
//This function takes no parameters
//and returns the user's input
string GetPhrase(void){
string itemInput;
cout << "\nWhat did you find? \n" << endl;
getline (cin, itemInput);
cout << "\nYou found " << itemInput << endl;
cin.ignore();
return itemInput;
}
//Asks user if they wish to continue
bool Continue(void){
//return false if no, true if yes
string continueString;
cout << "Would you like to continue?";
cout << " Yes or No would suffice" << endl;
getline(cin,continueString);
UpperCase(continueString);
cout << "You picked " << continueString;
if (UpperCase(continueString).find("NO") != string::npos){
return false;
} else if (UpperCase(continueString).find("YES") != string::npos){
return true;
}
}
//Changes the string to uppercase
string UpperCase(string stringUpper){
int i = 0;
while (i<stringUpper.size()){
stringUpper[i] = toupper(stringUpper[i]);
i++;
}
return stringUpper;
}
//Randomizes items found in game
string RandomItem(void){
int randomNumber;
int maxNumberOfItems = 5;
string randomizedItem;
randomNumber= rand() % maxNumberOfItems;
switch (randomNumber){
case 0:
randomizedItem = "Smaug";
break;
case 1:
randomizedItem = "Batman";
break;
case 2:
randomizedItem = "Yoda";
break;
case 3:
randomizedItem = "Paul Atreides";
break;
case 4:
randomizedItem = "Captain Kirk";
break;
default:
cout << "ERRORRRR! PANIC!" << endl;
}
return randomizedItem;
}
Remember that = is assignment, == for compare.
Also remember that you have to compare variable with value, such as:
if ((string == "a") or (string == "e") ...
If the or works for you, all the best. I've only been able to use ||. Must be compiler conformity issues.
Try this:
bool is_vowel(char letter)
{
const std::string vowels("aeiouAEIOU");
return (vowels.find_first(letter) != std::string::npos);
}
In other words, I place all the vowels in a string a search the string. If there is a match, the letter is a vowel.