Modul 0 (Dynamic Array) - AlproITS/StrukturData GitHub Wiki
Array mungkin sudah tidak asing lagi, merupakan struktur data paling dasar yang sering digunakan untuk menyimpan data. Array bersifat statis, yang artinya ukurannya selalu tetap dan tidak dapat berubah (grow/shrink). Namun, array memungkinkan kita untuk mengakses elemennya dengan waktu yang konstan ๐(1).
Kita akan menggunakan โStatic Arrayโ untuk menyebutkan array statis (fixed-size array).
Sama seperti namanya, Dynamic Array memungkinkan kita untuk membuat array yang memiliki kemampuan untuk berubah ukuran (size) sesuai dengan banyaknya data yang dimasukkan dengan tetap mempertahankan karakteristik array, yakni pengaksesan elemen menggunakan indexing.
Dynamic Array biasanya diimplementasikan menggunakan Static Array dengan kapasitas awal tertentu.
Misalkan, kapasitas awalnya adalah 2 dan sudah diisi dengan dua elemen yakni 6 dan 5. Ketika hendak mengisi lagi elemen 3, dapat dilihat bahwa kapasitas array sudah penuh.
Jika kapasitas array sudah penuh, maka akan mengalokasikan array baru dengan ukuran 2 kali ukuran awal (pada umumnya faktor pertumbuhannya adalah 2x), kemudian menyalin data dari array lama ke array baru. Array barulah yang akan digunakan. Disini, array terbagi menjadi dua area:
- Logical Size adalah area array yang dapat diakses.
- Capacity adalah ukuran array yang sebenarnya. Area diluar logical size seharusnya tidak dapat diakses.
Catatan : Dynamic Array berbeda dengan array yang dialokasikan secara dinamis.
Berikut tabel perbandingan antara Static Array dengan Dynamic Array.
Static Array | Dynamic Array |
---|---|
Ukurannya tetap. | Ukuran dapat berubah sesuai dengan banyaknya data. |
Sangat efisien dalam segi waktu, tidak melibatkan realokasi memori. | Sedikit kurang efisien dalam segi waktu dibandingkan Static Array karena memerlukan alokasi-realokasi memori pada saat run-time. |
Bagus digunakan apabila ukuran data diketahui dan tetap. | Bagus digunakan apabila ukuran data tidak tetap. |
Sangat mungkin wasting memori | Kecil kemungkinan wasting memori apabila diimplementasikan dengan benar |
Secara umum, Dynamic Array mendukung operasi-operasi dasar seperti berikut.
- pushBack โ menambahkan data baru dari belakang. Operasi ini mempunyai mekanisme yang sudah dijelaskan pada ilustrasi.
- popBack โ menghapus data terakhir/paling belakang.
- back โ mendapatkan data terakhir/paling belakang.
- front โ mendapatkan data terdepan/data pertama.
- getAt(i) โ mendapatkan data pada indeks ke-i (dilakukan secara konstan O(1)).
- setAt(i, value) โ mengubah data pada indeks ke-i dengan nilai baru.
- isEmpty โ memeriksa apakah array kosong atau tidak.
Link Implementasi Lengkap DynamicArray
dapat dilihat disini
Implementasi Dynamic Array akan dibawa ke Abstract Data Type dengan nama yang sama, yakni DynamicArray
yang menyimpan tipe data int
. Kapasitas awal array adalah 2 dengan faktor pertumbuhan 2 kali lipat.
Berikut adalah kompleksitas waktu dari implementasi di bawah.
Operasi | Kompleksitas Waktu |
---|---|
isEmpty | O(1) |
pushBack | amortized O(1) |
popBack | O(1) |
back | O(1) |
front | O(1) |
setAt | O(1) |
getAt | O(1) |
-
Struktur ADT Dynamic Array berisi array (variabel
_arr
), kemudian informasi ukuran (_size
) dan kapasitas array (_capacity
).typedef struct dynamicarr_t { int *_arr; unsigned _size, _capacity; } DynamicArray;
-
Untuk memeriksa apakah Array kosong, cukup dengan memeriksa
_size
(ukurannya) apakah bernilai 0.bool dArray_isEmpty(DynamicArray *darray) { return (darray->_size == 0); }
-
Terdapat dua kasus pada saat melakukan pushBack, yakni.
Kasus 1: kapasitas array masih cukup
- Cukup dengan memasukkan data pada index selanjutnya.
Kasus 2: kapasitas array sudah penuh
- Jika kapasitas array sudah penuh, maka perlu dibuat array baru.
- Alokasikan array baru dengan ukuran dua kali dari kapasitas semula.
- Salin semua data pada array lama ke array baru.
- Referensikan array yang sekarang ke array baru.
- Hapus array yang lama.
- Masukkan data baru pada index selanjutnya.
void dArray_pushBack(DynamicArray *darray, int value) { if (darray->_size + 1 > darray->_capacity) { unsigned it; darray->_capacity *= 2; int *newArr = (int*) malloc(sizeof(int) * darray->_capacity); for (it=0; it < darray->_size; ++it) newArr[it] = darray->_arr[it]; int *oldArray = darray->_arr; darray->_arr = newArr; free(oldArray); } darray->_arr[darray->_size++] = value; }
-
Melakukan popBack cukup dengan menurunkan ukuran dari array, sehingga index yang diakses tidak akan melebihi size. Pastikan saat melakukan popBack, array tidak kosong.
void dArray_popBack(DynamicArray *darray) { if (!dArray_isEmpty(darray)) darray->_size--; else return; }
-
Untuk mendapatkan data paling belakang, sangat sederhana, yakni ambil nilai index size-1 pada array.
int dArray_back(DynamicArray *darray) { if (!dArray_isEmpty(darray)) return darray->_arr[darray->_size-1]; else return 0; }
-
Untuk mendapatkan data paling depan, cukup dengan mengambil data pada indeks 0 pada array.
int dArray_front(DynamicArray *darray) { if (!dArray_isEmpty(darray)) return darray->_arr[0]; else return 0; }
-
Operasi setAt dapat dilakukan dengan sangat mudah yakni cukup ubah nilai pada indeks yang diinginkan.
Selain itu, lakukanlah validasi apakah indeks yang diinputkan sesuai.
void dArray_setAt( DynamicArray *darray, unsigned index, int value) { if (!dArray_isEmpty(darray)) { if (index >= darray->_size) darray->_arr[darray->_size-1] = value; else darray->_arr[index] = value; } }
-
Operasi getAt dapat dilakukan dengan sangat mudah yakni cukup ubah menggunakan indeks yang diinginkan pada array.
Selain itu, lakukanlah validasi apakah indeks yang diinputkan sesuai dan array memang tidak kosong.
int dArray_getAt(DynamicArray *darray, unsigned index) { if (!dArray_isEmpty(darray)) { if (index >= darray->_size) return darray->_arr[darray->_size-1]; else return darray->_arr[index]; } }