數據結構——隊列的學習

一、什麼是隊列

  1. 隊列實際上就是隻能在一端插入(隊尾),在另一端(隊頭)刪除(出隊)的特殊線性表;

二、隊列特點

  1. 只允許在一端進行插入操作,一端進行刪除操作,即入隊、出隊。
  2. 有先進先出(FIFO)的特性;
  3. 我們熟知的鍵盤緩衝區就用隊列實現的(scanf函數就有運用這種特性);
  4. 對於隊列可以順序存儲,也可以鏈式存儲;
三、代碼實例

1、鏈式存儲:實現簡單的隊列創建,入隊、出隊、打印隊列數據等操作;
#include <stdio.h>
#include <stdlib.h>

#define ElemType int

typedef struct QNode{
    ElemType data;
    struct QNode* next;
}QNode_t,*P_QNode_t;

typedef struct Queue{
    P_QNode_t front,rear;
}Queue,*LinkQueue;

void queue_creat(LinkQueue q);
void queue_insert(LinkQueue q,ElemType e);
ElemType queue_out(LinkQueue q);
void queue_show(LinkQueue q);

int main()
{
    int i;
    Queue q;
    queue_creat(&q);
    for(i=1;i<=5;i++)
    {
        queue_insert(&q,i);
    }
    queue_show(&q);
    printf("\noutput operation:\n");
    printf("the number is %d\n",queue_out(&q));
    printf("the number is %d\n",queue_out(&q));
    queue_show(&q);
    return 0;
}

/*創建隊列*/
void queue_creat(LinkQueue q)
{
    q->front=q->rear=(P_QNode_t)malloc(sizeof(QNode_t));/*front指針指向的是一個頭節點,這個節點只是爲了方便操作而創建的,也可不用頭節點*/
    if(!q->front)
    {
        printf("create failed\n");
        exit(0);
    }
    q->front->next=NULL;
}

/*入隊操作,從隊尾進入*/
void queue_insert(LinkQueue q,ElemType e)
{
    /*先創建一個節點,該節點含有數據和指針*/
    P_QNode_t q_node=(P_QNode_t)malloc(sizeof(struct QNode));
    if(!q_node)
    {
        printf("node create failed\n");
        exit(0);
    }
    /*給節點賦值*/
    q_node->data=e;
    q_node->next=NULL;
    q->rear->next=q_node;
    q->rear=q_node;
}

/*出隊操作:出隊操作,從隊頭出隊,即時頭節點中next指向的節點出隊,因此出隊後頭節點中的next指針指向第二個節點*/
/*出隊時要判斷隊列是否爲空,*/
ElemType queue_out(LinkQueue q)
{
    ElemType value;
    P_QNode_t p;
    if(q->front==q->rear)
    {
        printf("queue is empty\n");
        return -1;
    }
    p=q->front->next;
    value=p->data;
    q->front->next=p->next;
    /*當只有一個節點時,即rear指向的節點,出棧之後該棧爲空,k*/
    if(q->rear==p)
    {
        q->rear=q->front;
    }
    free(p);
    return value;
}
void queue_show(LinkQueue q)
{
    P_QNode_t p=q->front->next;
    if(q->front!=q->rear)
    {
        while(p->next)
        {
            printf("%d ",p->data);
            p=p->next;
        }
        printf("%d ",p->data);
    }
    else
        printf("is empty\n");

}


2、順序存儲:實現簡單的隊列創建,入隊、出隊、打印隊列數據等操作;

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXSIZE 20
typedef int data_t;
typedef struct
{
    data_t data[MAXSIZE];
    int front,rear;
}queue_t,*p_queue_t;

p_queue_t queue_create();
bool is_full(p_queue_t q);
void in_queue(data_t data,p_queue_t q);
bool is_empty(p_queue_t q);
void out_queue(p_queue_t q,data_t *data);
void queue_show(p_queue_t q);

int main()
{
    int i;
    p_queue_t q;
    q=queue_create();
    in_queue(1,q);
    in_queue(2,q);
    in_queue(5,q);
    in_queue(11,q);
    in_queue(5,q);
    in_queue(8,q);
    in_queue(5,q);
    queue_show(q);
    out_queue(q,&i);
    printf("%d\n",i);
    queue_show(q);
    out_queue(q,&i);
    printf("%d\n",i);
    queue_show(q);
    return 0;
}
p_queue_t queue_create()
{
    p_queue_t q;
    q=(p_queue_t)malloc(sizeof(queue_t));
    if(q==NULL)
    {
        printf("error\n");
        exit(-1);
    }
    q->front=q->rear=MAXSIZE-1;
    return q;
}
bool is_full(p_queue_t q)
{
    if((q->rear+1)%MAXSIZE==q->front)
        return true;
    else
        return false;
}
void in_queue(data_t data,p_queue_t q)
{
    if(is_full(q))
    {
        printf("q is full\n");
        return ;
    }
    q->rear=(q->rear+1)%MAXSIZE;
    q->data[q->rear]=data;

}
bool is_empty(p_queue_t q)
{
    if(q->rear==q->front)
        return true;
    else
        return false;
}
void out_queue(p_queue_t q,data_t *data)
{
    if(is_empty(q))
    {
        printf("q is empty\n");
        return;
    }
    q->front=(q->front+1)%MAXSIZE;
    *data=q->data[q->front];
}
void queue_show(p_queue_t q)
{
    int i;
    for(i=(q->front+1)%MAXSIZE;i!=(q->rear+1)%MAXSIZE;i++)
    {
        printf("%d\t",q->data[i]);
    }
    printf("\n");
}



隊列的順序存儲結構

在現實中也是如此,一羣人在排隊買火車票,前邊的人買好了離開,後面的人就要全部向前一步補上空位。

可是我們研究數據結構和算法的一個根本目的就是要想方設法提高我們的程序的效率,按剛纔的方式,出隊列的時間複雜度是O(n),效率大打折扣!

如果我們不去限制隊頭一定要在下標爲0的位置,那麼出隊列的操作就不需要移動全體元素。

但是這樣也會出現一些問題,會出現數組越界的錯誤。所以引出了循環隊列


循環隊列定義

循環隊列它的容量是固定的,並且它的隊頭和隊尾指針都可以隨着元素入出隊列而發生改變,這循環隊列邏輯上就好像是一個環形存儲空間。但要注意的是,在實際的內存當中,不可能有真正的環形存儲區,我們只是用順序表模擬出來的邏輯上的循環。

似乎循環隊列的實現只需要靈活改變front和rear指針即可。

也就是讓front或rear指針不斷加1,即時超出了地址範圍,也會自動從頭開始。我們可以採取取模運算處理:

(rear+1) % QueueSize

(front+1) % QueueSize

 

取模就是取餘數的意思,他取到的值永遠不會大於除數,大家結合實例拿張紙算一算就知道啦~


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