小工具知识网

当前位置: 首页 > 行业知识 > 数据结构:队列(C语言实现)&一些个人总结

行业知识

数据结构:队列(C语言实现)&一些个人总结

2026-10-29 04:14:34 来源:互联网转载

今天���于是把队列的基本操作学完了,队列和栈其实大同小异,队列遵循的是先进先出原则,而栈遵循的是先进后出原则,形象的来说,栈是一个杯子,而队列是一个水管,谁先进队自然就会先流出来。

1.队列创建以及初始化

这次还是用链表来实现,与栈不同的是,由于队列是一个两头都开口的结构,入队和出队分别在两个不同的方向进行,因此不仅需要头指针(head)还需要一个尾指针(tail)。

typedef struct NODE{int data;struct NODE*next;}NODE,*LINK_NODE;//创建节点typedef struct QUENE{   LINK_NODE head,tail;//队列首尾   int size;//队列大小}QUENE;

然后是初始化了,但是我自我觉得对节点的初始化好像一直没有什么用......

LINK_NODE initNODE(){    LINK_NODE newnode=(LINK_NODE)malloc(sizeof(NODE));    newnode->data=0;    newnode->next=NULL;    return newnode;}//节点初始化void initquene(QUENE* quene){    quene->head=NULL;    quene->size=0;//长度没有    quene->tail=NULL;//头尾指针为空}//队列的初始化

2.队列的插入(入队)以及删除(出队)

其实对于链表,栈,队列而言,感觉这两个操作都是最核心的操作,因为这涉及一些指针的转换,顺序的问题,自我感觉在实现的时候有点绕。

1.入队,操作队尾

入队是这样的,在队尾不断添加新节点,看起来比较简单但是在实现的时候,我想分享一下我自己的问题。

我对tail指针有一些误解,我一开始以为tail是一个节点中的next指针,因为我是从第一个节点的插入开始想的,我在想,head是新节点的首地址,那么tail不就是新节点中的next指针吗?

但是实际上,tail应该是队列中最后一个节点的地址,并非最后一个节点的next指针。针对第一个节点而言,第一个节点和最后一个节点是一个,那head和tail就重叠了,这样才是正确的操作。(见下图)

所以这样之后后面的操作就很顺畅了,只需要每次新添加一个节点,第一步,先连接,把新节点和原来的队尾连接;第二步,再更新,把队尾更新为现在新节点的地址即可。请看代码。

void pushquene(QUENE* quene,int element){      LINK_NODE newnode=(LINK_NODE)malloc(sizeof(NODE));//新节点      newnode->data=element;      if(quene->size==0){      //对插入第一个节点单独讨论        quene->head=newnode;        quene->tail=newnode;   //第一个节点就是最后一个节点,所以首尾指针一致      }      else{    quene->tail->next=newnode; //后面节点的插入,先连接    quene->tail=newnode;       //再更新      }      quene->size++;       //变更长度}
2.出队,操作队首

出队的时候是先入先出,因此都是从队首出去的,这里也有几个小细节。

第一,首先要判断队列是不是已经空了,如果size=0,那么就直接返回错误。当然,我们在实操的时候不会这样,因为最后一个元素出队之后,次数就会结束,比如5个元素,那么只操作5次,就不会出现长度为零的情况(最后一次长度是为一的,操作完之后才会为零)。

第二,在指针的变化中,针对使用新变量,我总结了一下:要被释放的节点,第一是要用新变量存储其中的数据(释放了之后就用不了了,所以先存起来,返回的时候用新变量),第二是要用新指针存储该节点的后继(next指针),道理也是一样的,释放了之后就不能用了。

然后,操作的顺序问题,我的总结:先不要更改head指针(因为这个head是要被释放的),因此先直接释放原有的head节点,再用已经存在新指针里面的head->next指针给已经被释放的head赋值,这样才是正确的更新操作。

第三,当最后一个元素出队的时候,head指针和tail指针再一次重叠(是不是和之前入队的时候似曾相识?),那么由于head指针是要被更换成为head->next的,而此时head->next指针就是指向NULL的,因此相应的,我们也要把tail指针置为空,否则,tail指针还是会指向这个已经被释放的节点,这是没有意义的。

下面先看一下图,再上代码。

对了,这里一直想说一下这个关系(橙色部分),感觉还是挺重要的。

代码部分:

int popquene(QUENE* quene){   if (quene->size == 0) {          printf("Queue is empty.\n");  //队列为空        return -1;       }      LINK_NODE cur=quene->head->next;//新指针存储    int res=quene->head->data;//新变量存储数据    free(quene->head);    quene->head=cur;      //更新头节点    if(quene->head==NULL){        quene->tail=NULL;   //针对最后一个节点的操作    }    quene->size--;       //更新长度    return res;}

3.查找元素

这就很简单了,但是我还是出了一些问题,第一次写函数的时候灵光乍现竟然用了popquene(出队)函数,然后***循环了。在AI的帮助下我才明白出队会改变队列的内容啊!所以乖乖的用遍历就好了~~~

bool SearchQuene(QUENE* quene, int target) {      LINK_NODE current = quene->head;      while (current != NULL) {          if (current->data == target) {              return true;          }          current = current->next;      }      return false;  }

虽然队列好像很简单,但是好像写的是最长的一次,里面有很多个人的教训经验在里面,希望大家多多支持~~~

上一篇:域名怎么传播

下一篇:在宝塔怎么查看服务器密码?