【隊列】隊列(queue)原理


像棧一樣,隊列(queue)也是一種線性表,它的特性是先進先出,插入在一端,刪除在另一端。就像排隊一樣,剛來的人入隊(push)要排在隊尾(rear),每次出隊(pop)的都是隊首(front)的人。如圖1,描述了一個隊列模型。

 

隊列(Queue)與棧一樣,是一種線性存儲結構,它具有如下特點:

  1. 隊列中的數據元素遵循“先進先出”(First In First Out)的原則,簡稱FIFO結構。
  2. 在隊尾添加元素,在隊頭刪除元素。
 

1.2 隊列的相關概念

隊列的相關概念:

  1. 隊頭與隊尾: 允許元素插入的一端稱為隊尾,允許元素刪除的一端稱為隊頭。
  2. 入隊:隊列的插入操作。
  3. 出隊:隊列的刪除操作。

例如我們有一個存儲整型元素的隊列,我們依次入隊:{1,2,3}

添加元素時,元素只能從隊尾一端進入隊列,也即是2只能跟在1后面,3只能跟在2后面。
如果隊列中的元素要出隊:

元素只能從隊首出隊列,出隊列的順序為:1、2、3,與入隊時的順序一致,這就是所謂的“先進先出”。

1.3 隊列的操作

隊列通常提供的操作:

  1. 入隊: 通常命名為push()
  2. 出隊: 通常命名為pop()
  3. 求隊列中元素個數
  4. 判斷隊列是否為空
  5. 獲取隊首元素

1.4 隊列的存儲結構

隊列與棧一樣是一種線性結構,因此以常見的線性表如數組、鏈表作為底層的數據結構。
本文中,我們以數組、鏈表為底層數據結構構建隊列。

 

2.基於數組的循環隊列實現

以數組作為底層數據結構時,一般講隊列實現為循環隊列。這是因為隊列在順序存儲上的不足:每次從數組頭部刪除元素(出隊)后,需要將頭部以后的所有元素往前移動一個位置,這是一個時間復雜度為O(n)的操作:

可能有人說,把隊首標志往后移動不就不用移動元素了嗎?的確,但那樣會造成數組空間的“流失”。
我們希望隊列的插入與刪除操作都是O(1)的時間復雜度,同時不會造成數組空間的浪費,我們應該使用循環隊列。
所謂的循環隊列,可以把數組看出一個首尾相連的圓環,刪除元素時將隊首標志往后移動,添加元素時若數組尾部已經沒有空間,則考慮數組頭部的空間是否空閑,如果是,則在數組頭部進行插入。

 

C語言實現:數組實現的隊列,並且只能存儲int數據

 

C語言數組實現隊列一(數組模擬):

 

#include <stdio.h>

/**
 * C 語言: 數組實現的隊列,只能存儲int數據。
 *
 * @author llz
 * @date 2018/7/02
 */

// 保存數據的數組
int arr[500];
// 隊列的實際大小
int count;


// 將val添加到隊列的末尾
void add(int val) 
{
    arr[count++] = val;
}

// 返回“隊列開頭元素”
int front() 
{
    return arr[0];
}

// 返回並刪除“隊列開頭元素”
int pop() 
{
    int i = 0;;
    int ret = arr[0];
    count--;
    while (i++<count)
        arr[i-1] = arr[i];
    return ret;
}

// 返回“隊列”的大小
int size() 
{
    return count;
}

// 返回“隊列”是否為空
int is_empty()
{
    return count==0;
}

int main() 
{
    int tmp=0,i;
    
    // 打印隊列
    for(i=0;i<size();i++)printf("%d ",arr[i]);
    printf("\n");
    
    // 將10, 20, 30 依次推入隊列中
    add(10);
    add(20);
    add(30);
    
    for(i=0;i<size();i++)printf("%d ",arr[i]);
    printf("\n");

    // 將“隊列開頭的元素”賦值給tmp,並刪除“該元素”
    tmp = pop();
    printf("tmp=%d\n", tmp);
    

    // 只將“隊列開頭的元素”賦值給tmp,不刪除該元素.
    tmp = front();
    printf("tmp=%d\n", tmp);

    add(40);

    // 打印隊列
    printf("is_empty()=%d\n", is_empty());
    printf("size()=%d\n", size());
    while (!is_empty())
    {
        printf("%d\n", pop());
    }
    return 0;

}

 

結果說明:該示例中的隊列,是通過"數組"來實現的!
由於代碼中已經給出了詳細了注釋,這里就不再對函數進行說明了。僅對主函數main的邏輯進行簡單介紹。
(01) 在主函數main中,先將 "10, 20, 30"依次入隊列。此時,隊列的數據是: 10 --> 20 --> 30 
(02) 接着通過pop()返回隊首元素;pop()操作並不會改變隊列中的數據。此時,隊列的數據依然是: 10 --> 20 --> 30 
(03) 接着通過front()返回並刪除隊首元素。front()操作之后,隊列的數據是: 10 --> 30 
(04) 接着通過add(40)將40入隊列。add(40)操作之后,隊列中的數據是: 10 --> 20 --> 40

 

C語言數組實現隊列二(數組模擬+隊頭隊尾指針+循環隊列):

 

#include <stdio.h>

/**
 * C 語言: 數組實現的隊列,只能存儲int數據。
 *
 * @author llz
 * @date 2018/7/02
 
 */

// 保存數據的數組
int arr[50];
// 隊列的實際大小
int count;

//隊頭和隊尾下標 
int front;
int tail; 


int size()
{
    return tail-front;
}

// 返回“隊列”是否為空
int is_empty()
{
    if(front==tail) return 1;
    return 0;
}
// 返回“隊列”是否為滿
int is_full()
{
    if(front==(tail+1)%50) return 1;
    return 0;
}
// 將val添加到隊列的末尾
void add(int val) 
{
    if(!is_full()) 
    {
        arr[tail] = val;
        tail=(tail+1)%50;
    }
     else
    {
        printf("隊列滿\n");
    }
}

// 返回“隊列開頭元素”
int first() 
{
    return arr[front];
}




// 返回並刪除“隊列開頭元素”
int pop() 
{
    int ret;
    if(!is_empty())
    {
        
        ret=arr[front] ;
        front=(front+1)%50;
    }
     else
    {
        printf("隊列空\n");
    }
    return ret;
}





int main() 
{
    int tmp=0,i;
    
    //輸出隊列中的每個元素 
    for(i=0;i<size();i++)printf("%d ",arr[i]);
       printf("\n");
    
    // 將10, 20, 30 依次推入隊列中
    add(10);
    add(20);
    add(30);
    
    for(i=0;i<size();i++)printf("%d ",arr[i]);
    printf("\n");

    // 將“隊列開頭的元素”賦值給tmp,並刪除“該元素”
    tmp = pop();
    printf("tmp=%d\n", tmp);
    

    // 只將“隊列開頭的元素”賦值給tmp,不刪除該元素.
    tmp = first();
    printf("tmp=%d\n", tmp);

    add(40);

    // 打印隊列
    printf("is_empty()=%d\n", is_empty());
    //printf("size()=%d\n", size());
    while (!is_empty())
    {
        printf("%d\n", pop());
    }
    return 0;

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM