I'm trying to add numbers from two linked lists and put it in a third one. It adds well but my code blocks compiler stops responding while running this code possibly because of an infinite loop or some exception.
Following code adds two numbers stored in reverse order in a linked list.
struct Node{
int x;
Node* next;
};
class LinkedList{
public:
Node* head;
LinkedList(){
head = NULL;
}
void addNode(int num){
Node* n = new Node();
n->x = num;
n->next = NULL;
if(head == NULL){
head = n;
}else{
Node* n1 = head;
while(n1 != NULL){
if(n1->next == NULL){
n1->next = n;
break;
}
n1 = n1->next;
}
}
}
int popNode(){
int num = NULL;
if (head != NULL){
num = head->x;
head = head->next;
}else{
cout << "Yay" << "\n";
num = NULL;
}
return num;
}
void printList(){
Node* n1 = head;
while(n1 != NULL){
if(n1->next == NULL){
cout << n1->x << "\n";
}else{
cout << n1->x << "->";
}
n1 = n1->next;
}
}
};
LinkedList* add_nums(LinkedList* l1, LinkedList* l2) {
LinkedList l3;
int num1= (*l1).popNode();
int num2= (*l2).popNode();
int carry = 0;
while(num1 != NULL || num2 != NULL){
int num3 = num1+num2+carry;
if (num3 > 9){
int temp = num3 % 10;
carry = (num3 - temp)/10;
num3 = temp;
}
l3.addNode(num3);
l3.printList();
num1 = (*l1).popNode();
num2 = (*l2).popNode();
}
return &l3;
}
int main(int argc, char const *argv[]) {
LinkedList list1;
LinkedList list2;
list1.addNode(2);
list1.addNode(4);
list1.addNode(3);
list2.addNode(5);
list2.addNode(6);
list2.addNode(4);
(*(add_nums(&list1, &list2))).printList();
return 0;
}
Can anyone tell me what I'm doing wrong?
Changes to code i should do after inputs from answers below:
I should change integer initializations from NULL to 0.
Should use LinkedList objects to terminate my loop.
Should change how i access the functions from a pointer
Thanks everyone.
Can anyone tell me what I'm doing wrong?
IMHO you might be making a wrong choice. The STL provides data structures for (doubly linked) list and forward list (which is singly linked). Maybe you want to use those. You can expect them to be efficient enough, bug free and important to know about if you want to be a proficient C++ programmer.
It would make sense to let someone do a code review (there is a code review StackExchange site); e.g. naming the integer variable x in the linked list is probably not considered a good practise.
You did not tell us what is wrong about your program. This is expected in SO. Your question qualifies for "off-topic (why is this code not working?)". You provided the program, which is good. But you did not provide your expected input and output. What is your program expected to do? If I consider your main function as a test, then what result did you expect ?
see below some errors/warnings
In the function popNode
int num = NULL; // should be 0, it's an integer
...
num = NULL; // same reason
In the functions add_nums
LinkedList l3; // it's a local variable (see return below)
...
while(num1 != NULL || num2 != NULL) // again num1 and num2 are integers
....
return &l3; // address of a local variable :-(
I think it is better you declare the variable l3 as a pointer to LinkedList:
LinkedList *l3 = new LinkedList;
... // adapt the code to use l3 appropriately
return l3;
As others in comments say, your error is this one: return &l3;
l3 is a local object and is deleted just before the end of the function, like any object that is not dinamically allocated. This is because of the scope of your LinkedList object.
You should have written:
LinkedList* l3 = new LinkedList();
//...
//...
return l3;
this function now returns a pointer to your object.
NB: the variable l3, which contains the pointer, is deleted just before the function, but it doesn't matter because the object lifetime is not bound to the function anymore.
Related
Hi I have a problem with Sieve of Eratosthenes in C++. I have to do this using single linked list. My program is running and showing first declaration of list but I don't know how to delete non prime numbers properly. My function just isn't working for me. How should I change my delete function?
#include <iostream>
#include <cmath>
using namespace std;
struct List
{
int number;
List* next;
};
List* head = new List;
void l_add(int n)
{
List* temp = head;
for (int i = 2; i <= n; i++)
{
temp->next = new List();
temp->number = i;
temp = temp->next;
}
}
void l_print()
{
List* temp = head;
while (temp->next != 0)
{
cout << temp->number << " ";
temp = temp->next;
}
cout << endl;
}
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
if (temp->number % i == 0)
{
head = temp->next;
delete temp;
temp = head;
}
while (temp->next != 0)
{
if (temp->next->number % i == 0)
{
temp->next = temp->next->next;
delete temp->next;
}
temp = temp->next;
}
}
}
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
cin >> n;
l_add(n);
l_print();
l_delete(n);
l_print();
return 0;
}
This would be a working version of the l_delete method:
void l_delete(int n)
{
List* temp = head;
for (int i = 2; i < sqrt(n); i++)
{
while (temp->next != 0)
{
if (temp->next->number % i == 0 && temp->next->number != i)
{
List* temp2 = temp->next->next;
delete temp->next;
temp->next = temp2;
}
if(temp->next == 0) break;
temp = temp->next;
}
temp = head;
if (temp->number % i == 0 && temp->number != i)
{
head = temp->next;
delete temp;
temp = head;
}
}
}
There were several problems with your deletion method.
Problems with algorithm logic: With your algorithm head should be checked last because otherwise if its deleted, the new head is not checked for primality, you immediately check new next, which is old ->next->next. Also you didn't check if number is equal to divider in which case it should not be deleted.
Problems with programming logic:
When you're deleting next node in the while loop, same as when deleting head, you need another temporary variable to store temp->next->next and then after deleting assign it to temp->next.
But the biggest problem here is that this is not Eratosthenes sieve at all, you are
just checking all numbers for divisibility with all others smaller than sqrt(n). It
is suboptimal compared to the Eratosthenes sieve. If you Google Eratosthenes sieve, you’ll find a lot of detailed tutorials and explanations.
I like what Bran is pitching, and I'm going to add a few tricks.
Comment: Global variables suck. They make things harder to trace when projects get bigger. I'd move head into main and pass it around as a parameter. I'm also ditching the sentry node because I find them more trouble than they are worth most of the time.
int main()
{
int n;
cout << "Enter up to which number to find prime numbers using Sieve of Eratosthenes: " << endl;
if (cin >> n)
{
// should be a bit more logic here to automatically handle ns of 1 or 2
List* head = nullptr; // not using a sentinel node
l_add(head, n); // passing in head rather than global variable free-for-all
l_delete(head);
l_print(head);
return 0;
}
else
{
cout << "invalid input." << endl;
return 1;
}
}
When adding to the linked list, you don't need any even numbers other than 2. So don't add them. Less time spent iterating the list. After that it's a matter of making sure nodes go in in the right order.
void l_add(List*& head, // passing in head. Easier to track
int n)
{
List** temp = &head; // head is a next pointer with a different name
// hiding it behind another pointer allows us to treat
// it like a next
// temp is now a pointer to next pointers. We can add directly to the
// last nodes's next pointer and also use it to access the current
// pointer if we need to
(*temp) = new List {2, nullptr}; // 2 is only even prime
temp = &(*temp)->next;
for (int i = 3; i <= n; i+=2) // start at 3 and only add odd numbers
{
(*temp) = new List {i, nullptr};
temp = &(*temp)->next; // Advance to next node
}
}
When we're iterating through the list looking to eliminate multiples we need two loops. One to keep track of the node we're eliminating multiples and another loop to do the hunting and eliminating. Note that I'm using the pointer-to-pointer trick again. This trick annihilates about half of the code needed to traverse and remove nodes.
void l_delete(List * head)
{
List* last = head->next; // track the last known prime node. skip node 2.
// note this will blow up if there is no node 2.
while (last) // for every node still in the list
{
List** current = &last->next; // similar to trick above.
// if we have a pointer to the next to be
// updated, we don't need to track the previous node
while ((*current)) // look at every node after the last prime
{
if ((*current)->number % last->number == 0) // if it's a multiple, remove it.
{
List * to_del = (*current); //save node to delete
(*current) = (*current)->next; // link previous node to next node.
// effectively automatically advances the node
delete to_del;
}
else // proceed to next node
{
current = &(*current)->next;
}
}
last = last->next; // advance to next prime number
}
}
Probably plenty of room in there for optimization, but I'm aiming more for readability because if I drop ten lines of cryptic gibberish nobody learns nuthin'.
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node* next;
};
//Node* head1 = new Node;
void search(int num , Node* head1)
{
if( (head1 != NULL) & (head1->data == num) )
{
cout << "Yes";
return ;
}
else if(head1 == NULL)
{
cout << "No";
return ;
}
search(num , head1->next);
//return FALSE;
}
int main() {
int max , n;
cin >> n;
Node* head = NULL;
Node* ptr;
for(int i = 0; i < n ; i++)
{
int num;
cin >>num;
Node* temp = new Node;
temp->data = num;
temp -> next = NULL;
if(head == NULL)
{
head = new Node;
head = temp;
ptr = new Node;
ptr = head;
}
else
{
ptr->next = temp;
ptr = ptr->next;
}
// linked list is made;
// traversing through the linked list;
// search for an element;
//cout << head->data <<"\n";
}
search(6 , head);
// I have assumed 6 won't be there in the list
}
The linked list work fine. I have been able to build the list without running into any kind of run time errors. The only problem I have is with the search method.
It will print "YES" perfectly when the element to be searched is present but runs into run time error when the element is not there instead of printing "NO";
I have used recursion(intended) to solve this problem as it is something I am not very comfortable with .
To save time you can ignore the main function as it runs fine. I have just provided that for reference or any other valuable suggestions.
Also I have checked other answers on SO and realized that most of the run time errors in Linked List is because of bad memory allocation . I have checked my code and found that memory allocation has been done properly , or so I think.
Your mistake is here
if( (head1 != NULL) & (head1->data == num) )
it should be
if( (head1 != NULL) && (head1->data == num) )
&& does a logical and, plus if the left hand side is false the right hand side is not evaluated. & does a bitwise and, but always evaluates both sides.
So, in your code, when head1 == NULL then head1->data still gets evaluated, resulting in a dereference of a null pointer and a crash.
Just change & to &&.
Nothing wrong with your recursion however.
I'm doing a program about doubly linked list. I have function find that helps locate, if per se, no. 7 is anywhere within that list. This function works fine and returns pointer to that node.
Then I have function afterElement that inserts for example no. 3 after no. 7, So it uses pointer to find function as parameter. I think this is where the problem stems from, but I might be wrong, you be the judge.
I wanna know, how can I correctly use this function? Is there something wrong with how I pass parameters or else?
The error I get is "overloaded function with no contextual type information".
Here is the relevant code:
#include <iostream>
using namespace std;
struct node {
int data;
node* prev;
node* next;
};
node* find(int,node*&);
void afterElement(int,int,node*&,node*&,node* (*find)(int, node*&));
int main() {
node* head = NULL;
node* tail = NULL;
// The program itself has a menu that allows for input of value in list but
// for the sake of relevancy and shortness of code I dropped it out from here
int x, y;
cout << "Insert 2 values: value you wish to insert, and value you wish to insert it after. ";
cin >> x;
cin >> y;
afterElement(x,y,head,tail,(*find)(y,head)); // here is the error "overloaded function..."
return 0;
}
node* find(int x,node*& head) {
node* curr = head;
while ((curr != NULL) && (curr->data != x))
curr = curr->next;
return curr;
}
void afterElement(int x,int after,node*& head,node*& tail,node* (*find)(int x, node*& head)) {
node* N;
node* compared = (*find)(after,head);
N->data = x;
if (compared == NULL)
cout << "There is no element " << after << " in the list!\n";
else {
if (compared->next == NULL) {
compared->next = N;
N->prev = compared;
N->next = NULL;
tail = N;
} else {
compared->next->prev = N;
N->next = compared->next;
compared->next = N;
N->prev = compared;
}
}
}
If you want to pass a function as an argument to another function, you just need to use the function name, not the entire call expression.
afterElement(x,y,head,tail,find);
This is the minimal fix that causes your program to compile. Live demo. Note this only demonstrates that the compilation errors are fixed, not that the program works!
In addition, because you are using namespace std, you are getting incomprehensible error messages, since the compiler cannot figure out what find you have in mind, your own or std::find. If you get rid of using namespace std, your error message becomes much clearer:
error: cannot convert ‘node*’ to ‘node* (*)(int, node*&)’
Live demo. Never use using namespace std.
However you may want to consider removing find from the parameter list of afterElement. afterElement doesn't need to be told which function to call in order to find an element.
void afterElement(int x,int after,node*& head,node*& tail)
would work just fine.
Passing a pointer to a node instead of int after will also work:
void afterElement(int x, node* after, node*& head, node*& tail)
Call afterElement(x, y, find(x, head), head, tail) to use this variant. Note you don't need to say (*find)(x, head).
There are more problems with your code than this compilation error. For example
node* N;
...
N->data = x;
is incorrect. You have not initialised N, it doesn't point anywhere, so you cannot use -> on it.
Another problem is that your program never modifies head, so the list doesn't have a chance to contain anything. This perhaps should be fixed by adding more functions (maybe something like beforeElement).
I observe that you want to pass the "find" function as an argument to afterElement function.
Sure you can pass a function as an argument to other function. A function also gets stored in a memory location. This memory location is stored in the variable named same as the function name (in this case "find").
Now you are receiving the find function argument as a pointer in the afterElement function, so it is expecting an address, but you are passing the whole function. That's the reason why it is giving a compilation error.
The correct code looks like :
#include <iostream>using namespace std;
struct node {
int data;
node* prev;
node* next;
};
node* find(int,node*&);
void afterElement(int,int,node*&,node*&,node* (*find)(int, node*&));
int main() {
node* head = NULL;
node* tail = NULL;
// The program itself has a menu that allows for input of value in list but
// for the sake of relevancy and shortness of code I dropped it out from here
int x, y;
cout << "Insert 2 values: value you wish to insert, and value you wish to insert it after. ";
cin >> x;
cin >> y;
afterElement(x,y,head,tail,find); // modified the passing argument
return 0;
}
node* find(int x,node*& head) {
node* curr = head;
while ((curr != NULL) && (curr->data != x))
curr = curr->next;
return curr;
}
void afterElement(int x,int after,node*& head,node*& tail,node* (*find)(int x, node*& head)) {
node* N;
node* compared = (*find)(after,head);
N->data = x;
if (compared == NULL)
cout << "There is no element " << after << " in the list!\n";
else {
if (compared->next == NULL) {
compared->next = N;
N->prev = compared;
N->next = NULL;
tail = N;
} else {
compared->next->prev = N;
N->next = compared->next;
compared->next = N;
N->prev = compared;
}
}
}
I have checked with compilation, but check once for the results you are expecting.
Thanks.
I wrote the code about merging two sorted lists. However,just the head1 running not the head2. For example, head1: 0 2 5 7 head2: 0 5 8 9. The output will be 0 2 5 7. Could anyone tell me why?
#include <iostream>
using namespace std;
// class node
class node {
private:
double num;
node *link;
public:
node() { }
node(double m, node *n) { num = m; link = n; }
node* getlink() { return link; }
double getdata() { return num; }
void setdata(double m) { num = m; }
void setlink(node* n) { link = n; }
};
typedef node* nodeptr;
void insertnode(nodeptr& head, double m);
void printlist(nodeptr head);
nodeptr mergelists(nodeptr& head1, nodeptr& head2);
void reverselist(nodeptr& head);
nodeptr search(nodeptr head, double searchterm);
void insert(nodeptr afterme, double newdata);
int main()
{
double input;
nodeptr head1 = NULL; // Pointer to the head of List #1
nodeptr head2 = NULL; // Pointer to the head of List #2
nodeptr temp;
// Part 1 - Create two sorted lists
cout << "-------------------------------------" << endl;
cout << "CREATE LIST #1: " << endl;
cout << "-------------------------------------" << endl;
do {
cout << "Enter value (0 to quit): ";
cin >> input;
// Insert the "input" value into the list
insertnode(head1, input);
} while (input != 0);
cout << "-------------------------------------" << endl;
cout << "CREATE LIST #2: " << endl;
cout << "-------------------------------------" << endl;
do {
cout << "Enter value (0 to quit): ";
cin >> input;
// Insert the "input" value into the list
insertnode(head2, input);
} while (input != 0);
// Part 1 - Print the lists to make sure that they are correct.
printlist(head1);
printlist(head2);
// Part 2 - Merge the two lists and display the new merged list
cout << "Merge lists: " << endl;
temp = mergelists(head1, head2);
printlist(temp);
// Part 3 - Reverse the merged list and then display it
return 0;
}
nodeptr search(nodeptr head, double searchterm)
{
nodeptr p = head;
nodeptr q = head->getlink();
if (p == NULL)
return NULL;
else
{
while (p != NULL)
{
q = p->getlink();
while (q != NULL && q->getdata() < searchterm)
{
p = p->getlink();
q = q->getlink();
}
return p;
}
}
}
void insertnode(nodeptr& head, double m)
{
// CASE 1 - List is empty
if (head == NULL)
{
head = new node(m, NULL);
}
// CASE 2 - List is not empty and new value is < 1st value
else if (m < head->getdata())
{
head = new node(m, head);
}
// CASE 3 - List is not empty and new value goes inside list
else
{
// search for correct location - notes on Search
nodeptr afterme = search(head,m);
// insert at this location -- see notes on insert inside list
nodeptr temp;
temp = new node(m, afterme->getlink());
afterme->setlink(temp);
}
}
void printlist(nodeptr head)
{
nodeptr p;
p = head;
while (p != NULL)
{
cout << p->getdata() << endl;
p = p->getlink();
}
}
// mergelist function -> wrong result
nodeptr mergelists(nodeptr& head1, nodeptr& head2)
{
if (head1 == NULL)
return head2;
if (head2 == NULL)
return head1;
nodeptr result = new node(0, NULL);
nodeptr head = result;
while (head1 != NULL&&head2 != NULL){
if (head1->getdata() <head2->getdata()){
result ->getlink() = head1;
head1 = head1 -> getlink();
}
else{
result->getlink() = head2;
head2 = head2->getlink();
}
result = result ->getlink();
}
if (head1 == NULL){
result ->getlink() = head2;
}
else{
result ->getlink() = head1;
}
return head->getlink();
}
Here is my output:
Helpful reading so you know a bit of terminology: What are rvalues, lvalues, xvalues, glvalues, and prvalues? If you already know what those terms mean, skip the link. If you don't read it before continuing and you will get a lot more than just the "How to fix the error" portion of this answer.
When you return a value from a function by value, all you are guaranteeed is you get a temporary copy1. So here
node* getlink() { return link; }
you return a pointer to a node, but the pointer itself is a copy of a pointer. It's not link, it is a temporary copy of link that only exists long enough to assign it to something else. Using the terminology linked above, this is an rvalue. So in
result ->getlink() = head1;
head1 would be assigned to a temporary copy of link that only exists for as long as it takes to do the assignment.
You don't get much from assigning data to a copy that only exists for a few nanoseconds, so the big brains who define how C++ works decided that doing it should be an error to drive home the point that the program will not work. The result is the error message you got. You can't assign to an rvalue, but you can assign to an lvalue.
So how do we turn an rvalue into an lvalue?
The easiest way is to not return a temporary copy. The easiest way to do that is to return a reference to the pointer
node* & getlink() { return link; }
Now instead of returning a copy of link, you return... Well that depends on the compiler. You might get link. You might get a pointer to link. If the compiler figures you won't be able to notice (the As-If Rule) you might get zelda instead. That whole function might be stripped out by the compiler and replaced with something brutally simple like link = head1.
What really happens only matters when you get down into the nitty-gritty of compiler design or performance tuning. However the compiler sees fit to do it,
result ->getlink() = head1;
can now assign head1 to link through the return of the function call.
This is the magic that allows you to set a value in a std::vector with vec[99] = 11; or a custom matrix class with mat(3,2) = 7;
The above only explains the error message and how to fix it. It makes no claims on whether or not the logic of the program is correct.
1 As with how a reference works, the compiler has a lot of leeway about what it does here, and the compiler is going to do some really sneaky smurf to turn that copy into something less computationally intensive if the object being copied is large or troublesome to copy. Look up Copy Elision and the many flavours of RVO if you are interested.
This is simple adding nodes to linked list. I'm not able to figure out why the head pointer is being set to null with every call to add function.
//struct declaration of node
struct node {
int data;
node* next;
};
//adding node to the head pointer
void add_node(node* head, int d)
{
node* temp = new node;
temp->data = d;
temp->next = NULL;
node* tmp = head;
if (tmp != NULL) {
cout << "shal";
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = temp;
}
else {
//cout<<temp->data;
head = temp;
}
cout << "dh" << head->data;
}
int main()
{
node* head = NULL;
// calling the add function
add_node(head, 10);
// head is being taken as null here
add_node(head, 20);
}
Output:
dh10nulldh20null
Please help me in understanding where it went wrong.
I guess you didn't get what a pointer is.
void plus_one(int num) {
num += 1;
}
int main() {
int num = 42;
plus_one(num);
std::cout << num << std::endl;
}
Obviously, num is still 42. Why? Because in function plus_one you get num by copy.
When you call your add_node, you send a copy of your head pointer. Since it is a pointer, you can modify what is POINTED BY the pointer, NOT the pointer itself. What you do is the same thing as trying to get 43 with my example... It's not possible if you are getting a copy.
You need to pass the address of your pointer, so call your function as it : add_node(&head, 10); and write your prototype as it : void add_node(node** head,int d). You will have to modify your function to fit with your new node**.
Why does it work? Because you modify the content of the pointer which is POINTING TO you original pointer (which is POINTING TO your structure).