歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> Linux C 數據結構——隊列

Linux C 數據結構——隊列

日期:2017/3/3 11:50:33   编辑:Linux技術
還是先放這張圖,以便對比和理解:

隊列是限制在兩端進行插入操作和刪除操作的線性表,允許進行存入操作的一端稱為“隊尾”,允許進行刪除操作的一端稱為“隊頭”。當線性表中沒有元素時,稱為“空隊”。特點:先進先出(FIFO)。

一、順序隊列
建立順序隊列結構必須為其靜態分配或動態申請一片連續的存儲空間,並設置兩個指針進行管理。一個是隊頭指針front,它指向隊頭元素;另一個是隊尾指針rear,它指向下一個入隊元素的存儲位置,如圖所示

每次在隊尾插入一個元素是,rear增1;每次哎隊頭刪除一個元素時,front增1。隨著插入和刪除操作的進行,隊列元素的個數不斷變化,隊列所占的存儲空間也在為隊列結構所分配的連續空間中移動。當front=rear時,隊列中沒有任何元素,稱為空隊列。當rear增加到指向分配的連續空間之外時,隊列無法再插入新元素,但這時往往還有大量可用空間未被占用,這些空間是已經出隊的隊列元素曾經占用過得存儲單元。
在實際使用隊列時,為了使隊列空間能重復使用,往往對隊列的使用方法稍加改進:無論插入或刪除,一旦rear指針增1或front指針增1 時超出了所分配的隊列空間,就讓它指向這片連續空間的起始位置。自己真從N(MaxSize)增1變到0,可用取余運算rear%N和front%N來實現。這實際上是把隊列空間想象成一個環形空間,環形空間中的存儲單元循環使用,用這種方法管理的隊列也就稱為循環隊列
在循環隊列中,當隊列為空時,有front=rear,而當所有隊列空間全占滿時,也有front=rear。為了區別這兩種情況,規定循環隊列最多只能有MaxSize-1個隊列元素,當循環隊列中只剩下一個空存儲單元時,隊列就已經滿了。因此,隊列判空的條件時front=rear,而隊列判滿的條件時front=(rear+1)%MaxSize。
總結:
1、隊頭指針front,指向隊頭元素的位置的前一個位置。即指向預留的位置;
2、隊尾指針rear,指向隊尾元素的位置;
3、入隊: rear = (rear + 1) % N (maxsize),然後元素放入隊尾rear所指向的位置;
4、出隊: front = (front + 1) % N,然後取出隊頭指針front所指向的元素;
5、隊空: front == rear;
6、隊滿: (rear + 1) % N == front, N為數組的元素個數;
7、為了區別空隊和滿隊,滿隊元素個數比數組元素個數少一個。
下面是順序隊列的運算:
順序隊列也是順序表的一種,具有順序表同樣的存儲結構,由數組定義,配合使用數組下表表示的隊頭指針和隊尾完成各種操作:
[cpp] view
plain copy
#define N 64 //隊列中數據元素的數據類型
typedef int data_t;
typedef struct
{
data_t data
; //用數組作為隊列的儲存空間
int front,rear; //指示隊頭位置和隊尾位置的指針
}sequeue_t;
1、創建空隊列
[cpp] view
plain copy
sequeue_t *CreateEmptySequeue()
{
sequeue_t *queue;
queue = (sequeue_t *)malloc(sizeof(sequeue_t));
if (NULL == queue) return NULL;
queue->front = queue->rear = 0;
return queue;
}
2、摧毀一個隊列
[cpp] view
plain copy
void DestroySequeue(sequeue_t *queue)
{
if (NULL != queue)
{
free(queue);
}
}
3、判斷一個隊列是否為空
[cpp] view
plain copy
int EmptySequeue(sequeue_t *queue)
{
if (NULL == queue)
return -1;
return (queue->front == queue->rear ? 1 : 0);
}
4、判斷一個隊列是否為滿
[cpp] view
plain copy
int FullSequeue(sequeue_t *queue)
{
if (NULL == queue) return -1;
return ((queue->rear + 1) % N == queue->front ? 1 : 0);
}
5、清空一個隊列
[cpp] view
plain copy
void ClearSequeue(sequeue_t *queue)
{
if (NULL == queue) return;
queue->front = queue->rear = 0;
return;
}
6、入隊
[cpp] view
plain copy
int EnQueue(sequeue_t *queue, data_t x)
{
if (NULL == queue) return - 1;
if (1 == FullSequeue(queue)) return -1; /* full */
queue->rear = (queue->rear + 1) % N;
queue->data[queue->rear] = x;
return 0;
}
7、出隊
[cpp] view
plain copy
int DeQueue(sequeue_t *queue, data_t *x)
{
if (NULL == queue) return -1;
if (1 == EmptySequeue(queue)) return -1; /* empty */
queue->front = (queue->front + 1) % N;
if (NULL != x) {
*x = queue->data[queue->front];
}
return 0;
}
二、鏈式隊列
用鏈表表示的隊列簡稱為鏈隊列,如下圖所示

