繁体   English   中英

如何获得多次删除循环双向链表节点的函数? (C)

[英]How do I Get This Function to Delete Nodes of Circular Doubly Linked List more than Once? (C)

我必须从链表中删除每个 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

我应该怎么做才能让每行输出删除另一个? 谢谢。

如果我知道您想从双向链接的循环链表中删除第 k节点,则如您的问题所示,例如,如果列表包含:

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

使用k=2 ,您需要删除2, 4, 6, 8, 10, 3, ...直到列表为空。 这有点像一个由两部分组成的问题。 (1) 删除第 k节点,以及 (2) 增加第 k位置,使其现在指向刚删除的节点之后的k节点。 这可以通过多种方式实现。 可能最实用的是实现删除k节点的功能,然后在需要时编写一个包装函数来更新计数器,以便按顺序删除下一个节点。

使用指向列表l第一个节点的指针,以及要删除的k节点,您可以执行类似于以下操作:

/** 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 */
}

注意:上面同时使用指向节点的指针和当前指针的地址来迭代并用列表中的下一个节点替换要删除的地址处的节点,请参阅理解指针的Linus

测试逻辑的半短示例实现可能是:

#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');
    }

它充当连续删除列表中所有其他节点的包装器,直到列表为空(这是让函数返回一个指向节点的指针,该指针仍保留在删除节点的地址处,如果列表为空,则返回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

希望这就是你的意图。 仔细检查一下,如果您还有其他问题,请告诉我。 (注意:您可能需要调整测试并添加额外的验证以捕获所有极端情况——这由您决定)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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