Link list add,delete and print imlementation - c++

The code bellow inserts nodes correctly but
I have a problem that when try to print the list the program unfortunately stop working.
The error message is : your project has stopped working.
This is my code:
#include <iostream>
#include <string>
using namespace std;
typedef struct st {
string data;
int ISBN;
string Title;
string Author;
int publishedyear;
bool borrow;
st* next;
} NODE;
NODE* add(NODE* head, int isbn)
{
NODE *p1, *p2;
NODE* n;
n = new NODE;
n->ISBN = isbn;
if (head == NULL) {
head = n;
return head;
}
if (n->ISBN < head->ISBN) {
n->next = head;
head = n;
return head;
}
p1 = p2 = head;
while (p2 != NULL) {
if (n->ISBN < p2->ISBN) {
n->next = p2;
p1->next = n;
return head;
}
else {
p1 = p2;
p2 = p2->next;
}
}
n->next = p2;
p1->next = n;
return head;
}
void print(NODE* head)
{
NODE* p;
p = head;
if (head == NULL) {
cout << "empty list" << endl;
}
while (p != NULL) {
cout << "Book ISBN Is : " << p->ISBN << endl;
p = p->next;
}
}
void main()
{
// cout << "hi";
NODE* head;
head = NULL;
string op;
int isbn;
cout << "Enter the opertion in the following format : op , ISBN" << endl;
while (1) {
cin >> op;
if (op == "add") {
cin >> isbn;
if (op == "add") {
head = add(head, isbn);
cout << "book with thie ISBN code " << isbn << " is added successfuly."
<< endl;
}
}
else if (op == "print") {
print(head);
}
else {
cout << "Enter vaild operation! ." << endl;
}
}
}
any suggestions ?

The answer was pointed out, but... I feel awfully unsatisfied by the state of your code, so allow me to give you a few tips.
Note: unless the point is to build a list, do reuse the existing standard containers (vector, in particular) and algorithms (sort) rather than building your own.
Let's start with the basics, this is the year 2016 you should have access to C++11 by now.
C++11 allows to initialize data-members straight at the point of declaration, and I recommend that you do it for all built-in types (integrals, booleans, floating points and pointers) since by default they otherwise contain garbage which is puzzling.
struct Node {
std::string data;
int ISBN = 0;
std::string title;
std::string author;
int publishedyear = 0;
bool borrow = false;
Node* next = nullptr;
};
Note that this alone solves your bug. And it also avoids forgetting it the next time.
Secondly, the add method should NOT be responsible for creating a node. This is mixing concerns, and it also leaves most of the node with default values and no way to access it without looking for it by its ISBN.
There's also a point that the add method does not account for: what if the ISBN is already in the list?
// Adds the new node to the list, maintaining the ordering by ISBN.
//
// Returns the new head of the list, unless an existing node in the list already
// has this ISBN in which case returns `nullptr`.
Node* add(Node* head, Node* node) {
assert(node != nullptr && "Null argument provided");
if (head == nullptr) {
return node;
}
if (node->ISBN < head->ISBN) {
node->next = head;
return node;
}
if (node->ISBN == head->ISBN) {
return nullptr;
}
// Find "current" such that "current->ISBN" < "node->ISBN" and
// "node->ISBN" <= "current->next->ISBN"
Node* current = head;
while (current->next != nullptr && node->ISBN > current->next->ISBN) {
current = current->next;
}
if (node->ISBN == current->next->ISBN) {
return nullptr;
}
node->next = current->next;
current->next = node;
return head;
}
Note: assert requires #include <cassert>.
Your print method is already pretty good, congratz!
Just two nitpicks:
if you know that nothing further will be executed, return immediately, don't wait
don't use endl, it both appends an end of line AND flushes the buffer immediately, which leads to performance issues more often than not
// Prints the list, in order.
void print(Node* head) {
if (head == nullptr) {
std::cout << "empty list\n";
return;
}
for (Node* p = head; p != nullptr; p = p->next) {
std::cout << "Book ISBN: " << p->ISBN << "\n";
}
}
And finally, the modified main.
Note that I expanded the help text a bit, and provided a (clean) quit operation.
The main change, however, is dealing without input error. Dealing with output error is left as an exercise to the reader (hint: make them throw).
It would also be a good exercise to properly deal with the allocated memory.
int main() {
std::cout << "Enter one of the following operations when prompted:\n"
" - add <isbn>\n"
" - print\n"
" - quit\n";
Node* head = nullptr;
while (1) {
std::cout << "> ";
std::string op;
if (!(std::cin >> op)) {
std::cerr << "An error occurred reading the operation, sorry\n";
break;
}
if (op == "quit") {
std::cout << "See you later!\n";
break;
}
if (op == "print") {
print(head);
continue;
}
if (op == "add") {
int isbn = 0;
if (!(std::cin >> isbn)) {
std::cout << "Please provide a correct ISBN!\n";
continue;
}
Node* node = new Node();
node->ISBN = isbn;
Node* h = add(head, node);
if (h == nullptr) {
std::cout << "This ISBN was already provided!\n";
delete node;
continue;
}
head = h;
continue;
}
std::cout << "Please enter a valid operation!\n";
}
// Deal with allocated memory ;)
}

