CPP[2]
基礎語法
章魚
INDEX
複雜度
Pair
Vector
Iterator
Iterator
Iterator
Stack
Queue
Priority_queue
List
複雜度 complexity
1.簡介
2.範例
3.怎麼算
簡介
複雜度
- 用來衡量解決一個問題所需的計算資源
- 這些資源通常是時間和空間
- 今天主要著重在時間部分
為什麼要衡量
美國進行人口普查,在沒有電腦前每10年進行一次,完成一次的統計需要7.5年 → 等你查完小孩子都長大了
簡介
怎麼衡量
直接用電腦跑一次?
太難了
每台電腦運算速度不同
運算速度也會受到當天狀況(溫度、濕度)影響
𝑂(𝑔(𝑛))
大𝑂符號
範例
來看個飯粒
int a[n];
for(int i=0;i<n;i++) cin>>a[i];
將n筆資料輸入陣列a裡
當n越大
需要的空間越大
0 | 1 | 2 | ... | n-1 |
---|
空間&時間複雜度:𝑂(𝑛)
程式執行的時間也越久
n
T
範例
再舉個例子,假設一個演算法的執行時間(或者所需步驟數)可以用
𝑇(𝑛)=2𝑛²+𝑛+10
表示,其中𝑛為輸入的大小
範例
𝑇(𝑛)=2𝑛²+𝑛+10
當𝑛夠大的時候,除了
2𝑛²
以外的其他項的影響可以忽略
n=10,T(10)=200+10+10=220
n=100,T(100)=20000+100+10=20110
n=1000,T(1000)=2000000+1000+10=2001010
參考自資訊之芽簡報
這時候我們就說這段程式的複雜度是𝑂(𝑛²)
範例
再舉個例子

複雜度:O(1) a.k.a 常數
複雜度:O(0.004)
怎麼算
乘法比加法慢,那複雜度是否相同?
答案是都一樣
兩者的計算時間都是常數
都是𝑂(1)
怎麼算
宣告跟輸入都要時間,這些時間要算進去嗎?
宣告跟輸入所花的時間遠小於計算
可以忽略
怎麼算
常見題目限制
時間限制: 1000 ms
記憶體量: 65536 MB
電腦每秒約10⁹次運算
複雜度 x 常數<10⁹
怎麼算
可以根據複雜度判斷你所用的演算法適不適合
input限制
O(1)
𝑂(1) -> ∞
𝑂(log(𝑛)) -> 10²⁰
𝑂(𝑛) -> 10⁸
𝑂(𝑛log(𝑛)) -> 10⁷
𝑂(𝑛²) -> 10⁴
𝑂(2ⁿ) -> 28
𝑂(𝑛!) -> 12

複雜度限制
實際情況因常數而定
STL
Standard Template Library
標準樣板函式庫
在C++中可以直接使用的
- 資料結構
- 演算法
- 迭代器
Standard Template Library
標準樣板函式庫
How to use
上cplusplus.com查STL

聲明
等等所有的STL都適用萬用標頭檔
#include<bits/stdc++.h>
也都需要
using namespace std;
但為了方便閱讀
等等的簡報裡會省略
pair
存兩個變數的方法

pair
first | second |
---|
pair
first(string) | second(bool) |
---|
怎麼宣告
#include<utility>
pair<string,bool> p;
pair
first(小黑) | second(false) |
---|
賦值
其一、
pair<string,bool> p("小黑",false);
其二、
p=make_pair("小黑",false);
其三、
p.first="小黑";
p.second=false;
vector

Vector
簡單來講
就是可以改變長度的array
#include<vector>
array
int arr[5]={};//{0,0,0,0,0}
vector
宣告
vector<int> v(5,0);//{0,0,0,0,0}
int arr[5]
vector<int> v(5);
404 not found
vector<int> v;
array
vector
花式宣告
int arr[5]={1,1,1,1,1}
vector<int> v(5,1);//{1,1,1,1,1}
int arr[5][3];
vector<vector<int>> v(5,vector<int>(3));
取值
與array相同
vector<int> v={1,4,2,8,5}
cout<<v[1];//4
.size()
vector<int> v(5,1);
cout<<v.size();//5
取得vector大小
.empty()
vector<int> v;
cout<<v.empty();//1
檢查vector是否為空
.push_back()
vector<int> v={1,4,2};
v.push_back(8);
v.push_back(5);
//v={1,4,2,8,5}
插入數字到vector後方
容量不足!!
1 | 4 | 2 |
---|
8
自動開兩倍大
&
自動複製過去
1
4
2
8
複雜度:𝑂(2𝑛)
複雜度:𝑂(𝑛)
.capacity()
vector<int> v={1,4,2};
v.push_back(8);
cout<<v.size()<<' '<<v.capacity();//4 6
取得容量空間大小
實際使用空間
分配到的空間
.pop_back()
vector<int> v={1,4,2,8,5};
v.pop_back();
v.pop_back();
//v={1,4,2}
將vector最後方的數字移除
不要做過頭!

#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v(5,0);
for(int i=0;i<6;i++){
v.pop_back();
cout<<v.size()<<' ';
}
}
2⁶⁴-1
不要做過頭!
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v(5,0);
for(int i=0;i<6;i++){
if(!v.empty()){
v.pop_back();
}
cout<<v.size()<<' ';
}
}
水啦

v1.swap(v2)
vector<int> v={1,4,2,8,5};
vector<int>().swap(v);//跟空的vector交換=>重置
cout<<v.empty();//1
高效交換兩個vector的內容
iterator

we call it 迭代
迭代器
已經寫好的
讓你便利遍歷

你會的遍歷
vector<int> v={1,4,2,8,5};
for(int i=0;i<v.size();i++){
cout<<v[i];
}
//14285
for迴圈&while迴圈
用iterator的遍歷
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v(5);
for(vector<int>::iterator it=v.begin();it!=v.end();it++){
cin>>*it;
}
for(vector<int>::reverse_iterator it=v.rbegin();it!=v.rend();it++){
cout<<*it<<" ";
}
}
vector<int> v(5);
for(vector<int>::iterator it=v.begin();it!=v.end();it++){
cin>>*it;
}
v(5)
v.begin()
v.end()
1
5
2
4
8
for(vector<int>::reverse_iterator it=v.rbegin();it!=v.rend();it++){
cout<<*it<<" ";
}
v(5)
v.rend()
1
5
2
4
8
5
8
2
4
1
output:
扣好長喔,怎麼辦
便利的遍歷
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v(5);
for(auto it=v.begin();it!=v.end();it++){
cin>>*it;
}
for(auto it=v.rbegin();it!=v.rend();it++){
cout<<*it<<" ";
}
}
讓auto幫你決定變數型態
變例的便利的遍歷
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> v(5);
for(int &i:v){
cin>>i;
}
for(auto i:v){
cout<<i<<" ";
}
}
這超好用
stack


stack
堆
新資料放最上層
拿也先從最上層
Last-In First-Out
LIFO

宣告
#include<stack>
stack<int> stk;
stk.push(1);
stk.push(4);
stk.push(1);
.push()
#不是push_back()
stk
1
1
4
.top()
取得最上方元素
stk.top()++;
cout<<stk.top();//2
stk
1
1
4
2
取得最上方元素
stack是空的時,會Segment Default
=>先判斷是否.empty()
.size()
取得大小
cout<<stk.size();//3
stk
1
2
4
queue

queue
佇(ㄓㄨˋ)列

First-In First-Out
FIFO
宣告
#include<queue>
queue<int> q;
q.push(1);
q.push(4);
q.push(2);
.push()
q
1
2
4
.front() & .back()
q.front()--;
q.back()=5;
q
1
2
4
5
0
.size() & .pop() & .empty()
while(q.size()>1){
cout<<q.front();
q.pop();
}
cout<<q.empty();
q
4
0
5
output:
0
4
0
priority_queue


priority_queue
優先權佇列
根據比較規則排列,最大者先出
預設數值大的在前
宣告
#include<queue>
priority_queue<int> pq;
//使用預設的由大到小
宣告
由小到大
priority_queue<int,vector<int>,greater<int>> pq;
宣告
自訂比較函式
#include<bits/stdc++.h>
using namespace std;
struct comp{
bool operator()(int a,int b){
return a<b;//小到大
}
};//<-加分號!!
int main(){
priority_queue<int,vector<int>,comp> pq;
}
.push() &
.top() &
.pop() &
.size() &
.empty()
你懂得
直接看扣
priority_queue<int> pq;//由大到小
pq.push(1);
pq.push(4);
pq.push(2);
while(!pq.empty()){
cout<<pq.top()<<' ';
pq.pop();
}
output:
1
2
4
pq
型態是heap(堆)但做動畫好麻煩
priority_queue<int> pq;//由大到小
pq.push(1);
pq.push(4);
pq.push(2);
while(!pq.empty()){
cout<<pq.top()<<' ';
pq.pop();
}
output:
1
2
4
pq
4
2
priority_queue<int> pq;//由大到小
pq.push(1);
pq.push(4);
pq.push(2);
while(!pq.empty()){
cout<<pq.top()<<' ';
pq.pop();
}
return 0;
output:
1
pq
4
2
1
補充
另一種自訂比較函式的方法
講師也不會
list
list
雙向鏈結串列
每個元素裡有:
- 一個數值
- 前一個元素的指標
- 後一個元素的指標
蛤
宣告
#include<list>
list<int> l={2,1}
0x1428
0x1429
2
1
nullptr
nullptr
0x1429
0x1428
宣告
基本上跟vector一樣
list<int> l(3,1);
list<int> l(3);
list<int> l;
.front() & .back()
取得最前方和最後方的元素
list<int> l={1,4,2,8};
cout<<l.front()+l.back();
//1+8=9
1
8
2
4
front
back
.push_front() & .push_back()
新增元素在最前方和最後方
l.push_front(0);
l.push_back(5);
front
back
1
8
2
4
front
0
back
5
迭代器
它也可以用迭代器ㄛ
#include<bits/stdc++.h>
using namespace std;
int main(){
list<int> l(5);
for(list<int>::iterator it=l.begin();it!=l.end();it++){
cin>>*it;
}
for(list<int>::reverse_iterator it=l.rbegin();it!=l.rend();it++){
cout<<*it<<" ";
}
}
迭代器
便利遍歷和變例便利遍歷也可以
#include<bits/stdc++.h>
using namespace std;
int main(){
list<int> l(5);
for(auto it=l.begin();it!=l.end();it++){
cin>>*it;
}
for(auto it=l.rbegin();it!=l.rend();it++){
cout<<*it<<" ";
}
}
迭代器
便利遍歷和變例便利遍歷也可以
#include<bits/stdc++.h>
using namespace std;
int main(){
list<int> l(5);
for(auto &i:l){
cin>>i;
}
for(auto i:l){
cout<<i<<" ";
}
}
它也可以
- .insert()
- .erase()
- .empty()
- .size()
But!
list不能用索引取值
list<int> l={1,4,2,8,5}
cout<<l[2];

來烤肉!!
點我
來烤肉!!
c++語法小社
By oct0920
c++語法小社
- 297