學習佇列 (轉)

themoney發表於2007-10-05
學習佇列 (轉)[@more@]

 

/*
=====================================================================
作者:rerli
時間:2004-02-11
目的:學習佇列
=====================================================================
*/
/*
 佇列是從日常排隊現象抽象出來的一種數學模型。當然資料結構中的佇列
遠沒有生活中的排隊靈活。資料結構中的佇列規定:資料只能從隊尾進,從隊
首出來。已經進入佇列的資料次序不能再做改變。這就叫做“先進先出”(FIFO)
或者說“後進後出”(LILO)。允許插入的一端稱為隊尾,通常用一個稱為尾指標
(rear)的指標指向隊尾元素,即尾指標總是指向最後被插入的元素;允許刪
除的一端稱為隊首,通常也用一個隊首指標(front)指向隊首元素的前一個位
置(當然也可以直接指向隊首元素,只是許多資料結構的書上都習慣這麼定義)。

 與佇列類似,我們可以用一維陣列來模擬佇列這種資料結構,也可以用連結串列
來模擬。

 根據以上描述,佇列可以整理出以下基本操作:
 1、建立初始化:按約定置佇列為空狀態。
 2、入佇列:在隊尾加入一個新資料項。
 3、出佇列:從隊首取出一個資料項,並使餘下諸項向隊首移動。
 4、佇列空:判斷佇列是否為空。
 5、佇列滿:判斷佇列是否已滿。
  從概念上說,佇列不存在“滿”狀態,其長度可以任意增加,
  但實現(不論靜態或動態)中總有空間限制的。

 下面我就來討論用陣列實現佇列結構。

 假定佇列中元素的型別為T,佇列的最大長度為queue_size,在任何一刻佇列
首、尾位置分別用下標head、tail指向。

 佇列初始狀態應為:head=0,tail=-1。根據佇列定義,head值應恆為0,
那麼每當出隊一個資料項,則必須多次移動操作(餘下諸項向隊首移動)。
顯然不能直接採用這種結構實現佇列。解決這個問題,可以從數學取模運算聯想
到一個解決辦法。比如x=(x+1) mod 100 ,則x的變化範圍在[0,99]之間,
超過100的又從0,1開始。這不就是我們所需要的嘛!許多書上把它叫作“迴圈
陣列”技術。即當入佇列時先移動tail(即tail=(tail+1) mod queue_size),
出佇列時先移動head(即head=(head+1) mod queue_size)。

 在移動中,若head(或tail)值為queue_size-1,則移動後head(或tail)的值
就變成0了,對這種特徵就是一個環,只要陣列有空間,就可以入佇列。

 用“迴圈陣列”實現佇列,必須注意怎樣判斷佇列的空與滿的狀態。除起始狀態
外。任何時刻tail所指為最後一個進入佇列的元素,而head所指的是剛剛出佇列的
那個元素原先所佔的位置。因此(head+1) mod queue_size才是真正當前佇列中首元
素位置。

 採用條件:(tail+1) mod queue_size == head 作為“佇列滿”的判斷條件。
實際上此時佇列中還有一個空位置,這樣佇列的利用空間比定義的最大空間少一個
單元。假如把這個單元也利用上,則就不好判斷“滿”或“空”了(當head==tail)
,必須根據是tail追上了head,還是head追上了tail才能區分,這樣給處理帶來了
不便。

*/
#include
#include
#define NULL 0

typedef struct node
{
 int data; 
}NODE;

#define LEN sizeof(NODE)

/*佇列的需要變數*/
typedef enum {false,true}bool; /*定義bool型別*/
unsigned int head; /*定義隊首下標變數*/
unsigned int tail; /*定義隊尾下標變數*/
static NODE *queue=NULL; /*定義一個佇列*/
static unsigned int queue_size=0;/*佇列的大小*/

/*
========================
 功能:初始化佇列的大小
 返回:true or false
========================
*/
bool InitQueue(unsigned int size)
{
 queue=(NODE *)malloc(size*LEN); /*開闢空間*/ 
 if (queue==NULL) /*開闢空間失敗,則返回false*/
 {
 return false;
 }
 queue_size = size; /*儲存佇列空間大小值*/
 head = queue_size-1;/*隊首下標賦初值*/ 
 tail = queue_size-1;/*隊尾下標賦初值*/
 return true; /*初始化成功,返回true*/
}

/*
======================
 功能:釋放佇列的
 返回:void
======================
*/
void FreeQueue()
{
 free(queue);
 /*
  注意:這一點很重要。free()之後並不能將queue
  置為NULL,所以我們一定要自己做。這樣能防止產生
  “野指標”,即地址不確定的指標。
 */
 queue = NULL; 
}

/*
==========================
 功能:判斷佇列是否已滿
 返回:true or false
==========================
*/
bool Full()
{
 return (((tail+1)%queue_size)==head);
}

/*
===========================
 功能:判斷佇列是否為空
 返回:true or false
===========================
*/
bool Empty(){
 
 return (head==tail);
}

/*
========================
 功能:入佇列
 返回:true or false
========================
*/
bool Push(NODE p)
{
 if (!Full()) /*佇列不滿,則入佇列;隊尾下標要加1*/
 {
 tail = (tail+1)%queue_size;
 queue[tail] = p;
 return true;
 }
 else
 {
 printf("queue is overflow !n");
 return false;
 }
}

/*
===================
 功能:出佇列
 返回:出佇列元素指標
===================
*/
NODE *Pop()
{
 if (!Empty()) /*佇列不空,則出佇列;隊首下標要加1*/
 {
 head = (head+1)%queue_size;
 return (&queue[head]);
 }
 else
 {
 printf("queue is empty !n");
 return NULL;
 }
}

void main(void)

 NODE node1 = {3};
 NODE *p;

 if (!InitQueue(3)) /*初始化不成功,則退出*/
 {
 exit(0);
 }
 Push(node1);
 /*去掉下面的註釋,你可以驗證講解中空間利用問題*/
 /*
 Push(node1);
 Push(node1);
 Push(node1);
 */
 p =Pop();
 printf("%d",p->data);

 FreeQueue(); /*注意退出時釋放佇列記憶體*/

 printf("n");
 system("pause");
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10794571/viewspace-974828/,如需轉載,請註明出處,否則將追究法律責任。

相關文章