【棧和隊列】隊列

隊列 ,又一種特殊的線性表


隊列的定義

隊列(Queue)是隻容許在一端進行插入,而在另外一端進行刪除的運算受限的線性表html

容許刪除的一端稱爲隊頭(Front)web

容許插入的一端稱爲隊尾(Rear)算法

當隊列中沒有元素時稱爲空隊列
測試

隊列的修改是依先進先出的原則進行的。動畫

新來的成員老是加入隊尾(即不容許"加塞"),每次離開的成員老是隊列頭上的(不容許中途離隊),即當前"最老的"成員離隊。ui


 



隊列的基本邏輯運算

(1)InitQueue(Q)spa

置空隊。構造一個空隊列Q。

(2)QueueEmpty(Q)3d

判隊空。若隊列Q爲空,則返回真值,不然返回假值。

(3) QueueFull(Q)指針

     判隊滿。若隊列Q爲滿,則返回真值,不然返回假值。
   注意:
     此操做只適用於隊列的順序存儲結構。

(4) EnQueue(Q,x)code

     若隊列Q非滿,則將元素x插入Q的隊尾。此操做簡稱 入隊

(5) DeQueue(Q)

     若隊列Q非空,則刪去Q的隊頭元素,並返回該元素。此操做簡稱 出隊

(6) QueueFront(Q)

     若隊列Q非空,則返回隊頭元素,但不改變隊列Q的狀態。


隊列的分類


順序隊列:


(1)定義 
隊列的順序存儲結構稱爲順序隊列,順序隊列其實是運算受限的順序表。
須要兩個變量frontrear 分別指示隊列頭元素隊列尾元素的位置!



(2) 基本操做
  1. 入隊:將新元素插入 rear 所指的位置,而後將rear加1。
  2. 出隊:刪去front所指的元素,而後將front加1並返回被刪元素。
注意:
  1. front = rear 時,隊列爲空
  2. 在非空隊列裏,隊頭指針始終指向隊頭元素,尾指針始終指向隊尾元素的下一位置。
(3)溢出現象
  1.     "下溢"現象:當隊列爲空時,作 出隊 運算產生的溢出現象。「下溢」是正常現象,經常使用做程序控制轉移的條件。
  2. "真上溢"現象:當隊列滿時,作 進隊 運算產生空間溢出的現象。「真上溢」是一種出錯狀態,應設法避免。
  3. "假上溢"現象:因爲入隊和出隊操做中,頭尾指針只增長不減少,導致被刪元素的空間永遠沒法從新利用。當隊列中實際的元素個數遠遠小於向量空間的規模時,也可能因爲尾指針已超越向量空間的上界而不能作入隊操做。該現象稱爲"假上溢"現象。爲了解決這個問題,咱們可使用‘循環隊列’。(因此不少狀況下,咱們不會使用普通的順序表)



循環隊列:


爲了克服順序隊列的 "假上溢"現象,將向量空間想象爲一個首尾相接的圓環,並稱這種向量爲循環向量。存儲在其中的隊列稱爲循環隊列(Circular Queue)。
 

(1)  循環隊列的類型定義
 
#define MaxQSize 100   //應根據具體狀況定義該值
typedef char  QElemType;  //QElemType的類型依賴於具體的應用

typedef struct
{                  
	QElemType * base;	//初始化的動態分配存儲空間
	int front;			//頭指針,隊非空時指向隊頭元素              
	int rear;			//尾指針,隊非空時指向隊尾元素的下一位置           
}CirQueue;

(2)循環隊列的基本操做

跟普通順序表同樣,循環隊列中進行出隊、入隊操做時,頭尾指針仍要加1,朝前移動。
只不過當頭尾指針指向向量上界(MaxQSize-1)時,其加1操做的結果是指向向量的下界0。
這種循環意義下的加1操做能夠描述爲:
方法一:
if(i+1 == MaxQSize) // i 表示front或rear
	i=0;
else
    i++;

方法二:利用"模運算"
i = (i+1) % MaxQSize;

