STL

講者:思諾&娟

  • STL=Standard Template Library=標準模板庫

  • 包含演算法/容器/迭代器

  • 其中,有很多好用的”容器”,例如:queue/vector/set

  • 每種容器都有自己的特性,可以善加利用

  • 注意時間複雜度,STL裡面的函式常常不是O(1)

STL是甚麼?

  • 後進先出(例如:一堆書本)

  • 從最頂端進行存取 / 刪除 / 新增 資料

Stack(堆疊)

指令

#include <stack>
stack <int> stk;
stk.top();  //回傳stack頂端的值
stk.pop();  //刪除stack頂端的資料
stk.push(); // 將新值加入stack
stk.size(); // 輸出stack的大小

例題:c123:rails

現在火車從A方向來,預定從B方向離開。火車共有N節車廂(N <=1000),並且各車廂依次以1到N來編號。你可以假設各車廂在進站之前可以單獨與其他車廂分離,也可以單獨離開車站到往B方向的鐵軌上。你也可以假設在任何時間火車站都可以容納所有的車廂。但是一旦一節車廂進站後,就不能再回到A方向的鐵軌上了,並且一旦離開車站往B方向後,也不能再回到車站。

現在你的任務是寫一個程式,判斷火車能否以一特定的排列方式在B方向的鐵軌上。

 

範例講解

以測資4 5 3 7 6 2 1為例

B軌道                          車站                  A軌道

4 5                               3 2 1                 6 7

4 5 3                            2 1                    6 7

4 5 3                            6 2 1                 7

4 5 3 7                         6 2 1        

可行! 

 

 

範例測資:

5

1 2 3 4 5

5 4 3 2 1

5 4 1 2 3

0

7

4 5 3 7 6 2 1

0

0

 

思考思路

當我們輸出的車廂還沒到的時候,就把他們先存在車站(一個stack)

 

 

參考答案

#include <bits/stdc++.h>
using namespace std;

int main() {
  int n;
  while (cin >> n)
  {
    if (n == 0)
    {
      cout << endl;
      break;
    }
    while (1)
    {
      stack <int> stk;
      int rail[1005];
      cin >> rail[0];
      if (rail[0] == 0) {cout << endl; break;}
      // 輸入要輸出的軌道
      for (int i=1; i<n; i++) 
        cin >> rail[i];
      int  ra = 0;
      //=======================
      for (int a=1; a<=n; a++)
      {
        stk.push(a);
        while (!stk.empty() && stk.top() == rail[ra])
        {
          stk.pop();
          ra++;
        }
        
      }
      if (stk.empty())  cout << "Yes" << endl;
      else cout << "No" << endl;
    }
  }
}
  • 先進先出(類似排隊)

  • 從最前端存取、刪除資料,從最後端新增資料

Queue(佇列)

指令:

#include <queue>
queue <int> q;
q.front();  //回傳 queue 最前端的值 
q.pop();    //刪除 queue 最前端的資料 
q.push();   //將一個新的值加入 queue 的最後端 
q.size();   //回傳 queue 的大小
  • 雙端佇列,也就是說包含了Stack和Queue的功能,可取代這兩者

Deque(雙端佇列)

Deque(雙端佇列)

#include <deque>
deque <int> dq;
dq.empty();     //測試 deque 是否為空。(回傳布林值)
dq.size();      //查詢目前 deque 中有幾個元素。
dq.push_front();//在 deque 的前端加入一個元素。
dq.push_back(); //在 deque 的後端加入一個元素。
dq.pop_front(); //移除目前 deque 中最前端元素。
dq.pop_back();  //移除目前 deque 中最後端元素。
dq.front();     //取得目前 deque 中最前端元素。
dq.back();      //取得目前 deque 中最後端元素。
dq.insert(iterator, n, val); //插入位置/次數/值
  • 存取、刪除 最頂端的資料 (為預設的極值)

  • 維持極值

