赞
踩
目录
中午在食堂打饭,真是一个令人头疼的事情,去食堂的路上也总是步伐匆匆,为什么啊,这还用说,迟一点去,你就会知道什么叫做人山人海了,在食堂排队的时候,相比较学生来说,打饭阿姨毕竟是少数,在每个窗口都有人的时候,不免我们就得等待,直到前面的一个学生打完饭离开,后面排队的人才可以继续向前走,直到轮到自己,别提多费劲了,但是秩序和规则却是我们每个人都应该遵守的,也只能抱怨自己来的迟了
一个“先进先出”的数据结构。队列是一种只允许在一段进行删除操作,在另一端进行插入操作的线性表。
例子补充:用电脑的时候,有时候机器会处于疑似死机的状态, 鼠标点什么似乎都没有用,双击任何快捷方式都不动,就当你失去耐心,打算reset的时候,突然它就像酒醒了一样,把你刚才点击的所有操作全部按照顺序执行了一遍,这其实是因为操作系统中的多个程序隐需要通过一个通道输出,而按照先后次序排队等待造成的 ——《大话数据结构》
Enqueue(入队):是在队尾进行插入操作。
Dequeue(出队):是在队首进行删除操作。
链式队列是队列的实现方式之一。链式队列内部使用带头结点的单向链表来实现。它的好处的是灵活,队列容量理论上是不受限制的。
我们使用链表的首结点来表示队列的队头,链表的尾结点代表队尾。
当队列为空时,队尾元素指针指向头结点headNode。
使用顺序结构(数组)来实现队列,将队头存放在数组开头的位置, 但是我们会遇到一个问题:如果执行出队后,array[0]就空出来了,但是又不能被利用,因为队列只能在队尾追加元素,这样就会造成“假满”的情况。
我们可以将一个固定长度的数组在逻辑上臆造成一个环形。这样,队头元素存放的位置不是固定的,他会随着 出队 动态改变,而队尾元素也会随着入队 动态改变。可以将front和rear变量看做是2个小孩子围着一颗树你追我赶一样,只要他们在追赶过程中没有相遇,队列就不是满的。 这样就会让每个数组空间都能得到利用。
双端队列是一种两端都可以 删除元素和追加元素的线性结构。双端队列比普通的队列更加灵活。
如果我们在使用时,自己限制自己的操作行为,则可以将双端队列当成其它的数据结构来使用。
如果我们对一个双端队列只调用他的removeFirst() 和 addLast() ,那么就是当做一个队列使用。
如果我们对一个双端队列只调用他的addLast() 和 removeLast() 【或者只调用addFirst和removeFirst()】,那么就是当做一个栈使用。
注:双端队列可以用双向链表实现。
注:若对循环队列不懂可以看我之前发的循环队列的插入与删除
- #include<stdio.h>
- #include<stdlib.h>
-
- //链表队列的结构体(其实就是一个链表)
- typedef struct Queue
- {
- int data;
- struct Queue* next;
- }Queue ;
-
- Queue * InitQueue()
- {
- Queue *Q=(Queue *)malloc(sizeof(Queue));
- Q->data=0; //队尾元素为0
- Q->next=NULL;
- return Q;
- }
- //进队
- void enQueue(Queue *Q,int data)
- {
- Queue *q=Q; //创建一个结点,并指向Q的头结点
- Queue *node=(Queue *)malloc(sizeof(Queue )); //创建一个新的结点
- node->data=data;
- for(int i=0;i<Q->data;i++) //遍历队列,到尾结点
- {
- q=q->next;
- }
- node->next=q->next;
- q->next=node;
- //上面两步与链表的插入操作原理相同
- Q->data++;
- }
- //判断是否为空
- int isEmpty(Queue *Q)
- {
- if(Q->data==0||Q->next==NULL) //队列为空
- {
- return 0;
- }
- else
- {
- return 1;
- }
-
- }
- //出队
- int deQueue(Queue *Q)
- {
- if(isEmpty(Q))
- {
- Queue *p=Q->next;
- int data=p->data;
- Q->next=p->next;
- free(p);
- //以上步骤与链表的删除操作原理相同
- return data;
- }
- else
- {
- printf("队列为空\n");
- return -1;
- }
- }
- //答应队列
- void printQueue(Queue *Q)
- {
- Queue *p=Q->next;
- for(int i=0;p;i++)
- {
- printf("%d->",p->data);
- p=p->next;
- }
- printf("NULL");
- }
- //主函数
- int main()
- {
- Queue *Q=InitQueue();
- enQueue(Q,1);
- enQueue(Q,2);
- enQueue(Q,4);
- enQueue(Q,6);
- printQueue(Q);
- int num=deQueue(Q);
- printf("\n删除元素为:%d\n",num);
- printQueue(Q);
- return 0;
- }
注:给读者的一点建议:大家可以学习一下我的代码的格式。因为如果一个代码敲出来不美观,乱七八糟的话,会导致给别人看代码不太方便理解以及自己去Debug的时候,不容易发现自己的bug出现在哪。
注:由于链表队列比较简单,所以并没有比较重要的知识点,只需读者掌握基本操作即可。所以我主要写一下循环链表的。
在循环队列中,画图易得知当循环队列为空时,队首指针(front)和队尾指针(rear)是指向同一个结点的。但又仔细的想想的,当循环队列满时,神奇的发现队首和队尾指针也是指向同一个结点的。所以,就引发了我们该如何判断一个循环队列是空还是满呢?
针对这个问题,我给出三个解决方案:
前两个相信读者的水平是可以自己编码实现的。所以,这里我重点讲解一下C方案:
根据C方案,我们可以总结出以下的等式:
(rear+1) % MaxSize == front
front == rear
(rear- front + maxSize) % MaxSize
rear = (rear + 1) % maxSize
front = (front + 1) % maxSize
如果文章中有什么不足,或者错误的地方,欢迎大家留言分享想法,感谢朋友们的支持!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。