Introduction to Data Structures
Author: Pakin Olanraktham
| Source | Resources |
|---|---|
| USACO.guide | Introduction to Data Structures |
โครงสร้างข้อมูล (Data Structure) คือ วิธีการจัดเก็บและจัดระเบียบข้อมูล ในหน่วยความจำของคอมพิวเตอร์ เพื่อให้สามารถเข้าถึง จัดการ หรือประมวลผลข้อมูลได้อย่างมีประสิทธิภาพและเหมาะสมกับงานที่ต้องการ
ในภาษา C++ เรามีสิ่งที่เรียกว่า STL หรือ Standard Template Library ซึ่งเป็น Built-in Library ให้เราสามารถใช้กันได้สะดวก โดยสิ่งที่เราต้องเขียนในโค้ดเพื่อที่จะใช้คือ
ไว้บรรทัดแรกของโปรแกรม
แล้วโค้ดบรรทัดนั้น ทำหน้าที่อะไร? โค้ดนั้น เปรียบเสมือนการ #include ทุก Library ที่จำเป็นมาให้ แปลว่า เราไม่ต้อง #include <iostream> อีกต่อไปแล้ว ให้ใช้ #include <bits/stdc++.h> เพียงอันเดียวเลย
แล้วถ้าหากเราต้องการใช้ Data Structure ใน STL ล่ะ เราสามารถประกาศได้ด้วยโครงสร้างนี้
ซึ่งโค้ดดังกล่าว เป็นการประกาศตัวแปรชื่อ v ซึ่งเป็นโครงสร้าง vector ที่เก็บ int
Static Array
ใน STL เรามี Array ให้ใช้ แต่ปกติไม่นิยมใช้กัน เราเลยจะมีกล่าวถึง Array ที่เราเคยเรียนมาแล้วเพิ่มเติม
โค้ดนี้ ประกาศ Array ของ int ยาว 1000 แต่เรารู้ว่าการประกาศ Array ภายในฟังก์ชัน เช่น main จะไม่ได้ทำให้แต่ละค่าเป็น 0
ใน STL เรามีฟังก์ชันให้ใช้ คือ memset() ซึ่งมีวิธีการใช้ดังนี้
ซึ่งจะทำให้ทุกค่าใน a เป็น 0 (ฟังก์ชันนี้ใช้ได้เฉพาะการ set ค่าให้เป็น 0 หากต้องการค่าอื่น สามารถทำได้ด้วยการ Loop ปกติ)
Dynamic Array (Vector)
Vector ในภาษา C++ ทำหน้าที่ได้เหมือน Array ทุกประการ เพียงแต่มีสิ่งที่เพิ่มมา คือความสามารถในการเพิ่มและลดขนาด เราสามารถ push หรือ pop ค่าเข้าไปใน vector ได้ ด้วยเวลา \(\mathcal{O}(1)\)
มีคำสั่งที่ควรรู้ เช่น
.push_back()เป็นการ push ค่าบางอย่าง เข้าไปที่ท้าย vector.pop_back()เป็นการนำค่าที่อยู่ด้านหลังสุดของ vector ออก แต่หาก vector ว่างอยู่ จะเกิด Error.empty()เป็นการคืนค่าว่า vector ว่างไหม ซึ่งหากว่างจะคืนค่า true (1) แต่จะคืนค่า false (0) หากมีสมาชิกอยู่.size()จะคืนค่าขนาดของ vector (จะไม่ได้คืนค่าเป็น int ควรเปลี่ยนเป็น int ก่อนโดย(int) (v.size())).back()จะคืนค่าสมาชิกตัวสุดท้ายของ vector แต่หาก vector ว่าง จะเกิด Error
vector <int> v;
for (int i = 0; i < 10; i++) v.push_back(i); // push ค่าตั้งแต่ 0 ถึง 9 เข้าไปใน vector
for (int i = 0; i < 10; i++) cout << v[i] << ' '; // จะส่งออก 0 1 2 3 4 5 6 7 8 9
cout << '\n' << v.size() << '\n'; // จะส่งออก 10
while (!v.empty()) { // เช็คว่า vector ว่างไหม
cout << v.back() << ' '; // ส่งออกตัวท้ายสุดของ vector
v.pop_back(); // นำค่าท้ายสุดออก
} // จะส่งออก 9 8 7 6 5 4 3 2 1 0
นอกจากนี้ เราสามารถประกาศ vector ด้วยขนาดหรือค่าที่ต้องการได้ โดย
vector <int> v(100); // จะประกาศ vector v ขนาด 100
vector <int> u(n); // จะประกาศ vector u ขนาด n
vector <int> x{1, 2, 3, 4, 5}; // ประกาศ vector ที่มีสมาชิกคือ 1 2 3 4 5
แล้วถ้าเกิดต้องการประกาศ vector หลายมิติล่ะ
เราสามารถนำ vector <int> ไปใส่ใน <> ของ vector อีกตัวได้ เนื่องจากภายใน <> จะเป็นตัวแปรหรือโครงสร้างข้อมูลชนิดใดก็ได้
vector <vector <int>> m; // ประกาศ 2D vector
vector <vector <int>> q(10, vector <int>(10)); // ประกาศ 2D vector ขนาด 10 x 10
Iterating
หนึ่งในวิธีการลูปไปใน Array คือ
ใน STL เราก็มีสิ่งที่คล้ายกับ pointer ด้วย เรียกว่า iterator ซึ่งจะเป็นการชี้ไปที่สมาชิกตัวหนึ่งในโครงสร้าง STL
เช่น v.begin() จะคืนค่าเป็น iterator ที่ตำแหน่งเริ่มต้นของ vector (index 0) ส่วน v.end() จะคืนค่าเป็น iterator ตำแหน่งที่มากกว่าตัวสุดท้ายของ vector อยู่ 1
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { // check ว่าเกินตัวสุดท้ายของ vector หรือยัง
// ...
}
แต่เราสามารถใช้ auto แทนการเขียน vector<int>::iterator ได้
for (auto it = v.begin(); it != v.end(); it++) { // check ว่าเกินตัวสุดท้ายของ vector หรือยัง
// ...
}
นอกจากนี้ เราสามารถลูปไปในทุกตัวของ vector ได้ โดย
โค้ดดังกล่าว จะลูปทุกค่าใน vector v โดยมีตัวแปรที่ชื่อ e เป็นตัวแทนของสมาชิกใน vector
สังเกตว่า หากเราใช้ auto &e : v เวลาเราเปลี่ยนแปลงค่าใดๆ ของ e ในลูป ค่านั้นใน vector จะเปลี่ยนด้วย แต่หากใช้ auto e : v การเปลี่ยนแปลงค่าของ e จะไม่ส่งผลใดๆ ต่อ vector เช่น
vector <int> x;
for (int i = 1; i <= 5; i++) x.push_back(i); // ให้ vector x มีสมาชิกคือ 1 2 3 4 5
for (auto e : x) e = 1;
for (int i = 0; i < 5; i++) cout << x[i] << ' '; // จะส่งออก 1 2 3 4 5
for (auto &e : x) e = 1;
cout << '\n';
for (int i = 0; i < 5; i++) cout << x[i] << ' '; // จะส่งออก 1 1 1 1 1
บทเรียนนี้ยังไม่สมบูรณ์
หากใครต้องการช่วยเหลือ สามารถส่ง Pull Request มาได้ทาง GitHub