我个人把链表、队列、栈分为一类,然后图、树分为一类。(串不考虑),分类的理由就是每一类有规律可循,即你能通过修改极少数的代码把链表变成队列、栈。(这里我们不考虑其他诸如设计模式等因素),因此本贴在讲完队列之后还会归纳一下这一类数据结构的规律,帮助大家更好理解数据结构
首先需要知道队列是什么,这里给一个定义:队列是只允许一段进行插入操作,一段进行删除操作的线性表,队列是先进先出的结构,允许插入成为队尾,允许删除成为队头
如上图就是一个队列,这里我相信你已经对队列有了一个概念了吧,于是就可以继续看下面了
队列同样存在插入删除操作,由于我们这里讨论的是链式队列的实现,所以不存在队列满的情况
学了这么多章数据结构我相信你能很容易的写出队列的结构了:
struct node{
char data;
struct node *next;
};
struct queue{
struct node *front;
struct node *rear;
};
就如上完成了一个队列的结构定义,然后是创建一个空队列:
struct queue *create_queue(){
struct queue *q=new queue;
q->front=NULL;
q->rear=NULL;
return q;
}
这没什么说的,队头队尾都指向NULL表示空队列。
然后来考虑入队操作:
如上图,我们希望把e节点插入到这个队列里面,其实细心的朋友可能已经发现了这其实就是链表的尾部插入,没错,等一下我会总结一下这些规律 ,这里暂且不谈。
我们能很容易写出下面插入节点到队列的代码(如果不能你就要发反思是否认真学习了):
void en_queue(struct queue *q,char c){
struct node *e=new node;
if(!n){
return;
}
e->data=c;
e->next=NULL;
if(q->rear==NULL){
q->front=q->rear=e;
}else{
q->rear->next=e;
q->rear=e;
}
}
这里稍作解释,后面的if用于判断是否队列为空,如果为空就让队头等于队尾等于新节点,然后新节点为队尾。如果队列不是空就按链表式尾插法进行插入
然后出队:
看着上面的图片如果你能与链表联系起来并想到这就是链表的头插法的逆向,那就说明你真的学懂了
我们只需要把front的next指向a2,然后把,然后删除a1即可完成出队,同样,要想删除a1就应该创建一个临时变量
代码如下:
void out_queue(struct queue *q){
struct node * temp;
if(q->front==NULL)
return;
if(q->front==q->rear)
{
q->front=q->rear=NULL;
return;
}
temp=q->front;
q->front=temp->next;
delete temp;
}
这里也简单解释一下,首先判断如果队列为空就不存在出队了,所以直接返回,如果队头等于队尾,也就是只有一个元素,就让队头队尾指向NULL(其实这里还可以删除队头),最后返回
遍历操作也顺利成章:
void print(struct queue *q){
struct node *n=q->front;
while(n!=NULL){
std::cout<< n->data;
n=n->next;
}
}
至此队列结束,考虑到排版问题,对着三种结构的总结放到下面一片文章。