【C++學習】STL容器——stack和queue

目錄

一、stack的介紹和使用

1.1 stack的介紹

1.2 stack的使用

1.3 stack的模擬實現

二、queue的介紹和使用

2.1 queue的介紹

2.2 queue的使用

2.3 queue的模擬實現

三、priority_queue的介紹和使用

3.1 priority_queue的介紹和使用

3.2 priority_queue的使用

3.4 priority_queue的模擬實現

四、容器適配器

4.1 什么是適配器

4.2 STL標準庫中stack和queue的底層結構

4.3 deque的簡單介紹

4.3.1 deque的原理介紹

4.3.2 deque的缺陷

4.4 為什么選擇deque作為stack和queue的底層默認容器

4.5 STL標準庫中對于stack和queue的模擬實現

4.5.1?stack的模擬實現

4.5.2 queue的模擬實現


一、stack的介紹和使用

1.1 stack的介紹

stack的文檔介紹

  1. stack是一種容器適配器,專門用在具有后進先出操作的上下文環境中,其刪除只能從容器的一端進行元素的插入與提取操作。
  2. stack是作為容器適配器被實現的,容器適配器即是對特定類封裝作為其底層的容器,并提供一組特定的成員函數來訪問其元素,將特定類作為其底層的,元素特定容器的尾部(即棧頂)被壓入和彈出。
  3. stack的底層容器可以是任何標準的容器類模板或者一些其他特定的容器類,這些容器類應該支持以下操作:
    • empty:判空操作
    • back:獲取尾部元素操作
    • push_back:尾部插入元素操作
    • pop_back:尾部刪除元素操作
  4. 標準容器vectordequelist均符合這些需求,默認情況下,如果沒有為stack指定特定的底層容器,默認情況下使用deque

1.2 stack的使用

函數說明接口說明
stack()構造空的棧
empty()檢測stack是否為空
size()返回stack中元素的個數
top()返回棧頂元素的引用
push()將元素val壓入stack
pop()stack中尾部的元素彈出

例題:

LeetCode155 最小棧

class MinStack
{
public: void push(int x){ // 只要是壓棧,先將元素保存到_elem中_elem.push(x);// 如果x小于_min中棧頂的元素,將x再壓入_min中if(_min.empty() || x <= _min.top())_min.push(x);}void pop(){// 如果_min棧頂的元素等于出棧的元素,_min頂的元素要移除if(_min.top() == _elem.top())_min.pop();_elem.pop();}int top(){return _elem.top();}int getMin(){return _min.top();}private:// 保存棧中的元素std::stack<int> _elem;// 保存棧的最小值std::stack<int> _min;
};

牛客網JZ31 棧的壓入、彈出序列

class Solution 
{
public:bool IsPopOrder(vector<int> pushV,vector<int> popV){//入棧和出棧的元素個數必須相同if(pushV.size() != popV.size())return false;// 用s來模擬入棧與出棧的過程int outIdx = 0;int inIdx = 0;stack<int> s;while(outIdx < popV.size()){// 如果s是空,或者棧頂元素與出棧的元素不相等,就入棧while(s.empty() || s.top() != popV[outIdx]){if(inIdx < pushV.size())s.push(pushV[inIdx++]);elsereturn false;}// 棧頂元素與出棧的元素相等,出棧s.pop();outIdx++;}return true;}
};

LeetCode150 逆波蘭表達式求值

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> s;for (size_t i = 0; i < tokens.size(); ++i){string& str = tokens[i];// str為數字if (!("+" == str || "-" == str || "*" == str || "/" == str)){s.push(atoi(str.c_str()));}else{// str為操作符int right = s.top();s.pop();int left = s.top();s.pop();switch (str[0]){case '+':s.push(left + right);break;case '-':s.push(left - right);break;case '*':s.push(left * right);break;case '/':// 題目說明了不存在除數為0的情況s.push(left / right);break;}}}return s.top();}
};

1.3 stack的模擬實現

????????從棧的接口中可以看出,棧實際是一種特殊的vector,因此使用vector完全可以模擬實現stack

#include<vector>
namespace bite
{template<class T>class stack{public:stack() {}void push(const T& x) {_c.push_back(x);}void pop() {_c.pop_back();}T& top() {return _c.back();}const T& top()const {return _c.back();}size_t size()const {return _c.size();}bool empty()const {return _c.empty();}private:std::vector<T> _c;};
}

二、queue的介紹和使用

2.1 queue的介紹

queue的文檔介紹

