3

我一直在努力解决这个问题但是没有成功我有如下的数据结构(这实际上非常复杂,我只是为了讨论而简化了):

typedef struct node{
 struct node* next;
  void* arg;
}node_t;

typedef struct queue{
node_t* head;
node_t* tail;
}queue_t;

addQ(queue_t*ptr , int data)
{
    queue_t* q = ptr;
    node_t * n = malloc(sizeof(*n));

    n->arg = data;
    n->next = NULL;

    if(NULL == q->head){
       q->head = q->tail = n;
       return ;
    }
    q->tail->next = n;
    q->tail = q->tail->next;
}

现在我想删除相同值的节点(我已经尝试了几种方法但没有成功),只需考虑这个序列以供参考:

addQ(q, 12);
addQ(q, 12);
addQ(q,  4);
addQ(q, 12);
addQ(q, 12);
addQ(q, 14);
addQ(q, 12);
addQ(q, 12);

我想删除所有值为 12 的节点。

4

3 回答 3

4

这个解决方案对双指针有点麻烦,但我仍然喜欢它,因为它不需要特殊情况下正在检查哪个节点(第一个与其他节点)。我试图发表足够多的评论来描述正在发生的事情,但即使是我,乍一看仍然很难理解。

伪代码..

Queue * q;
VALUE = 12;

// double pointer so we can treat the queue head and subsequent nodes the same.
//   because they are both pointers to Node.  
// Otherwise you'd have to have code that says if the one you're removing is the 
// first element of the queue, adjust q->head, otherwise adjust node->next.  
// This lets you not special case the deletion.
Node ** node_ptr = &(q->head)

while (*node_ptr != null) {
    if ((**node_ptr).arg == VALUE) {
        // store off the matching node to be freed because otherwise we'd orphan
        // it when we move the thing pointing to it and we'd never be able to free it
        Node * matched_node = *node_ptr;

        // when we find a match, don't move where node_ptr points, just change the value it
        // points to to skip the matched node and point to the one after it (or null)
        *node_ptr = matched_node->next; 
        free(matched_node);
    } else {
        // otherwise, nothing was deleted, so skip over that node to the next one.
        // remember, **node_ptr is a double dereference, so we're at the node
        // now, so then we grab the address of the non-matching node's next value so it can be
        // potentially changed in the next iteration
        node_ptr = &((**node_ptr).next);
    }
}
于 2013-05-13T07:20:10.200 回答
0

假设您已经有一个函数可以获取和删除队列中的下一个项目,我们称之为它getQ(q),那么您甚至无需知道队列的内部结构就可以实现您的目标,只需使用您已经拥有的操作,例如一些像(这不起作用,因为arg是 a void,但逻辑应该很清楚):

node_t *n;
queue_t *q2 = initialiseQ();
while (n = getQ(q)) {
    if (n->arg != 12) {
        addQ(q2,n);
    }
}
free(q);
q = q2;
于 2013-05-13T06:49:14.967 回答
0

这是一个不使用双指针的内联解决方案。由于要调整的指针从队列结构更改为节点结构,因此它必须区别对待第一个元素和后续元素。

此外,对于后续节点,您必须跟踪尾随节点,因为您必须在删除匹配节点时进行调整。

Queue * q;
VALUE = 12;


// handle the case where the first node matches.
// you have to adjust the q's head pointer
// delete from the head and set a new head node until a non-matching head is found
while (q->head != NULL && q->head->arg == VALUE) {
  Node * matching_node = q->head;
  q->head = q->head->next;
  free(matching_node);
}

// if there is more than one node left, need to check the subsequent nodes
if (q->head != NULL && q->head->next != NULL) {

    Node * node_ptr = q->head->next;
    Node * prev_node_ptr = q->head;

    while (node_ptr != NULL) {
        if (node_ptr->arg == VALUE) {
            Node * matched_node = node_ptr; // don't orphan it before it's freed

            // You don't move the prev_node pointer since that doesn't change when a match
            //   is found.  Only the node_ptr, which skips to the next one. 
            node_ptr = node_ptr->next;
            free(matched_node);            
        } else {
            prev_node_ptr = node_ptr;
            node_ptr = node_ptr->next;
        }
    }
}
于 2013-05-13T07:38:17.120 回答