Priority_queue(優先佇列)

  • 關於宣告:預設為由大至小排列,但可以再進行更改

指令

#include<queue>
priority_queue <int> pq;                       //由大至小
priority_queue <T, vector<T>, greater<T> > pq; //由小至大
priority_queue<T, vector<T>, cmp> pq;

pq.push(); //輸入 
pq.top();  //存取最大權重值
pq.pop();  //刪除最大權重值
pq.size(); //回傳 pioraity_queue 的大小
  • 查找資料

  • 可插入/刪除/選取資料

  • 會自動進行排序(由小到大)/不會選到重覆的

Set(集合)

 

指令

 

set <int> s;
s.insert(); //新增
s.erase();  //刪除
s.count();  //查詢是否存在於集合中
s.empty();  //判斷是否為空的set

指令

 

s.lower_bound(x);  
//用二分搜找出"大於或等於"x的最小值的位置
s.upper_bound(x); 
//用二分搜找出"大於"x的最小值的位置

//vector用法
auto it = lower_bound(v.begin(), v.end(), val);  
auto it = upper_bound(v.begin(), v.end(), val);  

lower_bound 跟 upper_bound(有經過排序的vector也可以用!)

 

休息&討論

  • 跟struct很像,但把兩個東西綁在一起
  • 包含兩個數值 前面的稱為first, 後面的稱為second
  • 兩個數值可以為不同種類的數據類型
  • 比較時,會先比first再比較second

Pair

 

指令

 

#include <utility>
pair <T1, T2> p1 // 宣告
make_pair (v1, v2) //直接使用v1 / v2來創建這個pair
//pair的操作
p1.front = 1;
p1.second = 2;
  • 使用關鍵字Key去索引該關鍵字的值value

  • 為一對一的功能

  • 可以修改value, 不能修改Key

  • 包含插入、修改、刪除、尋找

Map(映射)

 

 

指令

#include<map>
map <string, int> mp; //宣告一個 key為string, value為int 的map
//插入的方法
mp[key] = value; //也可進行更改
mp.insert(pair<string, int>(Hi, 1) );
//查詢
mp.find();  //返回資料所在位置,若無則返回與end()函數相同
mp.count(); 

mp.erase(); //刪除
mp.clear(); //清空
  • 可改變容量的陣列(比較好用的陣列)

Vector(陣列)

 

指令

 

#include<vector>
vector <int> adj;
adj.push_back();  //新增尾部元素
adj.pop_back();   //刪除尾部元素
  • 全名Disjoint Sets
  • 用以處理不交集合併查詢問題
    可以查詢兩點是否相通
    透過不斷尋找源頭進行

DSU(併查集)

 

指令

 

find,  查詢一個元素所在的集合

union, 合併兩個元素所在的集合

 

p[M] = {-1}; //先將陣列進行初始化
int find_root (int x) //找尋源頭
{
    if (par[x] != x)  //若x的源頭不等於x代表還有源頭,繼續找
        return find_root(par[x]);
    return x;
}

指令 

 

void union(int x, int y)
{
    int rx = find_root(x);
    int ry = find_root(y);
    par[rx] = ry;
}
  • 砍半砍半在砍半
  • 甚麼樣的性質可以這樣做?
  • 單調性
  • 甚麼時候停止?

二分搜

 

  • 000000001111111111111
  • 甚麼時候開始是1?
  • 左閉右閉

二分搜

 

int l, r;
while(l < r)
{
	int m = (l+r)/2;
    if (f(m))
    	r = m;
    else 
    	l = m+1;
}
ans = l;
  • 000000001111111111111
  • 甚麼時候開始是1?
  • 左閉右閉

二分搜

 

int l, r;
while(l < r)
{
	int m = (l+r)/2;
    if (f(m))
    	r = m;
    else 
    	l = m+1;
}
ans = l;

Serif

By yujuan

Serif

  • 277