基礎資料結構

Made by 12527 鄭竣陽

基礎資料結構

Make by 12527 鄭竣陽

大綱 Outline

本次課程將會介紹三種資料結構:

  • vector 向量
  • stack 堆疊
  • queue 隊列

Vector

動態陣列

  • 什麼是「陣列
  • 陣列的使用要點
  • 陣列相關內建函式
  • 陣列的缺點

Quick Review

Vector 是什麼?

Vector 是什麼?

\vec{g}

Vector 是什麼?

\vec{g}

Vector 是什麼?

\vec{g}
[\ \ \ ]
a\\b

Vector 是什麼?

\vec{g}
[\ \ \ ]
a\\b

如何在程式中使用 vector

#include <vector>
#include <iostream>

using namespace std;

int main() {
    vector<int> yourVector = {1, 2, 3};
    
    yourVector[2] = 4;
    
    for (int i = 0; i < 3; i++) {
        cout << yourVector[i] << ' ';
    }
}
# PRESENTING CODE

看起來和傳統陣列差不多?

#include <vector>
#include <iostream>

using namespace std;

int main() {
    vector<int> a{1, 2, 3};
    for (int i = 0; i < a.size(); i++) {
    	cout << a[i] << ' ';
    }
    cout << '\n';
    
    
    vector<char> c{'A', 'C'};
    
    for (int i = c.size() - 1; i >= 0; i--) {
    	cout << c[i] + 2 << ' ';
    }
    cout << '\n';
    
    
    
    vector<long long> zeros(100, 0);
    
    cout << zeros.size() << '\n';
    
    
    
    
}
# PRESENTING CODE

各種宣告和修改

#include <vector>
#include <iostream>

#define print(v) for (int &n: v) cout << n << " \n"[&n == &v.back()]
#define line(x) cout << #x << ":\n"

using namespace std;

int main() {
    line("Initialize with ()");
    vector<int> v1(5, 6);
    print(v1);
    
    line("Resize to a bigger size");
    v1.resize(7);
    print(v1);

    line("Resize to a smaller size");
    v1.resize(2);
    print(v1);
    
    line("Resize with default value");
    v1.resize(4, 3);
    print(v1);
    
    line("Add an element to the end");
    v1.push_back(2);
    print(v1);
    
    line("Add an element to the end(powerful, yet unsafe)");
    v1.emplace_back(2);
    print(v1);
    
    line("Remove the last element");
    v1.pop_back();
    print(v1);

    while (!v1.empty()) {
        v1.pop_back();
        print(v1);
    }
    
    v1.resize(10, 2);
    for (int i = 1; i < v1.size(); i++) {
        v1[i] *= v1[i - 1];
        print(v1);
    }
}
# PRESENTING CODE

內建排序

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int arr[30];
    vector<int> v;
    for (int i = 0; i < 30; i++) {
        int temp = rand() % 5 + 1;

        v.push_back(temp);
        arr[i] = temp;

        cout << temp << ' ';
    }
    cout << '\n';
    
    sort(arr, arr + 30);
    sort(v.begin(), v.end());

    for (int i = 0; i < 30; i++) {
        cout << arr[i] << ' ';
    }
    cout << '\n';
    for (int i = 0; i < 30; i++) {
        cout << v[i] << ' ';
    }
    cout << '\n';
    for (vector<int>::iterator it = v.begin(); it < v.end(); it++) {
        cout << *it << ' ';
    }
    cout << '\n';
}
# PRESENTING CODE

其他函式

v[index] = number;
v.at(index) = number;

v[0] = number;
v.front() = number;

v[v.size() - 1] = number;
v.back() = number;

v.insert(it, number);
v.insert(it, count, number);

v.erase(it);
v.erase(it_start, it_end);
# PRESENTING CODE
複雜度\ O(n)\ 非常不好
複雜度\ O(n)\ 非常不好

Stack

堆疊

堆疊是什麼

  • 像是一疊盤子
  • 最晚放上去的會最早拿起來
  • FILO & LIFO
  • 無法隨機存取

