问题
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