標籤:

C語言實現數據結構-隊列

隊列 (Queue):簡稱隊,是另一種限定性的線性表,它只允許在表的一端插入元素,而在另一端刪除元素。q=(a1, a2, a3, … an),其中a1為隊頭,an為隊尾。

隊列在生活中也比較常見,例如購物排隊——新來的成員總是加入隊尾,每次離開的成員總是隊列頭上的。

隊列按存儲方式可以分為兩種:順序隊列和鏈隊列。

鏈隊列

鏈式隊列中每個元素定義成一個結點,含數據域與指針域(指向下一結點),並設頭尾指針。用圖表示就是。

鏈隊的表示

前面的鏈式結構,總是使用一個結點的結構來表示鏈表,但是在這裡使用新的存儲結構。定義一個結點結構,和一個隊列結構。兩個結構嵌套。

//定義節點結構ntypedef struct QNoden{n QElemType data; /*數據域*/n struct QNode * next; /*指針域*/n }QNode, *QueuePtr;n//定義隊列結構n typedef structn {n QueuePtr front;n QueuePtr rear;n }LinkQueue;n

鏈隊的基本操作

1. 鏈隊的初始化

Status initQueue(LinkQueue *Q)n{ n Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));n if(!Q.front) exit(OVERFLOW);n Q.front->next = NULL;n return OK;n}n

2. 鏈隊的銷毀

Status destroyQueue(LinkQueue *Q)n{n while (Q.front)n {n Q.rear = Q.front->next;n free(Q.front);n Q.front = Q.rear;n }n return OK;n}n

3. 入隊

Status enQueue(LinkQueue *Q, QElemType e)n{n QueuePtr p = (QueuePtr)malloc(sizeof(QNode));n if(!p) exit(OVERFLOW);n //插入數據n p->data = e;n p->next = NULL;n //Q.rear一直指向隊尾n Q.rear->next = p;n Q.rear = p;n return OK;n }n

4. 出隊

Status deQueue(LinkQueue *Q, QElemType e)n{n if(Q.front == Q.rear) return ERROR;n QueuePtr p = Q.front->next;n e = p->data;n Q.front->next = p->next; //隊頭元素p出隊n if(Q.rear == p) //如果隊中只有一個元素p, 則p出隊後成為空隊n Q.rear = Q.front; //給隊尾指針賦值n free(p); //釋放存儲空間n return OK;n}n

順序隊列

用一組連續的存儲單元依次存放隊列的元素,並設兩個指針front、rear分別指示隊頭和隊尾元素的位置。

front:指向實際的隊頭;rear:指向實際隊尾的下一位置。

初態:front=rear=0;隊空:front=rear;隊滿:rear=M;

入隊:q[rear]=x; rear= rear+1; 出隊:x=q[front];front=front+1;

順序隊列的表示

#define MAXQSIZE 100ntypedef structn{n QElemType *base;n int front; //頭指針指示器 n int rear; //尾指針指示器n} SqQueue;n

存在的問題

隨著入隊、出隊操作的進行,整個隊列會整體向後移動,這樣就出現了下圖的現象:隊尾指針雖然已經移到了最後,而隊列卻未真滿的「假溢出」現象,使得隊列的空間沒有得到有效的利用

那我們該如何解決假溢出的問題呢?

有以下兩種方法:

  1. 將隊中元素向隊頭移動

    當移動數據較多時將會影響隊列的操作速度。
  2. 採用循環隊列:Q[0]接在Q[MAXQSIZE-1]之後

    一個更有效的方法是將隊列的數據區Q[0 .. MAXQSIZE-1]看成是首尾相連的環,即將表示隊首的元素Q[0]與表示隊尾的元素Q[MAXQSIZE–1]連接起來,形成一個環形表,這就成了循環隊列。當Q.rear=MAXQSIZE-1時再入隊,令Q.rear=0, 則可以利用已被刪除的元素空間。如下圖。

循環隊列

在循環隊列中,不可以根據等式front == rear可以判別隊滿和隊空。因為此時條件是相同的,解決這種問題的方法一般有兩種。

  1. 少用(損失)一個空間,以尾指針加1等於頭指針作為隊滿的標誌。因此:當front==rear,表示循環隊列為空;當front ==(rear+1)% MAXLEN,表示循環隊列為滿。
  2. 在定義結構體時,附設一個存儲循環隊列中元素個數的變數n,當n==0時表示隊空;當n==MAXLEN時為隊滿。

循環隊列的基本操作

1. 初始化

Status initQueue (SqQueue *Q)n{n Q.base=(QElemType *) malloc(MAXQSIZE * sizeof(QElemType));n if (!Q.base) exit(OVERFLOW);n Q.front = Q.rear = 0;n return OK;n}n

2. 求隊列長度

int queueLength(SqQueue *Q)n{n return (Q.rear - Q.front+MAXQSIZE) % MAXQSIZE;n}n

3. 入隊

Status enQueue (SqQueue *Q, QElemType e)n{n if((Q.rear+1)%MAXQSIZE == Q.front) return ERROR;n Q.base[Q.rear] = e;n Q.rear = (Q.rear+1) % MAXQSIZE;n return OK;n}n

4. 出隊

Status deQueue (SqQueue *Q, QElemType e)n{n if(Q.front == Q.rear)n return ERROR;n e = Q.base[Q.front];n Q.front = (Q.front+1)%MAXQSIZE;n return OK;n}n

歡迎指正 orz…


推薦閱讀:

九章演算法 | Snapchat 面試題 : 青蛙跳
九章演算法 | Google 2016 面試題7:翻轉遊戲(Flip Game II)
九章演算法 | Facebook面試題3 : Search a 2D Matrix II
九章演算法 | Google面試題 : 路線重現
Python中list的內存增長模型有何理論依據?

TAG:数据结构 |