自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

就幾幅圖,能干趴隊(duì)列?

開(kāi)發(fā) 前端
今天繼續(xù)來(lái)給大家上一盤(pán)硬菜,保證喂個(gè)半飽——嗝。和棧一樣,隊(duì)列(queue)也是一個(gè)非常有用的數(shù)據(jù)結(jié)構(gòu)。同時(shí)又非常特殊,它只允許在隊(duì)尾(rear)插入元素,在隊(duì)首(front)刪除元素,也就是一端進(jìn),一端出。

[[385574]]

今天繼續(xù)來(lái)給大家上一盤(pán)硬菜,保證喂個(gè)半飽——嗝。和棧一樣,隊(duì)列(queue)也是一個(gè)非常有用的數(shù)據(jù)結(jié)構(gòu)。同時(shí)又非常特殊,它只允許在隊(duì)尾(rear)插入元素,在隊(duì)首(front)刪除元素,也就是一端進(jìn),一端出。

在網(wǎng)上購(gòu)票普及之前,我們大多數(shù)人需要到車(chē)站的購(gòu)票大廳買(mǎi)票,經(jīng)常是排隊(duì)排到水泄不通,queue 就和現(xiàn)實(shí)中的排隊(duì)是一模一樣的,排在隊(duì)首的先買(mǎi)到票,然后離開(kāi),緊跟著的人移動(dòng)到隊(duì)首,直到隊(duì)列消失。

隊(duì)列遵循的是 First In First Out,縮寫(xiě)為 FIFO,也就是先進(jìn)先出,第一個(gè)進(jìn)入隊(duì)列的第一個(gè)先出來(lái)。

 

在上面這幅圖中,1 比 2 先進(jìn)入隊(duì)列,也比 2 先出隊(duì)列,規(guī)規(guī)矩矩的。

對(duì)于隊(duì)列這樣一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)說(shuō),它有兩個(gè)常見(jiàn)的動(dòng)作:

  • enqueue,我個(gè)人喜歡把它譯作入隊(duì),指的是把元素放入隊(duì)列這個(gè)動(dòng)作。
  • dequeue,出隊(duì),指的是把元素從隊(duì)列中移除這個(gè)動(dòng)作。

明白了隊(duì)列的基本操作后,我們來(lái)深入地思考一下,隊(duì)列是如何工作的。

1) 建立順序的隊(duì)列結(jié)構(gòu)需要為其靜態(tài)分配或者動(dòng)態(tài)申請(qǐng)一串連續(xù)的存儲(chǔ)空間。

2)然后設(shè)置兩個(gè)指針進(jìn)行管理:一個(gè)隊(duì)首指針 FRONT,指向隊(duì)首的元素,一個(gè)隊(duì)尾指針 REAR,指向隊(duì)尾的元素。初始化的時(shí)候,F(xiàn)RONT 和 REAR 都設(shè)置為 -1。

3)入隊(duì)時(shí)

檢查隊(duì)列是否已經(jīng)滿(mǎn)了,需要一個(gè) isFull() 的方法來(lái)判斷;

對(duì)于第一個(gè)元素,設(shè)置 FRONT 的值為 0;

每次在隊(duì)尾插入一個(gè)元素時(shí),REAR 加 1,然后把隊(duì)尾的元素指向 REAR。

4)出隊(duì)時(shí)

檢查隊(duì)列是否為空,需要一個(gè) isEmpty() 的方法來(lái)判斷;

用一個(gè)臨時(shí)變量來(lái)保存隊(duì)首的元素,以便出隊(duì)后返回;

每次在隊(duì)首刪除一個(gè)元素時(shí),F(xiàn)RONT 加 1;

如果是最后一個(gè)元素,重置 FRONT 和 REAR 為 -1。

 

隊(duì)列為空的時(shí)候,F(xiàn)RONT 和 REAR 等于 -1;把元素 1 入隊(duì)的時(shí)候,F(xiàn)RONT 變?yōu)?1,REAR 加 1 變?yōu)? 0,queue[FRONT]=queue[REAR] 為 1;把元素 2 入隊(duì)的時(shí)候,REAR 加 1 變?yōu)?1,queue[REAR] 為 2,queue[FRONT] 仍然為 1;接著,元素 3 入隊(duì);元素 4 入隊(duì);元素 5 入隊(duì),REAR 變?yōu)?4,queue[REAR] 為 5,queue[FRONT] 仍然為 1。

