【问题标题】:trouble updating tail pointer in queue adt using singly linked list使用单链表更新队列 adt 中的尾指针时遇到问题
【发布时间】:2012-10-07 19:02:45
【问题描述】:

我正在尝试制作一个基于我已经制作的链表库的队列库。具体来说,在将新节点添加到链表后,我无法更新队列结构中的尾指针。

链表结构:

struct listNode {
    int nodeLength;
    int nodeValue;
    struct listNode *next;
};

typedef struct listNode node;

队列结构:

struct QueueRecord {
    node *list;
    node *front;
    node *back;
    int maxLen;
};
typedef struct QueueRecord queue;

这是我在队列库中的添加函数

void add(queue currentQueue, int data){
    addTail(currentQueue.list, data, data+5);
    currentQueue.back = currentQueue.back->next;

}

以及链表库中的addTail函数

void addTail (node *head, int value, int length) {
    node *current = head;
    node *newNode = (struct listNode *)malloc(sizeof(node));
    newNode = initNode(value, length);

    while (current->next != NULL)   
        current = current->next;

    newNode->next = NULL;
    current->next = newNode;
}

所以我的问题是尾指针没有设置到列表中的最后一个节点。它与头指针保持在同一位置。我已经研究了好几个小时,想看看我是不是遗漏了一些小东西,但我找不到。如果需要更多代码或解释来理解我的问题,我可以提供。

如何创建队列:

queue createQueue(int maxLen){
    queue newQueue;
    newQueue.list = createList();
    newQueue.front = newQueue.list;
    newQueue.back = newQueue.list;
    newQueue.maxLen = maxLen;
    return newQueue;
}    

node *createList (){
    node *head = NULL;
    head = (struct listNode *)malloc(sizeof(node));
    head->next = NULL;
    return head;
}

node *initNode (int value, int length){
    node *newNode = NULL;
    newNode = (struct listNode *)malloc(sizeof(node));
    newNode->nodeValue = value;
    newNode->nodeLength = length;
    newNode->next = NULL;
    return newNode;
}

【问题讨论】:

  • 在我的答案中添加了工作示例。

标签: c linked-list queue


【解决方案1】:
void add(queue currentQueue, int data){

您正在将queue 结构的副本 传递给add,因此只有副本的成员被更改。您需要将 queue* 传递给函数才能更改 queue 本身的成员。

void add(queue *currentQueue, int data){
    if (currentQueue == NULL) {
        exit(EXIT_FAILURE);
    }
    addTail(currentQueue->list, data, data+5);
    currentQueue->back = currentQueue->back->next;
}

并将其称为add(&your_queue);

在你的addTail函数中,你应该检查head是否也是NULL

还有

node *newNode = (struct listNode *)malloc(sizeof(node));
newNode = initNode(value, length);

addTail,你有一个严重的问题。通过分配newNode = initNode(value, length);,您将失去对刚刚malloced 内存的引用。

如果initNodemallocs 是一个新的内存块,它“只是”一个内存泄漏,那么你应该删除addTail 中的malloc

否则,我担心initNode 返回一个局部变量的地址,à la

node * initNode(int val, int len) {
    node new;
    new.nodeValue = val;
    new.nodeLength = len;
    new.next = NULL;
    return &new;
}

如果initNode 看起来与此相似,那将导致问题,因为一旦函数返回,地址就会变得无效。但是,如果 initNode 看起来像那样,您的编译器应该会警告您。

无论如何,没有看到initNode的代码,我无法诊断原因。

但如果你将addTail 更改为

void addTail (node *head, int value, int length) {
    if (head == NULL) { // violation of contract, die loud
        exit(EXIT_FAILURE);
    }
    node *current = head;
    node *newNode = malloc(sizeof(node));
    if (newNode == NULL) {
        exit(EXIT_FAILURE); // or handle gracefully if possible
    }
    newNode->nodeValue = value;
    newNode->nodeLength = length;
    newNode->next = NULL;

    while (current->next != NULL)   
        current = current->next;

    current->next = newNode;
}

它应该可以工作。

但是,由于您有指向列表中第一个和最后一个节点的指针,因此使用back 指针附加一个新节点会更有效,

void add(queue *currentQueue, int data){
    node *newNode = malloc(sizeof *newNode);
    if (newNode == NULL) {
        exit(EXIT_FAILURE); // or handle gracefully if possible
    }
    newNode->nodeValue = data;
    newNode->nodeLength = data+5;
    newNode->next = NULL;
    currentQueue->back->next = newNode;
    currentQueue->back = newNode;
}

因为您无需遍历整个列表即可找到结尾。


一个简单的示例程序

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

struct listNode {
    int nodeLength;
    int nodeValue;
    struct listNode *next;
};

typedef struct listNode node;

struct QueueRecord {
    node *list;
    node *front;
    node *back;
    int maxLen;
};
typedef struct QueueRecord queue;

node *createList (){
    node *head = NULL;
    head = (struct listNode *)malloc(sizeof(node));
    head->next = NULL;
    return head;
}

void addTail (node *head, int value, int length) {
    if (head == NULL) { // violation of contract, die loud
        exit(EXIT_FAILURE);
    }
    node *current = head;
    node *newNode = malloc(sizeof(node));
    if (newNode == NULL) {
        exit(EXIT_FAILURE); // or handle gracefully if possible
    }
    newNode->nodeValue = value;
    newNode->nodeLength = length;
    newNode->next = NULL;

    while (current->next != NULL)   
        current = current->next;

    current->next = newNode;
}

queue createQueue(int maxLen){
    queue newQueue;
    newQueue.list = createList();
    newQueue.front = newQueue.list;
    newQueue.back = newQueue.list;
    newQueue.maxLen = maxLen;
    return newQueue;
}

void add(queue *currentQueue, int data){
    if (currentQueue == NULL) {
        exit(EXIT_FAILURE);
    }
    addTail(currentQueue->list, data, data+5);
    currentQueue->back = currentQueue->back->next;
}

int main(void) {
    queue myQ = createQueue(10);
    for(int i = 1; i < 6; ++i) {
        add(&myQ, i);
        printf("list:  %p\nfront: %p\nback:  %p\n",
                (void*)myQ.list, (void*)myQ.front, (void*)myQ.back);
    }
    node *curr = myQ.front->next;
    while(curr) {
        printf("Node %d %d, Back %d %d\n", curr->nodeValue,
                 curr->nodeLength, myQ.back->nodeValue, myQ.back->nodeLength);
        curr = curr->next;
    }
    while(myQ.list) {
        myQ.front = myQ.front->next;
        free(myQ.list);
        myQ.list = myQ.front;
    }
    return 0;
}

按预期工作,也可以使用替代 add 实现。

【讨论】:

  • 难道不是这样,在标准纯 c 中,所有结构都是通过引用传递的吗?
  • 不,一切都是按值传递的,但是对于数组,传递的是指向第一个元素的指针。
  • 确定吗?所以当我有 sizeof(queue) := 5000 并且我调用 fun(queue) 时,5000 字节被复制(当你写)到堆栈上?我们在 C 中,而不是在面向对象的环境中,其中“副本”放在堆栈上
  • 是的,就是这样。出于这个原因,你应该通过指针传递大的东西。
  • 好的,我之前确实是这样设置的,这给我带来了问题,但解释对我有帮助,非常感谢。现在我不确定我的尾巴指向什么,因为当我从那里打印列表时,它应该只打印最后一个节点时什么也不打印。
【解决方案2】:

我认为你从来没有初始化过,所以 back->next 是一些随机指针?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 2018-04-30
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多