  1. 隊列是一種容器適配器,專門用于在FIFO上下文(先進先出)中操作,其中從容器一端插入元素,另一端提取元素。
  2. 隊列作為容器適配器實現,容器適配器即將特定容器類封裝作為其底層容器類,queue提供一組特定的成員函數來訪問其元素。元素從隊尾入隊列,從隊頭出隊列。
  3. 底層容器可以是標準容器類模板之一,也可以是其他專門設計的容器類。該底層容器應至少支持以下操作:
    1. empty:檢測隊列是否為空
    2. size:返回隊列中有效元素的個數
    3. front:返回隊頭元素的引用
    4. back:返回隊尾元素的引用
    5. push_back:在隊列尾部入隊列
    6. pop_front:在隊列頭部出隊列
  4. 標準容器類dequelist滿足了這些要求。默認情況下,如果沒有為queue實例化指定容器類,則使用標準容器deque

2.2 queue的使用

函數聲明接口說明
queue()構造空的隊列
empty()檢測隊列是否為空,是返回true,否則返回false
size()返回隊列中有效元素的個數
front()返回隊頭元素的引用
back()返回隊尾元素的引用
push()在隊尾將元素val入隊列
pop()將隊頭元素出隊列

2.3 queue的模擬實現

????????因為queue 的接口中存在頭刪和尾插,因此使用 vector 來封裝效率太低,故可以借助 list 來模擬實現 queue , 具體如下:
#include <list>
namespace bite
{template<class T>class queue{public:queue() {}void push(const T& x) {_c.push_back(x);}void pop() {_c.pop_front();}T& back() {return _c.back();}const T& back()const {return _c.back();}T& front() {return _c.front();}const T& front()const {return _c.front();}size_t size()const {return _c.size();}bool empty()const {return _c.empty();}private:std::list<T> _c;};
}

三、priority_queue的介紹和使用

3.1 priority_queue的介紹和使用

priority_queue文檔介紹

