Как получить эту функцию для удаления узлов кругового двусвязного списка более одного раза? (C) - PullRequest
0 голосов
/ 23 февраля 2020

Я должен удалить каждый k узел из связанного списка. Когда эта функция вызывается, скажем, k = 2, она удаляет второй узел, но после этого больше не удаляет. Вот функция:

void remove(soldier* list, int n, int k)
{
    soldier* head = list;
    int counter = n;

    if (head == NULL)
        return;

    soldier *curr = head;
    soldier *prev1 = head;
    while (counter != 0) {

        if (curr->next == head && curr == head)
            break;

        displayList(head);

        for (int i = 0; i < k; i++) {
            prev1 = curr;
            curr = curr->next;
        }

        if (curr == head) {
            head = curr;
            prev1 = head;
            while (prev1->next != head)
                prev1 = prev1->next;
            head = curr->next;
            prev1->next = head;
            list = head;
            free(curr);
        }

        else if (curr->next == head) {
            prev1->next = head;
            free(curr);
        }
        else {
            prev1->next = curr->next;
            free(curr);
        }
        counter--;
    }
}

При вызове

remove(front, n, k);

n = 5, k = 2, я получаю этот вывод:

1 2 3 4 5
1 3 4 5
1 3 4 5
1 3 4 5
1 3 4 5

Что я должен сделать, чтобы получить так, чтобы по каждой строке вывода удалялось другое? Благодаря.

1 Ответ

0 голосов
/ 23 февраля 2020

Если я понимаю, что вы хотите удалить узел k th из двусвязного кругового связанного списка, то, как показано в вашем вопросе, например, если список содержал:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

С k=2 вы хотите удалить 2, 4, 6, 8, 10, 3, ..., пока список не станет пустым. Это что-то вроде проблемы из двух частей. (1) удалить узел k th и (2) увеличить позицию k th , чтобы она теперь указывала на узел k th после того, который вы только что удалил. Это может быть реализовано несколькими способами. Вероятно, наиболее прагматичным является c - реализовать функцию удаления узла k th , а затем написать функцию-обертку, если необходимо обновить счетчик, чтобы он удалял следующий узел в последовательности.

С указателем на указатель на узел 1 st в списке l и узлом k th , который нужно удалить, вы можете сделать что-то похожее на:

/** delete kth node in doubly-linked circular list from node *l
 *  returns pointer to new node at address of deleted node or NULL if
 *  list now empty.
 */
node_t *delkthnode (node_t **l, size_t kth)
{
    node_t  **ppn = l,      /* pointer to pointer to node */
            *pn = *l;       /* pointer to node */

    size_t n = kth ? kth - 1 : 1;   /* set no. to advance (1-based index) */

    if (pn == pn->next) {           /* last node left in list? */
        free (pn);                  /* free node */
        return *ppn = NULL;         /* set address for node to NULL */
    }

    while (n--) {                   /* loop to kth node */
        ppn = &pn->next;            /* update current address to next */
        pn = pn->next;              /* update current node to next */
    }

    *ppn = pn->next;                /* set current address to next node */
    (*ppn)->prev = pn->prev;        /* set current->prev to next->prev */
    if (pn->next == *l)             /* deleting tail node? */
        (*ppn)->prev->next = *l;    /* set new end->next to head */
    if (pn == *l)                   /* if current node is head */
        *l = *ppn;                  /* update list adddress to current */

    free (pn);      /* free node memory */

    return *ppn;    /* return pointer to new node at address of removed node */
}

( примечание: вышеизложенное использует и указатель на узел, и адрес текущего указателя для итерации и замены узла по адресу, который должен быть удален, следующим узлом в список см. Линус о понимании указателей )

Полу-короткий пример реализации, который проверяет лог c, может быть:

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

#ifndef NNODES
#define NNODES 10
#endif

typedef struct node_t {     /* list node */
    int data;
    struct node_t *prev, *next;
} node_t;

/** create new node initialize all members */
node_t *createnode (int v)
{
    node_t *node = malloc (sizeof *node);   /* allocate node */
    if (!node) {                            /* validate allocation */
        perror ("malloc-node");
        return NULL;
    }
    node->data = v;                         /* initialize members values */
    node->prev = node->next = NULL;

    return node;    /* return new node */
}

/** add node at end of list */
node_t *add (node_t **l, int v)
{
    node_t *node = createnode (v);      /* allocate node */
    if (!node)                          /* validate allocation */
        return NULL;

    if (!*l) {                          /* 1st node is self-referencing */
        *l = node;                      /* set head to node */
        (*l)->prev = (*l)->next = node; /* set prev & next to node */
    }
    else {                              /* otherwise - insert as new tail */
        node->prev = (*l)->prev;        /* node->prev is list->prev */
        node->next = *l;                /* node->next is head */
        (*l)->prev->next = node;        /* tail-next is node */
        (*l)->prev = node;              /* head->prev is node */
    }

    return node;    /* return new node */
}