元素 1 出隊(duì)的時(shí)候,F(xiàn)RONT 為 0,queue[FRONT] 為 1,然后 FRONT 加 1 變?yōu)?1;元素 2 出隊(duì)的時(shí)候,queue[FRONT] 為 2,然后 FRONT 加 1 變?yōu)?2;接著,元素 3 出隊(duì);元素 4 出隊(duì);元素 5 出隊(duì)的時(shí)候,queue[FRONT] 為 5,F(xiàn)RONT 為 4,REAR 為 4,出隊(duì)后,F(xiàn)RONT 和 REAR 重設(shè)為 -1。

假設(shè)隊(duì)列中的元素為 int 類(lèi)型,隊(duì)列的大小為 5,我們可以用 Java 語(yǔ)言來(lái)自定義一個(gè)最簡(jiǎn)單的 queue。它需要 3 個(gè)字段:

  • int queue[],一個(gè) int 類(lèi)型的數(shù)組,來(lái)存放數(shù)據(jù)
  • int front,一個(gè) int 類(lèi)型的隊(duì)首標(biāo)記
  • int rear,一個(gè) int 類(lèi)型的隊(duì)尾標(biāo)記
  1. class Queue { 
  2.     int SIZE = 5; 
  3.     int items[] = new int[SIZE]; 
  4.     int front, rear; 

初始化隊(duì)列:

  1. Queue() { 
  2.     front = -1; 
  3.     rear = -1; 

入隊(duì):

  1. void enQueue(int element) { 
  2.     if (isFull()) { 
  3.         System.out.println("隊(duì)列已經(jīng)滿(mǎn)了"); 
  4.     } else { 
  5.         if (front == -1) 
  6.             front = 0; 
  7.         rear++; 
  8.         items[rear] = element; 
  9.         System.out.println("插入 " + element); 
  10.     } 

出隊(duì):

  1. int deQueue() { 
  2.     int element; 
  3.     if (isEmpty()) { 
  4.         System.out.println("隊(duì)列空了"); 
  5.         return (-1); 
  6.     } else { 
  7.         element = items[front]; 
  8.         if (front >= rear) { 
  9.             front = -1; 
  10.             rear = -1; 
  11.         } 
  12.         else { 
  13.             front++; 
  14.         } 
  15.         System.out.println("刪除 -> " + element); 
  16.         return (element); 
  17.     } 

檢查隊(duì)列是否已經(jīng)滿(mǎn)了:

  1. boolean isFull() { 
  2.     if (front == 0 && rear == SIZE - 1) { 
  3.         return true
  4.     } 
  5.     return false

檢查隊(duì)列是否為空:

  1. boolean isEmpty() { 
  2.     if (front == -1) 
  3.         return true
  4.     else 
  5.         return false

來(lái)個(gè) main() 方法測(cè)試下:

  1. void display() { 
  2.     int i; 
  3.     if (isEmpty()) { 
  4.         System.out.println("隊(duì)列為空"); 
  5.     } else { 
  6.         System.out.println("\n隊(duì)首的下標(biāo)-> " + front); 
  7.         System.out.println("元素 -> "); 
  8.         for (i = front; i <= rear; i++) 
  9.             System.out.print(items[i] + "  "); 
  10.  
  11.         System.out.println("\n隊(duì)尾的下標(biāo)-> " + rear); 
  12.     } 
  13.  
  14. public static void main(String[] args) { 
  15.     Queue q = new Queue(); 
  16.  
  17.     // 隊(duì)列為空的時(shí)候不允許出隊(duì) 
  18.     q.deQueue(); 
  19.  
  20.     // enQueue 5 elements 
  21.     q.enQueue(1); 
  22.     q.enQueue(2); 
  23.     q.enQueue(3); 
  24.     q.enQueue(4); 
  25.     q.enQueue(5); 
  26.  
  27.     // 隊(duì)列滿(mǎn)了的時(shí)候不允許入隊(duì) 
  28.     q.enQueue(6); 
  29.  
  30.     q.display(); 
  31.  
  32.     // 出隊(duì) 
  33.     q.deQueue(); 
  34.  
  35.     // 打印 
  36.     q.display(); 

打印結(jié)果如下所示:

  1. 隊(duì)列空了 
  2. 插入 1 
  3. 插入 2 
  4. 插入 3 
  5. 插入 4 
  6. 插入 5 
  7. 隊(duì)列已經(jīng)滿(mǎn)了 
  8.  
  9. 隊(duì)首的下標(biāo)-> 0 
  10. 元素 ->  
  11. 1  2  3  4  5   
  12. 隊(duì)尾的下標(biāo)-> 4 
  13. 刪除 -> 1 
  14.  
  15. 隊(duì)首的下標(biāo)-> 1 
  16. 元素 ->  
  17. 2  3  4  5   
  18. 隊(duì)尾的下標(biāo)-> 4 

隊(duì)列空了插入 1插入 2插入 3插入 4插入 5隊(duì)列已經(jīng)滿(mǎn)了隊(duì)首的下標(biāo)-> 0元素 -> 1 2 3 4 5 隊(duì)尾的下標(biāo)-> 4刪除 -> 1隊(duì)首的下標(biāo)-> 1元素 -> 2 3 4 5 隊(duì)尾的下標(biāo)-> 4

好了,這種基本的隊(duì)列已經(jīng)可以正常工作了,但它有一個(gè)問(wèn)題:當(dāng)已經(jīng)出隊(duì)了 N 個(gè)元素后,按理說(shuō),應(yīng)該可以再入隊(duì) N 個(gè)元素,對(duì)吧?因?yàn)槭〕鰜?lái)了 N 個(gè)空間嘛。

  1. Queue q = new Queue(); 
  2.  
  3. // enQueue 5 elements 
  4. q.enQueue(1); 
  5. q.enQueue(2); 
  6. q.enQueue(3); 
  7. q.enQueue(4); 
  8. q.enQueue(5); 
  9.  
  10. // 出隊(duì) 
  11. q.deQueue(); 
  12. q.deQueue(); 
  13.  
  14. q.enQueue(6); 
  15. q.enQueue(7); 

但事實(shí)上,這段代碼在運(yùn)行的時(shí)候報(bào)錯(cuò)了:

  1. 插入 1 
  2. 插入 2 
  3. 插入 3 
  4. 插入 4 
  5. 插入 5 
  6. 刪除 -> 1 
  7. 刪除 -> 2 
  8. Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 
  9.  at com.itwanger.queue.Queue.enQueue(Queue.java:23) 
  10.  at com.itwanger.queue.Queue.main(Queue.java:89) 

看見(jiàn) ArrayIndexOutOfBoundsException 我們就知道,數(shù)組越界了。這是因?yàn)槲覀兪怯脭?shù)組實(shí)現(xiàn)的隊(duì)列,在出隊(duì)的時(shí)候 REAR 并沒(méi)有減小,導(dǎo)致入隊(duì)的時(shí)候 items[rear++]超出了數(shù)組的邊界。

可以把問(wèn)題歸咎于我們實(shí)現(xiàn)隊(duì)列的方式上,也可以淺顯地認(rèn)為基本類(lèi)型的隊(duì)列存在有局限性。隨著入隊(duì)和出隊(duì)的連續(xù)操作,隊(duì)列中的元素在不停地變化,隊(duì)列所占的存儲(chǔ)空間也在分配的連續(xù)空間中不停的移動(dòng)。

當(dāng) REAR 增加到超出數(shù)組大小的范圍之后,隊(duì)列就無(wú)法添加新的元素了,事實(shí)上還有很多空間可以利用,但它們?nèi)匀槐灰殉鲫?duì)的元素占用著——正所謂“附身”啊。除非所有的元素均被移除后, FRONT 和 REAR 被重置,隊(duì)列才能重新使用。

由于基本類(lèi)型的隊(duì)列存在這種局限性,我們就迫切的需要一種新型隊(duì)列的出現(xiàn)——環(huán)形隊(duì)列(Circular queue) 就閃亮登場(chǎng)了。

 

那環(huán)形隊(duì)列是如何工作的呢?它是怎么解決這個(gè)問(wèn)題的呢?

1)同樣需要一串連續(xù)的存儲(chǔ)空間。

2)初始化的時(shí)候和基本類(lèi)型的隊(duì)列 完全一樣;

3)入隊(duì)時(shí)

  • 檢查隊(duì)列是否已經(jīng)滿(mǎn)了,此時(shí)的條件除了 FRONT = 0 && REAR = SIZE + 1, 也就是隊(duì)首有元素,隊(duì)尾也有元素時(shí),也就是第一次把隊(duì)列填滿(mǎn)時(shí)。還需要再增加一個(gè):FRONT = REAR + 1,也就是隊(duì)尾緊跟在隊(duì)首后面的時(shí)候,循環(huán)把隊(duì)列填滿(mǎn)時(shí)。代碼如下所示。
  1. boolean isFull() { 
  2.     if (front == 0 && rear == SIZE - 1) { 
  3.         return true
  4.     } 
  5.      
  6.     if (front == rear + 1) { 
  7.         return true
  8.     } 
  9.     return false
  • 一旦 REAR 加 1 后超出了所分配的連續(xù)空間,就讓它指向連續(xù)空間的起始位置。也就是說(shuō),REAR 需要重新輪循了,從 0 開(kāi)始,可以用 (REAR + 1) % SIZE 取余的形式來(lái)表示。代碼如下所示。
  1. void enQueue(int element) { 
  2.     if (isFull()) { 
  3.         System.out.println("隊(duì)列已經(jīng)滿(mǎn)了"); 
  4.     } else { 
  5.         if (front == -1) 
  6.             front = 0; 
  7.         rear = (rear + 1) % SIZE
  8.         items[rear] = element; 
  9.         System.out.println("插入 " + element); 
  10.     } 

4)出隊(duì)時(shí)

  • 同樣的,當(dāng) FRONT 加 1 超出了所分配的連續(xù)空間,就讓它指向連續(xù)空間的起始位置。也就是說(shuō),F(xiàn)RONT 需要重新輪循了,從 0 開(kāi)始,可以用 (FRONT + 1) % SIZE 來(lái)表示。代碼如下所示。
  1. int deQueue() { 
  2.     int element; 
  3.     if (isEmpty()) { 
  4.         System.out.println("隊(duì)列空了"); 
  5.         return (-1); 
  6.     } else { 
  7.         element = items[front]; 
  8.         if (front >= rear) { 
  9.             front = -1; 
  10.             rear = -1; 
  11.         } 
  12.         else { 
  13.             front = (front + 1) % SIZE
  14.         } 
  15.         System.out.println("刪除 -> " + element); 
  16.         return (element); 
  17.     } 

main() 方法的測(cè)試代碼就不再貼了,和基本類(lèi)型的隊(duì)列時(shí)差別不大。一圖勝千言,我們來(lái)畫(huà)一幅圖表示下環(huán)形隊(duì)列的工作方式。

 

當(dāng)隊(duì)列第一次被填滿(mǎn)了以后,出隊(duì)了兩個(gè)元素,此時(shí)下標(biāo)為 0 和 1 的兩個(gè)位置空了出來(lái),然后入隊(duì)元素 6,意味著 6 變成了隊(duì)尾,也就是 REAR 等于 0 了;再入隊(duì)元素 7,7 變成了隊(duì)尾,也就是 REAR 等于 1 了。

現(xiàn)在,來(lái)思考一個(gè)問(wèn)題,假如此時(shí)執(zhí)行 deQueue() 方法出隊(duì)一個(gè)元素時(shí),哪一個(gè)元素會(huì)被移除呢?答案是元素 3,因?yàn)榇藭r(shí)它在隊(duì)首,之后是元素 4,元素 5,元素 6,元素 7,雖然直觀上看起來(lái)不是那么回事,但如果把它想象成一個(gè)環(huán)形的而不是直線(xiàn)型的就很好理解了。

對(duì)比來(lái)說(shuō),環(huán)形隊(duì)列比普通類(lèi)型的隊(duì)列在容量的利用上更充分一點(diǎn)。

 

除了基本類(lèi)型和環(huán)形隊(duì)列之外,隊(duì)列還有優(yōu)先級(jí)隊(duì)列和雙端隊(duì)列,雖然它們都?xì)w到了隊(duì)列這一類(lèi),但其實(shí)并不遵循 FIFO 的規(guī)則,所以我就打算把它們拎出來(lái)單獨(dú)來(lái)講。

