链队列的基本算法
一、介绍
队列(Queue),计算机中一种常用的数据结构,具有先进先出FIFO的特点。
通俗一点,就跟生活中超市购物结账排队一样,靠前的结账先走,新来的排在后面等待。
对于队列中的元素,一般都在队头出队,在队尾入队,队头用Q.front表示,队尾用Q.rear表示。
队列的实现有两种方式,通过数组或者链表实现。基于数组实现的队列一般称作顺序队列,基于链表实现的队列一般称作链式队列。
链式队列中,有两个指针,分别是队头指针和队尾指针。为了操作方便,可以给链队列添加一个头结点,并令头指针指向头结点。
空队列判决条件:头指针和尾指针均指向头结点。也即Q.front == Q.rear。
本文采用链表实现队列,链队列的操作即为单链表的插入和删除的特殊情况,只是尚需修改尾指针或头指针。
二、示图
三、算法
#define QUEUE_OVERFLOW -1 #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int QElemType; typedef int Status; /// ----- 单链队列 ------- 队列的链式存储结构 typedef struct QNode { QElemType data; struct QNode *next; }QNode, *QueuePtr; typedef struct { QueuePtr front; //队头指针 QueuePtr rear; //队尾指针 }LinkQueue; /// --- 基本操作的函数原型说明 ----- Status InitQueue(LinkQueue &Q); //构造一个空的队列Q Status DestroyQueue(LinkQueue &Q); //销毁队列Q,Q不再存在 Status ClearQueue(LinkQueue &Q); //将队列Q清空 Status QueueEmpty(LinkQueue Q); //判断队列Q是否为空,若空,返回TURE, 否则,返回FALSE int QueueLength(LinkQueue Q); //返回Q的元素个数,也即队列的长度 Status GetHead(LinkQueue Q, QElemType &e); //若队列Q不为空,则用e返回Q的队头元素,并返回OK;否则,返回ERROR Status EnQueue(LinkQueue &Q, QElemType e); //插入元素e为Q的新的队尾元素 Status DeQueue(LinkQueue &Q, QElemType &e); //若队列不空,则删除Q的队头元素,用e返回其值,并返回OK,否则,返回ERROR void QueueVisit(LinkQueue &Q); //访问队列元素
四、代码
Status InitQueue(LinkQueue &Q) { //构造一个空队列Q Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode)); if (!Q.front) exit(QUEUE_OVERFLOW); //存储分配失败 Q.front->next = NULL; return OK; } Status DestroyQueue(LinkQueue &Q){ //销毁队列Q while (Q.front){ Q.rear = Q.front->next; free(Q.front); //从队头取出每一个元素并释放内存,Q.rear作为一个临时指针使用 Q.front = Q.rear; } cout<<"队列已销毁"<<endl; return OK; } Status ClearQueue(LinkQueue &Q){ //清空队列Q Q.rear = Q.front; cout<<"队列已清空"<<endl; return OK; } Status QueueEmpty(LinkQueue Q){ //判断队列Q是否为空 if (Q.front == Q.rear) { cout<<"队列为空"<<endl; return TRUE; } cout<<"队列不为空"<<endl; return FALSE; } int QueueLength(LinkQueue Q){ //获取队列的长度 QNode *p = Q.front->next; int len = 0; while (p){ len++; p = p->next; } cout<<"队列长度:"<<len<<endl; return len; } Status GetHead(LinkQueue Q, QElemType &e){ //获取队头元素 if (Q.front == Q.rear) { return FALSE; } QNode *p = Q.front->next; e = p->data; cout<<"队头元素:"<<e<<endl; return OK; } Status EnQueue(LinkQueue &Q, QElemType e){ //插入元素e为Q的新的队尾元素 QNode *p = (QueuePtr)malloc(sizeof(QNode)); if (!p) exit(QUEUE_OVERFLOW); p->data = e; p->next = NULL; Q.rear->next = p;//当前队尾指针的next指针指向新元素 Q.rear = p;//修改队尾指针 cout<<"入队:"<<e<<endl; return OK; } Status DeQueue(LinkQueue &Q, QElemType &e){ //删除队头元素 if (Q.front == Q.rear) return ERROR; QNode *p = Q.front->next; e = p->data; Q.front->next = p->next; cout<<"出队:"<<e<<endl; if (Q.rear == p) { Q.rear = Q.front; } free(p); return OK; } void QueueVisit(LinkQueue &Q){ if (Q.front == Q.rear){ cout<<"队列为空"<<endl; return; } //访问队列元素 QNode *p = Q.front->next; printf("队列顺序为:"); while (p){ QElemType e = p->data; p = p->next; printf("%d ",e); } cout<<endl; }
五、测试
int main() { //构造队列 LinkQueue queue; if (InitQueue(queue) == OK){ for (int i = 1; i <= 10; ++i) { EnQueue(queue,i);//入队列 } } //判断队列是否为空 QueueEmpty(queue); //访问队列元素 QueueVisit(queue); //获取队列长度 QueueLength(queue); //获取队头元素 QElemType e; GetHead(queue, e); //出队列 for (int i=1; i<5 ; i++) { DeQueue(queue, e); } QueueVisit(queue); //清空队列 ClearQueue(queue); QueueEmpty(queue); //销毁队列 DestroyQueue(queue); return 0; }
六、打印
/Users/xiayuanquan/CLionProjects/queueTest/cmake-build-debug/queueTest 入队:1 入队:2 入队:3 入队:4 入队:5 入队:6 入队:7 入队:8 入队:9 入队:10 队列不为空 队列顺序为:1 2 3 4 5 6 7 8 9 10 队列长度:10 队头元素:1 出队:1 出队:2 出队:3 出队:4 队列顺序为:5 6 7 8 9 10 队列已清空 队列为空 队列已销毁 进程已结束,退出代码 0
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!