上篇博客說的棧是操作受限制的線性表,同樣的,隊列也是操作受限制的線性表,不同於棧,它的頭和尾兩頭都受限制,只能在一端進行插入(只進不出),我們稱爲隊尾,在另一端進行刪除(只出不進),稱作隊首。
遵循的原則是:”先進先出“(first in first out),簡稱”FIFO”.我們生活中的排隊現象就是隊列的一種應用,先來的人先進入隊伍亦先買到東西離開,即先進先出。
隊列也有順序和鏈式兩種存儲結構。
1.順序隊列的實現
順序存儲如圖:
順序存儲的存儲空間是靜態分配的,所以有可能沒有剩餘空間的情況,用循環列表可以解決這一問題。
頭文件聲明:
seqqueue.h
#pragma once
#include<stddef.h>
#define SeqQueueMaxSize 1000//隊列的最大長度
typedef char SeqQueueType;
typedef struct SeqQueue
{
SeqQueueType data[SeqQueueMaxSize];
size_t head;
size_t tail;
size_t size;
}SeqQueue;
void SeqQueueInit(SeqQueue* q);//初始化
void SeqQueueDestroy(SeqQueue* q);//銷燬
void SeqQueuePush(SeqQueue* q,SeqQueueType value);//入隊列
void SeqQueuePop(SeqQueue* q);//出隊列
int SeqQueueFront(SeqQueue* q,SeqQueueType* value);//取隊首元素
具體實現及測試代碼:
seqqueue.c
#include"seqqueue.h"
void SeqQueueInit(SeqQueue* q)
{
if(q == NULL)
{
return; //非法輸入
}
q->head = 0;
q->tail= 0;
q->size = 0;
return;
}
void SeqQueueDestroy(SeqQueue* q)
{
if(q == NULL)
{
return; //非法輸入
}
q->head = 0;
q->tail = 0;
q->size = 0;
}
void SeqQueuePush(SeqQueue* q,SeqQueueType value)
{
if(q == NULL)
{
return;//非法輸入
}
if(q->size >= SeqQueueMaxSize)
{
return;//隊列已滿
}
q->data[q->tail++] = value;//將value賦給tail指向的位置,tail指向它的下一個位置
if(q->tail == SeqQueueMaxSize)//如果尾指針指向的位置大於隊列最大容量,則將它指向下標爲0的位置
{
q->tail = 0;
}
q->size++;
}
void SeqQueuePop(SeqQueue* q)
{
if(q == NULL)
{
return;//非法輸入
}
if(q->size == 0)
{
return;//空列表
}
++q->head;
if(q->head == SeqQueueMaxSize)
{
q->head = 0;
}
--q->size;
return;
}
int SeqQueueFront(SeqQueue* q,SeqQueueType* value)
{
if(q == NULL||value == NULL)
{
return 0;//非法輸入
}
if(q->size == 0)
{
return 0;//空隊列
}
*value = q->data[q->head];
return 1;
}
////////////////////////////////////////
/////////以下是測試代碼////////////////
///////////////////////////////////////
#if 1
#include<stdio.h>
#define TEST_HEADER printf("\n==================%s================\n",__FUNCTION__)
void TestQueue()
{
TEST_HEADER;
SeqQueue queue;
SeqQueueInit(&queue);
SeqQueuePush(&queue,'a');
SeqQueuePush(&queue,'b');
SeqQueuePush(&queue,'c');
SeqQueuePush(&queue,'d');
SeqQueueType value;
int ret = SeqQueueFront(&queue,&value);
printf("ret expected 1,actual %d\n",ret);
printf("value expected a,actual %c\n",value);
SeqQueuePop(&queue);
SeqQueuePop(&queue);
ret = SeqQueueFront(&queue,&value);
printf("ret expected 1,actual %d\n",ret);
printf("value expected c,actual %c\n",value);
SeqQueuePop(&queue);
SeqQueuePop(&queue);
ret = SeqQueueFront(&queue,&value);
printf("ret expected 0,actual %d\n",ret);
}
int main()
{
TestQueue();
printf("\n");
return 0;
}
#endif
2.鏈式隊列的實現
頭文件聲明:
linkqueue.h
#pragma once
#include<stddef.h>
typedef char LinkType;
typedef struct LinkNode
{
LinkType data;
struct LinkNode* next;
}LinkNode;
typedef struct LinkQueue
{
LinkNode* head;
LinkNode* tail;
}LinkQueue;
void LinkQueueInit(LinkQueue* queue);//初始化
void LinkQueueDestroy(LinkQueue* queue);//銷燬
void LinkQueuePush(LinkQueue* queue,LinkType value);//入隊列
void LinkQueuePop(LinkQueue* queue);//出隊列
int LinkQueueFront(LinkQueue* queue,LinkType* value);//取隊首元素
具體實現及測試代碼:
linkqueue.c
#include"linkqueue.h"
#include<stdlib.h>
#include<stdio.h>
LinkNode* CreateLinkNode(LinkType value)
{
LinkNode* new_node = (LinkNode*)malloc(sizeof(LinkNode));//爲新結點開闢空間
if(new_node == NULL)//開闢空間失敗
{
printf("error\n");
exit(-1);
}
new_node->data = value;
new_node->next = NULL;
return new_node;
}
void LinkQueueInit(LinkQueue* q)
{
if(q == NULL)
{
return;
}
q->head = q->tail = NULL;
return;
}
void LinkQueueDestroy(LinkQueue* q)
{
LinkNode* cur = q->head->next;
//循環釋放鏈表結點
while(cur != q->head)
{
LinkNode* to_delete = cur;
free(to_delete);
cur = cur->next;
}
}
void LinkQueuePush(LinkQueue* q,LinkType value)
{
if(q == NULL)
{
return;//非法輸入
}
LinkNode* new_node = CreateLinkNode(value);//創建一個新結點
if(q->head == NULL)//隊列裏沒有元素
{
q->head = q->tail = new_node;//頭指針和尾指針都指向新結點
}
q->tail->next = new_node;//將新結點插入到尾指針之後
q->tail = new_node;//更新尾指針
q->tail->next = NULL;
return;
}
void LinkQueuePop(LinkQueue* q)
{
if(q == NULL)
{
return;//非法輸入
}
LinkNode* to_delete = q->head;
q->head = to_delete->next;//更新頭結點
free(to_delete);//釋放以前的頭指針
to_delete = NULL;
return;
}
int LinkQueueFront(LinkQueue* q,LinkType* value)
{
if(q == NULL)
{
return 0;//非法輸入
}
if(q->head == NULL)
{
return 0;//空隊列
}
*value = q->head->data;
return 1;
}
///////////////////////////////////////
///////////以下是測試代碼/////////////
/////////////////////////////////////
#if 1
#include<stdio.h>
#define TEST_HEADER printf("\n===========================%s==============================\n",__FUNCTION__);
void LinkQueuePrintChar(LinkQueue* q,char* msg)
{
if(q == NULL)
{
return;
}
printf("[%s]\n",msg);
LinkNode* cur = q->head;
while(cur != q->tail->next)
{
printf("[%c] ",cur->data);
cur = cur->next;
}
printf("\n");
return;
}
void TestQueue()
{
TEST_HEADER;
LinkQueue queue;
LinkQueueInit(&queue);
LinkQueuePush(&queue,'a');
LinkQueuePush(&queue,'b');
LinkQueuePush(&queue,'c');
LinkQueuePush(&queue,'d');
LinkQueuePrintChar(&queue,"入隊列四個元素");
LinkType value;
int ret = LinkQueueFront(&queue,&value);
printf("ret expected 1,actual %d\n",ret);
printf("value expected a,actual %c\n",value);
LinkQueuePop(&queue);
LinkQueuePop(&queue);
LinkQueuePrintChar(&queue,"出隊列兩個元素");
ret = LinkQueueFront(&queue,&value);
printf("ret expected 1,actual %d\n",ret);
printf("value expected c,actual %c\n",value);
LinkQueuePop(&queue);
LinkQueuePop(&queue);
LinkQueuePrintChar(&queue,"再出隊列兩個元素");
ret = LinkQueueFront(&queue,&value);
printf("ret expected 0,actual %d\n",ret);
}
int main()
{
TestQueue();
printf("\n");
return 0;
}
#endif