队列

前言
  本文在完成过程中,得到许多朋友的帮助,在此谢谢诸位。本人欢乐无限,技术有限,如有任何问题,欢迎各位不吝赐教。

1 队列是什么

  队列是在表的一端进行插入,而在另一端进行删除的线性表。队列具有先进先出(FIFO, First In, First Out)特性。
  在队列中,元素之间的位置关系主要有两个:

  • 队头(front):进行删除的一端。
  • 队尾(rear):进行插入的一端。

\
  队列的基本操作是入队(enqueue)和出队(dequeue)。入队是在表的后端插入一个元素,程序中用enqueue(x, Q)实现。出队删除表的前端的元素,程序中用dequeue(Q)实现。
  至此,大家应该对队列有了一个初步的认识。下面是一个队列模型,队列大小(指队列中元素的个数)为6。队头元素为a1,队尾元素为a6。
  1

2 队列的实现

  队列也是表,因此任何表的实现方法都可以用来实现队列。

2.1 队列的数组实现

  对于使用数组实现的队列的数据结构,可以用下面的图来直观的说明:
2
  从上面的图可以看到,队列的数据结构包括队列的结构(图中间的矩形)和队列的数组(图右边的矩形)两部分组成。
  其中队列的结构包含5个成员:

  • capacity:int变量,队列的容量;
  • front:int变量,指示队头的位置;
  • rear:int变量,指示队尾的位置;
  • size: int变量,队列的大小;
  • array:指针,指向队列的数组。

\
  特别指出的是front初始化为1,rear初始化为0。这使得队列不为空时,front指示队头而rear指示队尾。(注:有些程序员可能采用了不同的策略:rear指示队尾的下一位置)
  队列的数组是一个动态数组,用来存储队列的数据元素。由于在程序运行时,队列的插入和删除随时都可能在进行,为了充分利用数组空间,这里数组的使用方法有点特别,就是当front或rear到达数组尾端的时候,如果再执行出队或入队操作,它们又绕回到数组的开头,这种数组叫做循环数组(circular array)。采用这种数组实现的队列也就成为循环队列。
  下面是C实现的队列,首先是Queue.h的头文件:

typedef int ElementType;

#ifndef QUEUE_H
#define QUEUE_H

struct QueueRecord;
typedef struct QueueRecord *Queue;

int isEmpty( Queue Q );
int isFull( Queue Q );
Queue createQueue( int maxElements );
void disposeQueue( Queue Q );
void makeEmpty( Queue Q );
void enqueue( ElementType x, Queue Q );
ElementType front( Queue Q );
void dequeue( Queue Q );
ElementType frontAndDequeue( Queue Q );

#endif

  下面是Fatal.h的头文件:

#include <stdio.h>
#include <stdlib.h>

#define Error( Str )        FatalError( Str )
#define FatalError( Str )   fprintf( stderr, "%s\n", Str ), exit( 1 )

  下面是Queue.c的源文件:

#include <stdlib.h>
#include "Queue.h"
#include "Fatal.h"

#define MinQueueSize ( 5 )

struct QueueRecord{
    int capacity;
    int front;
    int rear;
    int size;
    ElementType *array;
};

int isEmpty( Queue Q )
{
    return Q->size == 0;
}

int isFull( Queue Q )
{
    return Q->size == Q->capacity;
}

Queue createQueue( int maxElements )
{
    Queue Q;

    if( maxElements < MinQueueSize )
        Error( "Queue size is too small" );

    Q = malloc( sizeof( struct QueueRecord ) );
    if( Q == NULL )
        FatalError( "Out of space!!!" );

    Q->array = malloc( sizeof( ElementType ) * maxElements );
    if( Q->array == NULL )
        FatalError( "Out of space!!!" );
    Q->capacity = maxElements;
    makeEmpty( Q );

    return Q;
}

void makeEmpty( Queue Q )
{
    Q->size = 0;
    Q->front = 1;
    Q->rear = 0;
}

void disposeQueue( Queue Q )
{
    if( Q != NULL ) {
        free( Q->array );
        free( Q );
    }
}

void enqueue( ElementType x, Queue Q )
{
    if( isFull( Q ) )
        Error( "Full queue" );
    else {
        Q->size++;
        Q->rear = (Q->rear + 1) % Q->capacity;
        Q->array[ Q->rear ] = x;
    }
}

ElementType front( Queue Q )
{
    if( isEmpty( Q ) )
        Error( "Empty queue" );
    return Q->array[ Q->front ];
}

void dequeue( Queue Q )
{
    if( isEmpty( Q ) )
        Error( "Empty queue" );
    else {
        Q->size--;
        Q->front = (Q->front + 1) % Q->capacity;
    }
}

