Store the address of previous node into the “prev” section of current node

青春壹個敷衍的年華 提交于 2020-05-28 06:42:46

问题


First, I defined my node using a struct called listrec. So each node has 3 parts: prev (used to store the address of the previous node), value (used to store the value), and next (used to store the address of next node).

#include <iostream>

using namespace std;

struct listrec
{
    struct listrec    *prev;
    float       value;
    struct listrec    *next;
};

listrec *head, *tail;

Then, I used a loop to initialize the linked list (based on the number of nodes requested by the user.

for (float i = 0; i < number; i++)
    {
        if (i == 0)
        {
            head = new listrec;
            head->prev = NULL;
            head->value = i;
            head->next = NULL;
            tail = head;
        }
        else
        {
            tail->next = new listrec;
            tail = tail->next;
            tail->value = i++;
            tail->next = NULL;

        }
    }

But I don’t know how to store the address of previous node into the current node’s prev.

Below is how the linked node should look like.

Since tail’s location is moving every time when a new node got created, and head is always pointed to the first node…how can I get the address of the previous node stored into the “prev” section of the current node?


回答1:


Create a new node, set the members, store the address in next and update tail

for (float i = 0; i < number; i++) {
    if (i == 0) {
        head = new listrec;
        head->prev = nullptr;
        head->value = i;
        head->next = nullptr;
        tail = head;
    } else {
        auto *newNode = new listrec;
        newNode->value = i++;
        newNode->next = nullptr;
        newNode->prev = tail;
        tail->next = newNode;
        tail = tail->next;
    }
}



回答2:


First of all, I don't recommend using the data type float for storing integer values (=whole numbers) intead of int. With higher numbers, you run the risk of losing precision when using float, which could cause your program to misbehave if this variable is used as a loop counter.

I recommend you use the following code for building the linked list:

head = nullptr;
tail = nullptr;
listrec **pp = &head;

for (int i = 0; i < number; i++)
{
    listrec *new_node;

    new_node = new listrec;
    new_node->prev = tail;
    new_node->value = static_cast<float>(i);

    *pp = new_node;
    pp = &new_node->next;

    tail = new_node;
}

*pp = nullptr;

Although this code requires one variable with multiple pointer indirection (pointers to pointers can be hard to understand), I believe it is worth it, because this makes the if conditional branch unnecessary.




回答3:


Before assigning tail a new value, store its current value in a temporary variable and use it to set tail->prev:

listrec *prev = tail;
tail = tail->next;
tail->prev = prev;



回答4:


You will need to create the new node and it to the next of the current after setting it up (you should do this anyway to provide exception safety). Also your current code is hemorrhaging memory (since you lose the pointer to the last item every time you add an item)

Your code here:

tail->next = new listrec;
tail = tail->next;

Causes the reference to the old item to be forgotten as tail becomes the new item and no reference is preserved. Do something like this:

auto* new_item = new listrec;
// Set up the new item
new_item->value = i + 1; // Increment the value of the new item
new_item->next = nullptr; // C++ now uses nullptr instead of NULL
new_item->last = tail; // Set the new items last to be the current item

tail->next = new_item; // Make the current item's next the new item
tail = tail->next; // Move forward in the list by moving the tail to the new item


Then to access the previouse item in the list:

auto* prev_item = tail->last;

This will also gurentee that if new throws then your list will be unmodified, rather than having the new front item in an unknown state.




回答5:


To start off, I would rewrite your listrec struct slightly:

struct listrec
{ 
    float    value = 0;
    listrec *prev = nullptr;
    listrec *next = nullptr;
};

This has the nice property that you can create a listrec object without worrying about uninitialized pointers. Also, this is the natural state that a linked list with one element should be in.

Then you could write your construction loop more easily.

for (int i = 0; i < number; i++) 
{
    if (i == 0) 
        tail = head = new listrec{i};
    else 
        tail = tail->next = new listrec{i, tail};
}

Note that assignment is right-to-left: looking at the else statement; first a new listrec is created with the correct prev and next members; then the tail->next is updated to point to the new node. Finally, the tail itself is updated to point to the new_node. (Draw out each step, to see how it works).

In your case, since your value member is a float, the new expression should never throw (and if it does, I doubt you would be able to recover in any sane way).

However, if you make value a type that is large, or if you decide to go ahead and template listrec, then you should allocate a new node separately, and then link up the new node to your linked list.

for (int i = 0; i < number; i++) 
{
    auto new_listrec = new listrec{i, tail}; // if this throws, your linked list invariants are still maintained.
    // also, tail is nullptr if the linked list is empty, which is fine.

    // then link stuff up
    if (i == 0) 
        tail = head = new_listrec;
    else 
        tail = tail->next = new_listrec;
}

I would say this is terse enough, but you could even write

for (int i = 0; i < number; i++) 
{
    auto new_listrec = new listrec{i, tail}; 

    tail = (i ? tail->next : head) = new_listrec;
}

Finally, please don't use using namespace std;



来源:https://stackoverflow.com/questions/60917667/store-the-address-of-previous-node-into-the-prev-section-of-current-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!