LINKED LIST
5.1 STRUKTUR BERKAIT
Pada pembicaraan kita dalam Bab 1, telah disinggung sekilas tentang sejenis struktur yang dibentuk dengan cara mengaitkan struktur yang lebih sederhana. Perhatikan Gambar 5.1.
A 100
50
POINTER
B 50
Alamat memori
POINTER
83
Kali ini kita bahas secara sederhana bagaimana operasi penyisipan atau insertion dan operasi penghapusan atau deletion bekerja pada struktur berkait. Kita mulai dengan struktur singly linked-list atau singkatnya linked list. Linked-list, yang kerap kali disebut pula one-way List, adalah koleksi linear dari elemen data yang disebut simpul atau node. Cara melinearkan urutan, adalah dengan menggunakan penuding atau pointer. Dalam hal ini, setiap simpul terdiri atas dua bagian. Bagian pertama berisi informasi data tersebut, sedangkan bagian kedua merupakan field, link, atau nextpointer. Link inilah yang menghubungkan satu elemen data ke elemen data lainnya, sehingga urutan elemen data tersebut membentuk suatu linear list. Field link ini berisi alamat dari simpul berikutnya dalam list. Ia bernilai 0 bila link tersebut tidak menuding ke data (simpul) lainnya. Penuding ini disebut penuding nol. Gambar 5.2 merupakan diagram secara skematik dari sebuah linked list dengan 6 buah simpul. Setiap Simpul digambarkan sebagai dua kotak, Kotak kiri menyajikan bagian informasi (dapat berupa sebuah field NAMA, ataupun field NOMOR-POKOK, ataupun dapat pula berupa sebuah record). Kotak kanan menyajikan field nextpointer. Dari kotak kanan ini tergambar panah mengarah ke simpul berikut. Penuding nol adalah penuding ke simpul akhir dari list yang disajikan dengan tanda X.
84
para pasien tersebut diurut secara alfabetik. Untuk itu kita buat sebuah linked list, dengan penuding NEXT. Variable START kita gunakan untuk menyatakan lokasi pasien pertama dalam list. Jadi START berisi 5, karena pasien pertama tersebut, yakni Adam, menempati tempat tidur nomor 5. Selanjutnya penuding dari Adam bernilai 3, karena pasien kedua dalam list adalah Deni, menempati tempat tidur nomor 3, demikian seterusnya. Akhirnya, untuk pasien terakhir, Samuel, penudingnya merupakan penuding (dinyatakan dengan bilangan 0). nol
85
bagian akhir dari LIST, nextpointer bernilai NULL. Apabila tidak disebutkan, nilai NULL adalah 0, dan nilai dari subscript larik INFO serta LINK selalu diambil positif. Contoh linked list berikut memperlihatkan bahwa elemen tak perlu menempati posisi yang berdampingan pada larik INFO serta LINK. Juga lebih dari satu linked list dapat disimpan dalam kedua larik yang sama tersebut di atas. Contoh 5.2 Gambar 5.4 menggambarkan suatu linked list dalam memori. Data dalam larik INFO(K) adalah sebuah karakter tunggal. Dengan setiap kali kita mengubah nilai larik LINK(K) serta START, kita dapat membentuk linked list lain, yang kalau dibaca elemennya akan merupakan sebuah string atau untai. String yang dinyatakan oleh Gambar 5.4 tersebut adalah NO EXIT. START = 9, jadi INFO(9) = N adalah karakter pertama yang dikunjungi, LNK(9) = 3, jadi INFO(3) = O adalah karakter kedua, LNK(3) = 6, jadi INFO(6) = (blank) adalah karakter ketiga, LNK(6) = 4, jadi INFO(4) = E adalah karakter keempat, LNK(4) = 7, jadi INFO(7) = X adalah karakter kelima, LNK(7) = 1, jadi INFO(1) = I adalah karakter keenam, LNK(1) = 5, jadi INFO(5) = T adalah karakter ketujuh, LNK(5) = 0, null pointer, list berakhir.
START 9 1 2 3 4 5 6 7 8 9 INFO LINK
O E T
6 7 0 4
86
Contoh 5.3 Pada contoh ini diperlihatkan dua buah linked list, ALG dan GEOM, yang berturut-turut berisi nilai testing mata kuliah Algoritma dan Geometri, dapat tersimpan bersama dalam larik TEST dan LINK yang sama. Perhatikan bahwa nama dari list sekaligus digunakan sebagai variabel penuding. Di sini penuding ALG berisi nilai 11, yakni lokasi dari simpul pertama list ALG, sedangkan penuding GEOM berisi nilai 5, yakni lokasi simpul pertama dari list GEOM. Mengikuti penuding tersebut, dapat dilihat bahwa list ALG berisi nilai-nilai : 88 84 74 62 93 74 82 100 74
TEST ALG 11 1 2 3 4 5 6 GEOM 5 7 8 9 10 11 12 13 14 15 16 88 62 74 93 82 84 78 74 100 74
87
Contoh 5.4 Lihat Gambar 5.6. Pandang suatu agen penjualan yang mempunyai 4 orang broker (perantara). Setiap broker mempunyai list customer (pelanggan) masing-masing. Data dapat diorganisir seperti pada Gambar 5.6. Di sini keempat list pelanggan digabung dalam satu linked list dengan larik CUSTOMER berisi nama pelanggan dan larik LINK merupakan nextpointer. Nama broker ditempatkan dalam larik BROKER, dan digunakan pula variabel penuding dalam bentuk larik POINT, sedemikian sehingga POINT(K) menuding ke lokasi dari simpul pertama BROKER(K). Dapat kita lihat bahwa broker Bond mempunyai pelanggan berturut-turut Grant, Scott,Vito, Katz Di sana, Tall tidak mempunyai pelanggan, karena POINT(3)=0. Kita dapat berbicara secara lebih umum, yakni bahwa bagian informasi dari setiap simpul merupakan sebuah record, dengan lebih dari satu satuan data. Dalam kasus ini, kita harus menyimpan data tersebut dalam bentuk struktur record ataupun dalam bentuk koleksi larik sejajar. Perhatikan contoh berikut : Contoh 5.5 Lihat Gambar 5.8. Pandang berkas personalia dari sebuah perusahaan kecil, yang terdiri dari record 9 orang pegawai, dengan field NAMA, SSN (Social Security Number), SEX dan Gaji per bulan (monthly salary) Gambar tersebut memperlihatkan bagaimana berkas diorganisir sebagai linked list yang terurut (alfabetik), dengan menempatkan informasi dalam empat buah larik sejajar NAMA, SSN, SEX, dan SALARY, serta menggunakan pula larik LINK sebagai nextpointer, dan variabel START yang menuding record pertama. Di sana 0 digunakan sebagai penuding nol.
88
POINT 12 3 0 9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
COSTUMER Vito
LINK 4 16
Hunter Katz
14 0 20
Nelson 4
Evans
0 13
15 10 19 18
Grant
17 0
McBride Weston
6 0 5
Scott
1 2
Adams
8 7
akan menggerakkan penuding ke simpul berikutnya sebagai digambarkan dalam Gambar 5.8. Secara rinci, algoritma traversal kita adalah demikian: mula-mula, kita awali dengan memberi nilai kepada PTR, sama dengan START. Kita proses INFO(PTR), yakni informasi pada simpul pertama dalam list. Selanjutnya kita perbaharui PTR melalui statement PTR := LINK(PTR). Kita proses sekarang INFO(PTR), yakni informasi pada simpul kedua. Demikianlah selanjutnya kita perbaharui lagi PTR, melalui statemen PTR := LINK(PTR), Proses INFO(PTR), yakni informasi pada simpul ketiga, dan seterusnya sampai nilai PTR := NULL, pertanda berakhirnya traversal.
89
90
NAMA START 6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Harris Evans Cohen Rubin Brown Lewis Davis Kelly Green
SSN
SEX
SALARY
LINK 0
12 7 14 1
178-52-1065 181-58-9939
9 10 11
177-44-4557 135-46-6262
Male Male
19,000 15,500
2 0 13
168-56-8113
Female Male
34,200
4 5
208-56-1654
22,800
Proses yang dilakukan terhadap INFO(PTR) dapat dalam berbagai bentuk. Misalnya proses mencetak, ataupun yang lainnya lagi. Silakan Anda memodifikasi algoritma di atas untuk dapat mencetak semua informasi dalam list. Juga pikirkan bagaimana menghitung banyaknya elemen (simpul) dari list.
91
5.4.1
Untuk list yang tidak terurut, kita dapat melakukan proses cari dengan cara yang cukup sederhana. Cara tersebut adalah melakukan traversal simpul list, sambil setiap kali memeriksa apakah informasi dalam simpul yang tengah dikunjungi tersebut sama dengan ITEM. Jadi dalam algoritma ini, kita memerlukan 2 buah pemeriksaan pada setiap putaran. Yang pertama adalah memeriksa apakah kita telah sampai pada akhir dari list, yakni dengan memeriksa apakah PTR = NULL. Yang kedua adalah memeriksa apakah ITEM telah diketemukan lokasinya, yakni dengan memeriksa apakah INFO(PTR):=ITEM.
ALGORITMA
SEARCH(INFO, LINK, START, ITEM, LOC) 1 PTR := START 2 Kerjakan langkah 3 dalam hal PTR <> NULL 3 Jika INFO(PTR) = ITEM maka LOC := PTR exit kalau bukan PTR := LINK(PTR) 4 LOC := NULL (pencarian gagal) 5 Exit Kompleksitas waktu dari algoritma ini adalah sama seperti kompleksitas waktu dari algoritma cari linier terhadap larik. Di sini worst-case running time adalah sebanding dengan n, banyaknya elemen list. Sedangkan average-case mendekati n/2. Di sini dengan catatan, kondisi adalah ITEM muncul paling banyak satu kali, serta probabilitas kemunculan ITEM dalam setiap simpul adalah sama. Contoh 5.6 Pandang berkas personalia pada Gambar 5.7 yang lalu. Modul berikut ini akan mencari lokasi pegawai dengan SSN = NNN dan kemudian menaikkan gajinya sebesar 5 persen. 1 Baca NNN 2 Panggil Prosedur SEARCH(SSN,LINK,START,NNN,LOC) 3 Jika LOC <> NULL maka SALARY(LOC) = 1.05 * SALARY(LOC) kalau tidak Tulis NNN tidak ada dalam berkas
92
ALGORITMA
SEARCH(INFO,LINK,START,ITEM,LOC) 1 PTR := START 2 Kerjakan langkah 3 dalam hal PTR <> NULL 3 Jika INFO(PTR) < ITEM maka PTR := LINK(PTR) bila tidak Jika ITEM = INFO(PTR) maka LOC := PTR Exit kalau tidak LOCK := NULL Exit 4 LOC := NULL Kompleksitas waktu dari algoritma ini juga sama seperti kompleksitas waktu dari algoritma cari linear terhadap larik. Di sini worst-case running time adalah sebanding dengan n, banyaknya elemen list. Sedangkan average-case mendekati n/2. Dapat dicatat bahwa untuk larik terurut, kita dapat menggunakan cari binar (binary search), yang waktu pelaksanaannya sebanding dengan log2n. Namun algoritma cari binar ini tidak dapat digunakan terhadap linked list terurut, karena kita tidak mempunyai cara untuk mengindeks elemen tengah dari list. Sifat ini adalah salah satu kelemahan pemakaian linked list sebagai sebuah struktur data.
93
Contoh 5.7 Pandang sekali lagi, berkas personalia pada Gambar 5.7 yang lalu. Modul berikut ini akan mencari lokasi pegawai dengan NAMA = EMP dan kemudian menaikkan gajinya sebesar 5 persen. 1. Baca EMP 2. Panggil prosedur SEARCH(NAMA, LINK, START, EMP, LOC) 3. Jika LOC <> NULL Maka SALARY(LOC) := 1.05 * SALARY(LOC) kalau tidak Tulis EMP tidak ada dalam Berkas Di sini kita dapat menggunakan algoritma cari untuk list terurut, karena NAMA telah terurut alfabetik.
94
Contoh 5.8 Pandang daftar pasien pada contoh Gambar 5.3 yang lalu. Kali ini, daftar kita simpan dalam dua larik BED dan LINK. Di sini tempat tidur K dinyatakan sebagai BED(K). Maka ruang yang tersedia dalam larik BED tersebut dapat dikaitkan seperti pada Gambar 5.9. Perhatikan bahwa BED(10) merupakan tempat tidur pertama yang tersedia, BED(2) adalah tempat tidur berikutnya, dan BED(6) merupakan yang terakhir tersedia. Karenanya BED(6) mempunyai field nextpointer nol atau LINK(6) = 0.
BED NUMBER START 5 1 2 3 4 AVAIL 10 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 Fields Nelson Lane Green Samuels Dean Maxwell Adams
PATIENT Kirk
Next 7 6 11 12 3 0 4 1 0 2 8 9
Contoh 5.9 (a) Ruang tersedia dalam larik TEST, pada Gambar 5.5, dapat dikaitkan seperti terlihat pada Gambar 5.10. Perhatikan bahwa masing-masing list ALG dan GEOM boleh menggunakan list AVAIL. Dapat dicatat bahwa AVAIL = 9, maka TEST(9) adalah simpul bebas yang pertama dalam list AVAIL tersebut. Karena LINK(AVAIL) = LINK(9) = 10, maka TEST(10) adalah simpul bebas kedua dalam AVAIL. Demikian selanjutnya. b. Larik NAME dapat dikaitkan seperti pada Gambar 5.11. Perhatikan bahwa list ruang bebas dalam NAME mengandung elemen NAME(8), NAME(11), NAME(13),
95
NAME(5), dan NAME(1). Selanjutnya perhatikan nilai LINK yang secara bersama mendaftar ruang bebas untuk larik SSN, SEX dan SALARY.
LINK 16 14 1 0 12 0 8 13 10 3 2 7 6 4 0 15
96
NAMA START 6 1 2 3 4 5 6 7 8 9 10 11 8 AVAIL 12 13 14 Harris Evans Cohen Rubin Brown Lewis Davis Kelly Green
SSN
SEX
SALARY
LINK 0
12 7 14 1
178-52-1065 181-58-9939
9 10 11
177-44-4557 135-46-6262
Male Male
19,000 15,500
2 0 13
168-56-8113
Female Male
34,200
4 5
208-56-1654
22,800
KOLEKSI SAMPAH
Setelah penghapusan suatu simpul dari linked list, terdapat ruang memori yang bebas (tidak terpakai). Kita menginginkan ruang memori tersebut dapat digunakan lagi. Jelasnya kita menginginkan tersedianya ruang untuk kelak dapat kita pakai. Salah satu caranya adalah memasukkannya segera ke dalam list ruang-bebas. Hal inilah yang kita kerjakan kalau kita mengimplementasikan linked list melalui larik, bahkan meskipun metode ini sangat memakan banyak waktu dalam sistem operasi komputer. Untuk ini kita mungkin mengambil alternatif metode dengan sistem operasi dapat secara periodik mengumpulkan semua ruang akibat penghapusan simpul list tersebut ke dalam list ruang-bebas. Metode ini dikenal sebagai koleksi sampah atau garbage collection.
97
POINT 12 3 0 9 1 2 3 4 5
COSTUMER Vito
LINK 4 16
Hunter Katz
14 0 20
AVAIL 11
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Evans
0 13
15 10 19 18
Grant
17 0
McBride Weston
6 0 5
Scott
1 2
Adams
8 7
98
LINK 2 3 4 5 6 7 8 9 10 0
LIST(INFO,LINK,START,AVAIL)
Gambar 5.14 tidak dapat memperlihatkan bahwa simpul baru N memanfaatkan ruang memori dari list AVAIL. Untuk kemudahan dalam proses, simpul pertama dari list AVAIL dipakai untuk menyimpan simpul baru N tersebut. Diagram skematik yang lebih tepat, terlihat pada Gambar 5.15.
99
START
Node A
Node B
Node A
Node B
Node N
Perhatikan bahwa field penuding berubah sebagai berikut : 1. Field nextpointer dari simpul A, sekarang menuding ke simpul baru N, ter-hadap mana, sebelumnya AVAIL menuding. 2. AVAIL sekarang menuding ke simpul kedua pada ruang bebas, terhadap mana, sebelumnya simpul N menuding. 3. Field nextpointer dari simpul N, sekarang menuding ke simpul B, yang tadinya dituding oleh simpul A. Di sini juga terdapat 2 kasus khusus, yakni jika simpul baru N adalah simpul pertama dalam list, maka START akan menuding ke N, dan jika simpul baru N adalah simpul terakhir dalam list, maka N akan berisi penuding nol. Contoh 5.11 a. Pandang Gambar 5.9, yakni daftar alfabetik pasien. Misalkan seorang pasien baru Hughes masuk. Perhatikan bahwa : (1) Hughes ditempatkan di ranjang 10, yakni ranjang pertama yang kosong (tersedia). (2) Hughes akan disisipkan dalam list, antara Green dan Kirk.
100
Terjadi 3 perubahan dalam field penuding, sebagai berikut : LINK(8) LINK(10) AVAIL
START
= 10 (Sekarang Green menuding Hughes) = 1 (Sekarang Hughes menuding Kirk) = 2 (Sekarang AVAIL menuding ranjang kosong kedua)
AVAIL
Node A
Node B
x
Node N
b. Pandang Gambar 5.12, daftar broker dan pelanggannya. Karena list pelanggan tidak terurut, asumsikan bahwa setiap pelanggan baru ditambahkan pada awal list. Misalkan Gordan adalah pelanggan baru dari Kelly. Perhatikan bahwa : (1) Gordan dimasukkan sebagai CUSTOMER(11), yakni simpul tersedia pertama (2) Gordan disisipkan di muka Hunter, yang tadinya adalah pelanggan pertama dari Kelly. Di sini terjadi 3 perubahan dalam field penuding, yakni sebagai berikut : POINT(2) = 11 (Sekarang list mulai dengan Gordan) POINT(11) = 3 (Gordan menuding Hunter) AVAIL c. = 18 (Sekarang AVAIL menuding ke simpul tersedia yang berikutnya).
Pandang bahwa elemen data A, B, C, D, E, dan F akan dimasukkan berturut-turut ke dalam list hampa Gambar 5.13. Sekali lagi kita asumsikan bahwa data disisipkan pada bagian awal list. Berdasarkan ini, sesudah 6 kali penyisipan, F menuding ke E; E menuding ke D, D menuding ke C, C menuding ke B, B menuding ke A. A berisi penuding nol. Di sini AVAIL = 7, yakni simpul pertama yang tersedia sesudah 6 penyisipan di atas, dan START = 6 yang menunjukkan lokasi simpul
101
pertama F. Gambar 5.16 menunjukkan list, setelah 6 penyisipan tersebut (untuk n = 10)
INFO 1 START 6 2 3 4 5 AVAIL 7 6 7 8 9 10 LINK 0 1 2 3 4 5 8 9 10 0
A B C D E F
LIST(INFO,LINK,START,AVAIL)
dan variabel ITEM menyatakan informasi baru yang akan ditambahkan ke dalam list. Karena semua algoritma penyisipan kita tersebut membutuhkan simpul dari list AVAIL, maka mereka selalu mengandung langkah : 1. Memeriksa ruang bebas dari list AVAIL, kalau ternyata tidak ada lagi, yakni dalam hal ini AVAIL = NULL, algoritma mengirim pesan overflow. 2. Pemindahan simpul pertama dari list AVAIL. Menggunakan variabel NEW kita dapat mengimplementasikan pemindahan ini melalui sepasang statement.
102
NEW AVAIL
:= AVAIL := LINK(AVAIL)
3. Menyalin informasi baru tersebut ke dalam simpul baru, atau dengan perkataan lain, kita memakai statement INFO(NEW) := ITEM Diagram skematik kedua langkah terakhir di atas terlihat pada Gambar 5.17.
NEW
AVAIL
ALGORITMA : INSFIRST(INFO,LINK,START,AVAIL,ITEM)
[Algoritma ini menyisipkan ITEM sebagai simpul pertama dari list.] 1. (Apakah overflow?) Jika AVAIL = NULL maka tulis OVERFLOW dan exit 2. (Memindahkan simpul pertama dari list AVAIL)
103
NEW := AVAIL dan AVAIL := LINK[AVAIL] 3. INFO[NEW] := ITEM (menyalin data baru ke dalam simpul baru) 4. LINK[NEW] := START (Simpul baru sekarang menuding ke simpul awal semula) 5. START := NEW (Mengubah START agar menuding ke simpul yang baru) 6. Exit. Langkah 1 sampai 3 telah dibahas sebelum ini, dan diagram skematik langkah 2 dan 3 terlihat pada Gambar 5.17. Sedangkan diagram skematik langkah 4 dan 5 dapat dilihat pada Gambar 5.18.
START
NEW
ITEM
Contoh 5.12 Pandang list pada Gambar 5.10. Misalkan angka 75 akan disisipkan pada awal dari list geometri. Kita akan memakai algoritma di atas. Perhatikan bahwa ITEM = 75, INFO = TEST, dan START = GEOM.
INSFIRST(INFO,LINK,START,AVAIL,ITEM)
1. Karena AVAIL <> NULL, kita pergi ke langkah 2 2. NEW = 9, maka AVAIL := LINK[9) = 10 3. TEST[9] = 75
104
Gambar 5.19 memperlihatkan keadaan setelah 75 dimasukkan ke dalam list geometri. Perhatikan bahwa hanya 3 penuding yang berubah, yakni AVAIL, GEM, dan LINK[9].
TEST ALG 11 1 2 3 4 5 6 GEOM 9 7 8 9 10 11 12 AVAIL 10 13 14 15 16 88 62 74 93 82 84 78 74 100 75 74 LINK 16 14 1 0 12 0 8 13 5 3 2 7 6 4 0 15
105
LINK[NEW] := LINK[LOC]
dan kita jadikan simpul A menuding ke simpul baru N, dengan menggunakan statement:
3. AVAIL-ITEM. [menyalin data baru ke dalam simpul baru] 4. Jika LOC = NULL, maka [sisipkan sebagai simpul pertama] LINK(NEW) := START dan START := NEW. dalam hal lain : [sisipkan sesudah simpul dengan lokasi LOC] LINK[NEW] := LINK[LOC] dan LINK[LOC] := NEW [Akhir dari struktur jika] 5. Exit
106
Berikut ini prosedur untuk mencari lokasi dari simpul A, yakni mencari lokasi dari simpul terakhir dari LIST yang nilainya kurang dari ITEM. Kita lakukan traversal list, pergunakan variabel penuding PTR, dan bandingkan ITEM dengan INFO (PTR) pada masing-masing simpul selama traversal. Kita jaga jejak lokasi simpul sebelumnya, dengan menggunakan variabel penuding SAVE, seperti digambarkan pada Gambar 5.20. Maka SAVE dan PTR terupdate dengan statement :
107
6. SAVE := PTR dan PTR := LINK[PTR] [mengupdate penuding] [Akhir dari loop langkah 4] 7. LOC := SAVE 8. Return. Sekarang kita mempunyai algoritma untuk menyisipkan ITEM ke dalam linked list terurut LIST, dengan memanfaatkan 2 prosedur terakhir.
Contoh 5.13 Perhatikan list yang terurut secara alfabetik dari para pasien pada Gambar 5.9 yang lalu. Pandang bahwa Jones akan disisipkan ke dalam list tersebut. Kita akan menggunakan algoritma INSSRT di atas, yang pada hakikatnya melaksanakan prosedur FINDA, dan kemudian algoritma INSLOC. Perhatikan bahwa ITEM = Jones dan INFO = BED. a. FINDA(BED,LINK, START,ITEM,LOC) 1. 2. 3. 4. Karena START <> NULL, maka kita melangkah ke langkah 2 Karena BED[5] = Adams < Jones, kendali beralih ke langkah 3 SAVE = 5 dan PTR LINK[5] = 3 Langkah 5 dan 6 diulang, sebagai berikut : a. BED[3] = Dean < Jones, maka SAVE = 3, dan PTR LINK[3] = 11 b. BED[11] = Fields < Jones, maka SAVE = 11, dan PTR = LINK[11] = 8 c. BED[8] = Green < Jones, maka SAVE = 8, dan PTR = LINK[8] = 1 d. BED[1] = Kirk > Jones, maka LOC = SAVE =8, dan Return
108
b. INSLOC(BED,LINK,START,AVAIL,LOC,ITEM) 1. 2. 3. 4. Karena AVAIL <> NULL, maka kita melangkah ke langkah 2 NEW = 10, dan AVAIL = LINK[10] = 2 BED[10] = Jones Karena LOC <> NULL, maka LINK[10] = LINK(8] =1, dan LINK[8]= NEW = 10 5. Exit Gambar 5.21 menunjukkan struktur data kita sesudah Jones disisipkan ke dalam list. Di sini hanya 3 penuding yang berubah, yakni AVAIL, LINK[10], dan LINK[8].
PENYALINAN
Pandang bahwa kita ingin menyalin seluruh bagian dari list, atau akan membentuk sebuah list baru, yang diperoleh dari penyambungan 2 list yang diketahui. Kita dapat melakukannya dengan mendefinisikan sebuah list hampa, dan menambahkan elemen list yang diketahui tersebut, satu persatu menggunakan berbagai macam algoritma penyisipan kita yang lalu. List hampa didefinisikan dengan cara sederhana, yakni dengan mengambil sebuah nama variabel, atau penuding untuk list, seperti misalnya NAME, dan kemudian memasang NAME := NULL.
BED START 5 1 2 3 4 5 6 AVAIL 2 7 8 9 10 11 12 Lane Green Samuels Jones Fields Nelson Dean Maxwell Adams Kirk LINK 7 6 11 12 3 0 4 10 0 1 8 9
109
LIST(INFO,LINK,START,AVAIL)
Gambar 5.22 tidak memperlihatkan fakta bahwa bila kita melakukan penghapusan simpul N, kita akan segera memulangkan ruang memori kepada list AVAIL. Diagram skematik yang lebih tepat terlihat pada Gambar 5.23. Perhatikan bahwa 3 field penuding berubah, yakni : 1. Nextpointer dari Simpul A sekarang menuding ke B, yang tadinya dituding oleh N. 2. Nextpointer dari Simpul N sekarang menuding ke simpul pertama dari ruang bebas (free pool), yang tadinya dituding oleh AVAIL. 3. AVAIL sekarang menuding ke simpul N Di sana juga terdapat 2 kasus istimewa. Yang pertama adalah penghapusan simpul N sebagai simpul pertama dalam list. Dalam hal ini, START akan menuding ke simpul B. Dalam kasus kedua, yakni penghapusan simpul N sebagai simpul terakhir dari list, simpul A akan berisi penuding NULL. Contoh 5.14 a. Perhatikan list pasien pada Gambar 5-21. Misalkan pasien Green sudah diper-bolehkan pulang, maka BED[8] sekarang menjadi kosong Agar linked list kita tersebut tetap terjaga, maka perlu dilakukan perubahan terhadap beberapa field penuding, yakni sebagai berikut : LINK[11] = 10 LINK[8] = 2 AVAIL = 8
110
START
Node A
Node N
Node B
Node A
Node N
Node B
Dengan perubahan pertama, Fields yang tadinya mendahului Green, sekarang menuding ke Jones, yang tadinya mengikuti Green. Perubahan kedua dan ketiga akan menambah jumlah ranjang kosong baru pada list AVAIL. Kita tekankan bahwa sebelum membuat penghapusan, kita harus mencari simpul BED[11], yang tadinya menuding ke simpul yang dihapus, BED[8].
START
Node A
Node N
Node B
x
AVAIL
111
b. Perhatikan Gambar 5.12, list para broker dan pelanggannya. Pandang Teller, pelanggan pertama dari Nelson, akan dihapus dari list. Untuk itu dilakukan perubahan: POINT[4] = 10 LINK[9] = 11 AVAIL = 9
Dengan perubahan pertama, Nelson sekarang menuding ke Jones, yang tadinya adalah pelanggan kedua. Perubahan kedua dan ketiga akan menambah simpul baru pada list AVAIL. c. Misalkan elemen data B dan C akan dihapus satu persatu dari list Gambar 5.16. List yang baru, digambarkan pada Gambar 5.24. Perhatikan bahwa sekarang ketiga simpul pertama yang tersedia adalah : INFO[3], yang tadinya berisi C INFO[2], yang tadinya berisi B INFO[5], yang tadinya berisi E
INFO 1 START 6 2 3 4 5 AVAIL 3 6 7 8 9 10 LINK 0 5 2
D F
1 7 4 8 9 10 0
112
LIST(INFO,LINK,START,AVAIL).
Semua algoritma penghapusan kita, selalu mengembalikan ruang memori dari simpul yang dihapus, kepada bagian awal dari list AVAIL. Karenanya, semua algoritma kita mengandung pasangan statement berikut ini : LINK[LOC] := AVAIL AVAIL := LOC
Di sini LOC adalah lokasi dari simpul N yang kita hapus. Kedua operasi di atas digambarkan pada Gambar 5.25.
LOC
Node N
113
START := LINK[START]
START
Node 1
Node 2
Node 3
LINK[LOCKP] := LINK[LOC]
114
START
LOCP
LOC
Node N
SIMPUL
YANG
DIKETAHUI
Procedure : FINDB(INFO,LINK,STARTJTEM,LOC,LOCP)
[Prosedur ini dimaksudkan untuk mencari lokasi LOC dari simpul N pertama yang mengandung ITEM dan lokasi LOCP dari simpul pendahulu N. Jika ITEM tidak terdapat pada list, maka prosedur akan menjadikan LOC NULL, dan jika ITEM muncul pada simpul pertama, maka LOCP = NULL. 1. [List hampa?] Jika START := NULL, maka: LOC := NULL, dan LOCP := NULL, dan return [Akhir dari struktur jika] 2. [ITEM, di dalam simpul pertama?] Jika INFO[START] := ITEM, maka : LOC := START dan LOCP := NULL, dan Return. 3. SAVE := START dan PTR := LINK[START] [Inisialisasi Penuding] 4. Ulangi langkah 5 dan 6 sementara PTR <> NULL 5. Jika INFO[PTR] = ITEM, maka LOC := PTR dan LOCP := SAVE, dan Return [Akhir dari struktur jika] 6. SAVE := PTR dan PTR := LINK[PTR] [Mengupdate penuding] [Akhir dari loop langkah 4] 7. LOC := NULL [cari tidak berhasil]
115
Contoh 5.15 Pandang list pasien pada Gambar 5.21. Misalkan pasien Green diperbolehkan pulang. Untuk menghapusnya dari list, kita laksanakan prosedur FINDB dan algoritma DELLOC di atas. Di sini ITEM Green, INFO = BED, START = 5, dan AVAIL = 2. (a). FINDB(BED,LINK,START,ITEM,LOC,LOCP) 1. Karena START <> NULL, kita lanjutkan ke langkah 2 2. Karena BED[5] = Adams <> Green, kita lanjutkan ke langkah 3
116
3. SAVE = 5 dan PTR = LINK[5] = 3 4. Langkah 5 dan 6 diulangi sebagai berikut : a. BED[3] = Dean <> Green, maka SAVE = 3, dan PTR LINK[3] =11 b. BED[11] = Fields <> Green, maka SAVE = 11, dan PTR = LINK[11] = 8 c. BED[8] = Green, maka kita peroleh LOCP = PTR = 8, dan LOCP = SAVE = 11, dan Return
BED START 5 1 2 3 4 5 6 7 8 9 10 AVAIL 8 11 12 Samuels Jones Fields Nelson Lane Dean Maxwell Adams Kirk LINK 7 6 11 12 3 0 4 2 0 1 10 9
117
Gambar 5.28 menunjukkan struktur data setelah Green dihapus dari list. Kita lihat bahwa hanya 3 penuding berubah, yakni LINK[11], LINK[8], dan AVAIL.
118
Meskipun data kita simpan dalam memori sebagai header list, namun list AVAIL tetap disimpan sebagai linked list biasa. Contoh 5.16 Perhatikan berkas Personalia pada Gambar 5.11. Data akan kita simpan sebagai header list seperti pada Gambar 5.30. Perhatikan bahwa sekarang LOC = 5 adalah lokasi dari record header. Karenanya, START = 5, dan karena Rubin adalah pegawai terakhir, maka LINK[10] = 5. Header dapat pula dipakai menyimpan informasi tentang isi berkas. Sebagai contoh, misalkan SSN[5] = 9 menunjukkan banyaknya pegawai, dan SALARY[5] = 191.600 menunjukkan total gaji yang dibayarkan kepada pegawai.
NAMA START 5 1 2 3 4 5 6 7 8 9 10 11 8 AVAIL 14 Harris 208-56-1654 12 13 Male 22,800 Evans 168-56-8113 Female 34,200 Cohen Rubin 177-44-4557 135-46-6262 Male Male 19,000 15,500 Brown Lewis Davis Kelly Green 192-38-7282 165-64-3351 175-56-2251 Male Female Male Male Male 22,800 19,000 27,200 SSN SEX SALARY LINK 0 12 7 14 6 9 10 11 2 5 13 4 1 3
009
178-52-1065 181-58-9939
191,600
14,700 16,400
119
120
Selanjutnya adalah prosedur untuk mencari lokasi LOC dari simpul N pertama yang mengandung ITEM dan lokasi LOCP dari simpul pendahulu N. Jika ITEM tidak terdapat pada list, maka prosedur akan menjadikan LOC = NULL, dan jika ITEM muncul pada simpul pertama, maka LOCP = NULL. Prosedur ini berfungsi sama seperti Prosedur FINDB(INFO,LINK,START,ITEM,LOC,LOCP) untuk linked list biasa, yang telah dibahas terdahulu.
121
Sebagai catatan, masih terdapat 2 lagi variasi dari linked list yang kadang-kadang muncul dalam literatur, yakni : 1. Linked list yang simpul terakhirnya menuding ke simpul awal. Linked list ini disebut Circular List. 2. Satu jenis lagi adalah linked list yang mempunyai simpul khusus (header) di bagian awal dan di bagian akhir list. Gambar 5.31 merupakan diagram skematik kedua list tersebut.
START
Gambar 5.31.
122
koefisien dan eksponen dari suku yang bersangkutan, dan simpul dikaitkan berdasar atas derajat menurun. Perhatikan bahwa variabel penuding POLY menuding ke simpul header, yang field eksponennya diberi nilai bilangan negatif, dalam hal ini adalah -1. Di sini penyajian larik dari list membutuhkan 3 larik linier, yang boleh kita sebut COEF, EXP dan LINK. Salah satu penyajian terdapat dalam Gambar 5.32b.
POLY Coefficient of term Exponent of term
0 -1
2 8
-5 7
-3 2
4 0
8
7
4 6 8 7 1 9
123
DATA LINK
FRONT
REAR
Operasi penghapusan dan penyisipan pada linked-stack sama seperti yang dilakukan pada stack biasa, yaitu pada TOP dari stack. Sedangkan operasi penyisipan dan penghapusan pada linked-queue juga sama seperti yang dilakukan pada queue bisa. Operasi penyisipan dilakukan pada REAR dan operasi penghapusan pada FRONT dari queue.
124
yang disebut dengan nodes, yang setiap nodenya dibagi atas tiga bagian utama, yaitu : (1) nilai data atau informasi (INFO), (2) penuding ke alamat node sebelumnya (BACK), dan (3) penuding ke alamat node berikutnya (FORW). Bila lokasi (alamat) suatu node dilambangkan dengan LOC, maka berlaku FORW(LOCA) = LOCB jika dan hanya jika, BACK(LOCB) = LOCA, atau lokasi berikutnya dari node A adalah lokasi node B, jika dan hanya jika, lokasi sebelumnya dari node B adalah lokasi node A. Skema dari two way list dapat dilihat di Gambar 5.35. FIRST adalah penunjukkan node awal dan LAST adalah penandaan node terakhir. Skema pemetaan di memori dari two way list dapat dilihat di Gambar 5.36.
FIRST
INFO (nilai data dari node N) BACK (penunjuk ke node sebelumnya) FORW (penunjuk ke node berikutnya)
x x
LAST
Node N
Lisa N . C o nny N .
8 0 6
5 8
N u r L o la N u r L o li
5 1
0 4
LA ST
8
8 9
M a rd ia na
2 3
125
Node N
126
NAMA START 5 1 2 3 4 5 6 7 8 9 10 11 8 AVAIL 12 13 14 Harris Evans Cohen Rubin Brown Lewis Davis Kelly Green
SSN
SEX
SALARY
FORW
BACK
0 192-38-7282 165-64-3351 175-56-2251 Male Female Male Male Male 22,800 19,000 27,200 12 7 14 6 9 10 11 177-44-4557 135-46-6262 Male Male 19,000 15,500 2 5 13 168-56-8113 Female Male 34,200 4 1 208-56-1654 22,800 3 4 3 6 7 9 14 12 10 5 3
009
178-52-1065 181-58-9939
191,600
14,700 16,400
LOC
Node N
127
LOCA
LOCB
Node A
x
Node B
NEW
Node N
128
LATIHAN 5
1. 2. 3.
Jelaskan istilah pointer dan link dalam linked list. Bagaimana kunjungan (traversal) terhadap suatu link list ? Buatlah suatu skema linked-list yang menggambarkan 10 buah abjad terurut. Sajikan skema tersebut ke penyajian dalam memori. Lakukan penghapusan dua elemen dari soal nomor 3 di atas, yaitu elemen pertama dan elemen kelima. Lakukan penambahan elemen di urutan elemen pertama dan ketujuh dari soal nomor 4 di atas (jadi tidak urut). Ubah pointer-pointer linknya sehingga data di soal nomor 5 di atas menjadi terurut kembali. Apa yang dimaksud dengan koleksi sampah (garbage collection) di linked-list ? Apa yang dimaksud dengan header linked list dan apa saja jenisnya ? Jelaskan perbedaan cara kerja one way list dan two way list ?
4.
5.
6.
7. 8. 9.
10. Apa yang dimaksud dengan two way header list ? 11. Buat program dengan bahasa pemrograman apapun untuk membuat mesin linked list yang bisa dilakukan untuk menyisip dan menghapus elemen data.
129