0

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: enter image description here

dandelion
  • 13
  • 5
  • Your `mergelists()` code neither creates new nodes to represent the sorted list nor uses `setlink()` to change where the pointers point. – Ken Y-N Apr 25 '17 at 05:24
  • @KenY-N so I changed my code. But result has an error: expression must be a modifiable lvalue. How can I fix it? Thanks a ton – dandelion Apr 25 '17 at 05:59
  • How familiar are you with references? You need to return a reference to a pointer to pull the trick I think you are trying – user4581301 Apr 25 '17 at 06:10
  • I am not really familiar with it. Is it like use another name for an already existing variable? Could you please give a specific example (to my code- would be great). I am really new to C++ sadly @user4581301 – dandelion Apr 25 '17 at 06:27

1 Answers1

0

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.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • thank you so much! It works. i also have a new solution: change result ->getlink() = head1 to result->setlink(head1) – dandelion Apr 26 '17 at 02:12
  • @dandelion Works for me. Wise man once said, "Adapt what is useful, reject what is useless, and add what is specifically your own." – user4581301 Apr 26 '17 at 03:47