C++灰灰的日常查漏補缺

是皮皮攀呀,發表於2019-02-20

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 迭代器,那麼只能使用該種型別和隨機訪問迭代器。

 

相關文章