  1. 優先隊列是一種容器適配器,根據嚴格的弱排序標準,它的第一個元素總是它所包含的元素中最大的。
  2. 此上下文類似于堆,在堆中可以隨時插入元素,并且只能檢索最大堆元素(優先隊列中位于頂部的元素)
  3. 優先隊列被實現為容器適配器,容器適配器即將特定容器類封裝作為其底層容器類,queue提供一組特定的成員函數來訪問其元素。元素從特定容器的“尾部彈出,其稱為優先隊列的頂部。
  4. 底層容器可以是任何標準容器類模板,也可以是其他特定設計的容器類。容器應該可以通過隨機訪問迭代器訪問,并支持以下操作:
    1. empty():檢測容器是否為空
    2. size():返回容器中有效元素個數
    3. front():返回容器中第一個元素的引用
    4. push_back():在容器尾部插入元素
    5. pop_back():刪除容器尾部元素
  5. 標準容器類vectordeque滿足這些需求。默認情況下,如果沒有為特定的priority_queue類實例化指定容器類,則使用vector
  6. 需要支持隨機訪問迭代器,以便始終在內部保持堆結構。容器適配器通過在需要時自動調用算法函數make_heap、push_heappop_heap來自動完成此操作。

3.2 priority_queue的使用

????????優先級隊列默認使用vector 作為其底層存儲數據的容器,在 vector 上又使用了堆算法將 vector 中元素構造成 堆的結構,因此 priority_queue 就是堆,所有需要用到堆的位置,都可以考慮使用 priority_queue 。注意: 默認情況下 priority_queue 是大堆
函數聲明接口說明
priority_queue()/priority_queue(first, last)構造一個空的優先級隊列
empty()
檢測優先級隊列是否為空,是返回 true ,否則返回 false
top()返回優先級隊列中最大(最小元素),即堆頂元素
push()在優先級隊列中插入元素x
pop()刪除優先級隊列中最大(最小)元素,即堆頂元素
【注意】
1. 默認情況下,priority_queue 是大堆。
#include <vector>
#include <queue>
#include <functional> // greater算法的頭文件
void TestPriorityQueue()
{// 默認情況下,創建的是大堆,其底層按照小于號比較vector<int> v{3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要創建小堆,將第三個模板參數換成greater比較方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}
2. 如果在 priority_queue 中放自定義類型的數據,用戶需要在自定義類型中提供 > 或者 < 的重載。
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};void TestPriorityQueue()
{// 大堆,需要用戶在自定義類型中提供<的重載priority_queue<Date> q1;q1.push(Date(2018, 10, 29));q1.push(Date(2018, 10, 28));q1.push(Date(2018, 10, 30));cout << q1.top() << endl;// 如果要創建小堆,需要用戶提供>的重載priority_queue<Date, vector<Date>, greater<Date>> q2;q2.push(Date(2018, 10, 29));q2.push(Date(2018, 10, 28));q2.push(Date(2018, 10, 30));cout << q2.top() << endl;
}

例題:LeetCode215 數組中的第K個最大元素

class Solution 
{
public:int findKthLargest(vector<int>& nums, int k) {// 將數組中的元素先放入優先級隊列中priority_queue<int> p(nums.begin(), nums.end());// 將優先級隊列中前k-1個元素刪除掉for(int i= 0; i < k-1; ++i){p.pop();}return p.top();}
};

3.4 priority_queue的模擬實現

????????通過對priority_queue 的底層結構就是堆,因此此處只需對對進行通用的封裝即可。
優先級隊列的模擬實現:
#pragma once#include <iostream>
using namespace std;#include <vector>
// priority_queue--->堆
namespace casso
{template<class T>struct less{bool operator()(const T& left, const T& right){return left < right;}};template<class T>struct greater{bool operator()(const T& left, const T& right){return left > right;}};template<class T, class Container = std::vector<T>, class Compare = less<T>>class priority_queue{public:// 創造空的優先級隊列priority_queue() : c() {}template<class Iterator>priority_queue(Iterator first, Iterator last): c(first, last){// 將c中的元素調整成堆的結構int count = c.size();int root = ((count - 2) >> 1);for (; root >= 0; root--)AdjustDown(root);}void push(const T& data){c.push_back(data);AdjustUP(c.size() - 1);}void pop(){if (empty())return;swap(c.front(), c.back());c.pop_back();AdjustDown(0);}size_t size()const{return c.size();}bool empty()const{return c.empty();}// 堆頂元素不允許修改,因為:堆頂元素修改可以會破壞堆的特性const T& top()const{return c.front();}private:// 向上調整void AdjustUP(int child){int parent = ((child - 1) >> 1);while (child){if (Compare()(c[parent], c[child])){swap(c[child], c[parent]);child = parent;parent = ((child - 1) >> 1);}else{return;}}}// 向下調整void AdjustDown(int parent){size_t child = parent * 2 + 1;while (child < c.size()){// 找以parent為根的較大的孩子if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))child += 1;// 檢測雙親是否滿足情況if (Compare()(c[parent], c[child])){swap(c[child], c[parent]);parent = child;child = parent * 2 + 1;}elsereturn;}}private:Container c;};
}void TestQueuePriority()
{casso::priority_queue<int> q1;q1.push(5);q1.push(1);q1.push(4);q1.push(2);q1.push(3);q1.push(6);cout << q1.top() << endl;q1.pop();q1.pop();cout << q1.top() << endl;vector<int> v{ 5,1,4,2,3,6 };casso::priority_queue<int, vector<int>, casso::greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;q2.pop();q2.pop();cout << q2.top() << endl;
}

四、容器適配器

4.1 什么是適配器

????????適配器是一種設計模式( 設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結) 該種模式是將一個類的接口轉換成客戶希望的另外一個接口

4.2 STL標準庫中stackqueue的底層結構

????????雖然stack queue 中也可以存放元素,但在 STL 中并沒有將其劃分在容器的行列,而是將其稱為 容器適配 ,這是因為 stack 和隊列只是對其他容器的接口進行了包裝, STL stack queue 默認使用 deque ,比如:

4.3 deque的簡單介紹

4.3.1 deque的原理介紹
????????deque(雙端隊列 ) :是一種雙開口的 " 連續 " 空間的數據結構 ,雙開口的含義是:可以在頭尾兩端進行插入和刪除操作,且時間復雜度為O(1) ,與 vector 比較,頭插效率高,不需要搬移元素;與 list 比較,空間利用率比較高。
????????
????????deque并不是真正連續的空間,而是由一段段連續的小空間拼接而成的,實際 deque 類似于一個動態的二維 數組
4.3.2 deque的缺陷
  • vector比較deque的優勢是:頭部插入和刪除時,不需要搬移元素,效率特別高,而且在擴容時,也不需要搬移大量的元素,因此其效率是必vector高的。
  • list比較,其底層是連續空間,空間利用率比較高,不需要存儲額外字段。
  • 但是,deque有一個致命缺陷:不適合遍歷,因為在遍歷時,deque的迭代器要頻繁的去檢測其是否移動到某段小空間的邊界,導致效率低下,而序列式場景中,可能需要經常遍歷,因此在實際中,需要線性結構時,大多數情況下優先考慮vectorlistdeque的應用并不多,而目前能看到的一個應用就是,STL用其作stackqueue的底層數據結構

4.4 為什么選擇deque作為stackqueue的底層默認容器

????????stack是一種后進先出的特殊線性數據結構,因此只要具有 push_back() pop_back() 操作的線性結構,都可以作為stack 的底層容器,比如 vector list 都可以; queue 是先進先出的特殊線性數據結構,只要具有push_back和 pop_front 操作的線性結構,都可以作為 queue 的底層容器,比如 list 。但是 STL 中對 stack 和queue默認選擇 deque 作為其底層容器,主要是因為:
  • stackqueue不需要遍歷(因此stackqueue沒有迭代器),只需要在固定的一端或者兩端進行操作。
  • stack中元素增長時,dequevector的效率高(擴容時不需要搬移大量數據)queue中的元素增長時,deque不僅效率高,而且內存使用率高。
結合了 deque 的優點,而完美的避開了其缺陷。

4.5 STL標準庫中對于stackqueue的模擬實現

4.5.1?stack的模擬實現
#include <deque>
namespace casso
{template<class T, class Con = deque<T>>//template<class T, class Con = vector<T>>//template<class T, class Con = list<T>>class stack{public:stack() {}void push(const T& x) {_c.push_back(x);}void pop() {_c.pop_back();}T& top() {return _c.back();}const T& top()const {return _c.back();}size_t size()const {return _c.size();}bool empty()const {return _c.empty();}private:Con _c;};
}
4.5.2 queue的模擬實現
#include <deque>
#include <list>
namespace casso
{template<class T, class Con = deque<T>>//template<class T, class Con = list<T>>class queue{public:queue() {}void push(const T& x) {_c.push_back(x);}void pop() {_c.pop_front();}T& back() {return _c.back();}const T& back()const {return _c.back();}T& front() {return _c.front();}const T& front()const {return _c.front();}size_t size()const {return _c.size();}bool empty()const {return _c.empty();}private:Con _c;};
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/38636.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38636.shtml
英文地址,請注明出處:http://en.pswp.cn/news/38636.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM---理解jvm之對象已死怎么判斷?

目錄 引用計數算法 什么是引用 可達性分析算法&#xff08;用的最多的&#xff09; 引用計數算法 定義&#xff1a;在對象中添加一個引用計數器&#xff0c;每當有一個地方引用它時&#xff0c;計數器值就加一&#xff1b;當引用失效時&#xff0c;計數器值就減一&#xff1…

國內外醫療器械政策法規網站集合

隨著醫療技術的不斷發展&#xff0c;醫療器械在現代醫療中扮演著重要的角色。為了確保醫療器械的安全性、有效性和質量&#xff0c;各國紛紛制定了一系列的政策法規來監管醫療器械的研發、生產、銷售和使用。這些政策法規的制定和實施對于保障公眾健康、促進醫療器械產業的健康…

docker--------介紹、常用命令,國內源配置

1 docker 國內源配置 # 鏡像&#xff1a;一堆文件 -目前從遠程倉庫下載的&#xff1a;https://hub.docker.com/ -鏡像有很多人提供&#xff1a;官方提供&#xff0c;第三方提供 -鏡像--》更新--》Tag不同版本 -centos:latest 最新 -docker pull 能找到…

舊版本docker未及時更新,導致更新/etc/docker/daemon.json配置文件出現docker重啟失敗

一、背景 安裝完docker和containerd之后&#xff0c;嘗試重啟docker的時候&#xff0c;報錯如下&#xff1a; systemctl restart dockerJob for docker.service failed because the control process exited with error code. See “systemctl status docker.service” and “…

學習ts(一)數據類型(基礎類型和任意類型)

運行 起步安裝 npm install typescript -g 運行tsc index.ts生成對應的js文件&#xff0c;然后使用node index.js執行js文件 為了方便運行還可以安裝插件&#xff0c;ts-node index.ts運行即可 npm i ts-node -g npm init -y npm i types/node -D基本數據類型 // 1.字符…

探索不同類型的代理服務器 (代理 IP、socks5 代理)及其在網絡安全與爬蟲中的應用

1. 代理服務器簡介 代理服務器是一臺充當中間人的服務器&#xff0c;它在客戶端與目標服務器之間傳遞網絡請求。代理服務器在不同層級上可以執行不同的任務&#xff0c;包括緩存、過濾、負載均衡和隱藏客戶端真實IP地址等。在網絡安全和爬蟲領域&#xff0c;代理服務器具有重要…

ARM(匯編指令)

.global _start _start:/*mov r0,#0x5mov r1,#0x6 bl LoopLoop:cmp r0,r1beq stopsubhi r0,r0,r1subcc r1,r1,r0mov pc,lr*/ mov r0,#0x1mov r1,#0x0mov r2,#0x64bl Loop Loop:cmp r0,r2bhi stopadd r1,r1,r0add r0,r0,#0x01mov pc,lr stop:B stop.end

現有的vue3+ts+vite項目集成electron

效果圖 什么時Electron Electron是使用JavaScript,HTML和CSS構建跨平臺的桌面應用程序框架。 Electron兼容Mac、Windows和Linux,可以構建出三個平臺的應用程序。 現有的vue3項目集成Electron 安裝依賴 原來有一個vue3+ts+vite+pnpm的項目,其中sub-modules是子項目,web是…

Monge矩陣

Monge矩陣 對一個m*n的實數矩陣A&#xff0c;如果對所有i&#xff0c;j&#xff0c;k和l&#xff0c;1≤ i<k ≤ m和1≤ j<l ≤ n&#xff0c;有 A[i,j]A[k,l] ≤ A[i,l]A[k,j] 那么&#xff0c;此矩陣A為Monge矩陣。 換句話說&#xff0c;每當我們從矩陣中挑…

全面梳理Python下的NLP 庫

一、說明 Python 對自然語言處理庫有豐富的支持。從文本處理、標記化文本并確定其引理開始&#xff0c;到句法分析、解析文本并分配句法角色&#xff0c;再到語義處理&#xff0c;例如識別命名實體、情感分析和文檔分類&#xff0c;一切都由至少一個庫提供。那么&#xff0c;你…

地理數據的雙重呈現:GIS與數據可視化

前一篇文章帶大家了解了GIS與三維GIS的關系&#xff0c;本文就GIS話題帶大家一起探討一下GIS和數據可視化之間的關系。 GIS&#xff08;地理信息系統&#xff09;和數據可視化在地理信息科學領域扮演著重要的角色&#xff0c;它們之間密切相關且相互增強。GIS是一種用于采集、…

歐拉函數和最大公約數

分析&#xff1a;如果兩個數的最大公約數是一個質數p&#xff0c;那么這兩個數都除以p&#xff0c;得到的兩個數的最大公約數一定是1. 反證法&#xff1a;如果得到的兩個數的最大公約數不是1&#xff0c;那么把此時的最大公約數乘以上邊的最大公約數&#xff0c;得到的一定比上…

文件操作 和 IO

目錄 ?編輯一、認識文件 1、文件路徑 2、其它知識 二、Java 中操作文件 三、文件內容的讀寫 1、Reader 2、InputStream 3、輸出 一、認識文件 文件是在硬盤上存儲數據的一種方式&#xff0c;操作系統幫我們把硬盤的一些細節都封裝起來了 我們只需要了解文件相關的一些…

【前端 | CSS】滾動到底部加載,滾動監聽、懶加載

背景 在日常開發過程中&#xff0c;我們會遇到圖片懶加載的功能&#xff0c;基本原理是&#xff0c;滾動條滾動到底部后再次獲取數據進行渲染。 那怎么判斷滾動條是否滾動到底部呢&#xff1f;滾動條滾動到底部觸發時間的時機和方法又該怎樣定義&#xff1f; 針對以上問題我…

數據集成革新:去中心化微服務集群的無限潛能

在當今數據密集型的業務環境下&#xff0c;傳統的集中式架構已經難以滿足高可用性和高并發性的要求。而去中心化微服務集群則通過分散式的架構&#xff0c;將系統劃分為多個小型的、獨立部署的微服務單元&#xff0c;每個微服務負責特定的業務功能&#xff0c;實現了系統的高度…

centos系統kubeadm安裝K8S_v1.27.x容器使用docker(K8S_v1.24版本以后依然使用docker容器管理)

kubeadm安裝K8S_v1.27.x容器使用docker 按照需要的文檔點擊這里下載 一.環境部署 1.1基礎環境配置 主機IP 主機名規劃 192.168.186.128 k8s-master01 192.168.186.129 k8s-node01 192.168.186.130 k8s-node02 1.2修改機器名稱 #永久修改主機名 hostnamectl set-hostname …

docker搭建opengrok環境

引言&#xff1a; 由于這幾天開始 http://aospxref.com/ 網站沒法用了。用習慣了opengrok的方式看AOSP的源碼&#xff0c;其他的在線查看源碼的網站用起來都不是很理想。所以考慮搭建一個環境。 首先網上看了下opengrok的環境搭建的方式&#xff0c;最終還是采用docker的方…

【JS 一個數組隨機選取x個元素】

可以使用Math.random()方法&#xff0c;結合循環和splice()方法來實現&#xff1a; let arr [1,2,3,4,5,6,7,8,9]; let randomArr [];for(let i 0; i < 4; i) {let randomIndex Math.floor(Math.random() * arr.length);let randomNum arr.splice(randomIndex, 1)[0];…

基于C#的無邊框窗體陰影繪制方案 - 開源研究系列文章

今天介紹無邊框窗體陰影繪制的內容。 上次有介紹使用雙窗體的方法來顯示陰影&#xff0c;這次介紹使用API函數來進行繪制。這里使用的是Windows API函數&#xff0c;操作系統的窗體也是用的這個來進行的繪制。 1、 項目目錄&#xff1b; 下面是項目目錄&#xff1b; 2、 函數介…

日常BUG——SpringBoot模糊映射

&#x1f61c;作 者&#xff1a;是江迪呀??本文關鍵詞&#xff1a;日常BUG、BUG、問題分析??每日 一言 &#xff1a;存在錯誤說明你在進步&#xff01; 一、問題描述 SpringBoot在啟動時報出如下錯誤&#xff1a; Caused by: java.lang.IllegalStateExceptio…