严蔚敏版数据结构学习笔记(4):队列

和上次的栈相反,队列是一种先进献出的线性表(FIFO);它只允许在它的一端进行删除操作,而在另一边进行插入操作。在队列里面,允许插入的一端我们称之为队尾,允许删除的一端称为队头;
严蔚敏版数据结构学习笔记(4):队列_第1张图片
队列和栈的基本操作差不多,也有八个,不同的一点是删除操作是在表的头部进行而不是尾部;
ADT Queue{
InitQueue(&Q);
DestroyQueue(&Q);
ClearQueue(&Q);
QueueEmpty(Q);
QueueLength(Q);
GetHead(Q,&e);
EnQueue(&Q,e);
DeQueue(&Q,&e);
QueueTraverse(Q,visit());
}
队列中有一种限定性的数据结构是双端队列(Deque),是限定插入和删除在表的两端进行的线性表,两端分别是端点1和端点2,实际中我们还可以定义限制输入和限制输出的双端链表(也就是其中一端可以进行删除和插入操作,另一端只能进行删除(插入)操作);

队列也有两种存储结构:顺序的队列和链式的队列;
上面说到的都是顺序队列,链队列需要两个分别指向队头和队尾的指针(头指针和尾指针)才能唯一确定。和线性表的链式结构一样,我们将给链式队列一个头结点,并令头指针指向头结点。所以可以清楚:链式队列的判空操作是头指针和尾指针均指向头结点。如图所示:
严蔚敏版数据结构学习笔记(4):队列_第2张图片
每当一个新的数据元素存到队列里面头指针不动,尾指针指向该新元素,头结点也指向该元素。
我们先来顶一个链式结构的结构体:

typedef struct QNode{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
    QueuePtr front;//队头指针
    QueuePtr rear;//队尾指针
}LinkQueue;

其中包括了队头指针和队尾指针,和数据元素;
同样的,链式队列也是有上面的八种基础操作的,我们来试着一一实现一下:
构造一个空的链队列:

Status InitQueue(LinkQueue &Q){
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
    if(!Q.front) exit(OVERFLOW);//当内存分配失败的时候
    Q.front->next = NULL;//此时front指向的结点就是头结点
    return OK;
}

当然有了创建一个队列,自然还要有队列的销毁和清空:

Status DestroyQueue(LinkQueue &Q){
    //销毁一个队列Q
    while(Q.front){
        Q.rear = Q.front->next;
        free(Q.front);
        Q.front = Q.rear;//释放一块内存要做两点:1.释放指向它的指针。2.将该指针指向空
    }
    return OK;
}

至于为什么要用循环呢,我之前也是迷茫了一下,第一次循环的时候front指向的是头结点,然后将这个front->next==NULL赋值给rear之后front依然存在,在将这个赋值给rear之后我们就达成了front和rear都指向空,也就是实现了销毁

Status ClearQueue(LinkQueue &Q){
    //清空一个队列Q
    Q.rear = Q.front;
    struct QNode *p,*q;
    p = Q.front->next;
    Q.front->next = NULL;//只留下头结点
    while(p){
        q=p;
        p = p->next;
        free(q);
    }
    return OK;
}

清空一个链式队列的话只要留下头结点 就行;达成头指针和尾指针均指向头结点即可;
(剩下的部分会在接下来的时间里慢慢上载的。)

你可能感兴趣的:(严蔚敏版数据结构代码实现,数据结构)