简体   繁体   English

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

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

I have to delete every k node from a linked list.我必须从链表中删除每个 k 节点。 When this function is called with say, k = 2, it deletes the second node, but doesn't delete any more after that.当以 k = 2 调用此函数时,它会删除第二个节点,但之后不再删除。 Here is the function:这是函数:

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--;
    }
}

When called被调用时

remove(front, n, k);

n = 5, k = 2, I get this output: 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

What should I do to get is so that another is deleted each line of output?我应该怎么做才能让每行输出删除另一个? Thanks.谢谢。

If I understand you want to delete the k th node from a doubly-linked circular linked-list, then as shown in you question, for example if the list contained:如果我知道您想从双向链接的循环链表中删除第 k节点,则如您的问题所示,例如,如果列表包含:

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

With k=2 , you would want to delete 2, 4, 6, 8, 10, 3, ... until the list was empty.使用k=2 ,您需要删除2, 4, 6, 8, 10, 3, ...直到列表为空。 It is somewhat of a 2-part problem.这有点像一个由两部分组成的问题。 (1) delete the k th node, and (2) increment the k th position so it is now points to the k th node after the one you just deleted. (1) 删除第 k节点,以及 (2) 增加第 k位置,使其现在指向刚删除的节点之后的k节点。 That can be implemented in several ways.这可以通过多种方式实现。 Probably the most pragmatic is to implement the delete k th node function, and then write a wrapper function if needed to update the counter so it will delete the next node in sequence.可能最实用的是实现删除k节点的功能,然后在需要时编写一个包装函数来更新计数器,以便按顺序删除下一个节点。

With a pointer-to-pointer to the 1 st node in list l , and the k th node being the one to delete, you could do something similar to:使用指向列表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 */
}

( note: the above uses both a pointer to the node and the address for the current pointer to iterate and replace the node at the address to be deleted with the next node in the list, see Linus on Understand Pointers ) 注意:上面同时使用指向节点的指针和当前指针的地址来迭代并用列表中的下一个节点替换要删除的地址处的节点,请参阅理解指针的Linus

A semi-short example implementation would that tests the logic could be:测试逻辑的半短示例实现可能是:

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

Where above you just build the list with integer values 1-10 for the node values and then call:在上面的地方,您只需为节点值构建具有整数值1-10的列表,然后调用:

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

which acts as the wrapper for continually deleting every other node in the list until the list is empty (which is the purpose of having the function return a pointer to the node that remains at the address where the node was deleted, or NULL if the list is now empty)它充当连续删除列表中所有其他节点的包装器,直到列表为空(这是让函数返回一个指向节点的指针,该指针仍保留在删除节点的地址处,如果列表为空,则返回NULL现在是空的)

Example Use/Output示例使用/输出

Printing the original list (both forward and reverse) and then printing the updated list (both forward and reverse) until the all second nodes in the list have been deleted would result in:打印原始列表(正向和反向),然后打印更新的列表(正向和反向),直到列表中的所有第二个节点都被删除将导致:

$ ./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

Or in your exact case with the list as 1, 2, 3, 4, 5 :或者在您的确切情况下,列表为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

Hopefully this is what you intended.希望这就是你的意图。 Look things over and let me know if you have further questions.仔细检查一下,如果您还有其他问题,请告诉我。 (note: you may have to adjust the tests and add additional validations to catch all corner cases -- this is left to you) (注意:您可能需要调整测试并添加额外的验证以捕获所有极端情况——这由您决定)

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

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