(3) 循環隊列邊界條件處理
循環隊列中,因爲入隊時尾指針向前追趕頭指針;出隊時頭指針向前追趕尾指針,形成隊空和隊滿時頭尾指針均相等。所以,沒法經過條件front==rear來判別隊列是"空"仍是"滿"。 【 參見動畫演示
解決這個問題的方法至少有三種:
  1. 另設一布爾變量以區別隊列的空和滿;
  2. 少用一個元素的空間。約定入隊前,測試尾指針在循環意義下加1後是否等於頭指針,若相等則認爲隊滿(注意:rear所指的單元始終爲空);
  3. 使用一個計數器記錄隊列中元素的總數(即隊列長度)。

(4) 循環隊列的基本運算(咱們使用第二種方法)

構造空隊列
bool InitQueue(CirQueue * Q)
{
	Q->base = (QElemType *)malloc(MaxQSize * sizeof(QElemType));
	if(!Q->base) exit(OVERFLOW);	//分配內存失敗
	Q->front = Q->rear = 0;			//初始化爲空棧
	return true;
}


判隊空
bool QueueEmpty(CirQueue * Q)
{//由於少用一個元素,因此只有空隊列纔有 front = rear
	if (Q->front == Q->rear)
	{
		return true;
	}
	else 
		return false;
}


判隊滿
bool QueueFull(CirQueue * Q)
{//若是插入後尾指針的位置等於頭指針的位置,則說明隊列滿了
	if ((Q->rear + 1) % MaxQSize == Q->front)
	{
		return true;
	}
	else
		return false;
}


入隊
bool EnQueue(CirQueue * Q, QElemType e)
{//插入元素e
	if (QueueFull(Q))
	{//若是隊滿,則返回false
		return false;
	}
	Q->base[Q->rear] = e;	//插入元素
	Q->rear = (Q->rear + 1) % MaxQSize;	//修改尾指針
	return true;
}


出隊
bool DeQueue(CirQueue * Q, QElemType * e)
{
	if (QueueEmpty(Q))
	{//若是隊空,則返回false
		return false;
	}
	*e = Q->base[Q->front];	//返回元素值
	Q->front = (Q->front + 1) % MaxQSize;	//修改頭指針
}


鏈隊列 :


(1)鏈隊列的定義 
隊列的鏈式存儲結構簡稱爲鏈隊列。它是限制僅在表頭刪除和表尾插入的單鏈表。


注意:
有一個頭結點!

(2)鏈隊列的類型定義
typedef struct QNode
{
	QElemType data;			//數據域
	struct QNode * next;	//指針域
}QNode, *QueuePtr;

typedef struct
{
	QueuePtr front;	//隊頭指針
	QueuePtr rear;	//隊尾指針
}LinkQueue;

(3)鏈隊列的基本運算
構造空隊
bool InitQueue(LinkQueue * Q)
{
	Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));//建立頭結點
	if (!Q->front) 
	{//若是內存分配失敗
		exit(OVERFLOW);
	}
	Q->front->next = NULL;	//初始化空隊列
	return true;
}

銷燬隊列
bool DestroyQueue(LinkQueue * Q)
{
	while(Q->front)
	{
		Q->rear = Q->front->next;//用rear暫時存儲新的隊頭指針
		free(Q->front);	//釋放內存
		Q->front = Q->rear;
	}
	return true;
}

入隊
bool EnQueue(LinkQueue * Q, QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));//爲新元素分配內存
	if (!p)
	{
		exit(OVERFLOW);
	}
	p->data = e;	//初始化新結點
	p->next = NULL;
	Q->rear->next = p;	//修改尾指針
	Q->rear = p;
	return true;
}


出隊
bool DeQueue(LinkQueue * Q, QElemType * e)
{
	if (Q->front == Q->rear)
	{//若是隊空
		return false;
	}
	QueuePtr p = Q->front->next;	//保存第一個結點的位置
	*e = p->data;
	Q->front->next = p->next;	//第一個結點出隊
	if (Q->rear == p)
	{//若是隻有一個結點,置爲空隊
		Q->rear = Q->front
	}
	free(p);
	return true;
}

注意:
和鏈棧相似,無須考慮判隊滿的運算及上溢。

在出隊算法中,通常只需修改隊頭指針。但當原隊中只有一個結點時,該結點既是隊頭也是隊尾,故刪去此結點時亦需修改尾指針,且刪去此結點後隊列變空。