STRUKTUR DATA

BAB 11 STRUKTUR DATA

Tabel di Lua bukan sebuah struktur data: Tetapi,kumpulan struktur data. Seluruh struktur data yang bahasa lain miliki seperti array, record, list, queues, sets digambarkan dalam tabel pada Lua. Lebih dari itu,Tabel mengimplementasikan seluruh struktur ini secara efisien.

Dalam bahasa tradisional,seperti C dan Pascal,kita mengimplementasi banyak struktur data dengan array dan lists(lists=record+pointer). Meskipun kita dapat mengimplementasi array dan lists menggunakan tabel Lua,tabel lebih baik dibanding array dan lists: Banyak algoritma disederhanakan menjadi nilai yang biasa menggunakan tabel. Sebagai contoh,kamu jarang menulis sebuah pencarian di Lua,karena tabel memberikan akses langsung untuk beberapa tipe.

Disini,kita akan belajar menggunakan tabel yang efisien. Disini,kita akan melihat bagaimana kamu dapat mengimplementasikan struktur data yang biasa dengan tabel dan akan memberikan beberapa contoh penggunaan. Kita akan mulai dengan array dan lists,bukan karena kita butuh mereka untuk struktur yang lain,tetapi karena banyak programmer sudah familiar dengan mereka. Kita juga sudah lihat bahan dasar pada bab ini,tentang bahasa tetapi saya akan ulangi lagi disini untuk kelengkapan.

11.1 Array

Kita mengimplementasikan array pada Lua dengan cara memberikan indeks pada tabel menggunakan integer. Oleh karena itu,array tidak memiliki ukuran yang tetap,tetapi tumbuh sesuai dengan yang kita butuhkan. Biasanya ketika kita menginisialisasi array kita definisikan ukuran secara tidak langsung. Sebagai contoh,lihat kode dibawah ini:

a = {} -- new array for i=1, 1000 do a[i] = 0 end

Mencoba mengakses field diluar jarak 1-1000 akan mengembalikan nil,sebagai ganti 0. Anda dapat memulai array apada index 0,1, atau nilai lain:

-- creates an array with indices from -5 to 5

a = {} for i=-5, 5 do a[i] = 0 end

Tetapi,biasanya untuk memulai array dengan indeks 1. Pustaka Lua berpegang pada konvensi ini. Jadi,jika array anda juga dimulai dengan 1 kamu akan dapat menggunakan fungsinya secara langsung.

Kita dapat menggunakan konstruktor untuk membuat dan menginisialisasi array dalam ekspresi tunggal:

squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}

Konstruktor bisa sama besar dengan yang kamu butuhkan.

11.2 Matriks dan Array Multi Dimensi

Disini ada jalur utama untuk menyatakan matriks dalam Lua. Cara yang pertama adalah array dalam array,maksudnya,sebuah tabel dimana setiap elemennya berada di tabel lain. Sebagai contoh,kamu dapat membuat sebuah matriks kosong dengan dimensi n x m seperti kode dibawah ini:

mt = {} -- create the matrix for i=1,N do

mt[i] = {} -- create a new row for j=1,M do

mt[i][j] = 0

end end

Karena tabel adalah objek pada Lua. Kamu buat setiap baris eksplisit untuk membuat sebuah matriks. Ketentuan ini lebih panjang dibandingkan pendeklarasian matriks,yang kamu lakukan di C atau Pascal. Tetapi ini lebih fleksibel,kamu dapat membuat matriks triangular dengan merubah baris:

for j=1,M do

Pada contoh sebelumnya menjadi

for j=1,i do

Dengan kode ini,matriks triangular hanya menggunakan setengah memori dari kode sebelumnya. Jalur kedua untuk membuat matriks di Lua dengan cara membuat 2 indeks menjadi satu. Jika 2 indeks adalah integer,kamu dapat mengalikan yang pertama dengan sebuah konstanta dan menambahkan indeks kedua. Dengan pendekatan ini,kode dibawah ini akan membuat matriks kosong dengan dimensi n x m:

mt = {} -- create the matrix for i=1,N do

for j=1,M do

mt[i*M + j] = 0

end end

Jika indeks adalah string,kamu dapat membuat penggabungan antara kedua indeks menjadi indeks tunggal dengan sebuah karakter diantaranya untuk pemisah. Sebagai contoh,kamu dapat mengindeks sebuah matriks m dengan indeks string s dan t dengan kode m[s..’:’..t],dilengkapi keduanya s dan t tidak mengandung ;. Jika kamu ragu,kamu dapat menggunakan karkater seperti ‘\0’ untuk memisahkan indeks.

