【问题标题】:C, How to Remove Element From Queue?C、如何从队列中删除元素?
【发布时间】:2021-08-18 06:52:55
【问题描述】:

更新:我们相信在这两种解决方案中都发现了一些错误,也邀请您分享您的想法:)

我正在尝试实现我自己的数据结构,它将列表与 C 中的队列相结合。

我的数据结构有 2 个指针,front 指向队列中最旧的成员,而后部指向新添加的成员,每个成员都指向 在它之后插入的那个

例如,如果我插入 1 然后 2 然后 3,我将有:

NULL <-3 <- 2 <- 1 // 1 is front and 3 is rear.

现在我想支持从这个 DS 中删除元素,所以我开始实施它并发现了数十种边缘情况,例如:

  1. 如果成员是前端,则将前端更改为 DS 并释放成员,但如果前端为空,则将后端也更改为空,否则其他代码将无法按预期工作。

  2. 如果成员处于中间版本,则返回上一个成员并更新其下一个成员但这似乎真的很难

  3. rear 成员几乎相同,只是我们现在需要更新后部,只需将指向元素的指针更改为右侧(NULL 在其左侧)

我应该怎么做这样的事情?

几天来我已经有了几十个想法和实现,但都失败了,或者我做了一些非常糟糕的事情,使运行时复杂度更高,或者我写了 170 行存在矛盾并留下未完成条件的行(通过使用 2 个指针)。

请帮我实现这个?

struct queue_node
{
    int key;
    struct queue_node *next;
};

struct queue
{
    int queue_size;
    struct queue_node *front, *rear;
};

int requeue(struct queue *q, int val)
{
    struct queue_node *tmp = q->front;
    while (tmp!=NULL)
    {
        if (tmp->key==val)
        {
            if (tmp==q->front)
            {
                q->front=tmp->next;
                if (q->front == NULL)
                {
                    q->rear = NULL;
                }
                free(tmp);
            }else if (tmp == q->rear)
            {

            }
            return 0; // found
        }
        tmp=tmp->next;
    }
    return -1; // not found
}