st::next is never set to NULL. This makes testing p!=NULL in print somewhat problematic.
Solution: NULL next when the node is the tail node.

Related

How to return the values of the char linked lists and store it as a string?

I created this program that should check the string entered by user in form of characters using doubly linked lists in C++, however I got stuck at the last point in which I should compare the original word with the reversed one to see if the two words are palindrome or not, how to store the content of function display() and reverse() to a string variable so that I can return the value and compare them?
Also, reverse() function doesn't display the reversed word
This is my code:
#include <iostream>
using namespace std;
class Storage {
public:
char lett;
Storage* next;
Storage* prev;
};
void push(char lett1, Storage** head) {
Storage* n = new Storage();
n->lett = lett1;
n->next = NULL;
if (*head == NULL) {
*head = n;
}
else {
n->next = *head;
*head = n;
}
}
void display(Storage* head, int no) {
Storage* s = head;
while (head != NULL) {
int i = 0;
cout << head->lett;
s = head;
head = head->next;
}
}
void reverse(Storage* tail) {
Storage* t = tail;
// Storage* original= tail;
while (t != NULL) {
cout << t->lett;
t = t->prev;
}
}
/*
string checkPalindrome() {
string check;
if ()
check == "Yes";
else
check == "No";
return check;
}
*/
int main() {
Storage* head = NULL; Storage* tail = NULL;;
char lett;
int size;
string result;
cout << ":: Palindrome Program ::\n" << endl;
cout << "Enter total character: ";
cin >> size;
cout << "Enter character: ";
for (int i=0; i < size; i++) {
cin >> lett;
push(lett, &head);
}
cout << "Your word: ";
display(head, size); //compare content of this
cout << "\nReversed word: ";
reverse(tail); // with this
/*
result = checkPalindrome();
cout << "Palindrome: " << result << endl;
*/
return 0;
}
You have some bugs in your code. First of all my tip is that you need to make a class/struct which will hold the head and tail of your list. For example:
class DLList{
public:
NODE *head;
NODE *tail;
};
Also, as you can see you should have a class for your list nodes, and every node should have a pointer to the next node, and to the node before. Don't forget to make the first node previous pointer to point to NULL, and also the last nodes next pointer. Some other things I noticed is that you forgot to deallocate the dynamic/heap memory. Fix that with using 'free' or consider using smart pointers, so you don't have any memory leaks. At the end, try to avoid using namespace std;. It is considered a bad habit, due to bad performance. Hope it helped you. Here is the not optimized code snippet.
#include <iostream>
using namespace std;
class Storage {
public:
char lett;
Storage* next;
Storage* prev;
};
void push(char lett1, Storage** head, Storage **tail) {
Storage* n = new Storage();
n->lett = lett1;
n->next = NULL;
n->prev = NULL;
if (*head == NULL) {
*head = n;
*tail = n;
}
else {
n->next = *head;
(* head)->prev = n;
*head = n;
}
}
std::string display(Storage* head) {
Storage* s = head;
std::string org = "";
while (s != NULL) {
org += s->lett;
s = s->next;
}
return org;
}
std::string reverse(Storage* tail) {
Storage* t = tail;
std::string rev = "";
// Storage* original= tail;
while (t != NULL) {
rev += t->lett;
t = t->prev;
}
return rev;
}
bool checkPalindrome(Storage* head, Storage* tail) {
return display(head) == reverse(tail);
}
int main() {
Storage* head = NULL; Storage* tail = NULL;;
char lett;
int size;
cout << ":: Palindrome Program ::\n" << endl;
cout << "Enter total character: ";
cin >> size;
cout << "Enter character: ";
for (int i = 0; i < size; i++) {
cin >> lett;
push(lett, &head,&tail);
}
cout << "Your word: ";
cout<<display(head)<<endl; //compare content of this
cout << "\nReversed word: ";
cout<<reverse(tail)<<endl; // with this
cout << "\nPalindrome: " << checkPalindrome(head, tail) << endl;
return 0;
}
If you want to build a string with the characters in the linked list, you can use the std::string::operator+= to concatenate the single characters together.
For instance, considering your display function:
void display(Storage* head, int no) {
Storage* s = head;
while (head != NULL) {
int i = 0;
cout << head->lett;
s = head;
head = head->next;
}
}
instead of using cout << head->lett to print a single character, just concatenate that character to the result string using string::operator+=:
// Assume: std::string result
result += head->lett;
You could write a function that takes the linked list of characters as input, and returns a std::string, along these lines:
std::string ToString(const Storage* head) {
std::string result;
// For each node in the linked list
while (...) {
// Append current node's character to the result string
result += currentNode->lett;
}
return result;
}

