永遠寫不出 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. vectorqueue

函式 Functions,function Object,去問 Aaw cuz 我不會

迭代器 Iterator,嗯對,就是 iterator

STL

演算法 Algorithm,e.g. sort()swap()

容器 Containers,e.g. vectorqueue

函式 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.

不過幫我投票一下