REVIEW

林卉家 巫伊璐 戴瑢溱

1

Stack / Queue

2

Vector / Deque

3

Greedy

5

Dynamic programming

4

Structures

6

空間複雜度 / 時間複雜度

Stack / Queue

  • 資料結構
  • 後進先出(LIFO, Last-In-First-Out)
  • 需引入函式庫<stack>

Stack

疊盤子

疊書本

疊熊熊(?

每個人都插隊

Stack

stack <型態> 名稱 ​宣告
​push(元素) 放入元素
​pop() 刪除第一個元素
top() 讀取最上面的元素
​empty() ​是否為空
​size() ​內有幾個元素

Stack

Data2.push(名稱)

Data2.pop()

Data2

Stack

#include <iostream>
#include <stack>

using namespace std;
int main(){

    stack <int> s;
    for(int i=1;i<=10;i++){
        s.push(i);
    }//s=[1,2,3,4,5,6,7,8,9,10]
    
    int m=s.size();
    for(int i=0;i<m;i++){
        cout<<s.top()<<endl;//依序讀取10,9,8...,1
        s.pop();//依序刪10,9,8...,1
    }
    cout<<s.size()<<"個元素"<<endl;//全部刪光剩0個元素
    return 0;
}
  • 資料結構
  • 先進先出(FIFO, First-In-First-Out)
  • 需引入函式庫<queue>

Queue

排隊

Queue

queue <型態> 名稱 ​宣告
​push(元素) 放入元素
​pop() 刪除第一個元素
front() 讀取最前面的元素
​empty() ​是否為空  ( 空: 1 / 有元素: 0)
​size() ​內有幾個元素

Data1.push()

Queue

Data1

Queue

queueData.pop()

Data1

Queue

#include <iostream>
#include <queue>

using namespace std;
int main(){

    queue <int> q;
    for(int i=1;i<=10;i++){
        q.push(i);
    }//q=[1,2,3,4,5,6,7,8,9,10]
    
    int m=q.size();
    for(int i=0;i<m;i++){
        cout<<q.front()<<endl;//依序讀取1,2,3,...,10
        q.pop();//依序刪1,2,3,...,10
    }
    cout<<q.size()<<"個元素"<<endl;//全部刪光剩0個元素
    return 0;
}

Vector / Deque

宣告與初始化

// 空的 vector
vector<int> v1;  
// 容量為 5,元素預設為 0
vector<int> v2(5);  
// 容量為 5,每個元素都初始化為 100
vector<int> v3(5, 100);  
// 列表初始化
vector<int> v4 = {1, 2, 3, 4, 5};  

宣告與初始化

// 空的 vector
vector<int> v1;  
// 容量為 5,元素預設為 0
vector<int> v2(5);  
// 容量為 5,每個元素都初始化為 100
vector<int> v3(5, 100);  
// 列表初始化
vector<int> v4 = {1, 2, 3, 4, 5};  
vector<int> v;

// 新增元素(尾部)
v.push_back(10);
v.push_back(20);
v.push_back(30);

// 刪除尾部元素
v.pop_back();

// 插入元素
v.insert(v.begin() + 1, 15); 

// 刪除指定位置的元素
v.erase(v.begin());

// 清空整個 vector
v.clear();

// 獲取元素數量
cout << "當前元素數量: " << v.size() << endl;

// 獲取最大容量
cout << "最大容量: " << v.capacity() << endl;

// 存取元素
if (!v.empty()) {
	// 使用索引存取
	cout << "第一個元素: " << v[0] << endl; 
    // 使用 at() 存取
    cout << "第二個元素: " << v.at(1) << endl;
} else {
cout << "vector 目前為空,無法存取元素。" << endl;
}

基本操作

deque<int> dq; // 宣告一個空的

// 插入元素
dq.push_back(10);  // [10]
dq.push_front(20); // [20, 10]
dq.push_back(30);  // [20, 10, 30]

// 訪問元素
cout << "第一個元素: " << dq.front() << endl; // 20
cout << "最後一個元素: " << dq.back() << endl; // 30
cout << "第二個元素: " << dq[1] << endl; // 10 

// 刪除元素
dq.pop_front(); // [10, 30]
dq.pop_back();  // [10]

// 判斷是否為空
if (dq.empty()) {
	cout << "Deque 是空的" << endl;
} else {
	cout << "Deque 長度: " << dq.size() << endl;
}

deque

vector deque
插入元素 push_back() push_back(), push_front()
刪除元素 pop_back() pop_back(), pop_front()
訪問元素 operator[], at() operator[], at()
元素量 size() size()
是否為空 empty() empty()
訪問首尾 front(), back() front(), back()
最大容量 capacity() X

compare

push_back(10)

10

push_front(20)

10

20 10

push_back(30)

20 10

20 10 30

dq.push_back(10); 
dq.push_back(20);
dq.push_front(30);
cout << dq.front() << endl; 
cout << dq.back() << endl; 
cout << dq[1] << endl; 
dq.push_back(10); 
dq.push_back(20);
dq.push_front(30);
cout << dq.front() << endl; 
cout << dq.back() << endl; 
cout << dq[1] << endl; 

30 20 10

pop_back()

20 10 30

20 10

pop_front()

20 10

10

dq.push_back(10); 
dq.push_back(20);
dq.push_front(30);

cout << dq.front() << endl; 
cout << dq.back() << endl; 
cout << dq[1] << endl; 

dp.pop_front();
dp.pop_back();

if (dq.empty()) {
	cout << "Deque 是空的" << endl;
} else {
	cout << "Deque 長度: " << dq.size() << endl;
}
dq.push_back(10); 
dq.push_back(20);
dq.push_front(30);

cout << dq.front() << endl; 
cout << dq.back() << endl; 
cout << dq[1] << endl; 

dp.pop_front();
dp.pop_back();

if (dq.empty()) {
	cout << "Deque 是空的" << endl;
} else {
	cout << "Deque 長度: " << dq.size() << endl;
}

1

vector內存使用少

deque比vector更適合頻繁push_front()

比list更適合隨機存取

常用於滑動視窗、BFS搜索

Greedy

  • 反覆執行某個任務
  • 當下最優解

貪婪演算法Greedy

最短路徑⚠️

刪數字

1 2 3 5 6

Greedy-刪數字

4 2 9 1 3 9 6

刪4個數字變最小

4 2 9 1 7 9 6

4 2 9 1 7 9 6

4 2 9 1 7 9 6

4 2 9 1 7 9 6

剩下2 1 6

Greedy-不適用於最短路徑

指令:連通所有點

任務:挑一個最短路線鋪道路

a

b

c

d

5

6

7

11

9

e

10

~9其實不需要~

Structures

public

private

class zsisc {
public:
	string name;
    int height;  
}
class zsisc {
private:
	string name;
    int mathScore;  
}

該類別內外皆可存取

外部程式可直接存取、修改

只能在該類別內存取

外部程式無法直接存取,必須用公有函式存取

public

private

class zsisc {
public:
	string name;
    int height;  
}
class zsisc {
private:
	string name;
    int mathScore;  
}

該類別內外皆可存取

外部程式可直接存取、修改

只能在該類別內存取

外部程式無法直接存取,必須用公有函式存取

public

private

class zsisc {
public:
	string name;
    int height;  
}
class zsisc {
private:
	string name;
    int mathScore;  
}

該類別內外皆可存取

外部程式可直接存取、修改

只能在該類別內存取

外部程式無法直接存取,必須用公有函式存取

struct class
預設 public private
繼承 X O
封裝
物件導向
struct class
預設 public private
繼承 X O
封裝
物件導向

struct----簡單資料結構

class ----物件導向

可將不同資料型態同時處存

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

struct scoreList {
    string name;
    double englishScore;
    float chineseScore;
    int mathScore;
    void avg() {
        cout << (englishScore + mathScore + chineseScore) / 3 << endl;
    }
};

int main() {
    // 賦值
    scoreList student = {"Amy", 59.99, 79.9, 60};
    student.avg();
}

可將不同資料型態同時儲存

注意:在主程式之外!

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

struct scoreList {
    string name;
    double englishScore;
    float chineseScore;
    int mathScore;
    void avg() {
        cout << (englishScore + mathScore + chineseScore) / 3 << endl;
    }
};

int main() {
    // 賦值
    scoreList student = {"Amy", 59.99, 79.9, 60};
    student.avg();
}

struct

struct id{
    int num;
    string name;
};
 
struct checkup{
    id studentNumber;
    int grade;
    int class;
    int number;
};
struct Grade {
    string name;
    int score;
};
    
Grade student[3] = {
    {"72", 60},
    {"73", 50},
    {"74", 90}
};

struct

struct可以放在struct裡

struct id{
    int num;
    string name;
};
 
struct checkup{
    id studentNumber;
    int grade;
    int class;
    int number;
};

struct在陣列

struct Grade {
    string name;
    int score;
};
    
Grade student[3] = {
    {"72", 60},
    {"73", 50},
    {"74", 90}
};

Dynamic programming

動態規劃

Dp - 定義

大問題

小問題

小問題

小問題

1.  最優子結構

問題的最優解可以由其子問題的最優解構成.

2. 重疊子問題

不同問題在求解過程中會包含重複的子問題 (透過記憶化或表格法可以避免重複計算).

3.  無後效性

當一個子問題的解確定後, 後續計算不會影響該解的正確性.

提升效率 !!!

Dp - 定義

Dp - Greedy VS. DP

海綿寶寶今天要去 拌咖哩國 與 不拌咖哩國 旅遊, 他想要在兩個國家都分別買一個15元的咖哩蟹堡, 請幫他想想該如何付錢吧~

拌咖哩國

不拌咖哩國

1

5

10

1

5

11

咖哩拌不拌不重要
​我們來吃咖哩蟹堡 !

Dp - Greedy VS. DP

拌咖哩國

不拌咖哩國

Greedy

DP

我要一15元的咖哩蟹堡 !!

1

5

10

5

10

11

1

1

1

5

5

5

1

5

10

1

5

11

Dp - 概念

設 f(x) 為價值 x 元的商品所需要的最少硬幣數

11

如果付

f(15) = f(4) + 1

如果付

f(15) = f(10)+ 1

5

如果付

1

f(x) = min{ f(x-11), f(x-5), f(x-1) } + 1

f(15) = min{ f(4), f(10), f(14) } + 1

f(15)

f(4)

f(10)

f(14)

.

.

.

.

.

.

.

.

.

f(15) = f(14)+ 1

Dp - 費氏數列

* f(n) = f(n1) + f(n2)      (n2)

#include<iostream>
using namespace std;

long long fib( long long num ){
	long long dp[num + 1];
	dp[0] = 0;
	dp[1] = 1;
	for(int i=2; i<num+1; i++){
		dp[i] = dp[i-1] + dp[i-2];
	}
	return dp[num]; 
}

int main(){
	long long num = 0;
	cin >> num;
	cout << fib(num) << endl;
	return 0;
}

使用陣列記憶化

Dp - 路徑問題

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

int main() {
	int grid[3][4] = {
        {0, 7, 8, 9},
        {1, 2, 5, 1},
        {1, 4, 10, 0}
    };
    int dp[3][4];
    dp[0][0] = grid[0][0];

    for (int i=1; i<4; i++) {
        dp[0][i] = dp[0][i - 1] + grid[0][i];
    }

    
    for (int i=1; i<3; i++) {
        dp[i][0] = dp[i - 1][0] + grid[i][0];
    }

    for (int i=1; i<3; i++) {
        for (int j = 1; j < 4; j++) {
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        }
    }

    cout << "最短路徑總和為:" << dp[2][3] << endl;
    return 0;
}

使用陣列記憶化

空間複雜度 / 時間複雜度

複雜度 - 定義

1.  時間複雜度

定性描述該演算法的執行時間

2. 空間複雜度

定性地描述該演算法或程式執行所需要的儲存空間大小

複雜度 - 時間複雜度

基礎運算(宣告、賦值、運算...)皆為一單位時間

int a;
a = 5;
a = a + 3;

T(n) = 3

BUT !!     實際運算時不需要那麼詳細的數值

複雜度 - 時間複雜度

使用大O符號( O(1) 、O(n)、O(n²)... )表示時間複雜​度

  • 忽略低次項與常數項
  • 聚焦於最壞情況

忽略低次項

忽略常數項

O(n+1) → O(n)
O(20n²) → O(n²)

O(n²+n) → O(n²)
O(nlog(n)+n) → O(nlog(n))

 描述一個演算法在輸入 n 個東西時, 總執行時間與 n 的關係.

複雜度 - 時間複雜度

常用的空間複雜度與演算法

O(1):陣列讀取

O(n):簡易搜尋(一層迴圈)

O(log n):二分搜尋

O(nlogn):合併排序

O(n²):選擇排序(兩層迴圈)

O(2^n):費波那契數列

複雜度 - 空間複雜度

大部分的原始型別(數字、布林值...)都是固定的空間

 O(1)

 

字串

 O(n)     (n為字串長度)

 

物件型別的陣列物件

 O(n)     (n為陣列的長度或是物件的 key 數量)

 

複雜度 - 空間複雜度

int i;
int a[n];
int b[n][n]

S(n)=+n+8=O( )

C++ Review

By zsisc32

C++ Review

  • 67