/** delete kth node in doubly-linked circular list from node *l
 *  returns pointer to new node at address of deleted node or NULL if
 *  list now empty.
 */
node_t *delkthnode (node_t **l, size_t kth)
{
    node_t  **ppn = l,      /* pointer to pointer to node */
            *pn = *l;       /* pointer to node */

    size_t n = kth ? kth - 1 : 1;   /* set no. to advance (1-based index) */

    if (pn == pn->next) {           /* last node left in list? */
        free (pn);                  /* free node */
        return *ppn = NULL;         /* set address for node to NULL */
    }

    while (n--) {                   /* loop to kth node */
        ppn = &pn->next;            /* update current address to next */
        pn = pn->next;              /* update current node to next */
    }

    *ppn = pn->next;                /* set current address to next node */
    (*ppn)->prev = pn->prev;        /* set current->prev to next->prev */
    if (pn->next == *l)             /* deleting tail node? */
        (*ppn)->prev->next = *l;    /* set new end->next to head */
    if (pn == *l)                   /* if current node is head */
        *l = *ppn;                  /* update list adddress to current */

    free (pn);      /* free node memory */

    return *ppn;    /* return pointer to new node at address of removed node */
}

void dellist (node_t *l)
{
    if (!l) {
        puts ("list-empty");
        return;
    }

    node_t *iter = l->next;

    do {
        node_t *victim = iter;
        iter = iter->next;
        free (victim);
    } while (iter != l);
    free (l);
}

void prnlist_fwd (node_t *l)
{
    node_t *iter = l;

    if (!l) {
        puts ("list-empty");
        return;
    }

    do {
        printf (" %d", iter->data);
        iter = iter->next;
    } while (iter != l);

    putchar ('\n');
}

void prnlist_rev (node_t *l)
{
    if (!l) {
        puts ("list-empty");
        return;
    }

    node_t *iter = l->prev;

    do {
        printf (" %d", iter->data);
        iter = iter->prev;
    } while (iter != l->prev);

    putchar ('\n');
}

int main (void) {

    node_t  *list = NULL;
    int kth = 2;

    for (int i = 0; i < NNODES; i++)    /* loop NNODES times */
        add (&list, i+1);               /* add node with i+1 value to list */

    prnlist_fwd (list);                 /* print original list fwd/rev */
    prnlist_rev (list);
    putchar ('\n');

    while (delkthnode (&list, kth++)) {
        prnlist_fwd (list);             /* print updated list fwd/rev */
        prnlist_rev (list);
        putchar ('\n');
    }

    dellist (list);
}

Где над вами просто создайте список с целочисленными значениями 1-10 для значений узлов, а затем вызовите:

    int kth = 2;
    ...
    while (delkthnode (&list, kth++)) {
        prnlist_fwd (list);             /* print updated list fwd/rev */
        prnlist_rev (list);
        putchar ('\n');
    }

, который действует как обертка для постоянного удаления всех остальных узлов в списке до тех пор, пока список не станет пустым (что является цель иметь фу nction возвращает указатель на узел, который остается по адресу, где был удален узел, или NULL, если список теперь пуст)

Пример использования / Вывод

Печать исходного списка (как прямого, так и обратного), а затем печать обновленного списка (прямого и обратного) до тех пор, пока все вторые узлы в списке не будут удалены, приведет к:

$ ./bin/lldcir_del_kthnode
 1 2 3 4 5 6 7 8 9 10
 10 9 8 7 6 5 4 3 2 1

 1 3 4 5 6 7 8 9 10
 10 9 8 7 6 5 4 3 1

 1 3 5 6 7 8 9 10
 10 9 8 7 6 5 3 1

 1 3 5 7 8 9 10
 10 9 8 7 5 3 1

 1 3 5 7 9 10
 10 9 7 5 3 1

 1 3 5 7 9
 9 7 5 3 1

 1 5 7 9
 9 7 5 1

 1 5 7
 7 5 1

 1 5
 5 1

 1
 1

list-empty

Или в вашем Точный случай со списком, как 1, 2, 3, 4, 5:

$ ./bin/lldcir_del_kthnode
 1 2 3 4 5
 5 4 3 2 1

 1 3 4 5
 5 4 3 1

 1 3 5
 5 3 1

 3 5
 5 3

 5
 5

list-empty

Надеюсь, это то, что вы хотели. Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы. (примечание: вам, возможно, придется скорректировать тесты и добавить дополнительные проверки, чтобы отследить все угловые случаи - это вам остается)

...