chunlvxiong的博客
本文默認#include <bits/stdc++.h>,默認using namesapce std。
一、vector
vector相當於一個動態的數組。
1、定義:vector <int> a--這樣a的存儲數據類型為int,你也可以定義一個結構體,例如vector <node> a。
2、清空:a.clear()
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、元素個數:a.size()--注意實際存儲區間是0..a.size()-1
5、讀取元素:a[i]--vector存儲區間連續,因此可以直接讀取。
6、尾部插入元素b:a.push_back(b)--復雜度O(1)。
7、尾部刪除元素:a.push_pop()--復雜度O(1)。
8、返回開頭元素的位置:a.begin()
9、返回末尾元素的后一個位置:a.end()
10、刪除元素:a.erase() 例如:a.erase(a.begin()+3)--刪除第4個元素
復雜度與元素在序列中的位置有關,元素位置越往后這個操作越快,如果刪除開頭元素復雜度為O(N)。
對比:
下面這是一個用於建邊的數組模擬鏈表。
#include <bits/stdc++.h> using namespace std; const int maxm=10005; const int maxn=10005; struct node{ int to,len,next; }edge[maxm]; int m,head[maxn],tot; void init(){ memset(head,0,sizeof(head)),tot=0; } void makedge(int u,int v,int t){ edge[++tot].to=v; edge[tot].len=t; edge[tot].next=head[u]; head[u]=tot; } int main(){ scanf("%d",&m),init(); for (int i=1,u,v,t;i<=m;i++){ scanf("%d%d%d",&u,&v,&t); makedge(u,v,t); } return 0; }
下面是用vector實現的程序。
#include <bits/stdc++.h> using namespace std; const int maxn=10005; struct node{ int to,len; }; int m; vector<node>edge[maxn]; void init(){ for (int i=1;i<=maxn;i++) edge[i].clear(); } int main(){ scanf("%d",&m),init(); for (int i=1,u,v,t;i<=m;i++){ scanf("%d%d%d",&u,&v,&t); edge[u].push_back(node{v,t}); } return 0; }
二、map
map是一種關聯容器,它能建立key-value的對應關系。
1、定義:例如map <string,int> a,定義一個key為string類型,value為int類型(一般這樣可以完成字符串Hash的功能)。
2、清空:a.clear()
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
5、插入元素:a["stjfsijf"]=5--即認為key為stjfsijf的value被修改為5--復雜度帶log
6、讀取元素:a["……"]--類似數組方式直接讀取即可。
對比:
下面是一個字符串hash的程序。
#include <bits/stdc++.h> using namespace std; int n,size; char s[1005],name[1005][1005]; int find(char s[]){ for (int i=1;i<=size;i++) if (strcmp(s,name[i])==0) return i; strcpy(name[++size],s); return size; } int main(){ size=0; scanf("%d",&n); for (int i=1;i<=n;i++){ scanf("%s",&s); printf("%d\n",find(s)); } return 0; }
然后下面是用map實現的程序。
#include <bits/stdc++.h> using namespace std; map <string,int> name; int n; string s; int main(){ name.clear(); scanf("%d",&n); for (int i=1,cnt=0;i<=n;i++){ cin>>s; if (name[s]==0) name[s]=++cnt; printf("%d\n",name[s]); } return 0; }
三、set
set是一種集合容器,它的用途在於高效檢索。
1、定義:set <int> a--這樣a的存儲數據類型為int,你也可以定義一個結構體,例如set <node> a。
2、清空:a.clear()
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
5、插入值為b的元素:a.insert(b)--復雜度帶log,但要注意相同的值只會保留最前面的一個。
6、刪除值為b的元素:a.erase(b)--復雜度帶log。
7、返回開頭元素的位置:a.begin()
8、返回末尾元素的后一個位置:a.end()
9、查找元素:a.find(b)--復雜度帶log,找到返回該元素迭代器的位置,如果找不到返回a.end()。
10、a.lower_bound(b)--返回第一個大於等於b的元素迭代器的位置,如果找不到返回a.end()(復雜度帶log)
11、a.upper_bound(b)--返回第一個大於b的元素迭代器的位置,如果找不到返回a.end()(復雜度帶log)
實例:
下面通過一個具體程序來說明set的用法。
#include <bits/stdc++.h> using namespace std; struct node{ int x,y; friend operator <(node a,node b){ return a.x<b.x; } }; set <node> a; set <node>::iterator id; int n,q; int main(){ a.clear(); scanf("%d",&n); for (int i=1,x,y;i<=n;i++){ scanf("%d%d",&x,&y); if (a.find(node{x,0})!=a.end()) a.erase(node{x,0}); a.insert(node{x,y}); } scanf("%d",&q); for (int i=1,x;i<=q;i++){ scanf("%d",&x); id=a.find(node{x,0}); if (id==a.end()) puts("-1"); else printf("%d\n",(*id).y); } return 0; } /* 程序要求:輸入n個key-value(均為int類型),要求使用set維護。 如果有相同的數在,將value改為后一個。 接下來有q個詢問,每個詢問一個數,如果它存在,那么輸出它的value。 如果不存在,輸出-1。 */
四、priority_queue
priority_queue是優先隊列,也就是堆。
1、定義:priority_queue <int> a--這樣a的存儲數據類型為int,你也可以定義一個結構體,例如priority_queue <node> a。
2、入堆:a.push(b)--復雜度帶log
3、堆頂元素出堆:a.pop()--復雜度帶log
4、判斷是否空:a.empty()--如果空返回1,否則返回0
5、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
6、取出堆頂元素:a.top()
對比:
下面給出堆排(降序)的程序。
#include <bits/stdc++.h> using namespace std; const int maxn=105; int n,heap_volume,heap[maxn]; void push(int x){ int i=++heap_volume; while (i>1 && x>heap[i>>1]){ heap[i]=heap[i>>1]; i>>=1; } heap[i]=x; } void pop(){ int x=heap[heap_volume--],i=1,j; while (i<=heap_volume){ j=i<<1; if (j+1<=heap_volume && heap[j+1]>heap[j]) j++; if (j<=heap_volume && heap[j]>x){ heap[i]=heap[j]; i=j; } else{ heap[i]=x; break; } } } int main(){ scanf("%d",&n); heap_volume=0; for (int i=1,x;i<=n;i++) scanf("%d",&x),push(x); for (int i=1;i<=n;i++) printf("%d ",heap[1]),pop(); return 0; }
下面給出使用priority_queue之后的堆排。
#include <bits/stdc++.h> using namespace std; int n; priority_queue <int> heap; int main(){ scanf("%d",&n); for (int i=1,x;i<=n;i++) scanf("%d",&x),heap.push(x); for (int i=1;i<=n;i++) printf("%d ",heap.top()),heap.pop(); return 0; }
五、list
list即雙向鏈表,跟vector很像,不同之處在於其中間修改元素較快但不支持隨機訪問元素。
1、定義:list <int> a--這樣a的存儲數據類型為int,你也可以定義一個結構體,例如list <node> a。
2、清空:a.clear()
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
5、插入元素:
尾部:a.push_back(b)--復雜度O(1)
頭部:a.push_front(b)--復雜度O(1)
6、返回開頭元素的位置:a.begin()
7、返回末尾元素的后一個位置:a.end()
8、刪除元素:
尾部:a.pop_back()--復雜度O(1)
頭部:a.pop_front()--復雜度O(1)
a.erase()--注意此時你不能使用a.erase(a.begin()+3)來刪除第4個元素,因為list不是vector,占用連續的內存空間。
9、排序:a.sort(cmp)--你可以自己寫比較函數
實例:
下面用一個程序來具體說明list的用法。
#include <bits/stdc++.h> using namespace std; list <int> a; list <int>::iterator id; bool cmp(int a,int b){ return a>b; } int main(){ int x; while (~scanf("%d",&x)){ a.push_back(x); if (a.size()>10) a.pop_front(); } a.sort(cmp); id=a.begin(); for (id=a.begin();id!=a.end();id++) printf("%d\n",(*id)); return 0; } /* 程序說明:輸入一些元素加入到list中,若元素個數超過10個,那么刪掉表頭元素。 最后降序輸出所有元素。 */
六、deque
deque,雙端隊列。
1、定義:deque <int> a--這樣a的存儲數據類型為int,你也可以定義一個結構體,例如deque <node> a。
2、清空:a.clear()
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
5、插入元素:
尾部:a.push_back(b)--復雜度O(1)
頭部:a.push_front(b)--復雜度O(1)
6、返回開頭元素的位置:a.begin()
7、返回末尾元素的后一個位置:a.end()
8、刪除元素:
尾部:a.pop_back()--復雜度O(1)
頭部:a.pop_front()--復雜度O(1)
9、刪除元素:a.erase() 例如:a.erase(a.begin()+3)--刪除第4個元素
這個東西復雜度與元素位置有關,如果元素位置靠近頭部或是尾部那么會比較快,但是如果元素位置在中間那么復雜度是O(N)的。
10、讀取元素:a[i]
實例:
#include <bits/stdc++.h> using namespace std; deque <int> a; int n; int main(){ a.clear(); scanf("%d",&n); for (int i=1,x,y;i<=n;i++){ scanf("%d%d",&x,&y); if (y) a.push_back(x); else a.push_front(x); } while (!a.empty()) printf("%d\n",a[0]),a.pop_front(); return 0; } /* 程序說明:輸入n個數,並給出其插入方式(1表末尾插入,0表頭部插入) 最后要求輸出最終序列。 */
七、stack/queue
這兩個東西誰都不會陌生,一個是棧,另一個是隊列。
1、定義:stack<int>a或是queue<int>a,支持結構體,例如:stack<node>a或是queue<node>a。
2、元素個數:a.size()--注意實際存儲區間為0..a.size()-1
3、判斷是否空:a.empty()--如果空返回1,否則返回0
4、入隊/入棧:a.push(x)
出隊/出棧:a.pop()
5、訪問棧頂/隊頭元素:
stack:a.top()
queue:a.front()
其實個人覺得這兩個東西還不如自己寫了算了。
八、iterator
迭代器,很多數據結構都要用到的東西。
1、定義:以vector為例:vector<int>::iterator a
2、雙向:a++,a-- 前后置迭代器
3、輸出:(*a)或(*a).val
4、隨機:a+=p,a-=p 前后移動迭代器p位
也支持引用a+p,a-p。
5、賦值:a=b
6、比較:a==b或a!=b判斷兩個迭代器是否相同
對於隨機迭代器,還可以通過<,>,<=,>=等符號來判斷位置關系。
下面給出上述數據結構的迭代器類型:
vector:隨機迭代器
map:雙向迭代器
set:雙向迭代器
priority_queue:不支持迭代器
list:雙向迭代器
deque:隨機迭代器
stack/queue:不支持迭代器