本文轉(zhuǎn)載自微信公眾號(hào)「 沉默王二」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 沉默王二公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: 沉默王二
相關(guān)推薦

2021-01-07 09:34:19

HTTPSHTTP抓包

2024-01-11 09:53:16

Kafka中間件編程語(yǔ)言

2021-04-08 07:37:39

隊(duì)列數(shù)據(jù)結(jié)構(gòu)算法

2024-09-27 13:09:30

2022-05-10 08:36:28

鏈路狀態(tài)協(xié)議IS-ISOSPF

2024-09-23 08:00:00

消息隊(duì)列MQ分布式系統(tǒng)

2010-08-30 09:58:56

超算高科技

2015-06-24 10:51:10

iOS學(xué)習(xí)流程

2021-10-27 10:30:04

Python字符串代碼

2021-02-07 09:01:10

Java并發(fā)編程

2019-01-29 11:08:48

NginxApacheHTTP協(xié)議

2017-09-19 11:00:09

音視頻技術(shù)

2021-09-15 06:21:36

Update語(yǔ)句數(shù)據(jù)庫(kù)

2021-06-07 06:25:35

畫(huà)流程圖開(kāi)發(fā)技能

2022-10-17 08:21:29

UDPTCP

2013-07-01 10:14:08

瘋狂猜圖App移動(dòng)應(yīng)用

2010-03-18 17:54:09

2020-10-16 09:18:29

Nginx

2018-08-30 17:14:56

2023-12-08 17:24:14

Redis緩存服務(wù)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)