C++灰灰的日常查漏補缺
1.c++中 . 和 -> 主要是用法上的不同。
A.B則A為物件或者結構體;
A->B則A為指標,->是成員提取,A->B是提取A中的成員B,A只能是指向類、結構、聯合的指標;
2.寫輸出檔案
#include<iostream>
ofstream f;
f.open("地址/想要建立的檔名及檔案型別如:pose_array.txt");
f << fixed;
此處是迴圈體,迴圈存入資料
f.close();
3.C++中的矩陣相乘
Mat矩陣dot——A.dot(B)
Opencv中.dot操作才算得上是真正的“點乘”,A.dot(B)操作相當於數學向量運算中的點乘,也叫向量的內積、數量積。
對兩個向量執行點乘運算,就是對這兩個向量對應位一一相乘之後求和的操作,點乘的結果是一個標量。
對於向量a和向量b:
a和b的點積公式為:
要求向量a和向量b的行列數相同。
Mat矩陣的dot方法擴充套件了一維向量的點乘操作,把整個Mat矩陣擴充套件成一個行(列)向量,之後執行向量的點乘運算,仍然要求參與dot運算的兩個Mat矩陣的行列數完全一致。
dot方法宣告中顯示返回值是double,所以A.dot(B)結果是一個double型別資料,不是Mat矩陣,不能把A.dot(B)結 果賦值給Mat矩陣!
Mat矩陣mul——A.mul(B)
Opencv中mul會計算兩個Mat矩陣對應位的乘積,所以要求參與運算的矩陣A的行列和B的行列數一致。計算結果是跟A或B行列數一致的一個Mat矩陣。
以簡單的情況為例,對於2*2大小的Mat矩陣A和B:
對A和B執行mul運算:
mul操作不對參與運算的兩個矩陣A、B有資料型別上的要求,但要求A,B型別一致,不然報錯;
Mat AB=A.mul(B),若宣告AB時沒有定義AB的資料型別,則預設AB的資料型別跟A和B儲存一致;
若AB精度不夠,可能產生溢位,溢位的值被置為當前精度下的最大值;
4.iterator begin(),end(),*first,*last
#include <iterator>
std::vector<int> IntVector;
std::vector<int>::iterator first=IntVector.begin();
// begin()得到指向vector開頭的Iterator,*first得到開頭一個元素的值
std::vector<int>::iterator last=IntVector.end();
// end()得到指向vector結尾的Iterator,*last得到最後一個元素的值
5. STL
1.容器
STL容器,即是將最常運用的一些資料結構(data structures)實現出來。容器是指容納特定型別物件的集合。根據資料在容器中排列的特性,容器可概分為序列式(sequence)和關聯式(associative)兩種。迭代器是一種檢查容器內元素並遍歷元素的資料型別。它提供類似指標的功能,對容器的內容進行訪問。
1.1序列式容器
序列式容器中的元素都可序(ordered),但未必有序(sorted)。陣列為C++語言內建的序列容器,STL另外提供vector、list、deque(double-ended queue)。它們的差別在於訪問元素的方式,以及新增或刪除元素相關操作的執行代價。
Vector
vector是標準C++建議替代C陣列的動態陣列模型,它維護的是一個連續線性空間。採用的資料結構非常簡單:線性連續空間。它以兩個迭代器start和finish分別指向配置得到的連續空間中目前已被使用的範圍,並以迭代器end_of_storage指向整塊連續空間(含備用空間)的尾端。
vector的實現技術,關鍵在於其對大小的控制以及重新分配時的資料移動效率。一旦vector原有空間用完,如果客戶端每新增一個元素,vector內部就只擴充一個元素的空間,實為不智。注意,所謂動態增加大小,並不是在原空間之後接續新空間(因為無法保證之後尚有可供配置的空間),而是每次再分配原大小兩倍的記憶體空間。因此,對vector的任何操作,一旦引起控制元件重新配置,指向原vector的所有迭代器就都失效了。
由於vector維護的是一個連續線性空間,因此vector迭代器具備普通指標的功能,支援隨機存取,即vector提供的是Random Access Iterators。
向量類别範本std::vector的成員函式
#include<vector>
std::vector<type> vec;
std::vector<type> vec(size);
std::vector<type> vec(size,value);
std::vector<type> vec(myvector);
std::vector<type> vec(first,last);
Operators:==、!=、<=、>=、<、>、[]
assign(first,last):用迭代器first,last所指定的元素取代向量元素
assign(num,val):用val的num份副本取代向量元素
at(n):等價於[]運算子,返回向量中位置n的元素,因其有越界檢查,故比[]索引訪問安全
front():返回向量中第一個元素的引用
back():返回向量中最後一個元素的引用
begin():返回向量中第一個元素的迭代器
end():返回向量中最後一個元素的下一個迭代器(僅作結束遊標,不可解引用)
max_size():返回向量型別的最大容量(2^30-1=0x3FFFFFFF)
capacity():返回向量當前開闢的空間大小(<= max_size,與向量的動態記憶體分配策略相關)
size():返回向量中現有元素的個數(<=capacity)
clear():刪除向量中所有元素
empty():如果向量為空,返回真
erase(start,end):刪除迭代器start end所指定範圍內的元素
erase(i):刪除迭代器i所指向的元素
erase()返回指向刪除的最後一個元素的下一位置的迭代器
insert(i,x);把x插入到迭代器i所指定的位置之前
insert(i,n,x):把x的n份副本插入到迭代器i所指定的位置之前
insert(i,start,end):把迭代器start和end所指定的範圍內的值插入到迭代器i所指定的位置之前
push_back(x):把x推入(插入)到向量的尾部
pop_back():彈出(刪除)向量最後一個元素
rbegin():返回一個反向迭代器,該迭代器指向的元素越過了向量中的最後一個元素
rend():返回一個反向迭代器,該迭代器指向向量中第一個元素
reverse():反轉元素順序
resize(n,x):把向量的大小改為n,新元素的初值賦為x
swap(vectorref):交換2個向量的內容
List
list與向量(vector)相比, 它允許快速的插入和刪除,且每次插入或刪除一個元素,就配置或釋放一個元素空間。因此,list對於空間的運用絕對的精準,一點也不浪費。而且,對於任何位置的元素插入或元素移除,list永遠是常數時間。
list不再能夠像vector那樣以普通指標作為迭代器,因為其節點不保證在儲存空間中連續存在。list迭代器必須有能力指向list的節點,並有能力進行正確的遞增、遞減、取值、成員存取等操作。所謂“list迭代器正確的遞增、遞減、取值、成員取用”操作是指,遞增時指向下一個節點,遞減時指向上一個節點,取值時取的是節點的資料值,成員取用時取用的是節點的成員。
list是一個環狀雙向連結串列,所以它只需要一個指標,便可以完整實現整個連結串列。由於list是一個雙向連結串列(double linked-list),迭代器必須具備前移、後移的能力,所以list提供的是Bidirectional Iterators。
list有一個重要性質:插入操作(insert)和合並操作(splice)都不會造成原有的list迭代器失效。這在vector是不成立的,因為vector的插入操作可能造成記憶體重新配置,導致原有的迭代器全部失效。甚至list的元素刪除操作(erase)也只有“指向被刪除元素”的那個迭代器失效,其他迭代器不受任何影響。
連結串列類别範本std::list成員函式
#include<list>
std::list<type> lst;
std::list<type> lst(size);
std::list<type> lst(size,value);
std::list<type> lst(mylist);
std::list<type> lst(first,last);
//以下未列出與vector相同的通用操作。
push_front(x):把元素x推入(插入)到連結串列頭部
pop_front():彈出(刪除)連結串列首元素
merge(listref):把listref所引用的連結串列中的所有元素插入到連結串列中,可指定合併規則
splice():把lst連線到pos的位置
remove(val):刪除連結串列中所有值為val的元素
remove_if(pred):刪除連結串列中謂詞pred為真的元素(謂詞即為元素儲存和檢索的描述,如std::less<>,std::greater<>那麼就按降序/升序排列,你也可以定義自己的謂詞)
sort():根據預設的謂詞對連結串列排序
sort(pred):根據給定的謂詞對連結串列排序
unique():刪除連結串列中所有重複的元素
unique(pred):根據謂詞pred刪除所有重複的元素,使連結串列中沒有重複元素
注意:vector和deque支援隨機訪問,而list不支援隨機訪問,因此不支援[]訪問!
Deque
vector是單向開口的連續線性空間,deque則是以中雙向開口的連續線性空間。可以在頭尾兩端分別做元素的插入和刪除操作。
deque和vector的最大差異,一在於deque允許於常數時間內對頭端進行元素的插入或移除操作,二在於deque沒有所謂容量(capacity)觀念,因為它是動態地以分段連續空間組合而成,隨時可以增加一段新的空間並連結起來。換句話說,像vector那樣“因舊空間不足而重新配置一塊更大空間,然後複製元素,再釋放舊空間”這樣的事情在deque中是不會發生的。也因此,deque沒有必要提供所謂的空間預留(reserved)功能。
雖然deque也提供Random Access Iterator,但它的迭代器並不是普通指標,其複雜度和vector不可同日而語,這當然涉及到各個運算層面。因此,除非必要,我們應儘可能選擇使用vector而非deque。對deque進行的排序操作,為了最高效率,可將deque先完整複製到一個vector身上,將vector排序後(利用STL的sort演算法),再複製回deque。
deque是由一段一段的定量連續空間構成。一旦有必要在deque的前端或尾端增加新空間,便配置一段定量的連續空間,串接在整個deque的頭端或尾端。deque的最大任務,便是在這些分段的定量連續空間上,維護其整體連續的假象,並提供隨機存取的介面。避開了“重新配置、複製、釋放”的輪迴,代價則是複雜的迭代器架構。
雙端佇列類别範本std::deque成員函式
#include<deque>
std::deque<type> deq;
std::deque<type> deq(size);
std::deque<type> deq(size,value);
std::deque<type> deq(mydeque);
std::deque<type> deq(first,last);
其成員函式如下:
Operators:[]用來訪問雙向佇列中單個的元素
front():返回第一個元素的引用
push_front(x):把元素x推入(插入)到雙向佇列的頭部
pop_front():彈出(刪除)雙向佇列的第一個元素
back():返回最後一個元素的引用
push_back(x):把元素x推入(插入)到雙向佇列的尾部
pop_back():彈出(刪除)雙向佇列的最後一個元素
Stack
stack是一種後進先出(FILO)的資料結構,只有一個出口。stack允許新增元素、移除元素、取得最頂端元素。但除了最頂端外,沒有任何其他方法可以存取stack的其他元素,stack不允許隨機訪問。
STL以deque作為stack的底層結構,對deque封閉期頭端開口,稍作修改便形成了stack。
將元素插入stack的操作稱為push,將元素彈出stack的操作稱為pop。只有stack頂端的元素,才有機會被外界取用。stack不提供走訪功能,也不提供迭代器。
容器介面卡堆疊類std::stack成員函式
#include<stack>
stack實現後進先出的操作
std::stack<type,container> stk;
type為堆疊操作的資料型別
container為實現堆疊所用的容器型別,預設基於deque,還可以為std::vector和std::list
例如std::stack<int,std::list<int>> IntStack;
其成員函式如下:
top():返回頂端元素的引用
push(x):將元素壓入棧(頂)
pop():彈出(刪除)頂端元素
Queue
queue是一種先進先出(FIFO)的資料結構,它有兩個出口。queue允許新增元素、移除元素、從最底端加入元素、取得最頂端元素。但除了最底端可以加入、最頂端可以取出,沒有任何其他方法可以存取queue的其他元素。換言之,queue不支援隨機訪問。
STL以deque作為queue的底層結構,對deque封閉其底端的出口和前端的入口,稍作修改便形成了queue。
容器介面卡佇列類std::queue成員函式
#include<queue>
queue實現先進先出的操作
std::queue<type,container> que;
type為佇列操作的資料型別
container為實現佇列所用的容器型別,只能為提供了push_front操作的std::deque或std::list,預設基於std::deque
其成員函式如下:
front():返回隊首元素的引用
back():返回隊尾元素的引用
push(x):把元素x推入(插入)到隊尾
pop():隊首元素出列(彈出(刪除)隊首元素)
1.2關聯式容器
關聯式容器:每項資料(元素)包含一個鍵值(key)和一個實值(value)。當元素被插入到關聯式容器中時,容器內部資料結構便依照其鍵值大小,以某種特定規則將這個元素放置於適當位置。關聯式容器沒有所謂頭尾(只有最大元素和最小元素),所以不會有push_back(),push_front(),pop_back(),pop_front(),begin(),end()這樣的操作。
標準的STL關聯式容器分為set(集合)和map(對映類)兩大類,以及這兩大類的衍生體multiset(多鍵集合)和multimap(多鍵對映表)。
Map
關聯式容器std::map成員函式
#include<map>
map建立key-value對映
std::map<key, value> mp;
std::map<key, value, comp> mp;
key為鍵值,value為對映值,comp可選,為鍵值對存放策略,例如可為std::less<>,鍵值對映對將按鍵值從小到大儲存
其成員函式如下:
count():返回map中鍵值等於key的元素的個數
equal_range():函式返回兩個迭代器——一個指向第一個鍵值為key的元素,另一個指向最後一個鍵值為key的元素
erase(i):刪除迭代器所指位置的元素(鍵值對)
lower_bound():返回一個迭代器,指向map中鍵值>=key的第一個元素
upper_bound():函式返回一個迭代器,指向map中鍵值>key的第一個元素
find(key):返回鍵值為key的鍵值對迭代器,如果沒有該對映則返回結束遊標end()
注意map的[]操作符,當試圖對於不存在的key進行引用時,將新建鍵值對,值為空。
2.STL常見容器的優缺點
verctor
vector類似於C語言中的陣列,它維護一段連續的記憶體空間,具有固定的起始地址,因而能非常方便地進行隨機存取,即 [] 操作符,但因為它的記憶體區域是連續的,所以在它中間插入或刪除某個元素,需要複製並移動現有的元素。此外,當被插入的記憶體空間不夠時,需要重新申請一塊足夠大的記憶體並進行記憶體拷貝。值得注意的是,vector每次擴容為原來的兩倍,對小物件來說執行效率高,但如果遇到大物件,執行效率就低了。
list
list類似於C語言中的雙向連結串列,它通過指標來進行資料的訪問,因此維護的記憶體空間可以不連續,這也非常有利於資料的隨機存取,因而它沒有提供 [] 操作符過載。
deque
deque類似於C語言中的雙向佇列,即兩端都可以插入或者刪除的佇列。queue支援 [] 操作符,也就是支援隨機存取,而且跟vector的效率相差無幾。它支援兩端的操作:push_back,push_front,pop_back,pop_front等,並且在兩端操作上與list的效率也差不多。或者我們可以這麼認為,deque是vector跟list的折中。
map
map類似於資料庫中的1:1關係,它是一種關聯容器,提供一對一(C++ primer中文版中將第一個譯為鍵,每個鍵只能在map中出現一次,第二個被譯為該鍵對應的值)的資料處理能力,這種特性了使得map類似於資料結構裡的紅黑二叉樹。
multimap
multimap類似於資料庫中的1:N關係,它是一種關聯容器,提供一對多的資料處理能力。
如果需要高效的隨機存取,不在乎插入和刪除的效率,使用vector;
如果需要大量的插入和刪除元素,不關心隨機存取的效率,使用list;
如果需要隨機存取,並且關心兩端資料的插入和刪除效率,使用deque;
如果打算儲存資料字典,並且要求方便地根據key找到value,一對一的情況使用map,一對多的情況使用multimap;
3.迭代器
迭代器提供對一個容器中的物件的訪問方法,並且定義了容器中物件的範圍。迭代器就如同一個指標。C++的指標也是一種迭代器。但迭代器不僅僅是指標,不一定具有地址值。例如,一個陣列索引,也可以認為是一種迭代器。
迭代器的型別
對於STL資料結構和演算法,你可以使用五種迭代器。下面簡要說明了這五種型別:
Input iterators 提供對資料的只讀訪問。
Output iterators 提供對資料的只寫訪問
Forward iterators 提供讀寫操作,並能向前推進迭代器。
Bidirectional iterators提供讀寫操作,並能向前和向後操作。
Random access iterators提供讀寫操作,並能在資料中隨機移動。
儘管各種不同的STL 實現細節方面有所不同,還是可以將上面的迭代器想象為一種類繼承關係。從這個意義上說,下面的迭代器繼承自上面的迭代器。由於這種繼承關係,你可以將一個 Forward迭代器作為一個output或input迭代器使用。同樣,如果一個演算法要求是一個bidirectional 迭代器,那麼只能使用該種型別和隨機訪問迭代器。
相關文章
- ROS灰灰的日常查漏補缺ROS
- SLAM 灰灰restudy及查漏補缺—octomapSLAMREST
- 查漏補缺
- HashMap 查漏補缺HashMap
- Typescript 查缺補漏TypeScript
- iOS 查漏補缺 - PerformSelectoriOSperformSelector
- Flutter查漏補缺1Flutter
- JavaScript Promise查缺補漏JavaScriptPromise
- C++ Primer 查漏補缺 —— C++ 中的各種初始化C++
- 正規表示式的查漏補缺
- shell基礎知識查缺補漏
- C# 執行緒查漏補缺C#執行緒
- 【查漏補缺】那些漏掉的面試知識面試
- 前端面試查漏補缺--(十三) 記憶體洩漏前端面試記憶體
- 前端面試查漏補缺--(八) 前端加密前端面試加密
- 前端面試查漏補缺--(十五) Event Loop前端面試OOP
- C# 執行緒同步查漏補缺C#執行緒
- 技術棧查漏補缺——架構師架構
- 前端面試查漏補缺--(十) 前端鑑權前端面試
- 前端面試查漏補缺--(九) HTTP與HTTPS前端面試HTTP
- [學習筆記]TypeScript查缺補漏(一):類筆記TypeScript
- 「查缺補漏」鞏固你的Redis知識體系Redis
- 前端面試查漏補缺--(四) 前端本地儲存前端面試
- 前端面試查漏補缺--(二) 垃圾回收機制前端面試
- Redis基礎你掌握多少了?來查漏補缺?Redis
- [筆記](更新中)CSP-S 2024 查漏補缺筆記
- 查漏補缺,盤點和toggle相關的幾個APIAPI
- [查漏補缺]正規表示式匹配演算法演算法
- 前端面試查漏補缺--(一) 防抖和節流前端面試
- 前端面試查漏補缺--(六) 瀏覽器快取前端面試瀏覽器快取
- 前端面試查漏補缺--(十四) 演算法及排序前端面試演算法排序
- Go語言學習查缺補漏ing Day8Go
- Go語言學習查缺補漏ing Day5Go
- Go語言學習查缺補漏ing Day6Go
- Go語言學習查缺補漏ing Day7Go
- Go語言學習查缺補漏ing Day3Go
- Go語言學習查缺補漏ing Day2Go
- Go語言學習查缺補漏ing Day4Go