Sering sekali aplikasi menggunakan sebuah matriks sparse,sebuah matriks dimana banyak sekali elemennya yang terdiri dari o & nil. Sebagai contoh,kamu dapat menggambarkan sebuah grafik dengan matriks adjasensi,yang mempunyai niali x di posisi m,n hanya ketika titik m dan n dikoneksi dengan biaya x; Jika titik tidak dikoneksi,nilai di posisi m,n adalah nil. Untuk menggambar sebuah grafik dengan 10000 titik,dimana setiap titik mempunyai 5 tetangga,kamu akan butuh sebuah matriks dengan 100000000 entry,tetapi kira-kira hanya 50000 dari mereka yang tidak nil. Banyak buku pada struktur data membicarakan bagaimana mengimplementasikan matriks sparse tanpa membuang memori sebanyak 400 MB,tetapi kamu tidak butuh teknik itu ketika Sering sekali aplikasi menggunakan sebuah matriks sparse,sebuah matriks dimana banyak sekali elemennya yang terdiri dari o & nil. Sebagai contoh,kamu dapat menggambarkan sebuah grafik dengan matriks adjasensi,yang mempunyai niali x di posisi m,n hanya ketika titik m dan n dikoneksi dengan biaya x; Jika titik tidak dikoneksi,nilai di posisi m,n adalah nil. Untuk menggambar sebuah grafik dengan 10000 titik,dimana setiap titik mempunyai 5 tetangga,kamu akan butuh sebuah matriks dengan 100000000 entry,tetapi kira-kira hanya 50000 dari mereka yang tidak nil. Banyak buku pada struktur data membicarakan bagaimana mengimplementasikan matriks sparse tanpa membuang memori sebanyak 400 MB,tetapi kamu tidak butuh teknik itu ketika

11.3 Senarai Berantai

Karena tabel adalah entity dinamis,tabel mudah untuk mengimplementasi senarai berantai pada Lua. Setiap titik digambarkan oleh sebuah tabel dan link adalah field tabel sederhana yang berisi hubungan ke tabel lain. Untuk contoh,mengimplementasikan sebuah list dasar dimana setiap titik punya 2 field,next dan value,kita butuh sebuah variabel untuk menjadi kepala list.

list = nil

Untuk memasukkan elemen pada awal list,dengan nilai v,kita buat:

list = {next = list, value = v}

Untuk mencari list kita tulis:

local l = list while l do

print(l.value) l = l.next

end

Untuk jenis list yang lain,seperti senarai berantai ganda atau list melingkar,juga mudah untuk diimplementasikan. Tetapi,kamu jarang membutuhkan struktur tersebut di Lua,karena biasanya ada jalur termudah untuk menggambarkan data kamu tanpa menggunakan list. Sebagai contoh,kita dapat menggambarkan sebuah stack dengan sebuah array,dengan field n dihubungkan ke atas.

11.4 Antrian dan Antrian Ganda

Meskipun kita dapat mengimplementasikan antrian biasa menggunakan insert dan remove,implementasi ini bisa menjadi lambat untuk struktur yang besar. Sebuah implementasi lebih efisien menggunakan 2 indeks,satu untuk yang pertama dan yang lain untuk elemen terakhir:

function ListNew () return {first = 0, last = -1} end

Untuk mengurangi penggunaan space yang besar,kita akan mendefiniskan seluruh daftar operasi dalam sebuah tabel,biasanya disebut List. Oleh karena itu,kita menuliskan contoh sebelumnya seperti ini:

List = {} function List.new ()

return {first = 0, last = -1} end

Sekarang kita dapat memasukkan atau mengeluarkan sebuah elemen pada akhir keduanya pada waktu yang tetap:

function List.pushleft (list, value) local first = list.first - 1 list.first = first list[first] = value

end

function List.pushright (list, value) local last = list.last + 1 list.last = last list[last] = value

end

function List.popleft (list) local first = list.first if first > list.last then error("list is empty") end local value = list[first] list[first] = nil -- to allow garbage collection list.first = first + 1 return value

end

function List.popright (list) local last = list.last if list.first > last then error("list is empty") end local value = list[last] list[last] = nil -- to allow garbage collection list.last = last - 1 return value

end

