在C中使用LinkedList创建队列

在C中使用LinkedList创建队列,c,C,因此,我正在阅读一个教科书上的例子,介绍如何用C语言从链表中生成队列,我有点被一段代码的工作原理所困扰 因此,教科书使用的例子是一个队列,它帮助模拟排队等待售票员服务的乘客 他们首先定义队列的实现结构: /* Insert typedef for queue_element_t */ typedef struct queue_node_s { queue_element_t element; struct queue_node_s *restp; }

因此,我正在阅读一个教科书上的例子,介绍如何用C语言从链表中生成队列,我有点被一段代码的工作原理所困扰

因此,教科书使用的例子是一个队列,它帮助模拟排队等待售票员服务的乘客

他们首先定义队列的实现结构:

    /*  Insert typedef for queue_element_t */

typedef struct queue_node_s {
      queue_element_t      element;
      struct queue_node_s *restp;
} queue_node_t;

typedef struct {
      queue_node_t *frontp,
                   *rearp;
      int           size;
} queue_t;
然后,他们继续展示两个功能的实现:

void add_to_q(queue_t *qp, queue_element_t ele);
queue_element_t remove_from_q(queue_t *qp);
第一个功能定义为:

/*
 *  Adds ele at the end of queue accessed through qp
 *  Pre:  queue is not empty
 */
void
add_to_q(queue_t         *qp,  /* input/output - queue   */
         queue_element_t  ele) /* input - element to add */
{
      if (qp->size == 0) {                /* adds to empty queue    */
            qp->rearp = (queue_node_t *)malloc(sizeof (queue_node_t));
            qp->frontp = qp->rearp;
      } else {                            /* adds to non-empty queue    */
            qp->rearp->restp = 
                  (queue_node_t *)malloc(sizeof (queue_node_t));
            qp->rearp = qp->rearp->restp;
      }
      qp->rearp->element = ele;           /* defines newly added node   */
      qp->rearp->restp = NULL;
      ++(qp->size);
}
类似地,从_q中删除_的实现方式如下:

    /*
 *  Removes and frees first node of queue, returning value stored there.
 *  Pre:  queue is not empty
 */
queue_element_t
remove_from_q(queue_t *qp) /* input/output - queue */
{
      queue_node_t    *to_freep;    /* pointer to node removed  */
      queue_element_t  ans;         /* initial queue value which is to  
be returned     */

      to_freep = qp->frontp;        /* saves pointer to node being 
deleted */
      ans = to_freep->element;          /* retrieves value to return    */
      qp->frontp = to_freep->restp; /* deletes first node   */
      free(to_freep);               /* deallocates space    */
      --(qp->size);

      if (qp->size == 0)            /* queue's ONLY node was deleted    */
            qp->rearp = NULL;

      return (ans);
}
当我一个人看的时候,我发现我仍然有点困惑,为什么它是这样工作的?如果我错了,请纠正我:在第一次调用函数add_to_q时,我们假设队列最初是空的,因此队列节点指针frontp和rearp都指向堆中分配的内存中的同一位置。因此,frontp->restp==rearp->restp,这就是为什么允许您写这行
qp->frontp=to_freep->restp
在从_q中删除_?另外,在第二次调用add_to_q时,当您添加第二个元素frontp指向同一个内存位置,但retar移动到一个新位置时

我的后续工作是,一旦队列中有一个元素,如果我们在队列的后面添加一个新成员,下面的代码块如何为我们提供我们期望的队列的正确功能

else {                            /* adds to non-empty queue    */
            qp->rearp->restp = 
                  (queue_node_t *)malloc(sizeof (queue_node_t));
            qp->rearp = qp->rearp->restp;
      }
      qp->rearp->element = ele;           /* defines newly added node   */
      qp->rearp->restp = NULL;
      ++(qp->size);
}
我试着从内存块的角度来描述这一点,但我不知道一旦程序到达行
qp->rearp=qp->rearp->restp,当您写入
qp->rearp->restp=NULL时它也不会将qp->rearp设置为NULL,因为它们(据我所知)应该指向内存中的同一点

任何指导都将不胜感激!!!
谢谢:)

队列是一种先进先出的结构(我想你已经知道了)。此特定代码使用链表实现它。它的基本功能是,每当您将某些数据“排队”时,您就将其添加到链表的后端(尾部)。因此,
rear
在每次调用
add\u to\u q
时都会被修改

我的后续工作是,一旦队列中有一个元素,如果我们在队列的后面添加一个新成员,下面的代码块如何为我们提供我们期望的队列的正确功能

else {                            /* adds to non-empty queue    */
            qp->rearp->restp = 
                  (queue_node_t *)malloc(sizeof (queue_node_t));
            qp->rearp = qp->rearp->restp;
      }
      qp->rearp->element = ele;           /* defines newly added node   */
      qp->rearp->restp = NULL;
      ++(qp->size);
}
qp->rearp
指向最后一个节点(代码的后面)
qp->rearp->restp
是该节点的所谓“下一个”指针
qp->rearp->restp=malloc…
在旧后方的“下一个”位置创建新节点
qp->rearp=qp->rearp->restp
使
qp->rearp
指向新的后方
qp->rearp->restp
使最后一个节点的“下一个”为
NULL


因此,代码基本上在链表的末尾添加新节点,并从前端删除节点(另一种方法应该更有效)。他们之所以使用“rearp”这个词,是因为你应该站在队列的“后方”



这基本上是处理一个链表,同时保留一个“尾部”指针和一个“头部”指针,以提高效率。

我建议用块和指针反复绘制链表。首先,确保您理解一个只使用头和下一个指针的简单链表。然后转到这个维护头部、尾部和尺寸信息的页面。实际上,您的注释听起来像是基本上得到了它,直到您最后一次关于将最后一个元素的下一个指针设置为NULL的注释。(提示:qp->rearp现在是我们的最后一个节点,我们将元素放入其中,并将其“next”指针设置为NULL)

让我们简要概述一下:

队列是一种线性数据结构,其中第一个元素从称为后方的一端插入,现有元素的删除从称为前方的另一端进行

关键点:将元素添加到队列中的过程称为排队(插入),从队列中移除元素的过程称为出列(删除)

现在,我创建了两个设计,让您了解插入和删除的基本概念

1。插入(也是创建)

2。队列中的删除:


我希望您能理解使用链表排队的基本概念,这样您以后就不会感到困惑,可以进一步学习。

使用调试器逐步完成代码,并观察添加/删除项目时所有值的变化。
qp
必须是一个有效指针,指向充分分配的类型
queue\t
,而不是
NULL
(如果没有,我们无法判断)。在第一次添加时,为
qp->frontp
分配
qp->rearp
的地址,
->ele
->restp
分配
NULL
。(基本上有1个元素
frontp
指向
rearp
)添加元素时,每个新节点
qp->rearp->restp
都会被分配,并且分配给
qp->rearp
的地址会将节点添加到列表中。包括MCVE将帮助我们进一步帮助您。我想我明白了。因此,基本上,我可以想象,当程序执行行
qp->rearp->restp=malloc…,
一个新的内存单元被放置在队列中第一个元素的“后面”(即新加入该行的人站在已经等待的人后面),然后该行
qp->rearp=qp->rearp->restp
将qp->rearp移动到内存中的新位置(即队列中最新的人)?为什么您认为将新节点放在队列前面会更有效(“另一种方式会更有效”)?特别是,如果您有si,您如何从队列尾部移除节点并更新尾部以指向前一个节点