C++/C++11中std::stack的使用
棧stack 是一個容器適配器(container adaptor)類型,被特別設計用來運行于LIFO(Last-in First-out,后進先出)場景,在該場景中,只能從容器末尾添加和刪除元素,其定義在stack頭文件中。stack默認基于std::deque實現,也可以在std::list或std::vector之上實現。
stack 通常被實現為容器適配器,即使用一個特定容器類的封裝對象作為它的底層容器。stack 提供了一系列成員函數用于操作它的元素,只能從容器”后面”壓進(Push)元素或從容器”后面”提取(Pop)元素。容器中的”后面”位置也被稱為”棧頂”。用來實現棧的底層容器必須滿足順序容器的所有必要條件。同時,它還必須提供以下語義的成員函數:back()、push_back()?、pop_back()。滿足上述條件的標準容器有 std::vector、std::deque 及 std::list,如果未特別指定 stack 的底層容器,標準容器 std::deque 將被使用。
? Stacks are a type of container adaptor, specifically designed to operate in a LIFO context(last-in first-out), where elements are inserted and extracted only from one end of the container.
stacks are implemented as containers adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container,providing a specific set of member functions to access its elements. Elements are pushed/popped from the "back" of the specific container, which is known as the top of the stack.
一個容器就是一些特定類型對象的集合。順序容器(sequential container)為程序員提供了控制元素存儲和訪問順序的能力。這種順序不依賴于元素的值,而是與元素加入容器時的位置相對應。
???????? 標準庫中的順序容器包括:
???????? (1)、vector:可變大小數組。支持快速隨機訪問。在尾部之外的位置插入或刪除元素可能很慢。
???????? (2)、deque:雙端隊列。支持快速隨機訪問。在頭尾位置插入/刪除速度很快。
???????? (3)、list:雙向鏈表。只支持雙向順序訪問。在list中任何位置進行插入/刪除操作速度都很快。
???????? (4)、forward_list:單向鏈表。只支持單向順序訪問。在鏈表任何位置進行插入/刪除操作速度都很快。
???????? (5)、array:固定大小數組。支持快速隨機訪問。不能添加或刪除元素。
???????? (6)、string:與vector相似的容器,但專門用于保存字符。隨機訪問快。在尾部插入/刪除速度快。
???????? 除了固定大小的array外,其它容器都提供高效、靈活的內存管理。我們可以添加和刪除元素,擴張和收縮容器的大小。容器保存元素的策略對容器操作的效率有著固定的,有時是重大的影響。在某些情況下,存儲策略還會影響特定容器是否支持特定操作。
???????? 例如,string和vector將元素保存在連續的內存空間中。由于元素是連續存儲的,由元素的下標來計算其地址是非常快速的。但是,在這兩種容器的中間位置添加或刪除元素就會非常耗時:在一次插入或刪除操作后,需要移動插入/刪除位置之后的所有元素,來保持連續存儲。而且,添加一個元素有時可能還需要分配額外的存儲空間。在這種情況下,每個元素都必須移動到新的存儲空間中。
???????? list和forward_list兩個容器的設計目的是令容器任何位置的添加和刪除操作都很快速。作為代價,這兩個容器不支持元素的隨機訪問:為了訪問一個元素,我們只能遍歷整個容器。而且,與vector、deque和array相比,這兩個容器的額外內存開銷也很大。
???????? deque是一個更為復雜的數據結構。與string和vector類似,deque支持快速的隨機訪問。與string和vector一樣,在deque的中間位置添加或刪除元素的代價(可能)很高。但是,在deque的兩端添加或刪除元素都是很快的,與list或forward_list添加刪除元素的速度相當。
???????? forward_list和array是新C++標準增加的類型。與內置數組相比,array是一個種更安全、更容易使用的數組類型。與內置數組類似,array對象的大小是固定的。因此,array不支持添加和刪除元素以及改變容器大小的操作。forward_list的設計目標是達到與最好的手寫的單向鏈表數據結構相當的性能。因此,forward_list沒有size操作,因為保存或計算其大小就會比手寫鏈表多出額外的開銷。對其他容器而言,size保證是一個快速的常量時間的操作。
???????? 通常,使用vector是最好的選擇,除法你有很好的理由選擇其他容器。
???????? 以下是一些選擇容器的基本原則:
???????? (1)、除法你有很好的理由選擇其他容器,否則應該使用vector;
???????? (2)、如果你的程序有很多小的元素,且空間的額外開銷很重要,則不要使用list或forward_list;
???????? (3)、如果程序要求隨機訪問元素,應使用vector或deque;
???????? (4)、如果程序要求在容器的中間插入或刪除元素,應使用list或forward_list;
(5)、如果程序需要在頭尾位置插入或刪除元素,但不會在中間位置進行插入或刪除操作,則使用deque;
(6)、如果程序只有在讀取輸入時才需要在容器中間位置插入元素,隨后需要隨機訪問元素,則:首先,確定是否真的需要在容器中間位置添加元素。當處理輸入數據時, 通常可以很容器地向vector追加數據,然后再調用標準庫的sort函數來重排容器中的元素,從而避免在中間位置添加元素。如果必須在中間位置插入元素,考慮在輸入階段使用list,一旦輸入完成,將list中的內容拷貝到一個vector中。
如果你不確定應該使用哪種容器,那么可以在程序中只使用vector和list公共的操作:使用迭代器,不使用下標操作,避免隨機訪問。這樣,在必要時選擇使用vector或list都很方便。
一般來說,每個容器都定義在一個頭文件中,文件名與類型名相同。即,deque定義在頭文件deque中,list定義在頭文件list中,以此類推。容器均定義為模板類。
順序容器幾乎可以保存任意類型的元素。特別是,我們可以定義一個容器,其元素的類型是另一個容器。這種容器的定義與任何其他容器類型完全一樣:在尖括號中指定元素類型(此種情況下,是另一種容器類型)。
除了順序容器外,標準庫還定義了三個順序容器適配器:stack、queue和priority_queue。適配器(adaptor)是標準庫中的一個通用概念。容器、迭代器和函數都有適配器。本質上,一個適配器是一種機制,能使某種事物的行為看起來像另外一種事物一樣。一個容器適配器接受一種已有的容器類型,使其行為看起來像一種不同的類型。下面是從其他文章中copy的測試代碼,詳細內容介紹可以參考對應的reference:
#include "stack.hpp"
#include <iostream>
#include <stack>
#include <vector>
#include <deque>
#include <list>
#include <string>// https://msdn.microsoft.com/en-us/library/56fa1zk5.aspx
int test_stack_2()
{using namespace std;// Declares stack with default deque base container stack <char> dsc1;//Explicitly declares a stack with deque base container stack <char, deque<char> > dsc2;// Declares a stack with vector base containers stack <int, vector<int> > vsi1;// Declares a stack with list base container stack <int, list<int> > lsi;// The second member function copies elements from a container vector<int> v1;v1.push_back(1);stack <int, vector<int> > vsi2(v1);cout << "The element at the top of stack vsi2 is "<< vsi2.top() << "." << endl;return 0;
}///
// reference: http://www.cplusplus.com/reference/stack/stack/
int test_stack_1()
{
{ // stack::stack: Constructs a stack container adaptor objectstd::deque<int> mydeque(3, 100); // deque with 3 elementsstd::vector<int> myvector(2, 200); // vector with 2 elementsstd::stack<int> first; // empty stackstd::stack<int> second(mydeque); // stack initialized to copy of dequestd::stack<int, std::vector<int> > third; // empty stack using vectorstd::stack<int, std::vector<int> > fourth(myvector);std::cout << "size of first: " << first.size() << '\n';std::cout << "size of second: " << second.size() << '\n';std::cout << "size of third: " << third.size() << '\n';std::cout << "size of fourth: " << fourth.size() << '\n';
}{ // stack::emplace: c++11, Adds a new element at the top of the stack, above its current top element.// This new element is constructed in place passing args as the arguments for its constructorstd::stack<std::string> mystack;mystack.emplace("First sentence");mystack.emplace("Second sentence");std::cout << "mystack contains:\n";while (!mystack.empty()) {std::cout << mystack.top() << '\n';mystack.pop();}
}{ // stack::empty: Returns whether the stack is empty: i.e. whether its size is zero// stack::pop: Removes the element on top of the stack, effectively reducing its size by one// stack::push: Inserts a new element at the top of the stack, above its current top element.// The content of this new element is initialized to a copy of val.std::stack<int> mystack;int sum(0);for (int i = 1; i <= 10; i++) mystack.push(i);while (!mystack.empty()) {sum += mystack.top();mystack.pop();}std::cout << "total: " << sum << '\n';
}{ // stack::size: Returns the number of elements in the stack.std::stack<int> myints;std::cout << "0. size: " << myints.size() << '\n';for (int i = 0; i < 5; i++) myints.push(i);std::cout << "1. size: " << myints.size() << '\n';myints.pop();std::cout << "2. size: " << myints.size() << '\n';
}{ // stack::swap: Exchanges the contents of the container adaptor (*this) by those of x.std::stack<int> foo, bar;foo.push(10); foo.push(20); foo.push(30);bar.push(111); bar.push(222);foo.swap(bar);// std::swap(foo, bar);std::cout << "size of foo: " << foo.size() << '\n';std::cout << "size of bar: " << bar.size() << '\n';
}{ // stack::top: Returns a reference to the top element in the stack. std::stack<int> mystack;mystack.push(10);mystack.push(20);mystack.top() -= 5;std::cout << "mystack.top() is now " << mystack.top() << '\n';
}return 0;
}
GitHub: https://github.com/fengbingchun/Messy_Test
總結
以上是生活随笔為你收集整理的C++/C++11中std::stack的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++/C++11中std::deque
- 下一篇: 矩阵特征分解介绍及雅克比(Jacobi)