在ACM中庫函數是非常重要的,因為有很多很多通用的操作和結構啊,非常實用,有些時候還是要深入了解一下這些庫函數,碼上一些庫函數還有他們通用的操作。
目錄
- math
- string
- algorithm
- vector
- set
- map
- queue
- stack
- 1.math
(1)int abs(int) double fabs(double)
很簡單的兩個函數,對int和double取絕對值,沒什么好水的。
(2)double ceil(double num) double floor(double x)
這兩個是很常用的取整函數,使用頻率很高。ceil是向上取整,floor是向下取整。
注意這兩個函數其實是帶等於號的,什么意思呢,就是如果你把3傳進去,他們返回的都是3。這會導致一個問題,你在計算過程中,期待的結果是一個整數,但是運算的過程中你得到了一個2.9999999,你去向下取整,你會發現你得到了一個2,這個地方經常出錯,記得向下取整要加一個eps,向上同理減一個就行。
大家對浮點數構造沒有了解的可以運行一下下面的代碼
int main() { double f=(0.3-0.1)*10; cout<<f<<endl; printf("%.20lf\n",f); cout<<ceil(f)<<endl; cout<<floor(f)<<endl; }
我的輸出結果是
2
1.99999999999999977796
2
1
這兩個函數,初學者在題目中經常不加eps(我說的是我自己,大佬們開始其實都會加),提醒一下自己。
(3)double pow(double x,double y)
這個函數運算的是x^y,其實對做題基本用不到這個,我沒測過復雜度是多少,但是它不能取模,用它的時候基本都是在開平方。
還有一個用法就是計算一個數字是不是平方數或者立方數之類的。
你只需要判斷一下它開方后取整在平方之后是不是原來的數字就行了。這個是很快的,但是這個東西有精度限制,有時候會不對,范圍大而且比較精確的還是用二分找吧。
(4)其他函數感覺沒什么說的必要了,比如三角函數那一堆,學了計算幾何之后沒什么難點,最后說一句用math.c的時候注意精度,卡精度很常見的。
- 2.string
基本打比賽的時候沒人會想用String類吧,畢竟速度太慢了,一般都用string.h.
1.其實string那些函數想說的很少,主要用的是strcpy,和strcmp。一個用來復制,一個用來判斷字典序,其實只有在上課的時候用的上,字符串題應該用不到這兩,有時候可能會用strcmp判斷字典序什么的。
2.void *memset(void *s, int ch, size_t n);
- 3.algorithm
1.排在首位的肯定是大名鼎鼎的我啦:void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
對於這個排序大家肯定都不陌生,最簡單的用法就是直接像這樣:sort(a,a+n);這樣就可以把a數組從小到達進行排序了。第三個是比較函數,你可以定義比較的方式的,如果缺省就是從小到大排序了。如果要從小到大排序就要自己寫了。而且可以對結構體進行排序,所以對於一個經典問題如何對二元組排序,你也可以用這個函數進行計算,你只需要寫一個cmp函數,說明什么時候是小於就行了(就是小於的時候返回1,大於等於返回0)。還有如果想從小到大排序的話,只需要把cmp寫成,什么時候是大於就行了。還有一個對多元組排序排序的好方法,那就是pair,使用pair你可以把任意兩個類型捏成一個二元組,只要這兩個類型都可以進行比較就行,因為pair自己內嵌了比較的規則,是按照第一關鍵字為首,第二關鍵字為次來計算的,這個用起來也非常舒服,在二元組比較的時候可以不寫結構體和比較函數,寫起來很快(主要是二元組,甚至三元組這種結構簡直不要太多),pair具體用法可以自行百度,介於篇幅原因,不再贅述。
最后說一點關於sort的效率問題,sort是目前最快的排序算法之一,它內部嵌套了多種排序算法會根據情況選用,基本不可能出現比這種排序還快的方案,你完全可以相信它nlogn的復雜度。
2.lower_bound()和upper_bound()
這兩個函數很多情況下會用的上,因為你要在一個有序的序列中查詢一個數的位置,這種操作十分常見
一般的用法是lower_bound(a,a+n,x)或者lower_bound(a,a+n,x,cmp)
分別是開始地址,結束地址,要查詢的數值,比較函數。第四個比較函數是可以缺省的,默認是找大於等於x的第一個位置,返回值不是下標!是它所在的地址。所以你要獲得數組下標,你還要剪掉開始地址才能得到下標。
注意在使用這兩個函數時一定要保證查詢的數組時有序的(一般是從小到大)
lower_bound()返回的是第一個大於等於x的位置地址,upper_bound()返回的是第一個大於x的位置地址。如果不存在,則會返回結束地址。
但是你這時候就會想了,我想查詢小於等於x的位置怎么辦呢,其實你可以把原來的數組從大到小排序,然后自己寫一下cmp函數(大於形式的)。但是我一直覺得這種比較麻煩,你可以把所有的數字都取負號,然后查詢的時侯查詢-x的位置就行了,這樣寫起來很快。
3.還有一些小的函數特別有用但是沒啥難度的:
max min swap
除了這些我就想不起來什么常用了
- 4.vector
1.先談談vector的機制吧
vector對於小白來說可以理解成一個變長數組,但是我十分不推薦這種理解,因為我當初學習的時候有人就是這么說的,讓我了解到了一個可以新增元素,但是卻可以o(1)時間查詢的奇怪玩意。但是vector不是一個會變長度的數組,它其實是一個已經開好了空間的數組,你每次往這個向量中添加一個元素的時候其實就是和數組操作沒什么區別。這時候你就想了,vector要開多大的空間呢?其實它開空間的時候是動態開的,或許它剛開始只有100的大小,但是這100個要是全部都被裝滿了,它就會開一個新的連續的200的空間,然后把這100復制到200的那里,然后把100的釋放掉。如果200的再滿了,就開一個400的,以此類推。所以vector其實有時候是比較慢的(應該沒人卡這個吧),但是也無傷大雅,基本是夠用的,但是vector的一些函數盡量少用,有些操作的o(n)的,這個就是一個數組,沒什么特別的。
2.vector<int> a;
這是一個簡潔的初始化,其實對於vector的初始化太多了,而且沒什么講的,掠過。
3.壓入push_back(),清空clear()
這兩個操作可以說是最常見的操作了,在建圖的過程中經常會用的到。
4.vetor和sort
sort(a.begin(),a.end());
非常暴力,但是非常好用。
5.vector內嵌了好多神奇操作,我曾見過cf大神為了追求速度,只用vector當數組用的,vector的函數有非常多種,都記住可以大量提高效率(但是覺得麻煩一直用的數組,看着舒服一點,想提高自己的速度的可以練一練,感覺是都可以被替代的操作,不會也沒關系)
- 5.set
1.set的原理:其實就是一種平衡樹,你們以后都會學習的,可以把查找的結構寫的非常的好,復雜度查詢和插入都是logn的,很穩定,但是開空間的常數也不小就是了,要是卡時間的話能hash盡量hash。注意:set只是判斷有沒有,不能判斷出現了幾次。
2.insert erase
insert(key_value),插入一個鍵值key_value
erase(iterator) ,刪除iterator指向的值
erase(first,second),刪除定位器first和second之間的值
erase(key_value),刪除鍵值key_value的值
3.count(key_value)
可以看這個值出現了多少次,但是因為是集合,如果有返回0,否則返回1
4.find(key_value)
返回的是迭代器,如果不存在就返回end()
5.迭代器iterator
迭代器是STL中都有的一種類似數組下標一樣的東西,迭代器可以++,但是不能一次跳躍多次。
所以說set是不能查詢第k大的,因為樹形結構不能讓迭代器一次跳躍很多次。
迭代器格式:set<int>::iterator it;
for(it=s.begin ();it!=s.end ();it++) 操作;
迭代器是一種指針,要*it才能拿到它所指向的值。
6.lower_bound()和 upper_bound()
雖然set不支持查詢第k大,但是我們可以查詢比一個數x大於(等於)的第一個迭代器是什么,也是很不錯了。
7.還有一些其他的小技巧,比如size(),empty()什么的,就沒什么可說的了,用過一次就記住了。
- 6.map
1.map原理:其實和set差不多,也是一顆紅黑樹,不過多了另外一個鍵值value,其他的操作和set基本一樣的。多了一個功能就是可以查詢鍵值對應的值。在set中,存的是一個鍵值,而在map中存的是一個pair結構,第一個是鍵值,只能出現一次,第二個是值。
2.map用來干什么?
map是一個映射工具,它可以用logn的時間去查詢一個鍵值對應的值,你可以用它去計數,或者就當一個logn的hash來用,但是一般卡時間的話用unordered_map,如果還不行就手寫一個hash,應該就可以過了。主要是map寫起來真的好方便,你只要把你要查詢的值用中括號擴上就可以啦,就可以返回你要的啦,和數組一樣,真的好好用啊。
3.對於map的操作基本和set差不多,網上寫的好的博客很多了,就不再贅述了。
- 7.queue
1.queue是一種只可以先進先出的數據結構,因為這種結構在很多算法中都有涉及,非常常用,所以也作為常用庫之一,雖然其實現並不復雜,但是非常實用。
2.最常用的入隊,出隊,獲取隊頭,獲取隊尾,大小,是否為空,都很容易,就不再贅述。
3.優先隊列:priority_queue<Type, Container, Functional>,其中Type 為數據類型,Container為保存數據的容器,Functional 為元素比較方式。
一般的用法是不帶后兩個的:
priority_queue<int> q;
這個隊列其實是個最大堆的實現,出隊的時候是用的是top,不是front。pop的時候也是會出隊最大的那一個。
注意一下,這個默認的是最大堆,要是最小堆的話,就要加上后面兩個參數:
priority_queue<int,vector<int>,greater<int> > q;
如果不是int就把int換了就行。
比如單調隊列就使用了隊列,還有djstl使用過了優先隊列
- 8.stack
1.棧其實和隊列特別像,很多操作都是共有的,對於棧,一個先進去的數,一定后更后面出來,和隊列相反,像是一個桶。
2.常用函數不再贅述,網上很多的。
3.用途:對於編譯器來說,你運行的函數就相當於一個棧。很多模擬的結構和棧也特別的像。單調棧。
寫到這里我的手已經要被敲斷了,很多地方沒辦法就省下去,畢竟網上很多博客寫的都是特別的全。
一些模版題:
poj 2823
poj 3250
hdu1053
hdu4585
hdu4302
poj2431
hdu6287