Разве «tempPtr» здесь избыточен? (Связанные списки) - PullRequest
0 голосов
/ 22 апреля 2020

Я практикую связанные списки, и этот код предоставлен нам нашим лектором из книги Пирсона.

struct listNode {
    char data;
    struct listNode *nextPtr;
};

typedef struct listNode ListNode;
typedef ListNode *ListNodePtr;

...

char delete( ListNodePtr *sPtr, char value )
{
    ListNodePtr previousPtr;
    ListNodePtr currentPtr;
    ListNodePtr tempPtr;

    /* delete first node */
    if ( value == ( *sPtr )->data ) {
        tempPtr = *sPtr;
        *sPtr = ( *sPtr )->nextPtr;
        free ( tempPtr );
        return value;
    }
    else{
        previousPtr = *sPtr;
        currentPtr = ( *sPtr )->nextPtr;

        /* loop to find correct location in the list */
        while ( currentPtr != NULL && currentPtr->data != value ) {
            previousPtr = currentPtr;
            currentPtr = currentPtr->nextPtr;
        }

        /* delete node at currentPtr */
        if ( currentPtr != NULL ) {
            tempPtr = currentPtr;
            previousPtr->nextPtr = currentPtr->nextPtr;
            free ( tempPtr );
            return value;
        }       
    }

    return '\0';
}

Я не понимаю, почему мне нужно использовать «tempPtr». Не могу я просто сделать:

/* delete first node */
if ( value == ( *sPtr )->data ) {
    *sPtr = ( *sPtr )->nextPtr;
    free ( *sPtr );
    return value;
}

и

if ( currentPtr != NULL ) {
    previousPtr->nextPtr = currentPtr->nextPtr;
    free ( currentPtr );
    return value;
}   

(то, что передается в функцию delete, это объект LinkedListPtr, определенный в main и переданный ссылка. Ответственный за хранение адреса первого элемента в списке.)

Ответы [ 2 ]

2 голосов
/ 22 апреля 2020

Не могу я просто сделать:

if ( value == ( *sPtr )->data ) {
    *sPtr = ( *sPtr )->nextPtr;           # this line changes *sPtr value
    free ( *sPtr );                       # frees `(*sPtr)->nextPtr`, not the old `*sPtr`
    return value;
}

Нет, это не эквивалентно. В вашем коде вы освобождаете (*sPtr)->nextPtr, а не *sPtr. Вы хотите освободить значение *sPtr и изменить его на значение следующего указателя. Таким образом, вы должны иметь временное значение - либо для указателя, либо для нового значения. В качестве альтернативы исходному коду вы можете сохранить nextPtr и освободить текущий указатель, а затем назначить его следующим:

if ( value == ( *sPtr )->data ) {
    tempPtr = (*sPtr)->nextPtr;
    free(*sPtr);
    *sPtr = tempPtr;
    return value;
}

и

if ( currentPtr != NULL ) {
    previousPtr->nextPtr = currentPtr->nextPtr;
    free ( currentPtr );
    return value;
}

Конечно , этот код эквивалентен.

2 голосов
/ 22 апреля 2020

Упрощенная версия:


struct listNode {
    struct listNode *next;
    char data;
   };

char delete(struct listNode  **pp, char value )
{
    struct listNode  *this;

        while ((this = *pp)) {
                if (this->data != value) { pp= &this->next; continue; }
                *pp = this->next; // this is why you need a temp pointer
                free(this);       // ::because you want to free() it
                return value;     // nonsense return
        }

    return '\0'; // nonsense return
}

и небольшой драйвер для тест функция:


#include <stdio.h>
#include <stdlib.h>

struct listNode {
    struct listNode *next;
    char data;
   };

struct listNode *root = NULL;

void push(char val)
{
struct listNode *new;
new = malloc (sizeof *new);
new->data = val;
new->next = root;
root = new;
}

void print(struct listNode *p)
{
for (; p; p = p->next) {
        printf(" %c", p->data);
        }
printf("\n");
}

int main(void)
{
push('o');
push('l');
push('l');
push('e');
push('H');

print(root);

delete( &root, 'o');
print(root);

delete( &root, 'H'); // <<-- test if we can delete the **first** node of the chain
print(root);

return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...