iT邦幫忙

2023 iThome 鐵人賽

DAY 2
2

哇!撐過第一天了,繼續努力/images/emoticon/emoticon08.gif


終於進入主題了,先讓我們來認識陣列吧

我們以一個有趣的故事可以幫助我們更好地理解陣列的優點和缺點並搭配C++程式碼加以輔助:
 若是不想看故事的可以直接跳到重點整理。


第一段

在這所學校中,使用陣列來管理學生名單一直是一個簡單方便且無懈可擊的方式。
每位學生都被賦予一個座號和一個姓名,這些座號和姓名被用來創建一個學生名單陣列。
每當新學年開始,學校都能確切預測到會有八位新學生入學,我們可以輕鬆地分配座號給學生。

struct Student{
    int id;
    string name;
};
int MAX_STUDENT = 8; 
Student studentList[MAX_STUDENT];

分配一個空間容納8個學生
https://ithelp.ithome.com.tw/upload/images/20230917/20162567h6eGivW4SP.png


第二段

然而,今年的情況出現了一些意外。在新學年開始時,學校只有五位新生入學,這是一個少見的情況,但陣列仍然能夠輕鬆地容納這些新學生,並且每位學生都被正確地添加到名單中。

    studentList.addStudent({1, "A"});
    studentList.addStudent({2, "B"});
    studentList.addStudent({3, "C"});
    studentList.addStudent({4, "D"});
    studentList.addStudent({5, "E"});

將學生一一放入陣列
https://ithelp.ithome.com.tw/upload/images/20230917/20162567RDdew3DfOO.png


第三段

有一天,由於學生C的轉走了,這意味著學生名單陣列中的一個位置將被空出來。為了填補這個空缺,我們需要將所有後面的學生往前移動。

studentList.removeStudent({3, "C"});

刪除學生C的資料並移動後面資料
https://ithelp.ithome.com.tw/upload/images/20230917/20162567psZPSTCfZO.png


第四段

在學生A的強烈推薦下,許多新學生加入了這個大家庭,學校再次需要調整座號以容納他們。

首先是學生F 轉學來了,因為之前同學轉走,所以學校決定先補上空缺。

studentList.insertStudent(2, {3, "F"});

將學生F 插入到陣列2中
https://ithelp.ithome.com.tw/upload/images/20230917/20162567FPaPfF2EPN.png

G ,H, I,J 也陸續轉學來了。最初,調整陣列大小的操作進行得順利,但當新生人數突然增加到超過八位時,學校開始感受到了一些壓力。由於陣列的固定大小,他們不得不重新考慮是否應該尋找一更大的陣列,以應對日益增長的學生數量。

    studentList.addStudent({6, "G"});
    studentList.addStudent({7, "H"});
    studentList.addStudent({8, "I"});
    studentList.outputStudent(); 

G ,H, I 也新增到陣列中
https://ithelp.ithome.com.tw/upload/images/20230917/20162567lgW7T1LCpt.png

    // J 也轉學來了,但是班上已經沒有空位了
    studentList.addStudent({9, "J"});

    // 班上人數太多了,需要更大的陣列
    studentList.resize(10);
    studentList.addStudent({9, "J"});

新開一個陣列長度為10的陣列,並複製原本資料
https://ithelp.ithome.com.tw/upload/images/20230917/201625675TPWCS1oTX.png

再將學生J放進陣列中
https://ithelp.ithome.com.tw/upload/images/20230917/20162567oYEgmEQ63b.png


說明 :

第一段

  • 使用陣列來管理學生名單一直都是一個極其簡便而無懈可擊的方法。 陣列被視為一種高效且廣泛應用的資料結構,能夠在固定的時間內輕鬆進行資料存取操作。
  • 我們可以輕鬆地分配學號給學生,以便迅速定位他們。透過索引值,我們可以快速找到資料,並以極高效率進行讀取和修改。
  • 每當新學年開始,學校都能確切預測到會有8位新學生入學。這顯示了陣列的特性,它擁有固定的大小,並佔據一個連續的記憶體位置,讓我們能夠事先確定所需的記憶體大小。

第二段

  • 學校只有五位新生入學,因為陣列必須預先配置固定的記憶體空間,造成記憶體的浪費。

第三段

  • 學生C的轉走導致,將所有後面的學生往前移動。這涉及到資料的刪除操作,其中一個陣列元素被移除,然後需要調整其餘元素的位置,以保持資料的連續性。