一個鏈隊列顯然需要兩個分別指示隊頭和隊尾的指針(分別成為頭指針和尾指針)才能唯一確定。這裡,和線性表的單鏈表一樣,為了操作方便起見,我們也給隊列添加一個頭結點,並令頭指針指向頭節點。由此,空的鏈隊列的判決條件為頭指針和尾指針均指向頭結點,如下圖所示:

鏈隊列的操作記為單鏈表的插入和刪除操作的特殊情況,插入操作在隊尾進行,刪除操作在隊頭進行,由隊頭指針和隊尾指針控制隊列的操作:
[cpp] view
plain copy
typedef int data_t;
typedef struct node_t
{
data_t data;
struct node_t *next;
}linknode_t,*linklist_t;
typedef struct
{
linklist_t front,rear;
}linkqueue_t;
1、創建空隊列
[cpp] view
plain copy
linkqueue_t *CreateEmptyLinkqueue()
{
linkqueue_t *lp = (linkqueue_t *)malloc(sizeof(linkqueue_t));
if(lp == NULL)
return;
lp->front = lp->rear = (linknode_t *)malloc(sizeof(linknode_t));
if(lp->front == NULL)
return;
lp->front->next = NULL;
return lp;
}
2、摧毀一個鏈隊列
[cpp] view
plain copy
void DestroyLinkqueue(linkqueue_t *queue)
{
if(queue != NULL)
{
ClearLinkqueue(queue);
free(queue);
}
}
3、清空一個鏈隊列
[cpp] view
plain copy
void ClearLinkqueue(linkqueue_t *queue)
{
linknode_t *qnode;
while(q->front)
{
qnode = queue->front;
queue->front= qnode->next;
free(qnode);
}
queue->rear = NULL;}
4、判斷鏈隊列為空
[cpp] view
plain copy
int EmptyLinkqueue(linkqueue_t *queue)
{
if(queue == NULL)
return -1;
return(queue->front == queue->rear ? 1 : 0);
}
5、入隊
[cpp] view
plain copy
int EnQueue(linkqueue_t *queue,data_t x)
{
linknode_t *node_new;
if(queue == NULL)
return -1;
node_new = (linknode_t *)malloc(sizeof(linknode_t));
if(node_new == NULL)
return -1;
node_new->data = x;
node_new->next = NULL;
if(queue->front->next == NULL)
{
queue->front->next = queue->rear = node_new;
}
else
{
queue->rear->next = node_new;
queue->rear = node_new;
}
return 0;
}
6、出隊
[cpp] view
plain copy
int DeQueue(linkqueue_t *queue,data_t *x)
{
linknode_t *node_remove;
if(queue == NULL || queue->front->next == NULL)
return -1;
node_remove = queue->front->next;
queue->front->next = node_remove->next;
if(x != NULL)
*x = node_remove->data;
free(node_remove);
return 0;
}
Copyright © Linux教程網 All Rights Reserved