堆疊

Stack 語法

#include <iostream>
#include <stack>

using namespace std;

int main() {
    stack<int> myStack;
    
    for (int i = 0; i < 10; i++) {
    	myStack.push(rand() % 10);
    }
    
    cout << "size: " << myStack.size() << '\n';
    
    while (!myStack.empty()) {
    	cout << "top: " << myStack.top() << '\n';
        myStack.pop();
    }
}
# PRESENTING CODE

好像不太對?

仔細想想剛剛講了什麼

哈哈是我啦

  • 仔細想想剛剛講了什麼
  • stack 不能被隨機存取
  • 從後面放進去
  • 從後面拿出來
  • 這不就是 vector 的弱化版嗎

結論

  • stack 其實沒什麼用特別的用處
  • 有類似結構都可以用 vector 處理
  • 只比 vector 快一點點,真的超時可以試試看
  • 但是stack 可以讓人比較容易看懂你想幹嘛

Queue

隊列

什麼是隊列

  • 像是一個排隊隊伍
  • 最早進去的會最早出來
  • FIFO & LILO
  • 無法隨機存取

Queue

Queue 語法

#include <iostream>
#include <queue>

using namespace std;

int main() {
    queue<int> myQueue;
    
    for (int i = 0; i < 10; i++) {
    	myQueue.push(rand() % 10);
    }
    
    cout << "size: " << myQueue.size() << '\n';
    
    while (!myQueue.empty()) {
    	cout << "front: " << myQueue.top() << '\n';
        myQueue.pop();
    }
}
# PRESENTING CODE

Queue 的內部

有兩種作法:

  • 循環陣列
  • 指標

由於你們學過指標了,我們就來看看吧

利用指標實作佇列

#include <iostream>
#include <vector>

using namespace std;

struct NodeOfQueue {
    NodeOfQueue *next = nullptr;

    int value;

    NodeOfQueue(int valueToPutIn): value(valueToPutIn) {}
};

class MyIntQueue {
private:
    NodeOfQueue *firstElement;
    NodeOfQueue *lastElement;
    unsigned int sizeOfQueue = 0;

public:
    unsigned int size() {
        return sizeOfQueue;
    }

    bool empty() {
        return (sizeOfQueue == 0);
    }

    int front() {
        return firstElement->value;
    }

    void push(int valueToBePushed) {
        NodeOfQueue *newNode = new NodeOfQueue(valueToBePushed);
        sizeOfQueue++;

        if (this->size() == 1) {
            firstElement = lastElement = newNode;
            return;
        }

        lastElement->next = newNode;
        lastElement = newNode;
    }

    void pop() {
        if (this->sizeOfQueue == 0) {
            return;
        }

        sizeOfQueue--;
        if (this->sizeOfQueue == 0) {
            firstElement = lastElement = nullptr;
            return;
        }

        NodeOfQueue *newFirst = firstElement->next;
        delete firstElement;
        firstElement = newFirst;
    }
};


int main() {
    
}
# PRESENTING CODE
# Fuck This

打那麼多誰看得完

你剛剛是不是發現你被騙了

這根本不只有指標

物件

我剛剛是被騙來上物件導向課程了嗎?

物件可以幹嘛

  • 讓程式更好看懂
  • 讓程式更難看懂

排版的重要性

#include <iostream>

using namespace std;

int main() {
    int a, b;
    cin >> a >> b;

    int counter = 0;
    while (a != b) {
        ((a > b) ? a : b) >>= 1;
        ++counter;
    }
    cout << counter << '\n';
}

// vs

#include <iostream>

using namespace std;signed main(){int a,b,counter;cin>>a>>b;counter=0;while(a!=b){((a>b)?a:b)>>=1;++counter;}
   cout<<counte<<'\n';}
# PRESENTING CODE

如何排版?

可是內建的很醜欸

  • 全世界的工程師都是這樣排版的
  • 其實可以調設定
  • 重要的是好看懂