【问题讨论】:

    标签: c list algorithm data-structures queue


    【解决方案1】:

    函数可以通过以下方式定义

    int requeue( struct queue *q, int val )
    {
        struct queue_node **current = &q->front;
        struct queue_node *prev = NULL;
    
        while ( *current && ( *current )->key != val )
        { 
            prev = *current;
            current = &( *current )->next;
        }
    
        int success = *current == NULL ? -1 : 0;
    
        if ( success == 0 )
        {
            struct queue_node *tmp = *current;
            *current = ( *current )->next;
            free( tmp );
            --q->queue_size;            
    
            if ( *current == NULL ) q->rear = prev;
        }
    
        return success;
    }
    

    这是一个演示程序。

    #include <stdio.h>
    #include <stdlib.h>
    
    struct queue_node
    {
        int key;
        struct queue_node *next;
    };
    
    struct queue
    {
        int queue_size;
        struct queue_node *front, *rear;
    };
    
    int requeue( struct queue *q, int val )
    {
        struct queue_node **current = &q->front;
        struct queue_node *prev = NULL;
    
        while ( *current && ( *current )->key != val )
        { 
            prev = *current;
            current = &( *current )->next;
        }
    
        int success = *current == NULL ? -1 : 0;
    
        if ( success == 0 )
        {
            struct queue_node *tmp = *current;
            *current = ( *current )->next;
            free( tmp );
            --q->queue_size;            
    
            if ( *current == NULL ) q->rear = prev;
        }
    
        return success;
    }
    
    
    int push( struct queue *q, int key )
    {
        struct queue_node *node = malloc( sizeof( struct queue_node ) );
        int success = node != NULL;
        
        if ( success )
        {
            node->key = key;
            node->next = NULL;
            
            if ( q->rear == NULL )
            {
                q->front = q->rear = node;
            }
            else
            {
                q->rear = q->rear->next = node;
            }
    
            ++q->queue_size;            
        }
        
        return success;
    }
    
    void display( const struct queue *q )
    {
        for ( struct queue_node *current = q->front; current; current = current->next )
        {
            printf( "%d -> ", current->key );
        }
        
        puts( "null" );
    }
    
    int main(void) 
    {
        struct queue q = { .front = NULL, .rear = NULL };
        
        push( &q, 1 );
        push( &q, 2 );
        push( &q, 3 );
        push( &q, 4 );
        
        display( &q );
        
        requeue( &q, 4 );
    
        display( &q );
    
        push( &q, 4 );
    
        display( &q );
    
        requeue( &q, 1 );
    
        display( &q );
    
        requeue( &q, 3 );
    
        display( &q );
    
        requeue( &q, 4 );
    
        display( &q );
    
        requeue( &q, 2 );
    
        display( &q );
    
        push( &q, 1 );
        push( &q, 2 );
        push( &q, 3 );
        push( &q, 4 );
        
        display( &q );
        
        return 0;
    }
    

    程序输出是

    1 -> 2 -> 3 -> 4 -> null
    1 -> 2 -> 3 -> null
    1 -> 2 -> 3 -> 4 -> null
    2 -> 3 -> 4 -> null
    2 -> 4 -> null
    2 -> null
    null
    1 -> 2 -> 3 -> 4 -> null
    

    如果为了测试添加一个函数printf的调用到函数requeue内的这段代码sn-p

    if ( success == 0 )
    {
        struct queue_node *tmp = *current;
        *current = ( *current )->next;
        printf( "tmp->key == %d, tmp == %p\n", tmp->key, ( void * )tmp );
        free( tmp );
        --q->queue_size;            
    
        if ( *current == NULL ) q->rear = prev;
    }
    

    那么演示程序的输出可以是这样的

    1 -> 2 -> 3 -> 4 -> null
    tmp->key == 4, tmp == 0x55b55f9e02c0
    1 -> 2 -> 3 -> null
    1 -> 2 -> 3 -> 4 -> null
    tmp->key == 1, tmp == 0x55b55f9e0260
    2 -> 3 -> 4 -> null
    tmp->key == 3, tmp == 0x55b55f9e02a0
    2 -> 4 -> null
    tmp->key == 4, tmp == 0x55b55f9e02c0
    2 -> null
    tmp->key == 2, tmp == 0x55b55f9e0280
    null
    1 -> 2 -> 3 -> 4 -> null
    

    【讨论】:

    • 谢谢,但它有一些错误,例如您的代码中没有更新后部
    • @lord97 这个语句 if ( *current == NULL ) q->rear = prev;更新后方。
    • @lord97 函数没有bug。
    • @lord97 看我的演示程序 指针前端更新了。:)
    • 这是一个错误:"&( *current )->next" 它可能是 NULL 并且您正在取消引用它
    【解决方案2】:
    typedef struct queue_node
    {
        int key;
        struct queue_node *next;
    }node;
    
    typedef struct 
    {
        size_t size;
        node *head;
        node *tail;
    }queue;
    
    node *append(queue *q, int key)
    {
        node *n = malloc(sizeof(*n));
        node *c = q -> head;
        if(n)
        {
            if(!q -> head) q -> head = n;
            else
            {
                while(c -> next) c = c -> next;
                c -> next = n;
            }
            n -> key = key;
            n -> next = NULL;
            q -> size++;
            q -> tail = n;
        }
        return n;
    }
    
    int removenode(queue *q, int key)
    {
        node *n = q -> head, *p = q -> head;
        int result = 0;
        while(n)
        {
            if(n -> key == key)
            {
                if(n == p)
                {
                    q -> head = n -> next;
                    if(!n -> next) q -> tail = n;
                }
                else
                {
                    p -> next = n -> next;                
                    if(!p -> next) q -> tail = p;
                } 
                free(n);
                q -> size--;
                result = 1;
                break;
            }
            if(p != n) p = p -> next;
            n = n -> next;
        }
        return result;
    }
    
    void printqueue(queue *q)
    {
        node *n = q -> head;
        printf("The queue:\n");
        while(n)
        {
            printf("Node key = %d\n", n -> key);
            n = n -> next;
        }
        printf("--------------\n");
        if(q -> head) printf("Head key: %d, Tail key: %d, Queue size: %zu\n -------------\n\n", q -> head -> key, q -> tail -> key, q -> size);
        else printf("Queue empty\n------------\n\n");
    }
    
    int main(void)
    {
        queue q = {0,};
        append(&q,1);
        append(&q,2);
        append(&q,3);
        append(&q,4);
        printqueue(&q);
        removenode(&q,3);
        printqueue(&q);
        removenode(&q,1);
        printqueue(&q);
        removenode(&q,4);
        printqueue(&q);
        removenode(&q,2);
        printqueue(&q);
    
    }
    

    结果:

    The queue:
    Node key = 1
    Node key = 2
    Node key = 3
    Node key = 4
    --------------
    Head key: 1, Tail key: 4, Queue size: 4
     -------------
    
    The queue:
    Node key = 1
    Node key = 2
    Node key = 4
    --------------
    Head key: 1, Tail key: 4, Queue size: 3
     -------------
    
    The queue:
    Node key = 2
    Node key = 4
    --------------
    Head key: 2, Tail key: 4, Queue size: 2
     -------------
    
    The queue:
    Node key = 2
    --------------
    Head key: 2, Tail key: 2, Queue size: 1
     -------------
    
    The queue:
    --------------
    Queue empty
    ------------
    

    Program demo

    【讨论】:

    • 嗨,我会看看你的代码,你能描述一下几秒钟前发生的变化
    • 也发现了一个bug,听起来这个问题真的太难了:) 如果它是空的怎么办?你回来了 0
    • 0 表示没有成功。成功是1在代码中已经很清楚了。 Ir 成功返回 1。没有错误。不同的约定
    • 头部是指前面或后面(我猜是前面)
    • 头部总是在前面。这是常见的命名约定:head 和 tail。后方可以理解为非常不同的方式:)避免:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 2014-12-16
    • 1970-01-01
    相关资源
    最近更新 更多