Jika kamu menggunakan struktur ini dalam sebuah antrian yang disiplinnya kuat,pemanggilan hanya pushright dan popleft,keduanya first dan last akan bertambah secara berkelanjutan. Tetapi,karena kita menggambarkan array di Lua menggunakan tabel,kamu dapat membuat indeks mereka dari 1 sampai 20 atau dari 16,777,216 sampai dengan 16,777,236. Dan lagi,karena Lua menggunakan presisi ganda untuk angka,program kamu dapat jalan untuk 200 tahun,mengerjakan 1 juta masukan per detik,sebelum masalah overflow datang.

11.5 Sets dan bags

Mungkin kamu ingin untuk mendaftar seluruh identifier yang digunakan dalam kode program. Bagaimanapun kamu butuh untuk menyaring sintaks pada kode yang kamu punya. Beberapa programmer C menggambarkan set sintaks sebagai array dari string dan kemudian mencari array untuk mengetahui apakah sebuah kata yang diberikan terdapat di set atau tidak. Untuk mempercepat pencarian,mereka dapat menggunakan pohon biner atau tabel hash untuk menggambarkan set.

Pada Lua,jalur yang sederhana dan efisien untuk menggambarkan set adalah meletakkan elemen set sebagai indeks dalam sebuah tabel. Kemudian,mencari elemen yang diberikan dalam tabel,kamu hanya membuat indeks tabel dan memeriks apakah hasilnya nil atau tidak. Sebagai contoh,kita dapat menulis kode dibawah ini: Pada Lua,jalur yang sederhana dan efisien untuk menggambarkan set adalah meletakkan elemen set sebagai indeks dalam sebuah tabel. Kemudian,mencari elemen yang diberikan dalam tabel,kamu hanya membuat indeks tabel dan memeriks apakah hasilnya nil atau tidak. Sebagai contoh,kita dapat menulis kode dibawah ini:

