鏈隊列

哎,又是大家,都快雙11了,打賞一下小編吧。(另外發現多行空格打字好像不能表示,因此這裏就把代碼塗紅了,有點鮮豔,-_-)node

言歸正傳,今天咱們講講鏈隊列,頭文件那些上次講過了,差很少,我就再也不贅述了。數組

咱們先講講隊列的特性:先進先出數據結構

(這裏說一下,此圖取自Leetcode)函數

 

在 FIFO 數據結構中,將首先處理添加到隊列中的第一個元素。
spa

如上圖所示,隊列是典型的 FIFO 數據結構。插入(insert)操做也稱做入隊(enqueue),新元素始終被添加在隊列的末尾。 刪除(delete)操做也被稱爲出隊(dequeue)。 你只能移除第一個元素。
指針

爲了實現插入和刪除操做,咱們須要用到一個數組來存儲元素和指針移到,另外還須要兩個指針front和rear來表示隊列的頭部和尾部(因此其實咱們能夠把它當成循環隊列來理解。)code

那麼目標明確了,就先定義結構體了。對象

 

typedef struct node
{
  elemtype data;                             //元素
  struct node *next;                         //移到的指針設置
}QNode,*queuenode;                          //QNode是數組,後面那個就是數組的指針形式了,能夠這麼理解的,名稱本身隨意了,最好是能表達意思的那種
typedef struct
{
  queuenode front, rear;                  //這裏的定義實際上是多變的,可是歸根結底仍是要把這兩個設置爲指針型。
}linkqueue;                                           //這裏的定義其實也是多變的,你能夠定義爲指針型,都OK的,可是數組簡單一點,就這樣了。blog

1,插入(也就是入隊)隊列

這裏補充一下,爲何今天沒有定義函數了呢,由於隊列的定義相對簡單,直接在主函數裏實現就行了。(但仍是要儘量的保持主函數的簡潔性)

再來剖析一下入隊操做:1,基礎的分配空間;2,插入必備的賦值,和地址轉換

 

status enqueue(linkqueue *Q, elemtype e){                    //可能有同窗會問,爲何個人是*Q,由於我上面的第二個數組我只設置了數組類型名,我想用地址來作,因此就加*號了,這裏看你們習慣了。除此以外,我這裏講一下,不知道講過沒有,仍是講一下,數  組的指針的引用區別:數組是加「.」 ,而指針則是用「->」 。
queuenode p;
p=(queuenode) malloc (sizeof (QNode));
if(!p) exit (ERROR);
p->data = e;
p->next = NULL;                                                              //你們尚未忘記咱們上面放的那個圖吧,隊列是先進先出,因此它的插入都是插在後面,也就是說插進來的那個元素的next始終指向NULL。
Q->rear->next = p;                                                           //這裏有沒有那個小夥伴有問題的啊,好,沒有,下一個
Q->rear = p;                                                                      //開玩笑開玩笑,爲何這裏會用rear呢,按理來講,插入不是應該要頭結點的next嗎?你們再好好想想咱們一開始的那個圖,隊列是先進先出,也就是說只有隊尾是在移動的,是可以用了插入的,你一直用front那豈不是每次插入的都是同一個位置,是吧,固然,你能夠再中間斷開,但那樣麻煩的十我是不會作的。
return OK;                                                                          //想必有小夥伴已經發現了一個問題了,嘿嘿,我先不說
}

 

2,刪除(也就是出隊)

剖析剖析,刪除之基本操做:1,彈出去一個元素,其餘的補上去,呸,我呸,知不知道那樣的時間複雜度爲O(n),隊列隊列,一開始設置那個頭結點用來幹什麼的,好看的嗎(固然不包括上面發現問題的同窗們的那個東西),這時咱們就能夠經過移動頭結點來進行刪除操做了,這樣的時間複雜度就少了太多了,2,切記要free空間,雖然系統本身會清理掉,但寫出來就是加分項哦

 

status dequeue(linkqueue *Q, elemtype *e){                        //Q我無論大家怎麼定義了,可是e必定要用指針,其實要做出改變的對象應該都要用*的,也就是指了(好習慣)
queuenode p;
if(Q->front == Q->rear) return ERROR;                                 //好了好了,如今咱們來講說上面發現的那個問題,我一開始是否是說了這是一個循環隊列,循環循 環,那是否是總有一天front會跟rear碰上,這就是一個目前爲止最能體現出插人函數分配空間的用處的了,由於每次插入,咱們都會給它分配空間,因此它是能夠無限插入直到電腦不行了的。

                                                                                                //那碰上了,怎麼辦。碰上了就表明到頭了,也就是循環一遍了,那刪除一開始,還沒開始動,就頭了,那確定就是一個空隊列了,就要退出了。
p = Q->front->next;                                                                  //移移移移動頭結點
*e = p->data;
Q->front->next = p->next;                                                        //這裏是必需要指一下next的哦,你們還記得鏈表嗎,頭結點位於第一個元素前面一點點
if(Q->rear ==p)Q->rear = Q->front;                                          //這裏是什麼意思,就是表明着隊列裏只有一個元素
free(p);
return OK;
}

好了好了,插入和刪除就到這裏結束了,再給你們講一下print函數吧

剖析again,怎麼輸出呢,有不少方法:1,從頭結點開始遍歷,2,咱們一開始不是有定義一個數組嗎,能夠經過數組輸出,3,由於是循環隊列,從隊尾開始也是OK的。(這裏講講第一種,比較經常使用的)

 

void printf_Q(linkqueue Q){
int i;
Q.front=Q.front->next;                                          //注意一開始必需要指一下next,緣由上面講過了
if(Q.front==Q.rear) return ERROR;                      //同樣的,空就退出
for(i=0;;i++){
printf("%d ",Q.front->data);                                   //輸出就很簡單了,由於結點也是定義的數組指針,因此直接值向data就行了
if(Q.front!=Q.rear)                                                 //直到他們碰上,就表明已經循環了一遍了
Q.front=Q.front->next;
else
break;
}

}

老師還有佈置一個返回長度的函數吧,那個跟print其實差很少,就不贅述了。

附:主函數:

void main()
{
QNode Q0; linkqueue Q; elemtype x;
Q0.next=NULL;
Q.front=&Q0; Q.rear=&Q0;
enqueue(&Q,3); enqueue(&Q,55); enqueue(&Q,2); enqueue(&Q,9); enqueue(&Q,7);
enqueue(&Q,32); enqueue(&Q,66);
printf("長度爲:%d, 元素爲:", length_Q(Q));printf_Q(Q);
dequeue(&Q,&x); dequeue(&Q,&x);
printf("\n長度爲:%d, 元素爲:", length_Q(Q));printf_Q(Q);
enqueue(&Q,77);
printf("\n長度爲:%d, 元素爲:", length_Q(Q));printf_Q(Q);
}

 

你們,下次再見吧(再說)!!!

相關文章
相關標籤/搜索