https://www.bilibili.com/video/av48068999?p=5
記錄一些在裏面提到的函數用法例子
第一講 容器
- 讀取時間
#include <ctime>
clock_t timeStart = clock();//單位ms
//...
cout << "milli-seconds:" << (clock() - timeStart) << endl;
-排序(list等不能用std::sort)
array<long, ASIZE> c;
for (long i = 0; i < ASIZE; ++i) {
c[i] = rand() % 65535;
}
qsort(c.data(), ASIZE, sizeof(long), compareLongs);
- 二分查找
#include<cstdlib>
int compareLongs(const void* a, const void* b)
{
return (*(long*)a - *(long*)b);
}
long* pItem = (long*)bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);
cout << "bsearch(), milli-seconds: " << (clock() - timeStart) << endl;
if (pItem != NULL)
cout << "found, " << *pItem << endl;
else
cout << "not found!" << endl;
將數字轉化爲char,再轉換爲string
#include<cstdio>
char buf[10];
snprintf(buf, 10, "%d", rand() % 65535);
cout<<string(buf);
在vector中find
auto pItem = find(c.begin(),c.end(),target);
if(pItem !- c.end())
cout<<"find:"<<*pItem<<endl;
else
cout<<"not find"<<endl;
在vector中用二分查找
vector<string> c;
sort(c.begin(),c.end());
int compareStrings(const void* a, const void* b)
{
if (*(string*)a > *(string*)b)
return 1;
else if(*(string*)a < *(string*)b)
return -1;
else
return 0;
}
string* pItem = (string*)bsearch(&target, (c.data()), c.size(), sizeof(string), compareStrings);
if (pItem != NULL)
cout << "found, " << *pItem << endl;
else
cout << "not found!" << endl;
- bsearch 函數使用說明
void *bsearch(const void *key, const void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *))
key -- 指向要查找的元素的指針,類型轉換爲 void*。
base -- 指向進行查找的數組的第一個對象的指針,類型轉換爲 void*。
nitems -- base 所指向的數組中元素的個數。
size -- 數組中每個元素的大小,以字節爲單位。
compar -- 用來比較兩個元素的函數。
- 某些容器自帶sort,例如list ,forward_list,
list<string> c;
c.sort();
- 某些容器自帶find,如set,multiset,map,
- multimap,unordered_multiset,unordered_multimao
auto pItem = c.find(target);//更快!!!!!!!!!!
auto pItem = find(c.begin(),c.end(),target);
- 分配器allocator
#include<memory>
包含了std::allocator
此外gnu還有大量的非標分配器
如
#include<ext/array_allocator.h>
#include<ext/mt_allocator.h>
#include<ext/debug_allocator.h>
等
第二講 容器
oop(object-oriented programming )vs GP(generic programming)
面向對象編程與模板編程
GP思維:容器containers和算法algorighms各自管自己,再通過Iterator迭代器聯結.
所有的算法,其中涉及元素本身的操作就是比大小
例子:比大小
strLonger(const string& s1,const string& s2)
{
return s1.size() < s2.size();
}
cout<<"longest: "<<max(string("zoo"),string("hello",strLonger));//輸出hello
基礎:
操作符重載 overloaded operators
節選一段list文件中的重載:
template<class _Mylist,
class _Base = _Iterator_base0>
class _List_unchecked_const_iterator
: public _Iterator012<bidirectional_iterator_tag,
typename _Mylist::value_type,
typename _Mylist::difference_type,
typename _Mylist::const_pointer,
typename _Mylist::const_reference,
_Base>
{ // unchecked iterator for nonmutable list
public:
typedef _List_unchecked_const_iterator<_Mylist, _Base> _Myiter;
typedef bidirectional_iterator_tag iterator_category;
typedef typename _Mylist::_Nodeptr _Nodeptr;
typedef typename _Mylist::value_type value_type;
typedef typename _Mylist::difference_type difference_type;
typedef typename _Mylist::const_pointer pointer;
typedef typename _Mylist::const_reference reference;
_List_unchecked_const_iterator()
: _Ptr(0)
{ // construct with null node pointer
}
_List_unchecked_const_iterator(_Nodeptr _Pnode, const _Mylist *_Plist)
: _Ptr(_Pnode)
{ // construct with node pointer _Pnode
this->_Adopt(_Plist);
}
reference operator*() const
{ // return designated value
return (_Mylist::_Myval(_Ptr));
}
pointer operator->() const
{ // return pointer to class object
return (_STD pointer_traits<pointer>::pointer_to(**this));
}
_Myiter& operator++()
{ // preincrement
_Ptr = _Mylist::_Nextnode(_Ptr);
return (*this);
}
_Myiter operator++(int)
{ // postincrement
_Myiter _Tmp = *this;
++*this;
return (_Tmp);
}
_Myiter& operator--()
{ // predecrement
_Ptr = _Mylist::_Prevnode(_Ptr);
return (*this);
}
_Myiter operator--(int)
{ // postdecrement
_Myiter _Tmp = *this;
--*this;
return (_Tmp);
}
bool operator==(const _Myiter& _Right) const
{ // test for iterator equality
return (_Ptr == _Right._Ptr);
}
bool operator!=(const _Myiter& _Right) const
{ // test for iterator inequality
return (!(*this == _Right));
}
_Nodeptr _Mynode() const
{ // return node pointer
return (_Ptr);
}
_Nodeptr _Ptr; // pointer to node
};
- 基礎知識:類模板 cass templates
template <typename T>
class complex
//複數類
{
public:
complex(T r = 0, T i = 0): re(r), im (i)
{}
complex& operator +=(const complex&);
T real () const{ return re;}
T imag () const {return im;}
private:
T re,im;
}
/***********使用**********************/
complex<double> c1(2.5,1.5);
- 基礎知識:模板函數 function templates
template <class T>
inline
const T& min(const T& a,const T& b)
{
return b < a? b : a;
}
- 基礎知識:特化 specialization
對具體模板寫對應的特化,如
template<> struct hash<bool>;
template<> struct hash<char>;
template<> struct hash<signed char>;
template<> struct hash<unsigned char>;
template<> struct hash<char8_t>; // C++20
template<> struct hash<char16_t>;
template<> struct hash<char32_t>;
template<> struct hash<wchar_t>;
template<> struct hash<short>;
template<> struct hash<unsigned short>;
template<> struct hash<int>;
template<> struct hash<unsigned int>;
template<> struct hash<long>;
template<> struct hash<long long>;
template<> struct hash<unsigned long>;
template<> struct hash<unsigned long long>;
template<> struct hash<float>;
template<> struct hash<double>;
template<> struct hash<long double>;
template<> struct hash<std::nullptr_t>; // C++17
template< class T > struct hash<T*>;
- 偏特化 partial specialization(個數,範圍(是否指針,是否const)兩種偏特化方式)
template<class Alloc>
class vector<bool,Alloc>
{
...
}
//對應泛化
template <class T,class Alloc = alloc>
class vector
{...}
- 分配器
- 使用容器的時候會調用分配器來分配內存。
- vc6+中的 allocator 只是通過new和delete來完成allocate()和deallocate(),沒有特殊設計。
- 舉個例子直接調用allocator(一般不直接用)
//分配512ints
int *p = allocator<int>().allocate(512,(int*)0);//創建
allocator<int>().deallocate(p,512);//釋放
不做任何處理的分配器會導致在大量malloc的時候產生cookie的額外開銷。
G 2.9 stl中對alloc進行了優化:減少malloc的次數。
現在在G4.9中優化方法改名爲pool_alloc,使用方法:
vector<string,gnu_cxx::_pool_alloc<string>> vec;
- 容器結構分類:
裏面的大小指控制所需,並不是每個元素的大小。
list
G2.9
4.9優化
Iterator提供5種associate types:
ptrdiff_t指的是兩個指針的距離的類型,這就限制了容器的大小。
- Iterator Traits(特性)
- 可以區分class iterators與non-class iterators
Vector
兩倍增長:
做了兩次檢測,是因爲insert_aux在別處也有被調用,比如insert等調用它。
deque
通過map對空間索引實現前後區域的擴展。
queue和stack
都不提供iterator
底層可以通過deque或者list封裝實現,stack也可以用vector做底層結構
注意使用時pop,push,不帶back或者front。
rb_tree
提供兩種insert操作,insert_unique()或者insert_equal()
第三講 算法
算法通過模板函數實現
bidirectional 雙向
紅黑樹生成的都是雙向迭代器
hash_table生成的容器用單項迭代器
find:
for_each:
count:
sort:
bineary_search:返回真/假
二分查找可以直接用lower_bound:他返回一個在first與last迭代器區間[first,last)內第一個不小於val的元素。
仿函數functors
爲算法提供服務,添加一些準則等,比如排序順序等
仿函數要繼承unary單參數或者binary雙參數來,以便被適配器後續改造。
適配器adapter
包含: 容器適配器,迭代器適配器,仿函數適配器
容器適配器:
函數適配器:
相當於將第二個參數綁定爲固定的,比如less()需要比較兩個參數大小,這裏就可以把第二個參數綁定爲40。但是bind在c++11已經改版了:
函數適配器not1,傳遞判斷條件,取非輸出.
新型適配器bind
cbegin()表示const型begin迭代器
舉個例子:
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;
using namespace std::placeholders;
int main()
{
vector<int> v{15,32,243,234,51,50,12};
auto fn_ = bind(less<int>(),_1,50);
cout << count_if(v.cbegin(), v.cend(), fn_) << endl;
cout << count_if(v.cbegin(), v.cend(), bind(less<int>(), _1, 50) )<< endl;
system("pause");
}
迭代器適配器
X(未知)適配器
ostream_iterator
測試一下:
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
using namespace std::placeholders;
int main()
{
vector<int> v{15,32,243,234,51,50,12};
ostream_iterator<int> out_it(cout, ",");
copy(v.begin(), v.end(), out_it);
system("pause");
}
測試一下:
#include<iostream>
#include<string>
#include<iterator>
#include<algorithm>
using namespace std;
int main()
{
string text;
istream_iterator<int> is(cin);//綁定標準輸入裝置
istream_iterator<int> eof;//定義輸入結束位置
copy(is, eof, back_inserter(text));
sort(text.begin(), text.end());
ostream_iterator<int> os(cout, ", ");//綁定標準輸出裝置
copy(text.begin(), text.end(), os);
system("pause");
}
第四講 應用
tuple元組
#include <iostream>
#include <vector>
#include <string>
#include <tuple>
using namespace std;
std::tuple<std::string, int>
giveName(void)
{
std::string cw("Caroline");
int a(2013);
std::tuple<std::string, int> t = std::make_tuple(cw, a);
return t;
}
int main()
{
std::tuple<int, double, std::string> t(64, 128.0, "Caroline");
std::tuple<std::string, std::string, int> t2 =
std::make_tuple("Caroline", "Wendy", 1992);
//返回元素個數
size_t num = std::tuple_size<decltype(t)>::value;
std::cout << "num = " << num << std::endl;
//獲取第1個值的元素類型
std::tuple_element<1, decltype(t)>::type cnt = std::get<1>(t);
std::cout << "cnt = " << cnt << std::endl;
//比較
std::tuple<int, int> ti(24, 48);
std::tuple<double, double> td(28.0, 56.0);
bool b = (ti < td);
std::cout << "b = " << b << std::endl;
//tuple作爲返回值
auto a = giveName();
std::cout << "name: " << get<0>(a)
<< " years: " << get<1>(a) << std::endl;
system("pause");
return 0;
}
遞歸繼承
type traits 類型萃取
trivial:不重要的。
舉個例子:
#include <iostream>
using namespace std;
class Parent{};
class Child : public Parent{}; //class Child : Parent{},爲private繼承
class Alone{};
int main()
{
cout << std::boolalpha; //以下的0、1按false和true格式輸出
/*基本的type_traits用法*/
cout << is_const<int>::value << endl; //false
cout << is_const<const int>::value << endl; //true
cout << is_const<const int&>::value << endl; //false
cout << is_const<const int*>::value << endl; //false
cout << is_const<int* const>::value << endl; //true
/*is_same用法*/
cout << is_same<int, int>::value << endl; //true
cout << is_same<int, unsigned int>::value << endl;//false
cout << is_same<int, signed int>::value << endl; //true
/*is_base_of*/
cout << is_base_of<Parent, Child>::value << endl; //true
cout << is_base_of<Child, Parent>::value << endl; //false
cout << is_base_of<Parent, Alone>::value << endl; //false
/*is_convertible<From, To>用法:判斷From類型是否可以轉爲To類型*/
cout << is_convertible<Parent*, Child*>::value << endl; //false
cout << is_convertible<Child*, Parent*>::value << endl; //true
cout << is_convertible<Parent*, Alone*>::value << endl; //false
return 0;
}
type traits的實現
cout
moveable對效率的影響
其他的差別不大。
完結撒花~~