ElementType frontAndDequeue( Queue Q )
{
    ElementType x = 0;

    if( isEmpty( Q ) )
        Error( "Empty queue" );
    else {
        Q->size--;
        x = Q->array[ Q->front ];
        Q->front = (Q->front + 1) % Q->capacity;
    }
    return x;
}

  测试程序main.c

#include <stdio.h>
#include <stdlib.h>
#include "Queue.h"

int main(int argc, char *argv[]) 
{
    Queue Q;
    Q = createQueue( 5 );

    for(int i = 0; i < 10; i++ ){
        enqueue( i, Q );
        printf("%d ", isFull(Q));
    }

    printf("\n");
    while( !isEmpty( Q ) ) {
        printf( "%d\n", front( Q ) );
        dequeue( Q );
    }

    for(int i = 0; i < 20; i++ )
        enqueue( i, Q );

    while( !isEmpty( Q ) ) 
        printf( "%d\n", frontAndDequeue( Q ) );

    disposeQueue( Q );
    return 0;
}

2.2 队列的链表实现

  队列也可以使用单链表实现。其数据结构包含了队列的大小size,指针front和rear。其中front指向头结点(注意不是队头,队头可以看做是头结点的后继),rear指向队尾。其初始状态可用如下模型表示:
3
  下面是一个大小为n的队列,队头元素为A1,队尾元素为An。
4
  我们通过在表的头结点后面插入来实现enqueue,在队尾后面插入来实现dequeue。
  首先是Queue.h

typedef int ElementType;
#ifndef QUEUE_H
#define QUEUE_H

struct ListNode;
typedef struct ListNode *PtrToNode;
struct QueueRecord;
typedef struct QueueRecord *Queue;

int isEmpty(Queue Q);
Queue createQueue();
void disposeQueue(Queue Q);
void makeEmpty(Queue Q);
void enqueue();
ElementType front(Queue Q);
void dequeue(Queue Q);

#endif

  Fatal.h

#include <stdio.h>
#include <stdlib.h>

#define Error(str)      FatalError(str) 
#define FatalError(str) fprintf(stderr, "%s\n", str), exit(1)

  Queue.c

#include <stdlib.h>
#include "Queue.h"
#include "Fatal.h"

struct ListNode{
    ElementType element;
    PtrToNode next;
};

struct QueueRecord{
    int size;
    PtrToNode front;
    PtrToNode rear;
};

int isEmpty(Queue Q)
{
    return Q->size == 0;
}

Queue createQueue()
{
    Queue Q = malloc(sizeof(struct QueueRecord));
    if(Q == NULL)
        FatalError("Out of space!!!");

    Q->size = 0;
    Q->front = Q->rear = malloc(sizeof(struct ListNode));
    if(Q->front == NULL)
        FatalError("Out of space!!!");
    Q->front->next = NULL;
    return Q;
}

void disposeQueue(Queue Q)
{
    makeEmpty(Q);
    free(Q);
}

void makeEmpty(Queue Q)
{
    while(!isEmpty(Q))
        dequeue(Q);
}

void enqueue(ElementType x, Queue Q)
{
    PtrToNode p = malloc(sizeof(struct ListNode));
    if(p == NULL)
        FatalError("Out of space!!!");

    p->element = x;
    p->next = NULL;
    Q->rear->next = p;
    Q->rear = p;
    Q->size++;
}

ElementType front(Queue Q)
{
    return Q->front->next->element;
}

void dequeue(Queue Q)
{
    PtrToNode p = Q->front->next;
    Q->front->next = p->next;

    if(Q->front->next == NULL) //队列为空 
        Q->rear = Q->front;
    free(p);

    Q->size--;
}

  测试程序main.c:

#include <stdio.h>
#include <stdlib.h>

#include "Queue.h"

int main(int argc, char *argv[]) 
{
    Queue Q = createQueue( );

    for(int i = 0; i < 10; i++)
        enqueue( i, Q );

    while(!isEmpty( Q ) ) {
        printf( "%d\n", front( Q ) );
        dequeue( Q );
    }

    for(int i = 0; i < 10; i++)
        enqueue( i, Q );

    while(!isEmpty( Q ) ) {
        printf( "%d\n", front( Q ) );
        dequeue( Q );
    }

    disposeQueue( Q );
    return 0;
}
参考文献

[1] Mark Allen Weiss,数据结构与算法分析:C语言描述(原书第2版)
[2] Thomas H.Cormen,Charles E.Leiserson,Ronald L.Rivest,Clifford Stein,算法导论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值