數據結構之循環順序隊列

隊列的定義

隊列(queue)是隻允許在一端進行插入操作,另一端進行刪除操作的線性表

 

    隊列是一種先進先出的線性表,允許插入的一端稱爲隊尾(rear),允許刪除的一端稱爲隊頭(front)。向隊列中插入元素稱爲入隊,從隊列中刪除元素稱爲出隊。當隊列中沒有元素時稱爲空隊列。隊列的操作是按先進先出的原則進行的,即新添加的元素總是加到隊尾,每次離開的元素總是隊頭的元素。和棧一樣,隊列也是一種運算受限制的線性表,所以又叫先進先出表(First In First Out),簡稱FIFO表。

順序隊列


        假設一個隊列有n個元素,則順序存儲的隊列需要建立一個大於n的數組,並把隊列的所有元素存儲在數組的前n個單元,數組下標爲0的一端即爲隊頭。
        所謂的入隊,就是在隊尾追加一個元素,不需要移動任何元素,所以時間複雜度爲O(1).


        隊列的出隊是在隊頭,即下標爲0的位置,也就意味着,隊列中的所有位置都得向前移動,以保證下標爲0的位置,即對頭不爲空。此時時間複雜度爲O(n)。
         

爲了避免當只有一個元素時,隊頭和隊尾重合使得處理變得麻煩,所以引入兩個指針,front指針 指向隊頭元素,rear指針 指向隊尾元素的下一個元素。這樣當 front 等於 rear 時,不是隊列中有一個元素,而是表示空隊列。

        假設數組的長度爲5,空隊列及初始狀態如圖所示,front與rear指針都指向下標爲0的位置。當隊列中有4個元素時,front指針不變,rear指針指向下標爲4的位置。
    

此時出隊兩個元素,則front指針指向下標爲2的位置,rear不變。再入隊一個元素,front指針不變,此時rear指針移動到數組之外 

 

    假設這個隊列中的總個數不超過5個,但目前如果接着入隊的話,會導致數組越界的錯誤,但是隊列在下標爲0和1的位置是沒有元素的。我們把這種現象叫做“假溢出”。

循環隊列

解決“假溢出”的辦法就是後面滿了,就再從頭開始,也就是頭尾相接的循環。我們把隊列的這種頭尾相接的順序存儲結構稱爲循環隊列

        爲了解決“假溢出”的問題,我們引入循環隊列。

 接着入隊兩個元素,會發現rear指針與front重合了。

 解決辦法爲:當隊列空時,判斷條件就是 rear == front, 當隊列滿時,我們修改其判斷條件,保留一個元素空閒。也就是說,隊列滿時,數組中還有一個空閒單元。以下兩種情況,我們都認爲隊列已經滿了。

循環隊列的順序存儲結構如下: 

#define SIZE 8
 
typedef struct Queue
{
	int elem[SIZE];  // 存放隊列元素
	int front;   // 隊頭
	int rear;    // 隊尾
}Queue,*QueueS;

 

    基本操作:

    void InitQueueS(QueueS queue);     // 初始化循環隊列
    bool Push(QueueS queue, int val);    // 入隊
    bool Pop(QueueS queue, int *rtv);     // 出隊
    void Show(QueueS queue);      // 打印隊列元素
    int GetLength(QueueS queue);  // 計算隊列長度
    bool IsEmpty(QueueS queue);   // 判空  
    void Clear(QueueS queue);    // 清空隊列

void InitQueueS(QueueS queue)
{
	assert(queue != NULL);
	queue->front = 0;
	queue->rear = 0;
}
static bool IsFull(QueueS queue)
{
	return (queue->rear + 1) % SIZE == queue->front;
}
bool Push(QueueS queue, int val)
{
	if (IsFull(queue))
	{
		return false;
	}
	queue->elem[queue->rear] = val;
	queue->rear = (queue->rear + 1) % SIZE;
	return true;
}

bool Pop(QueueS queue, int *rtv)
{
	if (IsEmpty(queue))
	{
		return false;
	}
	if (rtv != NULL)
	{
		*rtv = queue->elem[queue->front];
	}
	queue->front = (queue->front + 1) % SIZE;
	return true;
}

void Show(QueueS queue)
{
	for (int i = queue->front; i != queue->rear; i = (i + 1) % SIZE)
	{
		printf("%d ", queue->elem[i]);
	}
	printf("\n");
}

int GetLength(QueueS queue)
{
	return (queue->rear - queue->front + SIZE) % SIZE;
}

bool IsEmpty(QueueS queue)
{
	return queue->front == queue->rear;
}

void Clear(QueueS queue)
{
	queue->front = queue->rear;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章