行业知识
数据结构:队列(C语言实现)&一些个人总结
今天���于是把队列的基本操作学完了,队列和栈其实大同小异,队列遵循的是先进先出原则,而栈遵循的是先进后出原则,形象的来说,栈是一个杯子,而队列是一个水管,谁先进队自然就会先流出来。
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; } 虽然队列好像很简单,但是好像写的是最长的一次,里面有很多个人的教训经验在里面,希望大家多多支持~~~
上一篇:域名怎么传播
下一篇:在宝塔怎么查看服务器密码?