C++中的隊列及常見題目匯總


目錄

一、隊列的介紹

  1.1 靜態循環鏈表

  1.2 動態鏈式鏈表

  1.3 隊列的應用:廣度優先算法搜索路徑

二、隊列的相關題目

  1. 二叉樹的遍歷:
    1. 二叉樹的層序遍歷  
  2. 隊列的最大值
    1. 滑動窗口的最大值1 
    2. 隊列的最大值

一、隊列的介紹

  隊列是一個能實現“先進先出”的一個存儲結構。

  隊列分為鏈式隊列和靜態隊列:靜態隊列一般用數組來實現,但此時隊列必須是循環隊列,否則會造成巨大的內存浪費。鏈式隊列是用鏈表來實現隊列的。  

1.1 靜態循環隊列

  隊列的順序存儲結構通常由一個一維數組和一個記錄隊列頭元素位置的變量front以及一個記錄隊列尾元素位置的變量rear組成。

1 typedef struct _myqueue
2 {
3     char* _space;
4     int _len;
5     int _front;
6     int _rear;
7 }MyQueue;
  • 普通隊列和循環隊列的對比
    • 普通隊列

      對列初始化時,front和rear值都為0;

      當隊列不為空時,front指向隊列的第一個元素,rear指向隊列的最后一個元素的下一個位置;

      當隊列為空時,front和rear的值相等,但不一定為0;

                    

 

 

       由上普通隊列入隊出隊的方式我們可以發現,當元素出隊之后不能重復被使用,因此普通隊列空間利用率是很低的,我們一般不推薦此種方式。

    • 循環隊列  

      為了解決普通隊列存在的空間利用率低的問題,我們引入循環隊列來解決這個問題。循環問題的關鍵就是判空和判滿的問題

    

 

 

       因此為了實現循環隊列的判空和判滿,我們犧牲一個存儲單元來實現。

        當其為空時,front==rear;

        當其為滿時,front=(rear+1)%len;

          自己實現線性隊列代碼如下

typedef struct _myqueue
{
    char* _space;
    int _len;
    int _front;
    int _rear;
}MyQueue;

//由於普通隊列空間利用率過低,因此我們一般都使用循環隊列
//初始化
void initQueue(MyQueue* s,int len)
{
    s->_space = new char[len];
    s->_len = len;
    s->_front = 0;
    s->_rear = 0;
}

//判空:當front==rear時為空
bool isQueueEmpty(MyQueue* s)
{
    return s->_front == s->_rear;
}

//判滿:循環隊列,當(rear+1)%length==front時為滿
bool isQueueFull(MyQueue* s)
{
    return  (s->_rear + 1) % s->_len == s->_front;
}

//入隊
void enQueue(MyQueue* s,char ch)
{
    s->_space[s->_rear] = ch;
    s->_rear = (s->_rear + 1) % s->_len;//不能直接加1是因為其是循環隊列,有可能直接到達的隊尾
}

//出隊
char deQueue(MyQueue* s)
{
    char ch= s->_space[s->_front];
    s->_front = (s->_front + 1) % s->_len;
    return ch;
}

 

1.2 鏈式隊列

  隊列的鏈式存儲結構也可以用一個單鏈表實現,插入和刪除操作分別在鏈表的兩頭進行

  

 

 

   鏈式存儲結構

  

 

 

   需要進行的操作為:初始化,判空,入隊和出隊,其中最難的是出隊,分為兩種情況:隊列中只有兩個節點和隊列中有多個節點

    隊列中只有兩個節點的情況

    

 

 

     隊列中有多個節點的情況

    

 

 

 代碼參考

 1 typedef struct _node
 2 {
 3     char data;
 4     struct _node* next;
 5 }Node;
 6 
 7 typedef struct _QueueList
 8 {
 9     Node* _front;
10     Node* _rear;
11 }QueueList;
12 
13 //初始化
14 void initQueueList(QueueList* s)
15 {
16     s->_front = s->_rear = new Node[sizeof(Node)];
17     s->_rear->next = nullptr;
18 }
19 
20 //判空
21 bool isQueueListEmpty(QueueList* s)
22 {
23     return s->_front == s->_rear;
24 }
25 
26 //入隊:采用尾插法來實現入隊
27 void enQueueList(QueueList* s, char ch)
28 {
29     Node* cur = new Node;
30     cur->data = ch;
31     cur->next = nullptr;
32     s->_rear->next = cur;
33     s->_rear = cur;
34 }
35 
36 //出隊:分為兩種情況:隊列中只剩下兩個元素,和隊列中剩余多個元素
37 //若隊列中只剩下兩個元素,即front->next==rear
38 char deQueueList(QueueList* s)
39 {
40     char ch = s->_front->next->data;
41     if (s->_front->next == s->_rear)
42     {
43         s->_rear = s->_front;
44         delete s->_front->next;
45         s->_front->next = nullptr;
46     }
47     else
48     {
49         Node* t = s->_front->next;
50         s->_front->next = t->next;
51         delete t;
52     }
53     return ch;
54 }

  1.3 隊列的應用: 廣度優先算法搜索路徑

  • 代碼參考

  myqueue.h

 1 #pragma once
 2 typedef struct _point
 3 {
 4     int _x;
 5     int _y;
 6 }Point;
 7 
 8 
 9 typedef struct _node
10 {
11     Point data;
12     struct _node* next;
13 }Node;
14 
15 typedef struct _queue
16 {
17     Node* _front;
18     Node* _rear;
19 }Queue;
20 
21 //初始化
22 void initQueue(Queue* s);
23 //判空
24 bool isQueueEmpty(Queue* s);
25 //入隊
26 void enQueue(Queue* s, Point data);
27 //出隊
28 Point deQueue(Queue* s);

  myqueue.cpp

 1 #include <iostream>
 2 #include "myqueue.h"
 3 
 4 using namespace std;
 5 
 6 //初始化
 7 void initQueue(Queue* s)
 8 {
 9     s->_front = s->_rear = new Node;
10     s->_front->next = nullptr;
11 }
12 //判空
13 bool isQueueEmpty(Queue* s)
14 {
15     return s->_front == s->_rear;
16 }
17 
18 //入隊
19 void enQueue(Queue* s, Point data)
20 {
21     Node* cur = new Node;
22     cur->data = data;
23     //cur->next = nullptr;
24     s->_rear->next = cur;
25     s->_rear = cur;
26 }
27 
28 //出隊
29 Point deQueue(Queue* s)
30 {
31     Point ch = s->_front->next->data;
32     if (s->_front->next == s->_rear)
33     {
34         s->_rear = s->_front;
35         delete s->_front->next;
36         s->_front->next = nullptr;
37     }
38     else
39     {
40         Node* t = s->_front->next;
41         s->_front->next = t->next;
42         delete t;
43     }
44     return ch;
45 }

  main.cpp

 1 #include <iostream>
 2 #include "myqueue.h"
 3 
 4 #define MAXROW 10
 5 #define MAXLINE 10
 6 
 7 using namespace std;
 8 
 9 
10 //1 代表牆,2 走過的路,0 代表路
11 int maze[MAXROW][MAXLINE] =
12 {
13     1,1,1,1,1,1,1,1,1,1, 
14     0,0,0,1,1,1,1,1,1,1,
15     1,1,0,1,1,1,1,1,1,1,
16     1,1,0,0,0,0,1,1,1,1,
17     1,1,0,1,1,0,1,1,1,1,
18     1,1,0,1,1,0,1,1,1,1,
19     1,1,1,1,1,0,1,1,1,1, 
20     1,1,1,1,1,0,0,0,1,1, 
21     1,1,1,1,1,1,1,0,0,0,
22     1,1,1,1,1,1,1,1,1,1,
23 };
24 
25 void displyMaze() 
26 {
27     for (int i = 0; i < MAXROW; i++) 
28     {
29         for (int j = 0; j < MAXLINE; j++)
30         { if (maze[i][j] == 1) 
31             printf("%2s", " *"); 
32         else if (maze[i][j] == 2) 
33             printf("%2s", " #");
34         else 
35             printf("%2s", " ");
36         } 
37         putchar(10); 
38     }
39     printf(" ====================\n");
40 }
41 
42 Queue q;
43 
44 void visit(int x,int y)
45 {
46     Point p = { x,y };
47     enQueue(&q, p);
48 }
49 
50 
51 int main()
52 {
53     displyMaze();
54     Point sp = { 1,0 };
55     Point ep = { 8,9 };
56     enQueue(&q, sp);
57     bool flag = true;
58     while (!isQueueEmpty(&q))
59     {
60         Point t = deQueue(&q);
61         maze[t._x][t._y] = 2;
62         system("cls");
63         displyMaze();
64         if (t._x - 1 >= 0 && maze[t._x - 1][t._y]==0)
65             visit(t._x - 1, t._y);
66         if (t._x + 1 <= 9 && maze[t._x + 1][t._y]==0)
67             visit(t._x + 1, t._y);
68         if (t._y - 1 >= 0 && maze[t._x][t._y - 1]==0)
69             visit(t._x, t._y - 1);
70         if (t._y + 1 <= 9 && maze[t._x][t._y + 1]==0)
71             visit(t._x, t._y + 1);
72         if (t._x == ep._x && t._y == ep._y)
73             flag = true;
74     }
75     if (flag)
76         cout << "find the path" << endl;
77     return 0;
78 }

 