第四段:

  • 學生F 轉學來了,學校決定先補上空缺。進行插入操作較為複雜。
  • 新生人數突然激增,超過原本預期的十位,因此需要換一個新的陣列

完整程式碼如下:

# include<iostream>
# include<string>
using namespace std;

// 每位學生擁有座號、姓名
struct Student{
    int id;
    string name;
};
class StudentList{
    private:
        int MAX_STUDENT = 8; // 最多8位學生
        Student *studentList; // 宣告一個陣列,用來存放學生資料
        int studentNum; // 目前有幾位學生
    public:
        StudentList(); // 建構子
        void addStudent(Student student); // 新增學生
        void outputStudent(); // 顯示學生資料
        void removeStudent(Student student); // 移除學生
        void insertStudent(int seatNumber, Student student); // 插入學生
        // 調整正列大小
        void resize(int newSize);

};

StudentList::StudentList(){
    studentNum = 0;
    studentList = new Student[MAX_STUDENT];
};

void StudentList::addStudent(Student student){
    if (studentNum >= MAX_STUDENT){
        cout << "data is full" << endl;
        return;
    }
    else{
        studentList[studentNum] = student;
        studentNum++;
    }
};

void StudentList::insertStudent(int seatNumber, Student student){
    if (studentNum >= MAX_STUDENT){
        cout << "data is full" << endl;
        return;
    }
    else{
        for(int i=studentNum; i>=seatNumber; i--){
            studentList[i] = studentList[i-1];
        }
        studentList[seatNumber] = student;
        studentNum++;
    }
};

void StudentList:: outputStudent(){
    cout << "students: " << endl;
    cout << "id" << " " << "seatNumber" << " " << "name" << endl;
    for(int i=0; i<studentNum; i++)
        cout << i << " "<<studentList[i].id << " " << studentList[i].name << endl;

};

void StudentList::removeStudent(Student student){ // 移除學生
    for(int i=0; i<studentNum; i++){
        if(studentList[i].id == student.id && studentList[i].name == student.name){
            for(int j=i; j<studentNum-1; j++){
                studentList[j] = studentList[j+1];
            }
            studentNum--;
            return;
        }
    }
    cout << "not found" << endl;
    
}

void StudentList::resize(int newSize){
    Student *newStudentList = new Student[newSize];
    for(int i=0; i<studentNum; i++){
        newStudentList[i] = studentList[i];
    }
    delete [] studentList;
    studentList = newStudentList;
    MAX_STUDENT = newSize;
}

int main(){
    StudentList studentList; // 宣告一個學生清單

    // 新學年開始,添加新學生
    studentList.addStudent({1, "A"});
    studentList.addStudent({2, "B"});
    studentList.addStudent({3, "C"});
    studentList.addStudent({4, "D"});
    studentList.addStudent({5, "E"});
    studentList.outputStudent(); // 顯示學生資料
    

    // student C 轉學了
    studentList.removeStudent({3, "C"});
    studentList.outputStudent(); // 顯示學生資料

    // // 學生A的強烈推薦下,許多新學生加入了這個大家庭
    // // F 轉學來了補上空缺
    studentList.insertStudent(2, {3, "F"});
    studentList.outputStudent(); // 顯示學生資料

    // G ,H, I 也轉學來了
    studentList.addStudent({6, "G"});
    studentList.addStudent({7, "H"});
    studentList.addStudent({8, "I"});
    studentList.outputStudent(); // 顯示學生資料

    // J 也轉學來了,但是班上已經沒有空位了
    studentList.addStudent({9, "J"});

    // 班上人數太多了,需要更大的陣列
    studentList.resize(10);
    studentList.addStudent({9, "J"});
    studentList.outputStudent(); // 顯示學生資料

}

重點整理

陣列:

  1. 可以通過索引值快速存取資料

  2. 具有固定大小,無法改變

  3. 無法存取不同型態的資料

  4. 數組在記憶體中是連續存儲的


因為是假日寫稿,所以舉了個小故事當例子,之後可能也沒這個機會了,但若大家喜歡,我會努力。
毫不猶豫地投入時間,敢於嘗試,積極冒險,別怕走冤枉路,因為每次嘗試都是成長的機遇。



上一篇
介紹
下一篇
資料結構 — 鏈結串列(Linked List)介紹
系列文
30天冒險之旅: 資料結構與演算法筆記挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
hlb
iT邦新手 5 級 ‧ 2023-11-02 23:25:44

int MAX_STUDENT = 8; // 最多10位學生

這邊好像有點混淆,到底要 8 還是 10

我要留言

立即登入留言