How i can create a single list , then create two single lists from it one of them for even numbers and another for odd numbers?

I'm a beginner programmer in my first years in college, I'm working with single linked lists in c++, and I'm trying to write a program without using classes
to create a single linked list input from a user and print it, then I want to put the even numbers
in a new list and print this new list and the odd numbers in another new list and
print it too.
I began with this, I wish if someone can help me.
#include <iostream>
using namespace std;
struct node {
int data;
node* next;
};
struct Even_node {
int even_data;
Even_node* even_next;
};
void creat(node*& head, node*& tail)
{
int num;
cout << "enter number , (0) to quiet\n";
cin >> num;
while (num != 0) {
node* nptr = new node;
nptr->data = num;
if (head == nullptr)
head = nptr;
else
tail->next = nptr;
tail = nptr;
tail->next = nullptr;
cout << "enter number again or 0 to quiet\n";
cin >> num;
}
}
void print(node* head)
{
cout << "the list is:\t";
while (head != nullptr) {
cout << head->data << "\t";
head = head->next;
}
cout << endl;
}
main()
{
node *head = nullptr, *tail = nullptr;
creat(head, tail);
print(head);
}
First I fixed the problems
removed dynamic memory allocations and memory leaks
it's int main https://en.cppreference.com/w/cpp/language/main_function
#include <iostream>
#include <memory>
using std::cout;
using std::cin;
struct node {
int data;
std::unique_ptr<node> next;
};
struct list {
std::unique_ptr<node> head;
node *tail;
};
void creat(list &l)
{
int num;
cout << "enter number , (0) to quiet\n";
cin >> num;
while (num != 0) {
std::unique_ptr<node> nptr = std::make_unique<node>();
nptr->data = num;
if (!l.head) {
l.head = std::move(nptr);
l.tail = l.head.get();
} else {
l.tail->next = std::move(nptr);
l.tail = l.tail->next.get();
}
cout << "enter number again or 0 to quiet\n";
cin >> num;
}
}
void print(const list &l)
{
auto node = l.head.get();
cout << "the list is:\t";
while (node != nullptr) {
cout << node->data << "\t";
node = node->next.get();
}
cout << '\n';
}
int main()
{
list l;
creat(l);
print(l);
}
Now you can create a second list, call it even, iterate through the first list and copy all even elements into the second list.