簡易物件 Struct

#include <iostream>
#include <vector>

using namespace std;

struct Person {
    Person *parent[2];
    vector<Person*> child;
    int age;
    string name;
    int eatenLoavesOfBread = 0;

    Person(int value, string nameOfPerson): age(value), name(nameOfPerson) {}
    
    void printInfo() {
    	cout << "Kono " << name << " da!\n";
        cout << "Age: " << age << '\n';
    }

    void eatBread(int amount) {
        eatenLoavesOfBread += amount;
    }
};

int main() {
    Person Vampire = Person(155, (string)"Dio");
    Vampire.parent[0] = new Person(420, (string)"LoliTerrorist");

    Person electricGod = *Vampire.parent[0];
    
    cout << (*Vampire.parent[0]).name << '\n';
    cout << Vampire.parent[0]->name << '\n';
    Vampire.printInfo();
    Vampire.parent[0]->printInfo();

    cout << electricGod.name << " has eaten " << electricGod.eatenLoavesOfBread << " loaves of bread\n";
    electricGod.eatBread(10);
    cout << electricGod.name << " has eaten " << electricGod.eatenLoavesOfBread << " loaves of bread\n";
}
# PRESENTING CODE

不簡易物件 Class

# PRESENTING CODE

其實只多了存取標籤

  • private
  • public
  • friend

回來看實作吧

#include <iostream>
#include <vector>

using namespace std;

struct Coords {
    int x, y;
};

struct NodeOfQueue {
    NodeOfQueue *next = nullptr;

    int value;

    NodeOfQueue(int valueToPutIn): value(valueToPutIn) {}
};

class MyIntQueue {
private:
    NodeOfQueue *firstElement;
    NodeOfQueue *lastElement;
    unsigned int sizeOfQueue = 0;

public:
    unsigned int size() {
        return sizeOfQueue;
    }

    bool empty() {
        return (sizeOfQueue == 0);
    }

    int& front() {
        return firstElement->value;
    }

    void push(int valueToBePushed) {
        NodeOfQueue *newNode = new NodeOfQueue(valueToBePushed);
        sizeOfQueue++;

        if (this->size() == 1) {
            firstElement = lastElement = newNode;
            return;
        }

        lastElement->next = newNode;
        lastElement = newNode;
    }

    void pop() {
        if (this->sizeOfQueue == 0) {
            return;
        }

        sizeOfQueue--;
        if (this->sizeOfQueue == 0) {
            firstElement = lastElement = nullptr;
            return;
        }

        NodeOfQueue *newFirst = firstElement->next;
        delete firstElement;
        firstElement = newFirst;
    }
};


int main() {
    MyIntQueue seatPriority;
    vector<bool> chosen(30, false);
    vector<Coords> seat(30);

    bool taken[5][6] = {0};

    for (int i = 0; i < 30; i++) {
        int current = rand() % 30;
        while (chosen[current]) {
            current = rand() % 30;
        }
        seatPriority.push(current);
    }

    while (!seatPriority.empty()) {
        cout << seatPriority.front() + 1 << " to choose!\n";
        int &now = seatPriority.front();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 6; j++) {
                cout << taken[i][j];
            }
            cout << '\n';
        }

        do {
            cin >> seat[now].x >> seat[now].y;
        } while (taken[--seat[now].x][--seat[now].y]);
        taken[seat[now].x][seat[now].y] = true;

        seatPriority.pop();
    }
}
# PRESENTING CODE

總結

剛剛到底上了什麼?

Vector

  • 加強版陣列
  • 能夠做原版的所有事

Stack

  • 弱化版 vector
  • 能夠輕易地理解

Queue

  • 排隊機
  • 處理需要照順序的問題

感謝聆聽

好耶

練習時間

現場講題目給同學練習三種資料結構的應用

報告結束

謝謝收看

基礎資料結構(vector, stack, queue)

By BrineTaiwan

基礎資料結構(vector, stack, queue)

第一次做資訊簡報 ><

  • 177