STL dan Data Struktur
Post kali ini akan membahasa beberapa data struktur sederhana: vector, stack, queue, dequeue, priority queue, map, dan set.
Vector
Motivasi
Diberikan matriks berisi angka, berukuran \(N \times M\). Tuliskan hasil rotasi matriks 90 derajat. Batasan: \(1 \leq N \times M \leq 10^5\)
Soal di atas sebenarnya sangat mudah, namun batasan yang ada membuat kita berpikir
dua kali. Karena matriks cukup besar, kita perlu mendeklarasikan matriks di luar
program main. Namun, deklarasi matriks secara global membutuhkan ukuran array
secara eksplisit. Tidak mungkin kita membuat int matriks[100000][100000]
karena kebutuhan RAM yang dibutuhkan akan sampai 40 GB.
Karena itu, kita gunakan vektor yang ukurannya dinamis, yakni vektor.
Penggunaan
Contoh penggunaan vector untuk membaca array dan menuliskan array secara terbalik:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, x;
vector<int> v;
cin >> n;
for (int i=0; i<n; i++) {
cin >> x;
v.push_back(x);
}
for (int i=v.size()-1; v>=0; v++) {
cout << v[i] << endl;
}
}
Stack
Stack pada dasarnya seperti array, namun kita hanya dapat mengakses nilai terakhir yang dimaukkan ke dalam stack.
Pengunaan
#include <bits/stdc++.h>
using namespace std;
int main() {
int q, x;
stack<int> s;
cin >> q;
for (int i=0; i<q; i++) {
cin >> x;
// memasukkan elemen ke dalam stack
s.push(x);
}
while (!s.empty()) {
// menuliskan elemen terakhir yang belum di pop
cout << s.top();
// menghapus elemen terakhir yang belum di pop
s.pop();
}
}
Queue
Motivasi
Terdapat sebuah antrian dan K buah query. Query bisa berupa add X
(orang bernama
X
masuk ke dalam antrian) atau process
(menuliskan nama orang yang berada di
antrian paling depan, lalu mengeluarkan orang tersebut dari antrian). Dijamin
dalam satu waktu, panjang antrian maksimum \(10^5\), \(K \leq 10^8\).
Kita dapat menyelesaikan masalah ini dengan array:
string nama[100000], s, x;
int head = -1, tail = 0;
for (int i=0; i<k; i++) {
cin >> s;
if (s == "add") {
cin >> x;
nama[tail] = x;
tail++;
} else {
cout << nama[head] << endl;
head++;
}
}
Namun, kita tidak tahu ukuran array nama. Worst case, kita butuh menyimpan array
sebesar K (ketika query berisi add
saja). Karena itu, kita gunakan queue.
Penggunaan
Berikut contoh penggunaan queue untuk soal tadi:
#include <bits/stdc++.h>
using namespace std;
int main() {
int k, x;
string s;
queue<int> q;
cin >> k;
for (int i=0; i<n; i++) {
cin >> s;
if (s == "add") {
cin >> x;
q.push(x);
} else {
cout << q.front() << endl;
q.pop();
}
}
}
Dequeue
Pada dasarnya seperti stack ditambah queue, kita dapat melakukan push
di depan
dan di belakang, dan pop
di depan dan di belakang.
Priority Queue
Motivasi
Diberikan Q buah query. Query bisa berupa add X
(memasukkan X
ke dalam
sebuah array) atau remove
(menghapus elemen terkecil dari array dan menuliskan
ke layar).
Kita dapat menyelesaikan program ini dengan array, namun kita perlu sorting
array tiap kali dilakukan operasi add
atau remove
. Dengan sort \(O(Q log Q)\),
maka kompleksitas solusi ini menjadi \(O(Q^2 log Q)\).
Di sini lah kita membutuhkan priority queue. Data struktur priority queue seperti
queue, namun queue selalu terurut tidak menururn. Akses pq dapat dilakukan dengan
.push(x)
untuk memasukkan x, .top()
untuk melihat nilai paling besar, dan .pop()
untuk menghapus elemen paling besar.
Penggunaan
Contoh penggunaan untuk soal di atas:
#include <bits/stdc++h>
using namespace std;
int main() {
int q, x;
string s;
priority_queue<int> pq;
cin >> q;
for (int i=0; i<q; i++) {
cin >> s;
if (s == "add") {
cin >> x;
pq.push(x);
} else {
cout << pq.top() << endl;
pq.pop();
}
}
}
Perhatikan kalau jawaban di atas belum menyelesaikan soal pertama. Pada soal, diminta nilai minimum dari array, sedangkan pq selalu terurut dari nilai maksimum. Ada 2 cara untuk menyelesaikan ini:
- Sebelum di
push
, nilai dikali-1
terlebih dahulu, dan saat ditop
, nilai dikali-1
sebelum di proses. Prio-queue akan selalu berisi negatif dan nilai maksimum di pq adalah nilai minimum dari input. - Deklarasikan pq dengan
priority_queue<int, vector<int>, greater<int> >
pq akan otomatis terurut tidak menurun.
Map
Map pada dasarnya seperti array, tapi indeksnya bisa integer (hingga 2 milyar), string, dan lain-lain.
Penggunaan
#include <bits/stdc++.h>
using namespace std;
int main() {
map<string, string> m;
m["A"] = "B";
m["C"] = "D";
m["A"] = "F";
cout << m["A"]; // "F"
}
Set
Set adalah struktur data yang selalu menyimpan data-datanya tanpa duplikat terurut berdasarkan suatu comparator. set memiliki operasi-operasi yang penting, yaitu :
- Insert : menambah data ke set jika data belum ada di set
- Delete : menghapus data dari set
- Find : mencari data di set jika ada
Penggunaan
#include <bits/stdc++.h>
using namespace std;
int main() {
set<int> s;
s.insert(9);
s.insert(5);
s.insert(2);
s.insert(5);
s.insert(10);
for(int x : s){
cout<<x<<" ";
}
cout<<endl;
// 2 5 9 10
}