How to remove a certain node from a linked list by the data its holding?

We are suppose to enter a string, and then find where the string is in the linked list and remove that node
when i insert to the front of the list, so i enter data values a, b, c , d, when i print it it comes up as d,c,b,a. Now i insert to the rear of it, entering f and g, and the list now looks, d,c,b,a,f,g. I want to remove f but it just use the remove function it does not and still output the same list
using namespace std;
struct node {
string data;
node* next;
};
node* addFront(node* s);
node* addRear(node* s);
void remove(node* head, string abc);
void print(node* head);
int main() {
node* head = NULL;
cout << "Enter 5 data strings\n";
cout << "This will be inserted from the back\n";
for (int i = 0; i < 5; i++) {
head = addFront(head);
}
print(head);
cout << "Enter 3 strings and this will be inserted from the back of the orignal string\n";
for (int i = 0; i < 3; i++) {
head = addRear(head);
}
print(head);
cout << "Removing the head node\n";
string n;
cout << "Enter a string to remove\n";
cin >> n;
remove(head, n);
print(head);
}
node* addFront(node* s)
{
node* person = new node;
cin >> person->data;
person->next = s;
s = person;
return s;
}
node *addRear(node*s ) {
node* person = new node;
cin >> person->data;
person->next = NULL;
if (s == NULL) {
return person;
}
else {
node* last = s;
while (last->next != NULL) {
last = last->next;
}
last->next = person;
}
return s;
}
void remove(node* head, string a) {
node* previous = NULL;
node* current = head;
if (current == NULL) {
cout << "Value cannot be found\n";
return;
}
else {
while (previous != NULL) {
if (current->data == a) {
previous->next = current->next;
delete current;
break;
}
current = current->next;
}
}
}
void print(node * head)
{
node* temp = head;
while (temp != NULL) // don't access ->next
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
In remove function, previous is most certainly NULL when you hit that while loop.
Perhaps consider a do-while loop instead (with better handling of previous).
You may be better off handling the first node in a different manner since the holder of its previous is essentially the root pointer.

Linked List Program error in C++

I tried implementing Linked List using C++ using a structure.
I've included three functions - Size, Insertion and Deletion from the end.
The program compiled successfully. During execution, when I tried to give input for the LLInsert() function, there was just a cursor blinking on my execution window. I don't know if the function returned to main.
Also the LLSize() doesn't return 0 when I try to find the Size of a empty list.
I can't seem to figure out what I'm doing wrong. Here is my code.
#include<iostream>
using namespace std;
struct LL {
LL *next = NULL;
int data;
};
int LLSize(LL *head) {
LL *current = new LL;
current = head;
int count = 0;
while(current != NULL) {
current = current -> next;
count ++;
}
return count;
}
void LLInsert(LL *head,int value) {
LL *current = new LL;
current = head;
LL *Newnode = new LL;
Newnode -> data = value;
Newnode -> next = NULL;
if(head == NULL) {
head = Newnode;
return;
}
while(current->next != NULL) {
current = current->next;
}
current->next = Newnode;
return;
}
int LLDelete(LL *head) {
LL *current = new LL;
current = head;
int deleteddata;
while(current->next->next != NULL) {
current = current->next;
}
current->next->data = deleteddata;
current->next = NULL;
return deleteddata;
}
int main() {
int choice;
LL *A;
while(1) {
cout << "1. Size\n2. Insert\n3. Delete\n4. Exit" << endl;
cout << "Enter a choice : ";
cin >> choice;
switch(choice) {
case 1 : {
cout << "\nLength = " << LLSize(A) << endl;
break;
}
case 2 : {
int value;
cout << "\nEnter the element to insert : ";
cin >> value;
LLInsert(A,value);
break;
}
case 3 : {
cout << LLDelete(A);
break;
}
case 4 : {
exit(0);
}
default : {
cout << "\nInvalid choice. Enter a valid choice " << endl;
break;
}
}
}
}
Don't use using namespace.
Create a type for the list and a type for the nodes
struct LL {
LL* next;
int data;
};
struct L {
LL* head;
};
Use references and don't allocate new memory in each function
int LLSize(L& list) {
LL *current = list.head;
Check if the head of the list is set and use nullptr
if (list.head == nullptr) {
Use an instance of the list and not a pointer
int main() {
int choice;
L A;
Use a debugger like gdb to analyze your program.
Clean up at the end. Delete memory you allocated with new. One delete for each new.

Segmentation fault (core dumped) ? what is it and why is caused ??? ( doubly circular linked list program in c++) [duplicate]

This question already has answers here:
What is a segmentation fault?
(17 answers)
Closed 7 years ago.
My program (its not complete but I would really like to know my error):
#include <iostream.h>
using namespace std;
class dcllnode
{
private:
int data;
dcllnode *next;
dcllnode *prev;
public:
dcllnode(int ele)
{
data = ele;
prev = next;
next = prev;
}
friend class dcll;
};
class dcll
{
private:
dcllnode *head;
public:
dcll()
{
head = NULL;
}
void create();
void inserts(int ele);
void inserte(int ele);
void inserta(int ele, int pos);
void insertb(int ele, int pos);
void dels();
void dele();
void dela();
void display();
};
void dcll::create()
{
if (head == NULL)
{
head = new dcllnode(0);
cout << "list is created";
}
else
{
cout << "list has already been created";
}
}
void dcll::inserts(int ele)
{
if (head == NULL)
cout << "please create the list first ";
else
{
dcllnode *x;
x = new dcllnode(ele);
x->prev = head;
x->next = head->next;
(head->next)->prev = x;
head->next = x;
cout << "list is modified";
}
}
void dcll::inserte(int ele)
{
if (head == NULL)
cout << "please create the list first ";
else
{
dcllnode *x;
x = new dcllnode(ele);
x->next = head;
x->prev = head->prev;
(head->prev)->next = x;
head->prev = x;
cout << "list is modified";
}
}
void dcll::dels()
{
if (head == NULL)
cout << "please create the list first ";
else
{
dcllnode *x;
head->next = x;
head->next = x->next;
(x->next)->prev = head;
x->next = NULL;
x->prev = NULL;
delete(x);
cout << "list is modified";
}
}
void dcll::dele()
{
if (head == NULL)
cout << "please create the list first ";
else
{
dcllnode *x;
head->prev = x;
head->prev = x->prev;
(x->prev)->next = head;
x->prev = NULL;
x->next = NULL;
delete(x);
cout << "list is modified";
}
}
void dcll::display()
{
if (head == NULL)
cout << "please create the list first ";
else
{
dcllnode *p = head->next;
while (p != head)
{
cout << "\n" << p->data;
p = p->next;
}
}
}
int main()
{
dcll l1;
l1.create();
l1.inserte(10);
l1.display();
l1.inserts(20);
return 0;
}
The segmentation problem is not occurring when I use only the create function. I would like to know how to solve such problems and how to avoid segmentation errors in future any information and/or help is appreciated.
You typically get segmentation faults when using illegal pointers (null or uninitialized pointers, or pointers pointing to unallocated or otherwise illegal memory).
In your case it's easy to see what one of the problems are, it's in the dcllnode constructor where you do
prev = next;
next = prev;
When you do these assignments the pointers next and prev are uninitialized, and their values are indeterminate. Assigning them to each other like this will not initialize them, just make them both have the same indeterminate value. Later when you dereference these pointers you will have undefined behavior leading to your segmentation fault and the crash.
What you probably should to is to initialize both pointers to null:
prev = nullptr; // or 0
next = nullptr; // or 0
[Note: In C++ don't use NULL, use either nullptr (preferred) or if you don't have it then plain 0.]
To complete joachim's answer, in these two statements:
(head->next)->prev = x;
(head->prev)->next = x;
head->next and head->prev can be nullptr so you have to check it before dereferencing the pointer.