為了建立數據結構和算法的一套標準,并且降低他們之間的耦合關系,以提升各自的獨立性、彈性、交互操作性(相互合作性,interoperability),誕生了STL。
STL提供了六大組件,彼此之間可以組合套用,這六大組件分別是:容器、算法、迭代器、仿函數、適配器(配接器)、空間配置器。
STL六大組件的交互關系,容器通過空間配置器取得數據存儲空間,算法通過迭代器存儲容器中的內容,仿函數可以協助算法完成不同的策略的變化,適配器可以修飾仿函數。
STL容器就是將運用最廣泛的一些數據結構實現出來。
常用的數據結構:數組(array) , 鏈表(list), tree(樹),棧(stack), 隊列(queue), 集合(set),映射表(map), 根據數據在容器中的排列特性,這些數據分為序列式容器和關聯式容器兩種。
序列式容器強調值的排序,序列式容器中的每個元素均有固定的位置,除非用刪除或插入的操作改變這個位置。Vector容器、Deque容器、List容器等。
關聯式容器是非線性的樹結構,更準確的說是二叉樹結構。各元素之間沒有嚴格的物理上的順序關系,也就是說元素在容器中并沒有保存元素置入容器時的邏輯順序。關聯式容器另一個顯著特點是:在值中選擇一個值作為關鍵字key,這個關鍵字對值起到索引的作用,方便查找。Set/multiset容器 Map/multimap容器
array 是固定大小的順序容器,它們保存了一個以嚴格的線性順序排列的特定數量的元素。
#include<iostream>
#include<array>
using namespace std;
int main()
{
array<int, 8> myArr = {1,3,4,6,9};//固定大小為8
cout << "myArr元素序列:";
for (auto i = 0; i < 8; ++i)
{
cout << myArr[i] << " ";
}
cout << endl;
array<int, 8> myArr1 = {2,3,4,7,8,9};//固定大小為8
cout << "myArr1元素序列:";
for (auto i = 0; i < 8; ++i)
{
cout << myArr1[i] << " ";
}
cout << endl;
myArr.swap(myArr1); //交換兩個容器的內容
cout << "交換myArr與myArr1"<< endl;
cout << endl;
cout << "myArr.at(3) = " << myArr.at(3) << endl;//任意訪問
cout << "myArr[3] = " << myArr[3] << endl;//任意訪問
cout << "myArr.front() = " << myArr.front() << endl;//獲取第一個元素
cout << "myArr.back() = " << myArr.back() << endl;//獲取最后一個元素
cout << "myArr.data() = " << myArr.data() << endl;//獲取第一個元素的指針
cout << "*myArr.data() = " << *myArr.data() << endl;//獲取第一個元素的指針指向的元素
cout << "正向迭代器遍歷容器:";
for (auto it = myArr.begin(); it != myArr.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
//逆向迭代器測試
cout << "逆向迭代器遍歷容器:";
for (auto rit = myArr.rbegin(); rit != myArr.rend(); ++rit)
{
cout << *rit << " ";
}
cout << endl;
//正向常迭代器測試
cout << "正向常迭代器遍歷容器:";
for (auto it = myArr.cbegin(); it != myArr.cend(); ++it)
{
cout << *it << " ";
}
cout << endl;
//逆向常迭代器測試
cout << "逆向常迭代器遍歷容器:";
for (auto rit = myArr.crbegin(); rit != myArr.crend(); ++rit)
{
cout << *rit << " ";
}
cout << endl;
if(myArr.empty())
cout << "myArr為空 " << endl;
else
cout << "myArr不為空 " << endl;
cout << "myArr.size() = " << myArr.size() << endl;
cout << "myArr.max_size() = " << myArr.max_size() << endl;
return 0;
}
運行結果
vector 是表示可以改變大小的數組的序列容器。
方法說明vector構造函數~vector析構函數,銷毀容器對象operator=將新內容分配給容器,替換其當前內容,并相應地修改其大小begin返回指向容器中第一個元素的迭代器end返回指向容器中最后一個元素之后的理論元素的迭代器rbegin返回指向容器中最后一個元素的反向迭代器rend返回一個反向迭代器,指向中第一個元素之前的理論元素cbegin返回指向容器中第一個元素的常量迭代器(const_iterator)cend返回指向容器中最后一個元素之后的理論元素的常量迭代器(const_iterator)crbegin返回指向容器中最后一個元素的常量反向迭代器(const_reverse_iterator)crend返回指向容器中第一個元素之前的理論元素的常量反向迭代器(const_reverse_iterator)size返回容器中元素的數量max_size返回容器可容納的最大元素數resize調整容器的大小,使其包含 n(參數)個元素capacity返回當前為 vector 分配的存儲空間(容量)的大小empty返回 vector 是否為空reserve請求 vector 容量至少足以包含 n(參數)個元素shrink_to_fit要求容器減小其 capacity(容量)以適應其 size(元素數量)operator[]返回容器中第 n(參數)個位置的元素的引用at返回容器中第 n(參數)個位置的元素的引用front返回對容器中第一個元素的引用back返回對容器中最后一個元素的引用data返回指向容器中第一個元素的指針assign將新內容分配給 vector,替換其當前內容,并相應地修改其 sizepush_back在容器的最后一個元素之后添加一個新元素pop_back刪除容器中的最后一個元素,有效地將容器 size 減少一個insert通過在指定位置的元素之前插入新元素來擴展該容器,通過插入元素的數量有效地增加容器大小erase從 vector 中刪除單個元素(position)或一系列元素([first,last)),這有效地減少了被去除的元素的數量,從而破壞了容器的大小swap通過 x(參數)的內容交換容器的內容,x 是另一個類型相同、size 可能不同的 vector 對象clear從 vector 中刪除所有的元素(被銷毀),留下 size 為 0 的容器emplace通過在 position(參數)位置處插入新元素 args(參數)來擴展容器emplace_back在 vector 的末尾插入一個新的元素,緊跟在當前的最后一個元素之后get_allocator返回與vector關聯的構造器對象的副本swap(vector)容器 x(參數)的內容與容器 y(參數)的內容交換。兩個容器對象都必須是相同的類型(相同的模板參數),盡管大小可能不同relational operators (vector)形如 vectorA > vectorB;依此比較每個元素的大小關系
#include <vector>
#include <iostream>
using namespace std;
int main()
{
//構造函數,復制構造函數(元素類型要一致),
vector<int> vecA; //創建一個空的的容器
vector<int> vecB(10,20); //創建一個10個元素,每個元素值為20
vector<int> vecC(vecB.begin(),vecB.end()); //使用迭代器,可以取部分元素創建一個新的容器
vector<int> vecD(vecC); //復制構造函數,創建一個完全一樣的容器
//重載=
vector<int> vecE;
vecE = vecB;
//vector::begin(),返回的是迭代器
vector<int> vecF(10); //創建一個有10個元素的容器
cout << "vecF:";
for (int i = 0; i < 10; i++)
{
vecF[i] = i;
cout << vecF[i]<< " ";
}
cout << endl;
//vector::begin() 返回迭代器
vector<int>::iterator Beginit = vecF.begin();
cout<< "vecF.begin():" << *Beginit << endl;
//vector::end() 返回迭代器
vector<int>::iterator EndIter = vecF.end();
EndIter--; //向后移一個位置
cout <<"vecF.end():"<< *EndIter << endl;
//vector::rbegin() 返回倒序的第一個元素,相當于最后一個元素
vector<int>::reverse_iterator ReverBeIter = vecF.rbegin();
cout << "vecF.rbegin(): "<< *ReverBeIter << endl;
//vector::rend() 反序的最后一個元素下一個位置,也相當于正序的第一個元素前一個位置
vector<int>::reverse_iterator ReverEnIter = vecF.rend();
ReverEnIter--;
cout << "vecF.rend():"<< *ReverEnIter << endl;
//vector::size() 返回元素的個數
cout << "vecF.size():"<< vecF.size() << endl;
//vector::max_size()
cout << "vecF.max_size():"<< vecF.max_size() << endl;
//vector::resize()
cout<< "vecF.size():" << vecF.size() << endl;
vecF.resize(5);
cout<< "調整vecF大小后重新賦值:";
for(int k = 0; k < vecF.size(); k++)
cout << vecF[k] << " ";
cout << endl;
//vector::capacity()
cout<< "調整后vecF.size():"<< vecF.size() << endl;
cout<< "調整后vecF.capacity():" << vecF.capacity() << endl;
//vector::empty()
vecB.resize(0);
cout<< "vecB.resize(0)后"<< endl;
cout << "vecB.size():" << vecB.size() << endl;
cout << "vecB.capacity():" << vecB.capacity() << endl;
if(vecB.empty())
cout << "vecB為空"<< endl;
else
cout << "vecB不為空"<< endl;
//vector::reserve() //重新分配存儲空間大小
cout<< "vecC.capacity():" << vecC.capacity() << endl; //
vecC.reserve(4);
cout << "vecC.reserve(4)后vecC.capacity(): "<< vecC.capacity() << endl; //10
vecC.reserve(14);
cout << "vecC.reserve(14)后vecC.capacity(): "<< vecC.capacity() << endl; //14
//vector::operator []
cout << "vecF[0]:"<< vecF[0] << endl; //第一個元素是0
//vector::at()
try
{
cout << "vecF.size = " << vecF.size() << endl; //5
cout << vecF.at(6) << endl; //拋出異常
}
catch(out_of_range)
{
cout << "at()訪問越界" << endl;
}
//vector::front() 返回第一個元素的值
cout << "vecF.front():"<< vecF.front() << endl; //0
//vector::back()
cout << "vecF.back():"<< vecF.back() << endl; //4
//vector::assign()
cout <<"vecA.size():"<< vecA.size() << endl; //0
vector<int>::iterator First = vecC.begin();
vector<int>::iterator End = vecC.end()-2;
vecA.assign(First,End);
cout << vecA.size() << endl; //8
cout << vecA.capacity() << endl; //8
vecA.assign(5,3); //將丟棄原來的所有元素然后重新賦值
cout << vecA.size() << endl; //5
cout << vecA.capacity() << endl; //8
//vector::push_back()
cout << *(vecF.end()-1) << endl; //4
vecF.push_back(20);
cout << *(vecF.end()-1) << endl; //20
//vector::pop_back()
cout << *(vecF.end()-1) << endl; //20
vecF.pop_back();
cout << *(vecF.end()-1) << endl; //4
//vector::swap()
cout << "vecF:";
for (int i = 0; i < vecF.size(); i++)
{
vecF[i] = i;
cout << vecF[i]<< " ";
}
cout << endl;
cout << "vecD:";
for (int d = 0; d < vecD.size(); d++)
{
vecD[d] = d;
cout << vecD[d]<< " ";
}
cout << endl;
vecF.swap(vecD); //交換這兩個容器的內容
cout <<"vecD與vecF交換后:" <<endl;
cout << "vecF:";
for(int f = 0; f < vecF.size(); f++)
cout << vecF[f] << " ";
cout << endl;
cout << "vecD:";
for (int d = 0; d <vecD.size(); d++)
cout << vecD[d] << " ";
cout << endl;
//vector::clear()
vecF.clear();
cout << "vecF.clear()后vecF.size():"<< vecF.size() << endl; //0
cout << "vecF.clear()后vecF.capacity():"<< vecF.capacity() << endl; //10
return 0;
}
運行結果
deque容器為一個給定類型的元素進行線性處理,像向量一樣,它能夠快速地隨機訪問任一個元素,并且能夠高效地插入和刪除容器的尾部元素。但它又與vector不同,deque支持高效插入和刪除容器的頭部元素,因此也叫做雙端隊列。
deque的中控器: deque是由一段一段的定量連續空間構成。一旦有必要在deque的前端或尾端增加新空間,便配置一段定量連續空間,串接在整個deque的頭端或尾端。deque的最大任務,便是在這些分段的定量連續空間上,維護其整體連續的假象,并提供隨機存取的接口。避開了“重新配置、復制、釋放”的輪回,代價則是復雜的迭代器結構。
deque采用一塊所謂的map(不是STL的map容器)作為主控。
map是一小塊連續空間,其中每個元素(此處稱為一個節點,node)都是指針,指向另一段(較大的)連續線性空間,稱為緩沖區。
緩沖區才是deque的儲存空間主體。
template<class T, class Alloc = alloc, size_t BufSiz = 0>
class deque{
public :
typedef T value_type ;
typedef value_type* pointer ;
...
protected :
//元素的指針的指針(pointer of pointer of T)
// 其實就是T**,一個二級指針,維護一個二維數組
typedef pointer* map_pointer ;
protected :
map_pointer map ; //指向map,map是塊連續空間,其內的每個元素
//都是一個指針(稱為節點),指向一塊緩沖區
size_type map_size ;//map內可容納多少指針
...
};
map其實是一個T**,也就是說它是一個指針,所指之物也是一個指針,指向型別為T的一塊空間。
方法說明deque構造函數push_back在當前的最后一個元素之后 ,在 deque 容器的末尾添加一個新元素push_front在 deque 容器的開始位置插入一個新的元素,位于當前的第一個元素之前pop_back刪除 deque 容器中的最后一個元素,有效地將容器大小減少一個pop_front刪除 deque 容器中的第一個元素,有效地減小其大小emplace_front在 deque 的開頭插入一個新的元素,就在其當前的第一個元素之前emplace_back在 deque 的末尾插入一個新的元素,緊跟在當前的最后一個元素之后
#include "stdafx.h"
#include<iostream>
#include<deque>
using namespace std;
int main()
{
deque<int> d;
d.push_back( 11 );//在 deque 容器的末尾添加一個新元素
d.push_back(20);
d.push_back(35);
cout<<"初始化雙端隊列d:"<<endl;
for(int i = 0; i < d.size(); i++)
{
cout<<d.at(i)<<"\t";
}
cout<<endl;
d.push_front(10);//容器的開始位置插入一個新的元素,位于當前的第一個元素之前
d.push_front(7);
d.push_front(1);
cout<<"隊列d向前陸續插入10、7、1:"<<endl;
for(int i = 0;i < d.size();i++)
{
cout<<d.at(i)<<"\t";
}
cout<<endl;
d.pop_back(); //刪除 deque 容器中的最后一個元素,有效地將容器大小減少一個
d.pop_front(); //刪除 deque 容器中的第一個元素,有效地減小其大小
cout<<"刪除deque最后一個和第一個元素后:"<<endl;
for(int i = 0;i < d.size();i++)
{
cout<<d.at(i)<<"\t";
}
cout<<endl;
return 0;
}
在頭文件<forward_list>中,與list類似,區別就是list時雙鏈表,forward_list是單鏈表,forward_list(單向鏈表)是序列容器,允許在序列中的任何地方進行恒定的時間插入和擦除操作。在鏈表的任何位置進行插入/刪除操作都非常快。
forward_list的特點:
容器成員函數總結就不寫了,太多影響閱讀,感興趣小伙伴戳http://www.cplusplus.com/reference/stl/
list雙向鏈表,是序列容器,允許在序列中的任何地方進行常數時間插入和擦除操作,并在兩個方向上進行迭代,可以高效地進行插入刪除元素。
使用list容器之前必須加上頭文件:#include;
list容器的底層實現:
和 array、vector 這些容器迭代器的實現方式不同,由于 list 容器的元素并不是連續存儲的,所以該容器迭代器中,必須包含一個可以指向 list 容器的指針,并且該指針還可以借助重載的 *、++、--、==、!= 等運算符,實現迭代器正確的遞增、遞減、取值等操作。
template<tyepname T,...>
struct __list_iterator{
__list_node<T>* node;
//...
//重載 == 運算符
bool operator==(const __list_iterator& x){return node == x.node;}
//重載 != 運算符
bool operator!=(const __list_iterator& x){return node != x.node;}
//重載 * 運算符,返回引用類型
T* operator *() const {return *(node).myval;}
//重載前置 ++ 運算符
__list_iterator<T>& operator ++(){
node = (*node).next;
return *this;
}
//重載后置 ++ 運算符
__list_iterator<T>& operator ++(int){
__list_iterator<T> tmp = *this;
++(*this);
return tmp;
}
//重載前置 -- 運算符
__list_iterator<T>& operator--(){
node = (*node).prev;
return *this;
}
//重載后置 -- 運算符
__list_iterator<T> operator--(int){
__list_iterator<T> tmp = *this;
--(*this);
return tmp;
}
//...
}
stack沒有迭代器,是一種容器適配器,用于在LIFO(后進先出)的操作,其中元素僅從容器的一端插入和提取。
stack底層一般用list或deque實現,封閉頭部即可,不用vector的原因應該是容量大小有限制,擴容耗時
底層用deque實現:
//deque<T> >中間有個空格是為了兼容較老的版本
template <class T, class Sequence = deque<T> >
class stack {
// 以下的 __STL_NULL_TMPL_ARGS 會開展為 <>
friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; // 底層容器
public:
// 以下完全利用 Sequence c 的操作,完成 stack 的操作。
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() { return c.back(); }
const_reference top() const { return c.back(); }
// deque 是兩頭可進出,stack 是末端進,末端出(所以后進者先出)。
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};
template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c == y.c;
}
template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c < y.c;
}
底層用list實現:
#include<stack>
#include<list>
#include<algorithm>
#include <iostream>
using namespace std;
int main(){
stack<int, list<int>> istack;
istack.push(1);
istack.push(3);
istack.push(5);
cout << istack.size() << endl; //3
cout << istack.top() << endl;//5
istack.pop();
cout << istack.top() << endl;//3
cout << istack.size() << endl;//2
system("pause");
return 0;
}
queue 是一種容器適配器,用于在FIFO(先入先出)的操作,其中元素插入到容器的一端并從另一端提取。
隊列不提供迭代器,不實現遍歷操作。
template <class T, class Sequence = deque<T> >
class queue {
friend bool operator== __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
friend bool operator< __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c;
public:
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { return c.back(); }
const_reference back() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
template <class T, class Sequence>
bool operator==(const queue<T, Sequence>& x, const queue<T, Sequence>& y) {
return x.c == y.c;
}
template <class T, class Sequence>
bool operator<(const queue<T, Sequence>& x, const queue<T, Sequence>& y) {
return x.c < y.c;
}
優先隊列,其底層是用堆來實現的。在優先隊列中,隊首元素一定是當前隊列中優先級最高的那一個。
set 是按照特定順序存儲唯一元素的容器。
template<class _Kty,
class _Pr = less<_Kty>,
class _Alloc = allocator<_Kty> >
class set
multiset允許元素重復而set不允許。
template<class _Kty,
class _Pr = less<_Kty>,
class _Alloc = allocator<_Kty> >
class multiset
map 是關聯容器,按照特定順序存儲由 key value (鍵值) 和 mapped value (映射值) 組合形成的元素。
由于 RB-tree 是一種平衡二叉搜索樹,自動排序的效果很不錯,所以標準的STL map 即以 RB-tree 為底層機制。又由于 map 所開放的各種操作接口,RB-tree 也都提供了,所以幾乎所有的 map 操作行為,都只是轉調 RB-tree 的操作行為。
方法說明map構造函數begin返回引用容器中第一個元素的迭代器key_comp返回容器用于比較鍵的比較對象的副本value_comp返回可用于比較兩個元素的比較對象,以獲取第一個元素的鍵是否在第二個元素之前find在容器中搜索具有等于 k的鍵的元素,如果找到返回一個迭代器,否則返回 map::endcount在容器中搜索具有等于 k(參數)的鍵的元素,并返回匹配的數量lower_bound返回一個非遞減序列 [first, last)中的第一個大于等于值 val的位置的迭代器upper_bound返回一個非遞減序列 [first, last)中第一個大于 val的位置的迭代器equal_range獲取相同元素的范圍,返回包含容器中所有具有與 k等價的鍵的元素的范圍邊界
multimap 的特性以及用法與 map 完全相同,唯一的差別在于它允許鍵值重復,因此它的插入操作采用的是底層機制 RB-tree 的 insert_equal() 而非 insert_unique。
unordered_set是基于哈希表,因此要了解unordered_set,就必須了解哈希表的機制。哈希表是根據關鍵碼值而進行直接訪問的數據結構,通過相應的哈希函數(也稱散列函數)處理關鍵字得到相應的關鍵碼值,關鍵碼值對應著一個特定位置,用該位置來存取相應的信息,這樣就能以較快的速度獲取關鍵字的信息。
template < class Key,
class Hash = hash<Key>,
class Pred = equal_to<Key>,
class Alloc = allocator<Key>
> class unordered_set;
find(beg, end, val); // 返回一個迭代器,指向輸入序列中第一個等于 val 的元素,未找到返回 end
find_if(beg, end, unaryPred); // 返回一個迭代器,指向第一個滿足 unaryPred 的元素,未找到返回 end
find_if_not(beg, end, unaryPred); // 返回一個迭代器,指向第一個令 unaryPred 為 false 的元素,未找到返回 end
count(beg, end, val); // 返回一個計數器,指出 val 出現了多少次
count_if(beg, end, unaryPred); // 統計有多少個元素滿足 unaryPred
all_of(beg, end, unaryPred); // 返回一個 bool 值,判斷是否所有元素都滿足 unaryPred
any_of(beg, end, unaryPred); // 返回一個 bool 值,判斷是否任意(存在)一個元素滿足 unaryPred
none_of(beg, end, unaryPred); // 返回一個 bool 值,判斷是否所有元素都不滿足 unaryPred
adjacent_find(beg, end); // 返回指向第一對相鄰重復元素的迭代器,無相鄰元素則返回 end
adjacent_find(beg, end, binaryPred); // 返回指向第一對相鄰重復元素的迭代器,無相鄰元素則返回 end
search_n(beg, end, count, val); // 返回一個迭代器,從此位置開始有 count 個相等元素,不存在則返回 end
search_n(beg, end, count, val, binaryPred); // 返回一個迭代器,從此位置開始有 count 個相等元素,不存在則返回 end
search(beg1, end1, beg2, end2); // 返回第二個輸入范圍(子序列)在爹一個輸入范圍中第一次出現的位置,未找到則返回 end1
search(beg1, end1, beg2, end2, binaryPred); // 返回第二個輸入范圍(子序列)在爹一個輸入范圍中第一次出現的位置,未找到則返回 end1
find_first_of(beg1, end1, beg2, end2); // 返回一個迭代器,指向第二個輸入范圍中任意元素在第一個范圍中首次出現的位置,未找到則返回end1
find_first_of(beg1, end1, beg2, end2, binaryPred); // 返回一個迭代器,指向第二個輸入范圍中任意元素在第一個范圍中首次出現的位置,未找到則返回end1
find_end(beg1, end1, beg2, end2); // 類似 search,但返回的最后一次出現的位置。如果第二個輸入范圍為空,或者在第一個輸入范圍為空,或者在第一個輸入范圍中未找到它,則返回 end1
find_end(beg1, end1, beg2, end2, binaryPred); // 類似 search,但返回的最后一次出現的位置。如果第二個輸入范圍為空,或者在第一個輸入范圍為空,或者在第一個輸入范圍中未找到它,則返回 end1
for_each(beg, end, unaryOp); // 對輸入序列中的每個元素應用可調用對象 unaryOp,unaryOp 的返回值被忽略
mismatch(beg1, end1, beg2); // 比較兩個序列中的元素。返回一個迭代器的 pair,表示兩個序列中第一個不匹配的元素
mismatch(beg1, end1, beg2, binaryPred); // 比較兩個序列中的元素。返回一個迭代器的 pair,表示兩個序列中第一個不匹配的元素
equal(beg1, end1, beg2); // 比較每個元素,確定兩個序列是否相等。
equal(beg1, end1, beg2, binaryPred); // 比較每個元素,確定兩個序列是否相等。
lower_bound(beg, end, val); // 返回一個非遞減序列 [beg, end) 中的第一個大于等于值 val 的位置的迭代器,不存在則返回 end
lower_bound(beg, end, val, comp); // 返回一個非遞減序列 [beg, end) 中的第一個大于等于值 val 的位置的迭代器,不存在則返回 end
upper_bound(beg, end, val); // 返回一個非遞減序列 [beg, end) 中第一個大于 val 的位置的迭代器,不存在則返回 end
upper_bound(beg, end, val, comp); // 返回一個非遞減序列 [beg, end) 中第一個大于 val 的位置的迭代器,不存在則返回 end
equal_range(beg, end, val); // 返回一個 pair,其 first 成員是 lower_bound 返回的迭代器,其 second 成員是 upper_bound 返回的迭代器
binary_search(beg, end, val); // 返回一個 bool 值,指出序列中是否包含等于 val 的元素。對于兩個值 x 和 y,當 x 不小于 y 且 y 也不小于 x 時,認為它們相等。
fill(beg, end, val); // 將 val 賦予每個元素,返回 void
fill_n(beg, cnt, val); // 將 val 賦予 cnt 個元素,返回指向寫入到輸出序列最有一個元素之后位置的迭代器
genetate(beg, end, Gen); // 每次調用 Gen() 生成不同的值賦予每個序列,返回 void
genetate_n(beg, cnt, Gen); // 每次調用 Gen() 生成不同的值賦予 cnt 個序列,返回指向寫入到輸出序列最有一個元素之后位置的迭代器
7.使用輸入迭代器的寫算法,讀取一個輸入序列,將值寫入到一個輸出序列(dest)中
copy(beg, end, dest); // 從輸入范圍將元素拷貝所有元素到 dest 指定定的目的序列
copy_if(beg, end, dest, unaryPred); // 從輸入范圍將元素拷貝滿足 unaryPred 的元素到 dest 指定定的目的序列
copy_n(beg, n, dest); // 從輸入范圍將元素拷貝前 n 個元素到 dest 指定定的目的序列
move(beg, end, dest); // 對輸入序列中的每個元素調用 std::move,將其移動到迭代器 dest 開始始的序列中
transform(beg, end, dest, unaryOp); // 調用給定操作(一元操作),并將結果寫到dest中
transform(beg, end, beg2, dest, binaryOp); // 調用給定操作(二元操作),并將結果寫到dest中
replace_copy(beg, end, dest, old_val, new_val); // 將每個元素拷貝到 dest,將等于 old_val 的的元素替換為 new_val
replace_copy_if(beg, end, dest, unaryPred, new_val); // 將每個元素拷貝到 dest,將滿足 unaryPred 的的元素替換為 new_val
merge(beg1, end1, beg2, end2, dest); // 兩個輸入序列必須都是有序的,用小于號運算符將合并后的序列寫入到 dest 中
merge(beg1, end1, beg2, end2, dest, comp); // 兩個輸入序列必須都是有序的,使用給定的比較操作(comp)將合并后的序列寫入到 dest 中
8.劃分算法,要求雙向選代器(bidirectional iterator)
is_partitioned(beg, end, unaryPred); // 如果所有滿足謂詞 unaryPred 的元素都在不滿足 unarypred 的元素之前,則返回 true。若序列為空,也返回 true
partition_copy(beg, end, dest1, dest2, unaryPred); // 將滿足 unaryPred 的元素拷貝到到 dest1,并將不滿足 unaryPred 的元素拷貝到到 dest2。返回一個迭代器 pair,其 first 成員表示拷貝到 dest1 的的元素的末尾,second 表示拷貝到 dest2 的元素的末尾。
partitioned_point(beg, end, unaryPred); // 輸入序列必須是已經用 unaryPred 劃分過的。返回滿足 unaryPred 的范圍的尾后迭代器。如果返回的迭代器不是 end,則它指向的元素及其后的元素必須都不滿足 unaryPred
stable_partition(beg, end, unaryPred); // 使用 unaryPred 劃分輸入序列。滿足 unaryPred 的元素放置在序列開始,不滿足的元素放在序列尾部。返回一個迭代器,指向最后一個滿足 unaryPred 的元素之后的位置如果所有元素都不滿足 unaryPred,則返回 beg
partition(beg, end, unaryPred); // 使用 unaryPred 劃分輸入序列。滿足 unaryPred 的元素放置在序列開始,不滿足的元素放在序列尾部。返回一個迭代器,指向最后一個滿足 unaryPred 的元素之后的位置如果所有元素都不滿足 unaryPred,則返回 beg
sort(beg, end); // 排序整個范圍
stable_sort(beg, end); // 排序整個范圍(穩定排序)
sort(beg, end, comp); // 排序整個范圍
stable_sort(beg, end, comp); // 排序整個范圍(穩定排序)
is_sorted(beg, end); // 返回一個 bool 值,指出整個輸入序列是否有序
is_sorted(beg, end, comp); // 返回一個 bool 值,指出整個輸入序列是否有序
is_sorted_until(beg, end); // 在輸入序列中査找最長初始有序子序列,并返回子序列的尾后迭代器
is_sorted_until(beg, end, comp); // 在輸入序列中査找最長初始有序子序列,并返回子序列的尾后迭代器
partial_sort(beg, mid, end); // 排序 mid-beg 個元素。即,如果 mid-beg 等于 42,則此函數將值最小的 42 個元素有序放在序列前 42 個位置
partial_sort(beg, mid, end, comp); // 排序 mid-beg 個元素。即,如果 mid-beg 等于 42,則此函數將值最小的 42 個元素有序放在序列前 42 個位置
partial_sort_copy(beg, end, destBeg, destEnd); // 排序輸入范圍中的元素,并將足夠多的已排序元素放到 destBeg 和 destEnd 所指示的序列中
partial_sort_copy(beg, end, destBeg, destEnd, comp); // 排序輸入范圍中的元素,并將足夠多的已排序元素放到 destBeg 和 destEnd 所指示的序列中
nth_element(beg, nth, end); // nth 是一個迭代器,指向輸入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它
nth_element(beg, nth, end, comp); // nth 是一個迭代器,指向輸入序列中第 n 大的元素。nth 之前的元素都小于等于它,而之后的元素都大于等于它
remove(beg, end, val); // 通過用保留的元素覆蓋要刪除的元素實現刪除 ==val 的元素,返回一個指向最后一個刪除元素的尾后位置的迭代器
remove_if(beg, end, unaryPred); // 通過用保留的元素覆蓋要刪除的元素實現刪除滿足 unaryPred 的元素,返回一個指向最后一個刪除元素的尾后位置的迭代器
remove_copy(beg, end, dest, val); // 通過用保留的元素覆蓋要刪除的元素實現刪除 ==val 的元素,返回一個指向最后一個刪除元素的尾后位置的迭代器
remove_copy_if(beg, end, dest, unaryPred); // 通過用保留的元素覆蓋要刪除的元素實現刪除滿足 unaryPred 的元素,返回一個指向最后一個刪除元素的尾后位置的迭代器
unique(beg, end); // 通過對覆蓋相鄰的重復元素(用 == 確定是否相同)實現重排序列。返回一個迭代器,指向不重復元素的尾后位置
unique (beg, end, binaryPred); // 通過對覆蓋相鄰的重復元素(用 binaryPred 確定是否相同)實現重排序列。返回一個迭代器,指向不重復元素的尾后位置
unique_copy(beg, end, dest); // 通過對覆蓋相鄰的重復元素(用 == 確定是否相同)實現重排序列。返回一個迭代器,指向不重復元素的尾后位置
unique_copy_if(beg, end, dest, binaryPred); // 通過對覆蓋相鄰的重復元素(用 binaryPred 確定是否相同)實現重排序列。返回一個迭代器,指向不重復元素的尾后位置
rotate(beg, mid, end); // 圍繞 mid 指向的元素進行元素轉動。元素 mid 成為為首元素,隨后是 mid+1 到到 end 之前的元素,再接著是 beg 到 mid 之前的元素。返回一個迭代器,指向原來在 beg 位置的元素
rotate_copy(beg, mid, end, dest); // 圍繞 mid 指向的元素進行元素轉動。元素 mid 成為為首元素,隨后是 mid+1 到到 end 之前的元素,再接著是 beg 到 mid 之前的元素。返回一個迭代器,指向原來在 beg 位置的元素
reverse(beg, end); // 翻轉序列中的元素,返回 void
reverse_copy(beg, end, dest);; // 翻轉序列中的元素,返回一個迭代器,指向拷貝到目的序列的元素的尾后位置
random_shuffle(beg, end); // 混洗輸入序列中的元素,返回 void
random_shuffle(beg, end, rand); // 混洗輸入序列中的元素,rand 接受一個正整數的隨機對象,返回 void
shuffle(beg, end, Uniform_rand); // 混洗輸入序列中的元素,Uniform_rand 必須滿足均勻分布隨機數生成器的要求,返回 void
min(val1, va12); // 返回 val1 和 val2 中的最小值,兩個實參的類型必須完全一致。參數和返回類型都是 const的引引用,意味著對象不會被拷貝。下略
min(val1, val2, comp);
min(init_list);
min(init_list, comp);
max(val1, val2);
max(val1, val2, comp);
max(init_list);
max(init_list, comp);
minmax(val1, val2); // 返回一個 pair,其 first 成員為提供的值中的較小者,second 成員為較大者。下略
minmax(vall, val2, comp);
minmax(init_list);
minmax(init_list, comp);
min_element(beg, end); // 返回指向輸入序列中最小元素的迭代器
min_element(beg, end, comp); // 返回指向輸入序列中最小元素的迭代器
max_element(beg, end); // 返回指向輸入序列中最大元素的迭代器
max_element(beg, end, comp); // 返回指向輸入序列中最大元素的迭代器
minmax_element(beg, end); // 返回一個 pair,其中 first 成員為最小元素,second 成員為最大元素
minmax_element(beg, end, comp); // 返回一個 pair,其中 first 成員為最小元素,second 成員為最大元素
lexicographical_compare(beg1, end1, beg2, end2);
lexicographical_compare(beg1, end1, beg2, end2, comp);
需要根據容器的特點和使用場景而定,可能滿足需求的不止一種容器。
按是否有序關聯性分為:
注意:deque 容器歸為使用連續存儲空間的這一類,是存在爭議的。因為 deque 容器底層采用一段一段的連續空間存儲元素,但是各段存儲空間之間并不一定是緊挨著的。
選擇容器流程圖(來源于網絡)
選擇容器的幾點建議:
vector底層是一個動態數組,包含三個迭代器,start和finish之間是已經被使用的空間范圍,end_of_storage是整塊連續空間包括備用空間的尾部。
當空間不夠裝下數據(vec.push_back(val))時,會自動申請另一片更大的空間(1.5倍或者2倍),然后把原來的數據拷貝到新的內存空間,接著釋放原來的那片空間【vector內存增長機制】。
當釋放或者刪除(vec.clear())里面的數據時,其存儲空間不釋放,僅僅是清空了里面的數據。
因此,對vector的任何操作一旦引起了空間的重新配置,指向原vector的所有迭代器會都失效了
map 、set、multiset、multimap的底層實現都是紅黑樹,epoll模型的底層數據結構也是紅黑樹,linux系統中CFS進程調度算法,也用到紅黑樹。
紅黑樹的特性:
存儲結構:hash_map以hashtable為底層,而map以RB-TREE為底層。
總的說來,hash_map查找速度比map快,而且查找速度基本和數據量大小無關,屬于常數級別。而map的查找速度是logn級別。但不一定常數就比log小,而且hash_map還有hash function耗時。
如果考慮效率,特別當元素達到一定數量級時,用hash_map。
考慮內存,或者元素數量較少時,用map。
插入操作:
刪除操作:
http://www.cplusplus.com/reference/stl/ https://blog.csdn.net/qq_23350817/article/details/87930715 https://blog.csdn.net/bizhu12/article/details/6769976 http://c.biancheng.net/view/7385.htmlhttps://blog.csdn.net/daaikuaichuan/article/details/80717222
如果使用npm,可以通過以下命令安裝Three.js:
npm install three
然后在你的JavaScript文件中引入它:
import * as THREE from 'three';
如果直接在網頁中使用,可以通過<script>標簽引入:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
// 創建一個場景
const scene = new THREE.Scene();
// 創建一個相機,設置透視投影
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 創建一個WebGL渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement); // 將渲染器的DOM元素添加到頁面中
// 添加環境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
// 添加一個點光源
const pointLight = new THREE.PointLight(0xffffff, 0.8);
pointLight.position.set(5, 5, 5);
scene.add(pointLight);
Three.js提供了STLLoader來加載.stl文件。確保你已經引入了STLLoader模塊。
// 創建STLLoader實例
const stlLoader = new THREE.STLLoader();
// 異步加載.stl文件
stlLoader.load(
'path/to/your/model.stl', // 替換為你的.stl文件路徑
function (geometry) {
// 創建材質
const material = new THREE.MeshPhongMaterial({ color: 0x00ff00, specular: 0xffffff, shininess: 30 });
// 創建網格(mesh)并添加到場景中
const stlMesh = new THREE.Mesh(geometry, material);
scene.add(stlMesh);
},
function (xhr) {
// 可以在這里添加加載進度的邏輯
},
function (error) {
// 可以在這里添加錯誤處理的邏輯
}
);
使用OrbitControls允許用戶與3D模型交互。
// 創建控制器
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0); // 設置控制器的目標點
controls.update(); // 更新控制器
創建一個動畫循環,用于連續渲染場景。
function animate() {
// 更新控制器
controls.update();
// 渲染場景
renderer.render(scene, camera);
// 使用requestAnimationFrame創建一個循環
requestAnimationFrame(animate);
}
// 開始動畫循環
animate();
為了更好地查看模型,你可能需要調整相機的位置。
camera.position.set(0, 50, 100); // 可以調整這些值
camera.lookAt(scene.position); // 使相機指向場景的中心
為了確保渲染器適應不同窗口大小,添加以下事件監聽器。
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
將上述代碼整合到一個HTML頁面中,并確保替換path/to/your/model.stl為你的.stl文件的實際路徑。這樣,你就能夠在網頁上渲染.stl文件了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。