二、隊列的相關題目

1. 二叉樹的遍歷

  1.1 二叉樹的層序遍歷

  

  • 問題分析

  

 

  •  代碼參考
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<vector<int>> levelOrder(TreeNode* root) {
13         vector<vector<int>> B;
14         if(root==nullptr)
15             return B;
16         vector<int> line;
17         queue<TreeNode*> parent;
18         queue<TreeNode*> child;
19         parent.push(root);
20         while(!parent.empty()||!child.empty())
21         {
22             TreeNode* t=parent.front();
23             line.push_back(t->val);
24             parent.pop();
25             if(t->left)
26                 child.push(t->left);
27             if(t->right)
28                 child.push(t->right);
29             if(parent.empty())
30             {
31                 B.push_back(line);
32                 line.clear();
33                 while(!child.empty())
34                 {
35                     parent.push(child.front());
36                     child.pop();
37                 }
38             }
39         }
40         return B;
41     }
42 };

 

2. 隊列的最大值

  2.1 滑動窗口的最大值

  

 將滑動窗口看成一個隊列,窗口滑動時,處於窗口第一個數字被刪除,同時在窗口的末尾添加一個新的數字,符合隊列先進先出的原則。因此采用隊列來存儲滑動窗口。但我們不用隊列來存儲滑動窗口的所有值,而是存儲滑動窗口中可能最大的值。從頭到尾掃描整個數組,如果當前數組元素大於滑動窗口隊列中的元素,則隊列中的元素不可能成為滑動窗口的最大值,將其從隊尾刪除;如果當前數組元素小於滑動窗口隊列中的元素,則當元素從滑動窗口隊列頭刪除后,其可能成為滑動窗口最大元素,因此將元素入

 

 

  •  代碼參考
 1 class Solution {
 2 public:
 3     vector<int> maxSlidingWindow(vector<int>& nums, int k) {
 4         vector<int> maxInWindow;
 5         if(nums.empty()||k<0||nums.size()<k)
 6             return maxInWindow;
 7         int len=nums.size();
 8         deque<int> index;
 9         for(int i=0;i<k;++i)
10         {
11             while(!index.empty()&&nums[i]>nums[index.back()])
12                 index.pop_back();
13             index.push_back(i);
14         }
15         
16         //當滑動窗口中元素值等於滑動窗口的尺寸時,還要考慮滑動窗口中元素的個數問題
17         for(int i=k;i<len;++i)
18         {
19             maxInWindow.push_back(nums[index.front()]);
20             while(!index.empty()&&nums[i]>nums[index.back()])
21                 index.pop_back();
22             while(!index.empty()&&(int)(i-index.front())>=k)
23                 index.pop_front();
24             index.push_back(i);
25             
26         }
27         maxInWindow.push_back(nums[index.front()]);
28         return maxInWindow;
29     }
30 };

 

  2.2 滑動窗口的最大值

  

 

  •  題目描述

  為了解決上述問題,即定義一個函數得到隊列中的最大值,則其可以參考上述滑動窗口的最大值來解決問題,剛開始可能思考,直接定義一個隊列,每次入隊操作時更新其最大值

 

 

 但是出隊后,這個方法會造成信息丟失,即當最大值出隊后,我們無法知道隊列里的下一個最大值

為了解決上述問題,我們只需記住當前最大值出隊后,隊列中的下一個最大值即可

具體方法是使用一個雙端隊列dequeue,在每次入隊時。如果dequeue隊尾元素小於即將入隊的元素,則將小於value的全部元素出隊后,再將value入隊,否則直接入隊

  • 代碼參考
 1 class MaxQueue {
 2 public:
 3     MaxQueue() {
 4 
 5     }
 6     deque<int> data;
 7     deque<int> maxinums;
 8     int max_value() {
 9         if(maxinums.empty())
10             return -1;
11         return maxinums.front();
12     }
13     
14     void push_back(int value) {
15         data.push_back(value);
16         while(!maxinums.empty()&&value>maxinums.back())
17             maxinums.pop_back();
18         maxinums.push_back(value);
19     }
20     
21     int pop_front() {
22         if(data.empty())
23             return -1;
24         int ans=data.front();
25         if(ans==maxinums.front())
26             maxinums.pop_front();
27         data.pop_front();
28         return ans;
29     }
30 };
31 
32 /**
33  * Your MaxQueue object will be instantiated and called as such:
34  * MaxQueue* obj = new MaxQueue();
35  * int param_1 = obj->max_value();
36  * obj->push_back(value);
37  * int param_3 = obj->pop_front();
38  */

 


免責聲明!

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



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