for w in allwords() do if reserved[w] then -- `w' is a reserved word ...

Anda dapat menginisialisasi menggunakan fungsi bantuan untuk membangun set.

function Set (list) local set = {} for _, l in ipairs(list) do set[l] = true end return set

end

reserved = Set{"while", "end", "function", "local", }

11.6 Buffer String

Mungkin anda ingin membuat sebuah string sedikit demi sedikit. Sebagai contoh membaca sebuah file baris per baris. Ketikkan kode dibawah ini:

-- WARNING: bad code ahead!! local buff = "" for line in io.lines() do buff = buff .. line .. "\n" end

Walaupun ini terlihat tidak mungkin,kode ini dapat menyebabkan keruskan untuk file yang besar. Sebagai contoh,ini akan mengambil waktu hampir 1 menit untuk membaca file berukuran 350 kb.

Mengapa ini terjadi? Lua menggunakan algoritma garbage collection: Ketika Lua mendeteksi sebuah program menggunakan memori yang terlalu banyak,Lua akan membuang struktur data dan membebaskan ruang memori dari struktur data hingga tidak bisa digunakan lagi. Biasanya algoritma ini mempunyai performa yang baik,tetapi apabila banyak terjadi loop ini akan merusak algoritma.

Untuk mengerti apa yang terjadi,kita asumsikan bahwa kita berada di pertengahan loop pembacaan: buff sudah terisi sebuah string dengan 5o kb dan setiap baris memiliki 20 bytes. Ketika Lua menggabungkan buff..line..”\n”,ini membuat sebuah string dengan 50,020 bytes dan menyalin

50 kb dari buff kedalam string baru untuk setiap baris baru,Lua membutuhkan 50 kb memori. Setelah membaca 100 baris baru,Lua sudah menggunakan memori lebih dari 5 MB. Akan lebih buruk lagi,setelah persetujuan:

buff = buff .. line .. "\n"

String yang lama sekarang dibuang. Setelah 2 kali perputaran. Ada 2 string lama yang totalnya lebih dari 100 kb tempat pembuangan. Jadi,Lua memutuskan,untuk membenarkannya. Ini adalah waktu yang baik untuk menjalankan garbage collector dan membuatnya menjadi bebas 100kb. Masalah yang akan terjadi setiap 2 perputaran,Lua akan menjalankan garbage collector 2000 kali sebelum membaca file. Dengan begini,memori yang digunakan kira-kira 3 kali ukuran file.

Masalah ini tidak aneh untuk Lua. Bahasa lain dengan garbage collection,dan string adalah objek yang berubah,ada yang mirip seperti itu,java adalah contoh yang paling terkenal. Sebelum kita lanjutkan,kita harus memberi tanda terlebih dahulu,situasi ini bukan masalah biasa. Untuk string ukuran kecil,loop ini bagus,untuk membaca sebuah file,kita gunakan “*all”,yang akan membaca 1 kali. Tetapi, terkadang ini bukan masalah sederhana. Hanya solusi yang memiliki algoritma yang lebih efisien yang kita lihat.

Perulangan yang asli mengambil pendekatan linier terhadap masalah,menggabungkan string kecil satu per satu kedalam akumulator. Algoritma yang baru menghindari ini,menggunakan pendekatan binary. Ini menggabungkan beberapa yang besar ke dalam yang besar lainnya. Inti dari algoritma ini adalah sebuah stack yang berisi string yang besar yang sudah dibuat dibawah,ketika string kecil masuk ke bagian kepala. Jenis stack ini mirip dengan model yang sudah terkenal yaitu menara Hanoi: sebuah string dalam stack tidak pernah dapat sebuah string yang lebih pendek. Jika sebuah string dimasukkan lebih dari satu,algoritma akan menggabung keduanya. Penggabungan membuat sebuah string yang besar,yang mungkin lebih besar dari tetangganya di lantai sebelumnya. Jika ini terjadi,mereka akan menggabungkannya juga. Penggabungan ini akan dilakukan menurun pada stack hingga string terbesar berada pada stack hingga string terbesar berada pada stack bawah:

function newStack () return {""} -- starts with an empty string end

function addString (stack, s) table.insert(stack, s) -- push 's' into the the stack for i=table.getn(stack)-1, 1, -1 do

if string.len(stack[i]) > string.len(stack[i+1]) then

break end stack[i] = stack[i] .. table.remove(stack)

end end

Untuk mendapatkan hasil akhir dari buffer kita hanya butuh menggabungkan seluruh string. Fungsi table.concat dapat melakukan penggabungan seluruh string yang ada di list.

Menggunakan struktur data yang baru,kita dapat menulis program dibawah ini:

local s = newStack() for line in io.lines() do

addString(s, line .. "\n")

end s = toString(s)

Program baru ini mengurangi waktu aslinya untuk membaca file 350 kb dari 40 detik menjadi 0.5 detik. Pemanggilan io.read(“*all”) masih lebih cepat penyelesaian pekerjaan dalam 0.02 detik.

Nyatanya, ketika kita memanggil io.read(“*all”),io.read menggunakan struktur data yang digambarkan,tetapi diimplementasikan dalam C. Beberapa fungsi lain pada pustaka Lua juga menggunakan implementasi C. Satu dari fungsi ini table.concat. Dengan concat,kita dapat dengan mudah mengoleksi seluruh string dalam seluruh tabel dan kemudian menggabungkan semuanya sekaligus. Karena concat menggunakan implementasi C,ini lebih efisien untuk string yang kuat.

Fungsi concat menerima sebuah pilihan argument kedua,dimana sebuah separator dimasukkan diantara string menggunakan pemisah,kita tidak perlu untuk memasukkan sebuah baris baru setelah setiap baris:

local t = {} for line in io.lines() do

table.insert(t, line) end s = table.concat(t, "\n") .. "\n"

Concat memasukkan pemisah antara string,tetapi bukan setelah yang terakhir. Jadi kita dapat menambah baris baru diakhir. Penggabungan terakhir menduplikat hasil string,yang dapat menjadi besar sekali. Disini tidak ada pilihan untuk membuat concat memasukkan pemisah tambahan,tetapi kita dapat memperdaya memasukkan string kosong tambahan pada t:

table.insert(t, "") s = table.concat(t, "\n")

Baris baru tambahan akan ditambahkan sebelum string kosong diakhir string yang kita inginkan.

Latihan

Ketikanlah kode program operasi-operasi matriks berikut. Jalankan program dengan memasukan elemen-elemen matrik. Cek apakah hasilnya sudah sesuai dengan mengerjakan secara manual

A={} B={} C={} D={} E={} F={} G={}

function menu() print("\n") print("\t \t ******************************") print("\t \t * M E N U *") print("\t \t ******************************") print("\t \t * 1. Input Matriks *") print("\t \t * 2. Penjumlahan Matriks *") print("\t \t * 3. Perkalian Matriks *") print("\t \t * 4. Invers Matriks *") print("\t \t * 5. Keluar *") print("\t \t ******************************") io.write("\t \t Pilihan : ") pil=io.read("*number")

if pil==1 then print("\n") print("\t *********************************************") print("\t * INPUT MATRIKS *") print("\t *********************************************") io.write("\t \t Orde Matriks A (2 atau 3) = ")

a=io.read("*number") a=io.read("*number")

io.write("\t \t Orde Matriks B (2 atau 3) = ") b=io.read("*number ") print("\n") print(inputB(B,b)) print(menu())

else if pil==2 then

if a==b then print("\n")

print("\t *********************************************") print("\t * HASIL PENJUMLAHAN MATRIKS *") print("\t *********************************************")

print(tambah(A,B,a)) else print("\n")

print("\t**********************************************************") print("\t Penjumlahan tidak dapat dilakukan karena orde tidak sama ")

print("\t**********************************************************") print("\n") end print(menu())

else if pil==3 then

if a==b then print("\n")

print("\t *********************************************") print("\t * HASIL PERKALIAN MATRIKS *") print("\t *********************************************")

print(kali(A,B,a,b)) else print("\n") print("\t********************************************************")

print("\t Perkalian tidak dapat dilakukan karena orde tidak sama ") print("\t********************************************************") print("\n")

end print(menu())

else if pil==4 then

print("\n")

print("\t *********************************************") print("\t * HASIL INVERS MATRIKS *") print("\t *********************************************") print("\t \t Invers Matriks A :") for i = 1,a do

E[i] = {}

for j = 1,a do

E[i][j] = A[i][j] end end print(inv(E,a))

print("\t \t Invers Matriks B :") for i = 1,b do

E[i] = {}

for j = 1,b do

E[i][j] = B[i][j] end end print(inv(E,b)) print(menu())

else if pil==5 then

print("\n") print("\t **********Keluar yuuk...!**********") print("\t ***********Terima Kasih...***********")

else print("\n") print("\t **********Pilihan cuma 4!**********") print("\t ***********Coba Pilih Lagi***********")

print("\n") print(menu())

end end end end end end

function inputA(A,a) print("\t \t Input Matriks A :") for i = 1,a do

A[i] = {} for j = 1,a do io.write("\t \t \t Baris [",i,"][",j,"] = ") A[i][j] = io.read("*number") end end print("\n")

print("\t \t Matriks A :") for i = 1,a do

io.write("\t \t \t ") for j = 1,a do

io.write(A[i][j] , "\t") end print("\v")

end end

function inputB(B,b) print("\t \t Input Matriks B :") for i = 1,b do

B[i]={} for j = 1,b do io.write("\t \t \t Baris [",i,"][",j,"] = ") B[i][j] = io.read("*number") end end print("\n")

print("\t \t Matriks B :") for i = 1,b do

io.write("\t \t \t ") for j = 1,b do

io.write(B[i][j] , "\t") end io.write(B[i][j] , "\t") end

function tambah(A,B,a) print("\t \t Matriks C = Matriks A + Matriks B ") print("\t \t -->") for i = 1,a do

C[i] = {} io.write("\t \t \t ") for j = 1,a do

C[i][j] = A[i][j] + B[i][j]

io.write(C[i][j] , "\t") end print("\v")

end end

function kali(A,B,a,b) print("\t \t Matriks D = Matriks A x Matriks B ") print("\t \t -->") for i = 1,b do

D[i]={} io.write("\t \t \t ") for j = 1,a do

D[i][j] = 0

for k = 1,a do

D[i][j] = D[i][j] + (A[i][k] * B[k][j]) end io.write(D[i][j] , "\t") end print("\v")

end

end

function inv(E,a) for i = 1,a do F[i]={} for j =1,a do if i==j then F[i][j]=1 else F[i][j]=0 end

end end if E[1][1]==0 then G[1]={} for j = 1,a do G[1][j]=E[2][j]

E[2][j]=E[1][j] E[1][j]=G[1][j] G[1][j]=F[2][j] F[2][j]=F[1][j] F[1][j]=G[1][j]

end end

for i = 1,a do

D = E[i][i] for j = 1,a do

E[i][j] = E[i][j] / D F[i][j] = F[i][j] / D

end for k = 1,a do if k~=i then M=E[k][i] for j = 1,a do

E[k][j]=E[k][j]-(E[i][j]*M) F[k][j]=F[k][j]-(F[i][j]*M) end end end end for i = 1,a do io.write("\t \t \t ") for j = 1,a do

io.write(F[i][j] , "\t") end print("\v")

end end

--MENU UTAMA print(menu())