隊列即爲只允許在一端進行插入數據隊列,在另一端進行刪除數據操作的特殊線性表。但也有一些例外,如優先級隊列。
隊列具有先進先出的特性,即最先進入隊列的元素將被最先出隊列
有時也需要把進入隊列中的元素分優先級(比如線程調度),出隊列時首先選擇優先級最高的元素出隊列,對於優先級相同的元素則按照先進先出的原則出隊列
順序隊列很容易實現,主要是控制好頭和尾,通常用循環的方式實現,避免溢出的問題。基本操作同棧類似,具體注意的點我就在代碼中細說了
- 結構體聲明
typedef struct TreeNode* SeqQueueType;
//head作爲隊首,tail作爲隊尾
//插入數據時,tail向後移,從隊列裏刪除數據時,head往後移
//數據出隊列時其實並沒有真實的被刪除,而是隨着head的後移,之前的隊首元素不在有效範圍內了
//tail到了數組末尾時,檢查一下head是否表示的是數組(不是隊列)頭部,如果不是的話說明數組的頭部還可以插入數據
//作爲隊列的尾部。直到size等於數組的最大容量時,才說明隊列已經滿了
typedef struct SeqQueue{
SeqQueueType data[SeqQueueMaxSize];
size_t head;
size_t tail;
size_t size;
}SeqQueue;
- 基本操作函數聲明
//初始化
void SeqQueueInit(SeqQueue* seq);
//入隊列
void SeqQueuePush(SeqQueue* seq,SeqQueueType value);
//出隊列
void SeqQueuePop(SeqQueue* seq);
//取隊首元素
int SeqQueueGetTop(SeqQueue* seq,SeqQueueType* value);
//銷燬隊列
void SeqQueueDestroy(SeqQueue* seq);
注意,雖然我們實現順序隊列沒有在堆上開闢空間,但是我們依然需要一個銷燬函數,不光是爲了代碼工整,更多的是一個提示作用,在一個較大的項目中,如果每個部分都有明確的銷燬以及初始化體現,那麼就會大大提高代碼的可讀性,不至於還要區分半天,這也是種編程習慣,即使在這種小工作中也儘量要求自己保持一個好的編程習慣,不要偷工減料
初始化和銷燬(即使代碼一模一樣,也要區分開來寫)
void SeqQueueInit(SeqQueue* seq)
{
if(seq==NULL)
{
//非法輸入
return;
}
seq->head = 0;
seq->tail = 0;
seq->size = 0;
}
void SeqQueueDestroy(SeqQueue* seq)
{
if(seq==NULL)
{
//非法輸入
return;
}
seq->head = 0;
seq->tail = 0;
seq->size = 0;
}
入隊列出隊列
void SeqQueuePush(SeqQueue* seq,SeqQueueType value)
{
if(seq==NULL)
{
//非法輸入
return;
}
if(seq->size == SeqQueueMaxSize)
{
//隊列已滿
return;
}
if(seq->tail==SeqQueueMaxSize&&seq->size<SeqQueueMaxSize)
//此時tail已經到了數組末尾,而size還沒有達到最大值,說明
//head前有空出的位置,所以將tail賦值0,直到size達到最大值,才說明隊列已經滿了
{
seq->tail = 0;
}
seq->data[seq->tail++] = value;
seq->size++;
}
void SeqQueuePop(SeqQueue* seq)
{
if(seq==NULL)
{
//非法輸入
return;
}
if(seq->size == 0)
{
//空隊列
return;
}
if(seq->head == SeqQueueMaxSize)
{
seq->head = 0;
}
else
{
seq->head++;
}
seq->size--;
}
取隊首元素
int SeqQueueGetTop(SeqQueue* seq,SeqQueueType* value)
{
if(seq==NULL)
{
//非法輸入
return 0;
}
if(seq->size==0)
{
//空隊列
return 0;
}
*value = seq->data[seq->head];
return 1;
}
這裏有鏈式棧隊列實現入口->鏈式隊列實現