简体   繁体   中英

Singly Linked List

I have a project from https://hotfile.com/dl/253309046/133284f/4_SinglyLinkedList.rar.html

The function insertOrdered() inserts scores in order.

My questions is: can this loop be rewritten without using a "previous" variable?

SinglyNode* current = head;
SinglyNode* previous= NULL;
while (current != NULL)
{
    if(newNode->score >= current->score)
        previous = current; 
    else
        break;
    current = current->next;
}

newNode->next   = previous->next;
previous->next  = newNode;  

获取另一个变量(例如x)中先前变量的值(例如p),并使用x代替p。

A simple solution is to first check if it should be inserted before the head. If not then use a loop similar to your but compare against current->next (if not NULL ), then when the loop ends the new node should be inserted between current and current->next , ie current is used as previous in the code you have now. If current->next is NULL then insert at end.

Not able to test this, but moving the new node setup code into the if block should allow you to remove the previous variable.

SinglyNode* current = head;
while (current != NULL)
{
    if(newNode->score >= current->score) {
        newNode->next  = current->next;
        current->next  = newNode; 
    }
    else break;
    current     = current->next;
}
if(current == NULL) { // got to end of list
    current->next  = newNode;
    newNode->next  = NULL;
}

This should work:

SinglyNode* current = head;
if(current == NULL) {
    head = newNode;
}
else if(newNode->score < current->score) {
    newNode->next  = current;
    head  = newNode;  
}
else {
    while (current->next != NULL)
    {
        if(newNode->score < current->next->score)
          break;
        current = current->next;
    }

    newNode->next  = current->next;
    current->next  = newNode;  
}

You cannot eliminate the "previous" variable, but you can disguise it; and furthermore, you can structure the loop so that it is the only iteration variable.

Of course to insert the new, you need to update the previous node to point to it.

You can do that from the current node by looking ahead in the list and handling various cases.

Another way is to keep a pointer to the pointer field in the previous node.

node **ppnode;

for (ppnode = &head;
     *ppnode != NULL && (*ppnode)->value >= newnode->value;
     ppnode = &(*ppnode)->next) 
   ; /* empty body */

newnode->next = (*ppnode) ? (*ppnode)->next : NULL;
*ppnode = newnode;

Here, instead of using a current pointer to point to the current, we use a ppnode pointer which points to the current node indirectly. Instead of pointing to that node, it points to the pointer which points to that node (and so it must be suitably typed: it is a pointer to pointer: double star).

The pointer to the first node is the list head variable, so ppnode points to that head variable initially. The pointer to every other node after that is the next field of the previous node: each one of these next fields is really like a head of the rest of the list. So with this one ppnode variable, we keep track of the location within the previous node that must be updated, without keeping track of the previous node itself. And this lets us handle the front of list case where there is no previous node.

Let's trace through the case that head is null (the list is empty).

ppnode points to head . But *ppnode is null, and so the loop body never executes.

Since ppnode points to head , the lines:

newnode->next = (*ppnode) ? (*ppnode)->next : NULL;
*ppnode = newnode;

have the same meaning as:

newnode->next = head ? head->next : NULL;
head = newnode;

The conditional check in these lines handles the case when the new node is added to an empty list or to the tail of a nonempty list. If the list is empty or all the values in it are smaller than the new value, then the loop terminates with ppnode pointing at the list's null terminator, which is head if the list is empty, or else the next field of the tail node. Since *ppnode is null, we cannot deference (*ppnode)->next . There is no next; the new node is the last node and its next must be nulled.

Now let's look what happens in the case that there is a head node, and its value is greater so that the new node must be inserted at the front. In this case ppnode points to head , as before, and the *ppnode != NULL condition is true. However the (*ppnode)->value >= newnode->value condition fails and so the loop never executes.

Now, again, we are executing the equivalent of this code:

newnode->next = head ? head->next : NULL;
head = newnode;

But this time head is not null, and so newnode->next = head->next , and, as before, newnode becomes the new head .

All the other cases proceed from these two: except instead of head , the action plays out using the next pointer of the previous node, which is like the head of the rest of the list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM