永遠寫不出 pD 的那個人
aka Repkironca
大社課 - 10
STL introduction、vector、deque
ㄟ這個模板看起來好酷喔
好圓好圓的 Content
01.
What Is Data Structure
01.
What Is Data Structure
What Is Data Structure
In computer science, a data structure is a data organization, management, and storage format that enables efficient access and modification
:什麼鬼啦,講人話,在官腔幾點ㄉ,你是資訊之芽嗎
- 一種 有系統 的資料儲存、組織 方法 / 策略
- 大多是靠最基本的變數型態和語法刻出來的
- 內建許多功能(function),方便我們對其操作
- 能夠 節省時間、縮小空間
舉例來說,array 是一種 Data Structure
2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 |
---|
0x25
0x26
0x27
0x28
0x29
0x2A
0x2B
0x2C
0x2D
0x2E
int arr[10];
for (int i = 1; i <= 10; i++) arr[i] = 2*i;
如果你有乖乖上小社,linked_list 也是一種 Data Structure
struct node{
long long value;
node *next = nullptr;
};
struct linked_list{
unsigned int length = 0;
node *root = nullptr;
node *end = nullptr;
bool isempty = true;
bool empty(){
return isempty;
}
unsigned int size(){
return length;
}
void push_front (long long num){
node *tmp = new node;
tmp->value = num;
if (!isempty) tmp->next = root; //root 被往後推一格
if (length == 0) end = tmp; //什麼都沒有,這點是 root 加 end
else if (length == 1) end = root; //root 要變成 end 了
root = tmp;
length++;
isempty = false;
}
void push_back(int tar){
node *tmp = new node;
tmp->value = tar;
length++;
if (isempty){
root = tmp;
end = tmp;
isempty = false;
return;
}
end->next = tmp;
end = tmp;
}
void print_list (){
if (!isempty){
node *now = new node;
now = root;
cout << now->value << ' ';
while (now->next != nullptr){
now = now->next;
cout << now->value << ' ';
}
delete now;
}
}
node *find_node(int loc){
if (loc == 0) return root;
if (loc == size()-1) return end;
node *tmp = root;
for (int i = 0; i < loc && i < size(); i++) tmp = tmp->next;
return tmp;
}
void insert (int loc, long long tar){
node *now = new node;
now->value = tar;
length++;
if (empty()){
root = now;
end = now;
isempty = false;
}else if (loc == 0){
now->next = root;
root = now;
}else if (loc == size()-1){
end->next = now;
end = now;
}else{
now->next = find_node(loc)->next;
find_node(loc)->next = now;
}
}
void erase_by_location (int loc){
if (loc == 0) root = root->next;
else R_erase_by_location(find_node(loc-1), loc);
}
void R_erase_by_location (node *last, int loc){
if (loc == size()-1){
end = last;
last->next = nullptr;
}else{
last->next = last->next->next;
}
length--;
if (length == 0) isempty = true;
}
};
root
5
17
3
end
之前搞我搞得很開心的二元搜尋樹,亦為 Data Sturcture
〞
蛤真的假的,所以我們每個
Data Sturcture 都要用手刻嗎
– 現在為你介紹 C++ 最偉大的發明之一
02.
What Is STL
:斯顛大得天普類特賴不噁瑞
STL
-
Standard Template Library,標準模板庫
-
主要包含下面四種東西:
-演算法 Algorithm,e.g. sort()、swap()
-容器 Containers,e.g. vector、queue
-函式 Functions,function Object,去問 Aaw cuz 我不會
-迭代器 Iterator,嗯對,就是 iterator
STL
-演算法 Algorithm,e.g. sort()、swap()
-容器 Containers,e.g. vector、queue
-函式 Functions,老實說我也不知道包含哪些
-迭代器 Iterator,嗯對,就是 iterator
-演算法 Algorithm
-容器 Containers
-函式 Functions
-迭代器 Iterator
整個 STL 裡的精華
11/18,今天
12/2,二段後
12/16,大社賽前
- vector
- deque
- stack
- list
- queue
自我鞭屍時間
容器是 STL 的精華,或著說 STL 大多是由 Data Structure 組成的
BUT
STL 跟 Data Structure 並不等價
簡報製作者是白癡,他想說 "手刻 Data Structure"
03.
Vector
- 中文叫他 向量
這是 vector
- 我唬爛的中文是 伸縮陣列
這也是 vector
- 符號的話,大概會長這樣$$\overrightarrow{AB}$$
- 有起點與終點,具方向
- 常見的表示法長這樣
vector <int> vec;
- 有 begin() 跟 end()
- 這才是我今天要講的
Vector
- 功能類似 array,不過其 長度是可變的
int arr[MAXN]; // 一旦宣告完就不能變,只有 MAXN 格
vector <int> vec; // 可以不設定長度,隨時能夠改變
- 本身是一個 物件,而非指標
- 除非你是直接砸萬用標頭檔,否則要記得 include 進來
#include <vector>
#include <bits/stdc++.h>
萬用標頭檔,但建中電腦會爛
最安全不會爛掉的用法
Vector 宣告
vector <變數型態> 命名;
vector <int> vec;
// 一個存 int 的 vector,命名為 vec
vector <bool> judge;
// 一個存 bool 的 vector,命名為 judge
那我可以開多維 vector 嗎?
vector <vector <int> > graph;
// 一個vector,裡面存很多個 vector <int>
我哪有差
你開心就好
把 x 加進 vector 尾端
vector 名稱.push_back(x)
vector <int> vec;
vec.push_back(5);
\(\leftarrow\) 頭
尾 \(\rightarrow\)
vec.push_back(3);
vec.push_back(7);
vec.push_back(9);
5
vec[0]
3
vec[1]
7
vec[2]
9
vec[3]
對 vector 取值
vector 名稱[index]
\(\leftarrow\) 頭
尾 \(\rightarrow\)
5
vec[0]
3
vec[1]
7
vec[2]
9
vec[3]
你在 array 中怎麼做,在 vector 中就怎麼做
cout << vec[1] << '\n';
cout << vec[0] << '\n';
cout << vec[4] << '\n';
5
Runtime Error!
3
把尾端元素踢掉
vector 名稱.pop_back();
\(\leftarrow\) 頭
尾 \(\rightarrow\)
5
vec[0]
3
vec[1]
7
vec[2]
9
vec[3]
for (int i = 0; i < 4; i++) vec.pop_back();
把尾端元素踢掉
vector 名稱.pop_back();
\(\leftarrow\) 頭
尾 \(\rightarrow\)
5
vec[0]
3
vec[1]
7
vec[2]
for (int i = 0; i < 4; i++) vec.pop_back();
把尾端元素踢掉
vector 名稱.pop_back();
\(\leftarrow\) 頭
尾 \(\rightarrow\)
5
vec[0]
3
vec[1]
for (int i = 0; i < 4; i++) vec.pop_back();
把尾端元素踢掉
vector 名稱.pop_back();
\(\leftarrow\) 頭
尾 \(\rightarrow\)
5
vec[0]
for (int i = 0; i < 4; i++) vec.pop_back();
把尾端元素踢掉
vector 名稱.pop_back();
\(\leftarrow\) 頭
尾 \(\rightarrow\)
for (int i = 0; i < 4; i++) vec.pop_back();
vec.pop_back();
空的,Runtime Error!
訪問尾端元素
vector <int> vec;
for (int i = 0; i < 10; i++) vec.push_back(i);
while (!vec.empty()){
cout << vec.back() << " out of this vector\n";
vec.pop_back();
}
vector <int> vec;
vec.push_back(8);
cout << vec.back() << '\n'; // 8
vector 名稱.back()
直接回傳該元素
檢測 vector 是否為空
vector 名稱.empty();
回傳一個 bool,若為 true 表示 vector 中沒東西
vector <int> vec;
cout << vec.empty() << '\n'; // 1
vec.push_back(6);
cout << vec.empty() << '\n'; // 0
vec.pop_back();
cout << vec.empty() << '\n'; // 1
檢測 vector 長度
vector 名稱.size();
回傳一個 size_t,反正就是 unsigned int 的一種
vector <int> vec;
cout << vec.size() << '\n'; // 0
for (int i = 0; i < 10; i++) vec.push_back(i);
cout << vec.size() << '\n'; // 10
for (int i = 0; i < 5; i++) vec.pop_back();
cout << vec.size() << '\n'; // 5
快速初始化
- vector <變數型別> 命名(初始大小, 統一填入什麼);
vector <vector <int> > vec(MAXN, vector <int>(MAXN, 5));
// 一個 vector,裡面裝著 MAXN 個 vector <int>
// 其中每個裡面的 vector <int>,大小皆為 MAXN,初始值為 5
- 同 array,直接用大括號列出初始元素
vector <int> vec = {0, 2, 4, 6, 8, 10, 12, 14};
vector <int> vec(MAXN);
=
int arr[MAXN];
vector <int> vec(MAXN, 5);
=
int arr[MAXN];
for (int i = 0; i < MAXN; i++) arr[i] = 5;
食酢
可能有用的提示 (1):
這題的輸入很無聊,要用這個方法吃
char tmp;
while (cin >> tmp && !cin.eof()){
}
可能有用的提示 (2):
vector 名稱.clear(); 能快速清空整個 vector
vec.clear();
AC CODE 可以點我
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
using namespace std;
int main (){
icisc
char tmp;
vector <char> T, F;
while (cin >> tmp && !cin.eof()){
if (tmp == '*'){
if (T.size() >= F.size()) for (auto to:T) cout << to << ' ';
else for (auto to:F) cout << to << ' ';
cout << '\n';
T.clear(); // 清空 T
F.clear(); // 清空 F
}else{
if (tmp >= '0' && tmp <= '9') T.push_back(tmp);
else F.push_back(tmp);
}
}
}
AC CODE
那我可以也用 array 做啊,題目都會給 MAXN
我哪有差
我哪次有差
我怎麼可能有差
你開心就好
BUT 你會被我傳教
vector 教榮光不滅
為何 Vector > Array
- Vector 是可伸縮的,彈性較大、省空間
- 大部分操作都能在 O(1) 內完成
[ 官方一點的理由 ]
為何 Vector > Array
- Vector 本身是 物件,可以達成各種 Array 不能的操作,超級爽
[ 正常一點的理由 ]
vector <int> vec_1, vec_2;
for (int i = 0; i < 10; i++) vec_1.push_back(i*2);
vec_2 = vec_1;
直接砸等號
vector <int> func(vector <int> vec){
}
直接作為
參數 / 回傳
直接做比較
if (vec_1 != vec_2){
}
為何 Vector > Array
- 跟 Array 比起來,初始化超級快
[ 正常一點的理由 ]
[創造一個大小為 MAXN 的二維布林陣列,初始化為 true]
vector <vector <bool> > visited(MAXN, vector <bool>(MAXN, true));
bool graph[MAXN][MAXN];
for (int i = 0; i < MAXN; i++)
for (int j = 0; j < MAXN; j++)
graph[i][j] = true;
- 裡面什麼都可以塞,自由度很高
vector <set <int> > vec(MAXN, set <int>());
為何 Vector > Array
因為初始化可以壓成一行,特別帥
[ 超級奇怪的理由 ]
因為可以砸 iterator,iterator 打起來很爽
因為他很有魅力
#define pbpii pair <bool, pair <int, int>>
vector <pbpii> judge(MAXN, {false, {0, 0}});
for (vector <int> ::iterator to = vec.begin(); to != vec.end; to++){}
// 或
for (auto to:vec){}
04.
Deque
Deque
- Double Ended QUEue,中文是 雙向佇列
- 念法同 deck,雖然你要唸 de-queue 我也不會阻止你
不過 dequeue 是 Java 的東西
- 可以想像成對頭尾都能 O(1) 操作的 vector
- 天底下哪有這麼好的事,雖然我寫 O(1),但它的 常數比 vector 大
\(註_2\):常數的話,可以想像成 這個東西本身運行 需要的時間
Deque 宣告
deque <變數型態> 命名;
vector <bool> deq;
// 一個存 bool 的 deque,命名為 deq
deque <vector <int>> devec;
deque <deque <int>> dedeque;
當然
如果你想
這些奇怪事情都能達到
我懶得教的部分
- 取值
- 小括號初始化
- .size()
- .empty()
做法都跟 vector 一樣,我要直接跳過
對元素做操作
.push_back(x)
.push_front(x)
.pop_back(x)
.pop_front(x)
把 x 插進尾端
把 x 插進前端
把尾端元素踢除
把前端元素踢除
deque <int> deq(2, 0);
deq[1] = 1; // {0, 1}
deq.push_back(2); // {0, 1, 2}
deq.push_front(1); // {2, 0, 1}
deq.pop_back(); // {0}
deq.front(); // {1}
Jan. 29. 2023 ~ Feb. 3. 2023
Coming Soon...
The End.
不過幫我投票一下