Koleksi
8.1 Pengantar
.NET Framework
menyediakan tiga namespace yang
didedikasikan untuk koleksi. Namespace
System.Collections memuat
koleksi-koleksi yang menyimpan referensi-referensi ke object-object. Anda
perlu mencantumkan namespace ini
karena ia kaya akan akan kode yang dipakai pada industri perangkat lunak dewasa
ini. Hampir semua aplikasi mutakhir menggunakan koleksi pada namespace System.Collections.Generic, yang memuat kelas-kelas generik seperti
List<T> dan Dictionary<K,V>.
Namespace System.Collections.Specialized
memuat beberapa koleksi yang mendukung tipe-tipe spesifik, seperti string dan bit. Anda dapat belajar
tentang namespace ini di halaman
msdn.microsoft.com/en-us/library/system.collections.specialized.aspx.
Koleksi-koleksi pada namespace ini menyediakan komponen-komponen yang dapat didaur-ulang
terstandarisasi, sehingga Anda tidak perlu menuliskan kelas-kelas koleksi
sendiri.
8.2
Sekilas Tentang Koleksi
Semua kelas koleksi pada .NET Framework mengimplementasikan beberapa
kombinasi dari antarmuka-antarmuka koleksi. Setiap antarmuka ini
mendeklarasikan operasi-operasi yang dilakukan secara generik pada pelbagai
tipe koleksi. Gambar 8.1 mencantumkan beberapa antarmuka pada koleksi .NET Framework. Semua antarmuka pada Gambar
8.1 dideklarasikan pada namespace System.Collections dan memiliki ekivalensi
generik pada namespace System.Collections.Generic.
Implementasi dari tiap antarmukan ini disediakan pada .NET Framework. Programer juga bisa menyediakan implementasi spesifik
untuk memenuhi kebutuhannya.
Antarmuka
|
Penjelasan
|
ICollection
|
Antarmuka yang diwarisi oleh
antarmuka IList dan IDictionary. Memuat sebuah properti Count untuk menentukan ukuran koleksi
dan sebuah metode CopyTo untuk
menyalin isi sebuah koleksi ke array tradisional.
|
IList
|
Sebuah koleksi terurut yang dapat
dimanipulasi seperti array. Menyediakan sebuah indekser untuk mengakses
elemen-elemen dengan indeks int. Juga memiliki metode-metode untuk melakukan
pencarian dan pemodifikasian sebuah koleksi, termasuk Add, Remove, Contains, dan IndexOf.
|
IDictionary
|
Sebuah koleksi yang memuat
nilai-nilai, yang diindeks oleh objek “key”.
Menyediakan sebuah indekser untuk mengakses elemen-elemen dengan sebuah
indeks objek dan metode-metode untuk memodifikasi koleksi (misalnya, Add, Remove). Properti Keys
pada antarmuka ini memuat objek-objek yang dipakai sebagai indeks, dan
properti Values memuat semua objek
yang disimpan.
|
IEnumerable
|
Sebuah objek yang dapat dienumerasi.
Antarmuka ini hanya memuat satu metode, GetEnumerator,
yang menghasilkan sebuah objek IEnumerator.
Antarmuka ICollections mewarisi IEnumerable, jadi semua kelas koleksi
mengimplementasikan IEnumerable secara langsung maupun tak-langsung.
|
Gambar 8.1 Beberapa
antarmuka koleksi pada namespace System.Collections
Pada versi C# sebelumnya, .NET Framework hanya menyediakan kelas-kelas
koleksi pada namespace System.Collections dan System.Collections.Specialized.
Kelas-kelas ini menyimpan dan memanipulasi referensi-referensi object-object. Anda dapat menyimpan sembarang object di dalam sebuah koleksi. Aspek yang menyulitkan pada
penyimpanan referensi-referensi object-object terjadi ketika membacanya dari
koleksi. Aplikasi normalnya memproses tipe-tipe spesifik dari objek. Hasilnya,
referensi-referensi object-object yang didapatkan dari sebuah
koleksi perlu didowncast menjadi tipe
yang sesuai agar aplikasi dapat memproses objek-objek secara tepat.
.NET Framework juga memuat namespace System.Collections.Generic, yang menggunakan kapabilitas generik
yang telah dikenalkan sebelumnya. Banyak dari kelas-kelas pada namespace tersebut merupakan kelas-kelas
ekivalen dari namespace System.Collections.
Pada bab ini akan didemonstrasikan
kelas-kelas koleksi Array, ArrayList, Stack, Hashtable, SortedDictionary generik, dan LinkedList generik. Namespace System.Collections menyediakan beberapa struktur data lain,
termasuk BitArray (sebuah koleksi
yang memuat nilai-nilai true/false), Queue dan SortedList
(sebuah koleksi dengan pasangan-pasangan kunci/nilai yang diurutkan menggunakan
kunci dan dapat diakses dengan kunci atau dengan indeks). Gambar 8.2
mencantumkan beberapa kelas koleksi yang akan didiskusikan. Di sini juga akan
didiskusikan mengenai antarmuka IEnumerator.
Kelas-kelas koleksi dapat menciptakan enumerator yang memampukan programer
untuk menjelajah koleksi-koleksi.
Kelas
|
Mengimplementasikan
|
Penjelasan
|
namespace System:
|
||
Array
|
IList
|
Kelas basis untuk semua array konvensional.
|
namespace System.Collections:
|
||
ArrayList
|
IList
|
Menyerupai array konvensional, tetapi ia dapat
mengekspansi atau menyusut jika diperlukan untuk mengakomodasi jumlah elemen.
|
BitArray
|
ICollection
|
Sebuah array efisien dengan elemen-elemen bertipe bool.
|
Hashtable
|
IDictionary
|
Sebuah koleksi yang memuat pasangan-pasangan kunci/nilai
tak-terurut yang dapat diakses dengan kunci.
|
Queue
|
ICollection
|
Sebuah koleksi dalam tatanan FIFO (first-in, first-out).
|
SortedList
|
IDictionary
|
Sebuah koleksi yang memuat pasangan-pasangan kunci/nilai
yang dapat diurutkan dengan kunci dan yang dapat diakses dengan kunci atau
dengan indeks.
|
Stack
|
ICollection
|
Sebuah koleksi dalam tatanan LIFO (last-in, first-out).
|
namespace System.Collections.Generic:
|
||
Dictionary< K, V >
|
IDictionary<
K, V >
|
Sebuah koleksi yang memuat pasangan-pasangan kunci/nilai
tak-terurut yang dapat diakses dengan kunci.
|
LinkedList<
T >
|
ICollection< T >
|
Sebuah senarai berantai ganda.
|
List<
T >
|
IList< T >
|
Sebuah ArrayList
generik.
|
Queue<
T >
|
ICollection< T >
|
Sebuah Queue
generik.
|
SortedDictionary<
K,
V >
|
IDictionary< K, V >
|
Sebuah Dictionary
yang mengurutkan data berdasarkan kunci-kunci pada suatu pohon biner.
|
SortedList<
K, V >
|
IDictionary< K, V >
|
Sebuah SortedList
generik.
|
Stack<
T >
|
ICollection< T >
|
Sebuah Stack
generik.
|
Gambar 8.1 Beberapa
antarmuka koleksi pada namespace System.Collections
8.3
Kelas Array dan Enumerator
Semua array secara implisit mewarisi
kelas basis abstrak Array (namespace System); kelas ini mendefinisikan properti Length, yang menetapkan jumlah elemen pada array. Selain itu, kelas
Array menyediakan metode-metode static yang menyediakan
algoritma-algoritma untuk pemrosesan array. Umumnya, kelas Array mengoverload metode-metode
tersebut. Misalnya, metode Reverse
dapat membalikkan urutan dari elemen-elemen array atau dapat membalikkan
elemen-elemen pada rentang elemen tertentu pada array.
Gambar 8.3 mendemonstrasikan beberapa
metode static dari kelas Array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
// Gambar 8.3: MenggunakanArray.cs
// Metode-metode static pada kelas
Array untuk memanipulasi array.
using System;
using
System.Collections;
// mendemonstrasikan
algoritma-algoritma dari kelas Array
public class MenggunakanArray
{
private static int[] nilai2Int = { 1, 2, 3, 4, 5, 6 };
private static double[] nilai2Double = { 8.4, 9.3,
0.2, 7.9, 3.4 };
private static int[] nilai2SalinInt;
// metode Main mendemonstrasikan metode-metode dari kelas Array
public static void Main(
string[] args )
{
nilai2SalinInt = new int[ nilai2Int.Length ]; // default menjadi nol
Console.WriteLine( "Nilai-nilai
awal array:\n" );
TampilArray(); // menampilkan isi awal dari array
// mengurutkan nilai2Double
Array.Sort(
nilai2Double );
// menyalin nilai2Int ke nilai2SalinInt
Array.Copy(
nilai2Int, nilai2SalinInt, nilai2Int.Length );
Console.WriteLine( "\nNilai-nilai array setelah Sort dan Copy:\n" );
TampilArray(); // menampilkan isi array
Console.WriteLine();
// mencari 5 di dalam nilai2Int
int hasil =
Array.BinarySearch( nilai2Int, 5 );
if ( hasil >= 0 )
Console.WriteLine( "5 ditemukan pada elemen {0} di
dalam nilai2Int",
hasil );
else
Console.WriteLine( "5 tidak ditemukan di dalam
nilai2Int" );
// mencari 8763 di dalam nilai2Int
hasil
= Array.BinarySearch( nilai2Int, 8763 );
if ( hasil >= 0 )
Console.WriteLine( "8763 ditemukan pada elemen {0} di
dalam nilai2Int",
hasil );
else
Console.WriteLine("8763 tidak ditemukan di dalam
nilai2Int");
} // akhir Main
// menampilkan isi array dengan enumerator
private static void TampilArray()
{
Console.Write( "nilai2Double:
" );
// beriterasi menjelajahi array double dengan sebuah
IEnumerator
enumerator = nilai2Double.GetEnumerator();
while ( enumerator.MoveNext()
)
Console.Write( enumerator.Current +
" " );
Console.Write( "\nnilai2Int:
" );
// beriterasi menjelajahi array int dengan sebuah
enumerator
= nilai2Int.GetEnumerator();
while ( enumerator.MoveNext()
)
Console.Write( enumerator.Current +
" " );
Console.Write( "\nnilai2SalinInt:
" );
// beriterasi menjelajahi array int kedua
dengan statemen foreach
foreach ( var elemen in
nilai2SalinInt )
Console.Write( elemen + " " );
Console.WriteLine();
} // akhir metode TampilArray
} // akhir kelas
MenggunakanArray
|
Nilai-nilai awal array:
nilai2Double: 8.4 9.3 0.2 7.9 3.4
nilai2Int: 1 2 3 4 5 6
nilai2SalinInt: 0 0 0 0 0 0
Nilai-nilai array setelah Sort dan Copy:
nilai2Double: 0.2 3.4 7.9 8.4 9.3
nilai2Int: 1 2 3 4 5 6
nilai2SalinInt: 1 2 3 4 5 6
5 ditemukan pada elemen 4 di dalam nilai2Int
8763 tidak ditemukan di dalam nilai2Int
|
Direktif using pada baris 3-4 mencantumkan namespace System (untuk
kelas Array dan Console) dan namespace System.Collections (untuk antarmuka IEnumerator).
Kelas uji ini mendeklarasikan tiga
variabel static (baris 9-11). Dua baris pertama menginisialisasi nilai2Int dan nilai2Double dengan array int dan array double. Variabel static nilai2SalinInt dimaksudkan untuk
mendemonstrasikan metode Copy dari
kelas Array, jadi ia diberikan nilai
default null.
Baris 16 menginisialisasi nilai2SalinInt dengan sebuah array int yang memiliki panjang sama dengan
array nilai2Int. Baris 19 memanggil
metode TampilArray (baris 49-74)
untuk menampilkan isi awal dari ketiga array. Anda dapat melihat dari keluaran
bahwa setiap elemen array nilai2SalinInt
diinisialisasi dengan nilai default 0.
Baris 22 menggunakan metode Sort dari kelas Array untuk mengurutkan array nilai2Double.
Ketika metode ini selesai dieksekusi, array akan memiliki elemen-elemen yang
terurut dalam tatanan menaik. Elemen-elemen pada array harus
mengimplementasikan antarmuka IComparable.
Baris 25 menggunakan metode Copy dari kelas Array untuk menyalin elemen-elemen dari array nilai2Int ke array nilai2SalinInt.
Argumen pertama adalah array yang akan disalin (nilai2Int), argumen kedua merupakan array destinasi (nilai2SalinInt), dan argumen ketiga
adalah sebuah int yang merepresentasikan jumlah elemen yang akan disalin (pada
kasus ini, nilai2Int.Length
menetapkan semua elemen).
Baris 32 dan 40 memanggil metode BinarySearch dari kelas Array untuk melakukan pencarian biner
atas array nilai2Int. Metode BinarySearch menerima array terurut dan
kunci pencarian sebagai argumen. Metode ini menghasilkan indeks pada array
dimana ia menemukan kunci yang dicari (atau menghasilkan nilai balik negatif
jika kunci tidak ditemukan). BinarySearch
mengasumsikan bahwa ia menerima array terurut. Kinerja metode ini untuk array
tak-terurut tidak dapat didefinisikan dan tak-terduga.
Metode TampilArray (baris 49-74) menggunakan metode-metode dari kelas Array untuk menjelajah tiap array.
Metode GetEnumerator (baris 54)
mendapatkan sebuah enumerator untuk array nilai2Double.
Ingat bahwa kelas Array mengimplementasikan antarmuka IEnumerable. Semua array mewarisi secara implisit dari kelas Array, jadi kedua tipe array int[ ] dan double[ ] mengimplementasikan metode GetEnumerator dari antarmuka IEnumerable,
yang menghasilkan sebuah enumerator yang dapat beriterasi menjelajah koleksi.
Antarmuka IEnumerable (yang
diimplementasikan oleh semua enumerator) mendefinisikan metode MoveNext dan Reset dan properti Current.
Metode MoveNext memajukan enumerator
ke elemen depan pada koleksi. Pemanggilan pertama terhadap MoveNext memposisikan enumerator pada elemen pertama dari koleksi.
Metode MoveNext menghasilkan true jika terdapat sedikitnya satu
elemen lagi di dalam koleksi; sebaliknya, metode ini menghasilkan false. Metode Reset memposisikan enumerator ke posisi sebelum elemen pertama pada
koleksi. Metode MoveNext dan Reset melemparkan sebuah eksepsi InvalidOperationException jika isi
koleksi dimodifikasi setelah enumerator diciptakan. Properti Current menghasilkan objek pada lokasi
sekarang (terkini) di dalam koleksi.
Ketika sebuah enumerator dihasilkan
oleh metode GetEnumerator pada baris
54, ia awalnya diposisikan ke posisi sebelum elemen pertama pada array nilai2Double. Kemudian ketika baris 56
memanggil MoveNext pada iterasi
pertama di dalam loop while,
enumerator maju ke elemen pertama pada array nilai2Double. Statemen while
pada baris 56-57 beriterasi menjelajahi tiap elemen sampai enumerator melewati
akhir dari array nilai2Double dan MoveNext menghasilkan false. Pada tiap iterasi, Anda
menggunakan properti Current pada
enumerator untuk membaca dan menampilkan elemen array terkini. Baris 62-65
beriterasi menjelajah array nilai2Int.
Perhatikan bahwa TampilArray dipanggil dua kali (baris 19 dan 28), jadi GetEnumerator dipanggil dua kali pada nilai2Double. Metode GetEnumerator (baris 54 dan 62) selalu
menghasilkan sebuah enumerator yang diposisikan pada posisi sebelum elemen
pertama. Perhatikan pula bahwa properti Current
adalah read-only. Enumerator tidak dapat dipakai untuk memodifikasi isi
koleksi, karena ia hanya dipakai untuk membaca elemen-elemen koleksi.
Baris 70-71 menggunakan sebuah statemen
foreach untuk beriterasi menjelajah
elemen-elemen koleksi seperti sebuah enumerator. Pada dasarnya, statemen foreach berperilaku seperti enumerator.
Keduanya (statemen foreach dan
enumerator) menjelajahi elemen-elemen sebuah array satu demi satu secara
berurutan). Keduanya tidak membolehkan Anda untuk memodifikasi elemen-elemen
selama iterasi. Statemen foreach
secara implisit mendapatkan sebuah enumerator melalui metode GetEnumerator dan menggunakan metode MoveNext dan properti Current dari enumerator itu menjelajah
koleksi. Karena alasan ini, Anda dapat menggunakan statemen foreach untuk menjelajah sembarang
koleksi yang mengimplementasikan antarmuka IEnumerable,
bukan hanya untuk array. Fungsionalitas ini akan didemonstrasikan pada bagian
selanjutnya ketika kelas ArrayList
didiskusikan.
Metode-metode static lain dari kelas Array
mencakup Clear (menetapkan suatu
rentang elemen menjadi 0, false,
atau null), CreateInstance (menciptakan sebuah array baru dengan tipe
tertentu), IndexOf (mencari lokasi kemunculan pertama dari sebuah objek pada
suatu array atau pada potongan array), LastIndexOf
(mencari lokasi kemunculan terakhir dari sebuah objek pada suatu array atau
pada potongan array), dan Reverse
(membalikkan urutan isi array atau potongan array).
8.4
Koleksi Tak-Generik
Namespace System.Collections
pada Pustaka Kelas .NET Framework
merupakan sumber primer bagi koleksi-koleksi tak-generik. Kelas-kelas ini
menyediakan implementasi standar bagi banyak struktur data dengan
koleksi-koleksi yang menyimpan referensi-referensi bertipe object. Pada bagian ini, akan didemonstrasikan kelas ArrayList, Stack, dan Hashtable.
8.4.1
Kelas ArrayList
Pada kebanyakan bahasa pemrograman,
array konvensional memiliki ukuran tetap. Array tidak dapat diubah secara
dinamis untuk mengikuti kebutuhan memori pada saat eksekusi. Pada beberapa
aplikasi, keterbatasan ukuran-tetap ini menyebabkan masalah bagi para
programer. Mereka harus memilih antara penggunaan array berukuran-tetap yang
cukup besar untuk menyimpan jumlah elemen maksimum yang dibutuhkan aplikasi
atau menggunakan struktur data dinamis yang dapat mengembang dan menyusut
secara dinamis mengikuti kebutuhan pada saat eksekusi aplikasi.
Koleksi ArrayList pada .NET Framework
menyerupai fungsionalitas dari array konvensional dan menyediakan
pengaturan-ukuran koleksi secara dinamis pada metode-metode kelas. Kelas ArrayList memuat sejumlah tertentu
elemen yang kurang dari atau sama dengan kapasitasnya. Aplikasi dapat
memanipulasi kapasitas ArrayList
dengan properti Capacity.
Kelas ArrayList menyimpan referensi-referensi ke object-object. Semua
kelas mewarisi kelas object, jadi ArrayList
dapat memuat objek-objek dengan tipe sembarang. Gambar 8.4 menyajikan beberapa
metode dan properti dari kelas ArrayList.
Metode
|
Penjelasan
|
Add
|
Menambah sebuah objek pada ArrayList dan menghasilkan sebuah int yang menetapkan indeks dimana
objek itu ditambahkan.
|
Capacity
|
Properti yang mendapatkan dan
menetapkan jumlah elemen yang saat ini sedang disediakan pada ArrayList.
|
Clear
|
Menghapus
semua elemen dari ArrayList.
|
Contains
|
Menghasilkan true jika objek-objek tertentu berada di dalam ArrayList; sebaliknya, menghasilkan false.
|
Count
|
Properti read-only yang
mendapatkan jumlah elemen yang disimpan di dalam ArrayList.
|
IndexOf
|
Menghasilkan indeks kemunculan
pertama dari objek tertentu pada ArrayList.
|
Insert
|
Menyisipkan
sebuah objek pada indeks tertentu.
|
Remove
|
Menghapus
kemunculan pertama dari objek tertentu.
|
RemoveAt
|
Menghapus
sebuah objek pada indeks tertentu.
|
RemoveRange
|
Menghapus sejumlah elemen tertentu
diawali dari indeks tertentu pada ArrayList.
|
Sort
|
Mengurutkan
ArrayList.
|
TrimToSize
|
Menetapkan properti Capacity dari ArrayList menjadi sejumlah elemen yang sekarang sedang dimuat di
dalam ArrayList (Count).
|
Gambar 8.4 Beberapa metode
dan properti dari kelas ArrayList
Gambar 8.5 mendemonstrasikan kelas ArrayList dan beberapa metodenya. Kelas
ArrayList berada di dalam namespace System.Collections (baris 4). Baris 8-11 mendeklarasikan dua array
bertipe string (warna2 dan hapusWarna) yang akan dipakai untuk
mengisi dua objek ArrayList. Ingat
bahwa konstanta harus diinisialisasi pada waktu kompilasi, tetapi variabel readonly dapat diinisialisasi pada
waktu eksekusi. Array merupakan objek yang diciptakan pada waktu eksekusi, jadi
Anda mendeklarasikan warna2 dan hapusWarna dengan readonly, bukan const.
Ketika aplikasi memulai eksekusi, Anda
menciptakan sebuah ArrayList dengan
kapasitas awal satu elemen dan menyimpannya pada variabel list (baris 16). Statemen foreach
pada baris 19-20 menambahkan lima elemen dari array warna2 pada list melalui
metode Add pada kelas ArrayList, sehingga list mengembang untuk mengakomodasi
elemen-elemen baru tersebut. Baris 24 menggunakan konstruktor teroverload ArrayList untuk menciptakan sebuah ArrayList baru yang diinisialisasi dengan isi dari array hapusWarna, kemudian menugaskannya
kepada variabel hapusList.
Konstruktor ini dapat menginisialisasi isi dari sebuah ArrayList dengan elemen-elemen dari sembarang ICollection yang dilewatkan kepadanya. Banyak kelas koleksi
memiliki konstruktor semacam itu. Perhatikan bahwa konstruktor pada baris 24
melakukan tugas dari baris 19-20.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
// Gambar 8.5: UjiArrayList.cs
// Menggunakan kelasArrayList.
using System;
using
System.Collections;
public class UjiArrayList
{
private static readonly string[]
warna2 =
{ "MAGENTA",
"MERAH", "PUTIH",
"BIRU", "COKLAT" };
private static readonly string[] hapusWarna =
{ "MERAH", "PUTIH", "BIRU" };
// menciptakan ArrayList, menambahkan
warna2 padanya dan memanipulasinya
public static void Main( string[] args )
{
ArrayList list = new
ArrayList( 1 ); // kapasitas awal 1
// menambahkan elemen-elemen dari warna2 pada ArrayList list
foreach ( var warna in warna2 )
list.Add( warna ); // menambahkan
warna pada ArrayList list
// menambahkan elemen-elemen di dalam hapusWarna pada
// ArrayList hapusList dengan konstruktor ArrayList
ArrayList
hapusList = new ArrayList(
hapusWarna );
Console.WriteLine( "ArrayList:
" );
TampilInformasi( list ); // menampilkan list
// menghapus dari ArrayList list warna-warna di dalam hapusList
HapusWarna( list, hapusList );
Console.WriteLine( "\nArrayList
setelah pemanggilan HapusWarna: " );
TampilInformasi( list ); // menampilkan isi list
} // akhir Main
// menampilkan informasi tentang isi ArrayList
private static void TampilInformasi( ArrayList arrayList )
{
// menjelajah array list dengan statemen foreach
foreach ( var elemen in
arrayList )
Console.Write( "{0} ", elemen
); // memanggil ToString
// menampilkan isi dan kapasitas
Console.WriteLine("\nUkuran
= {0}; Kapasitas = {1}",
arrayList.Count,
arrayList.Capacity);
int indeks =
arrayList.IndexOf( "BIRU"
);
if ( indeks != -1 )
Console.WriteLine( "ArrayList memuat BIRU pada indeks {0}.",
indeks );
else
Console.WriteLine( "ArrayList tidak memuat BIRU." );
} // akhir metode TampilInformasi
//
menghapus warna-warna pada listKedua dari listPertama
private static void
HapusWarna( ArrayList listPertama,
ArrayList listKedua )
{
// menjelajah ArrayList kedua seperti
array biasa
for
( int hitung = 0; hitung <
listKedua.Count; hitung++ )
listPertama.Remove( listKedua[ hitung
] );
} // akhir
metode HapusWarna
} // akhir kelas UjiArrayList
|
ArrayList:
MAGENTA MERAH PUTIH BIRU COKLAT
Ukuran = 5; Kapasitas = 8
ArrayList memuat BIRU pada indeks 3.
ArrayList setelah pemanggilan HapusWarna:
MAGENTA COKLAT
Ukuran = 2; Kapasitas = 8
ArrayList tidak memuat BIRU.
|
Baris 27 memanggil metode TampilInformasi (baris 37-54) untuk
menampilkan isi dari list. Metode
ini menggunakan sebuah statemen foreach
untuk menjelajah tiap elemen pada suatu ArrayList.
Seperti yang telah didiskusikan, statemen foreach
merupakan cara pintas untuk memanggil metode GetEnumerator dari kelas ArrayList
dan untuk menggunakan sebuah enumerator untuk menjelajah elemen-elemen pada
koleksi. Selain itu, baris 40 menyimpulkan bahwa tipe variabel iterasi adalah object karena kelas ArrayList merupakan kelas tak-generik
dan menyimpan referensi-referensi ke object-object.
Anda menggunakan properti Count dan Capacity (baris 45) untuk menampilkan jumlah elemen terkini dan
jumlah elemen maksimum yang dapat disimpan di dalam ArrayList tanpa perlu mengalokasikan memori tambahan. Keluaran pada
Gambar 8.5 mengindikasikan bahwa ArrayList
memiliki kapasitas 8.
Pada baris 47, Anda memanggil metode IndexOf untuk menentukan posisi dari string “BIRU” di dalam arrayList
dan menyimpan hasilnya pada variabel lokal indeks.
Metode IndexOf menghasilkan -1 jika
elemen tidak ditemukan. Statemen if
pada baris 49-53 memeriksa jika indeks
adalah -1 untuk menentukan apakah arrayList
memuat “BIRU”. Jika ya, akan
ditampilkan indeks tersebut. ArrayList
juga menyediakan metode Contains,
yang menghasilkan true jika sebuah
objek berada di dalam ArrayList, dan
false jika sebaliknya. Metode Contains lebih direkomendasikan jika
Anda tidak memerlukan indeks elemen yang dicari.
Setelah metode TampilInformasi selesai dieksekusi, Anda memanggil metode HapusWarna (baris 57-63) dengan dua ArrayList. Statemen for pada baris 61-62 beriterasi
menjelajah listKedua. Baris 62
menggunakan sebuah indekser untuk mengakses sebuah elemen ArrayList, dengan menempatkan sepasang kurung siku ([]) setelah nama referensi ArrayList. Eksepsi ArgumentOutOfRangeException terjadi jika indeks yang ditentukan
tidak lebih besar (atas sama dengan) dan kurang dari jumlah elemen yang sedang
disimpan di dalam ArrayList
(ditentukan oleh properti Count dari
ArrayList).
Anda menggunakan indekser untuk
mendapat tiap elemen listKedua,
kemudian menghapus tiap elemen tersebut dari listPertama dengan metode Remove.
Metode ini menghapus item tertentu dari sebuah ArrayList dengan melakukan pencarian linier dan hany menghapus
kemunculan pertama dari objek tertentu.
Setelah pemanggilan terhadap HapusWarna, baris 33 menampilkan
kembali isi dari list, yang
menegaskan bahwa elemen-elemen dari hapusList
telah terhapus.
8.4.2
Kelas Stack
Kelas Stack mengimplementasikan struktur data tumpukan. Pada Gambar 8.6
didemonstrasikan kelas koleksi Stack
dari .NET Framework.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
// Gambar 8.6: UjiStack.cs
// Mendemonstrasikan kelas Stack.
using System;
using
System.Collections;
public class UjiStack
{
public static void Main(
string[] args )
{
Stack tumpukan = new
Stack(); // menciptakan sebuah Stack kosong
// menciptakan objek-objek yang akan disimpan pada tumpukan
bool aBoolean = true;
char aCharacter = '#';
int anInteger = 34567;
string aString = "hallo";
// menggunakan metode Push untuk menempatkan item-item pada tumpukan
tumpukan.Push(
aBoolean );
TampilStack( tumpukan );
tumpukan.Push(
aCharacter );
TampilStack( tumpukan );
tumpukan.Push(
anInteger );
TampilStack( tumpukan );
tumpukan.Push(
aString );
TampilStack( tumpukan );
// memeriksa elemen atas tumpukan
Console.WriteLine( "Elemen atas dari tumpukan adalah
{0}\n",
tumpukan.Peek() );
// menghapus item-item dari tumpukan
try
{
while ( true )
{
object
hapusObjek = tumpukan.Pop();
Console.WriteLine( hapusObjek + " dihapus" );
TampilStack( tumpukan );
} // akhir
while
} // akhir try
catch (
InvalidOperationException eksepsi )
{
// jika eksepsi terjadi,
menampilkan jejak tumpukan
Console.Error.WriteLine( eksepsi
);
} // akhir catch
} // akhir Main
// menampilkan isi sebuah stack
private static void TampilStack( Stack tumpukan )
{
if ( tumpukan.Count == 0 )
Console.WriteLine( "tumpukan kosong\n" ); // tumpukan
kosong
else
{
Console.Write( "Tumpukan: " );
// menjelajah tumpukan dengan
statemen foreach
foreach ( var elemen in tumpukan
)
Console.Write( "{0} ", elemen
); // memanggil ToString
Console.WriteLine( "\n"
);
} // akhir else
} // akhir metode TampilStack
} // akhir kelas UjiStack
|
Tumpukan: True
Tumpukan: # True
Tumpukan: 34567 # True
Tumpukan: hallo 34567 # True
Elemen atas dari tumpukan adalah hallo
hallo dihapus
Tumpukan: 34567 # True
34567 dihapus
Tumpukan: # True
# dihapus
Tumpukan: True
True dihapus
tumpukan kosong
System.InvalidOperationException: Stack empty.
at
System.Collections.Stack.Pop()
at
UjiStack.Main(String[] args) in e:\Projects Visual C#\UjiStack\
UjiStack\Program.cs:line
37
|
Direktif using pada baris 4 menghindarkan Anda untuk menggunakan kelas Stack dengan nama penuhnya (System.Collections.Stack). Baris 10
menciptakan sebuah Stack. Seperti
yang Anda harapkan, kelas Stack
memiliki metode Push dan Pop untuk melakukan operasi-operasi
tumpukan dasar.
Metode Push memerlukan sebuah object
sebagai argumen dan menyisipkannya ke atas Stack.
Jika jumlah item pada Stack
(properti Count) sama dengan
kapasitasnya pada saat operasi Push
dilakukan, maka Stack akan
mengembang untuk mengakomodasi object-object baru. Baris 19-26 menggunakan
metode Push untuk menambahkan empat
elemen (sebuah bool, sebuah char, sebuah int, dan sebuah string)
ke atas tumpukan dan memanggil metode TampilStack
(baris 50-64) setelah tiap pemanggilan Push
untuk menampilkan isi dari tumpukan. Perhatikan bahwa kelas Stack tak-generik ini hanya dapat
menyimpan referensi-referensi ke object-object, jadi tiap item tipe-nilai
secara implisit dikonversi sebelum ditambahkan ke Stack. (Namespace System.Collections.Generic menyediakan
sebuah kelas Stack generik yang
memiliki banyak metode dan properti. Versi ini mengeliminasi kebutuhan akan
konversi tipe).
Metode TampilStack (baris 50-64) menggunakan properti Count dari kelas Stack
(diimplementasikan untuk memenuhi kontrak dengan antarmuka ICollection) untuk mendapatkan jumlah elemen di dalam tumpukan. Jika tumpukan tidak kosong
(yaitu, properti Count tidak sama
dengan 0), maka Anda menggunakan statemen foreach
untuk menjelajah tumpukan dan menampilkan isinya dengan secara implisit
memanggil metode ToString pada tiap
elemen. Statemen foreach secara
implisit memanggil metode GetEnumerator
dari kelas Stack, yang dapat Anda
panggil secara eksplisit untuk menjelajah tumpukan melalui enumerator.
Metode Peek menghasilkan nilai dari elemen atas tumpukan tetapi tidak
menghapus elemen tersebut dari Stack.
Anda menggunakan Peek pada baris 30 untuk mendapatkan objek atas pada Stack, kemudian menampilkan objek
tersebut dan secara implisit memanggil metode ToString pada objek tersebut. Eksepsi InvalidOperationException terjadi ketika Stack kosong ketika aplikasi memanggil Peek.
Metode Pop tidak memerlukan argumen. Metode ini menghapus objek yang
sekarang berada di atas tumpukan dan manghasilkan nilai balik berupa objek
tersebut. Loop pada baris 35-40 menghapus objek-objek dari tumpukan dan
menampilkannya sampai tumpukan kosong. Ketika aplikasi memanggil Pop pada tumpukan kosong, maka eksepsi InvalidOperationException akan
dilemparkan. Blok catch (baris
42-46) menampilkan eksepsi, secara implisit memanggil metode ToString pada eksepsi InvalidOperationException untuk
mendapatkan pesan error dan jejak tumpukan.
Meskipun Gambar 7.6 tidak
mendemonstrasikannya, kelas Stack
memiliki metode Contains, yang
menghasilkan true jika Stack memuat objek tertentu, dan
menghasilkan false jika sebaliknya.
8.4.3
Kelas Hashtable
Ketika sebuah aplikasi menciptakan
objek-objek dari tipe baru atau tipe yang sudah ada, ia perlu mengelola
objek-objek tersebut secara efisien. Pengelolaan ini mencakup pengurutan dan
pembacaan objek-objek. Pengurutan dan penarikan informasi dengan array hanya
efisien jika beberapa aspek pada data secara langsung cocok dengan nilai kunci
dan jika kunci unik. Jika Anda memiliki 100 karyawan dengan nomor KTP 9 dijit
dan Anda ingin menyimpan dan menarik data karyawan menggunakan nomor KTP
sebagai kuncinya, maka hal itu akan memerlukan 1 000 000 000 elemen karena
terdapat satu milyar angka 9 dijit yang unik. Jika Anda memiliki sebuah array
sebesar itu, maka Anda bisa menyimpan dan menarik rekaman informasi karyawan
menggunakan nomor KTP sebagai indeks, tetapi hal itu merupakan tindakan
pemborosan memori.
Banyak aplikasi mempunyai masalah
seperti ini. Misalnya, kunci memiliki tipe yang salah (misalnya, kunci
negatif), atau kunci dengan tipe benar tetapi tersebar secara jarang pada
rentang yang sangat luas.
Apa yang diperlukan adalah skema
berkecepatan-tinggi untuk mengkonversi kunci, seperti nomor KTP, menjadi
indeks-indeks array yang unik. Kemudian, ketika aplikasi perlu menyimpan
sesuatu, skema ini dapat mengkonversi kunci dengan cepat menjadi sebuah indeks dan
rekaman informasi dapat disimpan pada lokasi tersebut di dalam array. Penarikan
informasi dilakukan dengan cara yang sama. Ketika aplikasi memiliki sebuah
kunci untuk menarik rekaman data, aplikasi hanya perlu mengkonversi kunci
tersebut, yang menghasilkan indeks array dimana terdapat data yang disimpan di
dalam array.
Skema yang dijelaskan di sini merupakan
basis untuk suatu teknik yang disebut dengan hashing, dimana di dalamnya Anda menyimpan data pada sebuah
struktur data yang dikenal dengan tabel hash.
Kekuarang pada skema ini terjadi ketika
terdapat tubrukan (yaitu, dua kunci yang berbeda dikonversi menjadi indeks
array yang sama). Karena Anda tidak dapat mengurutkan dua rekaman data yang
berbeda pada ruang yang sama, Anda perlu mencari rumah baru alternatif bagi
semua rekaman di luar rekaman pertama yang menghasilkan indeks array tertentu.
Salah satu skema untuk melakukan ini adalah dengan menghashkan kembali kunci
untuk menghasilkan kandidat indeks pada array.
Skema lain menggunakan satu hash untuk mencari kandidat indeks yang
pertama. Jika indeks tersebut telah ditempati, maka sel-sel tetangganya (yang
berurutan) diteliti secara linier sampai sebuah indeks yang kosong ditemukan.
Penarikan informasi bekerja dengan cara yang sama, dimana kunci dihash sekali
saja, indeks yang dihasilkan diperiksa untuk menentukan apakah ia memuat data
yang diinginkan. Jika ya, pencarian selesai. Jika tidak, indeks-indeks
tetangganya diteliti secara linier sampai data yang diinginkan ditemukan.
Faktor beban (load factor) mempengaruhi kinerja dari skema hashing. Faktor beban merupakan rasio dari jumlah objek yang
disimpan pada tabel hash dengan
jumlah sel (indeks) total pada tabel hash.
Semakin tinggi rasio ini, peluang tubrukan cenderung meningkat.
Fungsi hash melakukan perhitungan untuk menentukan di mana menempatkan
data pada tabel hash. Fungsi hash
diterapkan terhadap pasangan kunci/nilai dari objek-objek. Kelas Hashtable dapat menerima sembarang object sebagai kunci. Karena itu, kelas
object mendefinisikan metode GetHashCode, yang diwarisi oleh semua
objek. Gambar 8.7 menggunakan sebuah Hashtable
untuk menghitung jumlah kemunculan dari tiap kata pada sebuah string.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
// Gambar 8.7: UjiTabelHash.cs
// Aplikasi menghitung jumlah
kemunculan dari tiap kata pada sebuah string
// dan menyimpannya di dalam suatu
tabel hash.
using System;
using
System.Text.RegularExpressions;
using
System.Collections;
public class UjiTabelHash
{
public static void Main( string[] args )
{
// menciptakan tabel hash berdasarkan masukan pengguna
Hashtable tabel = KumpulKata();
// menampilkan isi tabel hash
TampilTabelHash( tabel );
} // akhir Main
// menciptakan tabel hash dari masukan pengguna
private static Hashtable KumpulKata()
{
Hashtable tabel = new
Hashtable(); // menciptakan tabel hash baru
Console.WriteLine( "Masukkan
sebuah string: " ); // meminta
masukan penguna
string masukan =
Console.ReadLine(); // membaca masukan
// memecah teks masukan menjadi token-token
string[] kata2 =
Regex.Split( masukan, @"\s+" );
// memproses kata-kata masukan
foreach ( var kata in kata2 )
{
string
kunciKata = kata.ToLower(); // membaca
kata dalam huruf kecil
// jika tabel hash memuat kata
if
( tabel.ContainsKey( kunciKata ) )
{
tabel[ kunciKata ] = ( ( int
) tabel[ kunciKata ] ) + 1;
} // akhir if
else
// menambah kata baru dengan hitungan satu pada tabel hash
tabel.Add( kunciKata, 1 );
} // akhir
foreach
return tabel;
} // akhir metode KumpulKata
// menampilkan isi tabel hash
private static void TampilTabelHash( Hashtable tabel )
{
Console.WriteLine( "\n Hashtable
memuat:\n{0,-12}{1,-12}",
"Kunci:", "Nilai:" );
// menghasilkan keluaran untuk tiap kunci pada tabel hash
// dengan menjelajah dengan properti Keys
dengan statemen foreach
foreach ( var kunci in
tabel.Keys )
Console.WriteLine( "{0,-12}{1,-12}", kunci, tabel[ kunci ]
);
Console.WriteLine( "\nukuran:
{0}", tabel.Count );
} // akhir metode TampilTabelHash
} // akhir kelas UjiTabelHash
|
Masukkan sebuah string:
Klaten merupakan sebuah kota dengan kualitas air
yang cukup baik bagi sebuah
kota kabupaten.
Hashtable memuat:
Kunci:
Nilai:
cukup 1
sebuah 2
merupakan 1
bagi 1
kabupaten. 1
dengan 1
yang 1
klaten 1
baik 1
kualitas 1
air 1
kota 2
ukuran: 12
|
Baris 4-6 memuat direktif using untuk namespace System (untuk
kelas Console), namespace System.Text.RegularExpressions
(untuk kelas Regex), dan namespace System.Collections (untuk kelas Hashtable). Kelas UjiTabelHash
mendeklarasikan tiga metode static.
Metode KumpulKata (baris 20-46)
membaca sebuah string dan
menghasilkan sebuah Hashtable dimana
di dalamnya setiap nilai menyimpan jumlah perulangan kata pada string dan kata dipakai sebagai kunci.
Metode TampilTabelHash (baris 49-60
menampilkan Hashtable yang
dilewatkan kepadanya pada format kolom. Metode Main (baris 10-17) memanggil KumpulKata
(baris 13), kemudian melewatkan Hashtable yang dihasilkan oleh KumpulKata kepada TampilTabelHash pada baris 16.
Metode KumpulKata (baris 20-46) memulai dengan menginisialisasi variabel
lokal tabel dengan sebuah Hashtable
baru (baris 22) yang memiliki beban faktor maksimum default sebesar 1. Ketika Hashtable meraih faktor beban yang
ditetapkan, kapasitasnya ditambah secara otomatis. Baris 24-25 meminta pengguna
memasukkan sebuah string dan program
membacanya. Anda menggunakan metode static
(Split) dari kelas Regex pada baris 28 untuk membagi
string berdasarkan karakter-karakter spasi-putihnya. Ini menciptakan array yang
memuat kata-kata, Kemudian Anda menyimpannya pada variabel lokal kata2.
Baris 31-43 menjelajah setiap elemen
pada array kata2. Setiap kata
dikonversi menjadi huruf kecil dengan metode ToLower dari kelas string,
kemudian menyimpannya pada variabel kunciKata
(baris 33). Kemudian baris 36 memanggil metode ContainsKey dari kelas Hashtable
untuk menentukan apakah kata ada di dalam tabel hash atau tidak. Jika Hashtable tidak memuat sebuah entri
untuk kata tersebut, baris 42 akan menggunakan metode Add dari kelas Hashtable
untuk menciptakan sebuah entri pada di dalam tabel hash, dengan kata huruf kecil sebagai kunci dan sebuah objek yang
memuat 1 sebagai nilai.
Jika kata telah menjadi sebuah kunci
pada tabel hash, baris 38 akan
menggunakan indekser dari Hashtable untuk mendapatkan dan menetapkan nilai dari
kunci terkait (jumlah kata) pada tabel hash. Anda pertama-tama melakukan downcast terhadap nilai yang didapatkan
oleh aksesor get dari sebuah object menjadi sebuah int. Ini dilakukan agar Anda bisa
menginkremennya sebesar 1. Kemudian, ketika Anda menggunakan aksesor set dari indekser untuk menugaskan
nilai dari kunci tertentu, nilai terinkremen secara implisit downcast ulang sehingga ia dapat
disimpan pada tabel hash.
Perhatikan bahwa pemanggilan aksesor get dari sebuah indekser Hashtable dengan suatu kunci yang tidak
ada pada tabel hash akan menghasilkan
referensi null. Penggunaan aksesor set dengan sebuah kunci yang tidak ada
pada tabel hash akan menciptakan
sebuah entri baru, seperti Anda menggunakan metode Add.
Baris 45 menghasilkan tabel hash dan diberikan kepada metode Main, yang kemudian melewatkannya
kepada metode TampilTabelHash (baris
49-60), yang menampilkan semua entri. Metode ini menggunakan properti readonly (Keys) pada baris 56 untuk mendapatkan sebuah ICollection yang memuat semua kunci. Karena ICollection mewarisi antarmuka IEnumerable,
Anda dapt menggunakan koleksi ini pada statemen foreach pada baris 56-57 untuk menjelajah kunci-kunci pada tabel hash. Loop ini mengakses dan menampilkan
setiap kunci dan nilainya pada tabel hash
menggunakan variabel iterasi dan akses get
dari tabel. Setiap kunci dan
nilainya ditampilkan pada lebar bidang -12. Lebar bidang negatif
mengindikasikan bahwa keluaran disejajarkan ke kiri. Tabel hash tidak terurut, jadi pasangan-pasangan kunci/nilai tidak
ditampilkan dalam urutan tertentu. Baris 59 menggunakan properti Count dari kelas Hashtable untuk mendapatkan jumlah pasangan kunci/nilai pada Hashtable.
Baris 56-57 dapat pula menggunakan
statemen foreach dengan objek Hashtable, menggantikan penggunaan
properti Keys. Jika Anda menggunakan
statemen foreach dengan sebuah objek
Hashtable, maka variabel iterasi
akan bertipe DictionaryEntry.
Enumerator dari sebuah Hashtable
(atau sembarang kelas lain yang mengimplementasikan IDictionary) menggunakan struktur DictionaryEntry untuk menyimpan pasangan-pasangan kunci/nilai.
Struktur ini menyediakan properti Key
dan Value untuk penarikan kunci dan
nilai dari elemen terkini. Jika Anda tidak memerlukan kunci, maka kelas Hashtable juga menyediakan sebuah
properti read-only Values yang
mendapatkan sebuah ICollection dari
semua nilai-nilai yang disimpan di dalam Hashtable.
8.5
Koleksi Generik
Namespace System.Collections.Generic
memuat kelas-kelas generik yang memampukan Anda untuk menciptakan
koleksi-koleksi dengan tipe spesifik. Seperti Anda lihat pada Gambar 8.2,
banyak kelas merupakan versi-versi generik dari koleksi-koleksi tak-generik. Di
sini, akan didemonstrasikan koleksi generik SortedDictionary dan LinkedList.
8.5.1
Kelas Generik SortedDictionary
Kamus merupakan istilah umum untuk
sebuah koleksi yang memuat pasangan-pasangan kunci/nilai. Tabel hash merupakan salah satu cara dalam
mengimplementasikan sebuah kamus. .NET Framework
menyediakan beberapa implementasi atas kamus, baik generik maupun tak-generik,
yang semuanya mengimplamentasikan antarmuka IDictionary. Aplikasi pada Gambar 8.8 merupakan modifikasi dari
Gambar 8.7 yang menggunakan kelas SortedDictionary
generik. Kelas ini tidak menggunakan sebuah tabel hash, tetapi menyimpan pasangan-pasangan kunci/nilai pada suatu
pohon pencarian biner. Entri-entri pada SortedDictionary
diurutkan pada pohon berdasarkan kunci. Ketika kunci mengimplementasikan
antarmuka IComparable<T>
generik, SortedDictionary
menggunakan hasil-hasil dari metode CompareTo
(dari antarmuka IComparable<T>)
untuk mengurutkan kunci-kunci.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
// Gambar 8.8: UjiSortedDictionary.cs
// Aplikasi menghitung jumlah
kemunculan dari tiap kata pada sebuah string
// dan menyimpannya di dalam suatu
kamus terurut generik.
using System;
using
System.Text.RegularExpressions;
using
System.Collections.Generic;
public class UjiSortedDictionary
{
public static void
Main(string[] args)
{
// menciptakan kamus terurut berdasarkan masukan pengguna
SortedDictionary<string,
int> kamus = KumpulKata();
// menampilkan isi kamus terurut
TampilKamus(kamus);
} // akhir Main
// menciptakan tabel hash dari masukan pengguna
private static SortedDictionary<string, int> KumpulKata()
{
// menciptakan sebuah kamus terurut yang baru
SortedDictionary<string, int> kamus =
new
SortedDictionary<string, int>();
Console.WriteLine("Masukkan sebuah string: "); // meminta masukan penguna
string masukan = Console.ReadLine(); // membaca masukan
// memecah teks masukan menjadi token-token
string[] kata2 =
Regex.Split(masukan, @"\s+");
// memproses kata-kata masukan
foreach (var kata in kata2)
{
string kunciKata = kata.ToLower(); // membaca kata dalam huruf kecil
// jika kamus memuat kata
if (kamus.ContainsKey(kunciKata))
{
++kamus[kunciKata];
} // akhir if
else
// menambah kata baru dengan
hitungan satu pada kamus
kamus.Add(kunciKata, 1);
} // akhir foreach
return kamus;
} // akhir metode KumpulKata
// menampilkan isi tabel kamus
private static void
TampilKamus<K, V>(
SortedDictionary<K, V> kamus)
{
Console.WriteLine("\nKamus
terurut memuat:\n{0,-12}{1,-12}",
"Kunci:", "Nilai:");
// menghasilkan keluaran untuk tiap kunci pada kamus terurut
// dengan menjelajah dengan properti Keys dengan statemen foreach
foreach (var kunci in kamus.Keys)
Console.WriteLine("{0,-12}{1,-12}", kunci, kamus[kunci]);
Console.WriteLine("\nukuran:
{0}", kamus.Count);
} // akhir metode TampilKamus
} // akhir kelas UjiSortedDictionary
|
Masukkan sebuah string:
Danau itu hening tanpa kebisingan, tanpa keserakahan
manusia, keserakahan yang
menjijikkan.
Kamus terurut memuat:
Kunci:
Nilai:
danau 1
hening 1
itu 1
kebisingan, 1
keserakahan 2
manusia, 1
menjijikkan.1
tanpa 2
yang 1
ukuran: 9
|
Baris 6 memuat sebuah direktif using untuk namespace System.Collections.Generic,
yang memuat kelas SortedDictionary.
Kelas SortedDictionary generik
mengambil dua argumen tipe, satu untuk menetapkan tipe kunci (yaitu, string) dan yang lain untuk tipe nilai
(yaitu, int). Anda hanya perlu
mengganti Hashtable pada baris 13
dan baris 23-24 dengan SortedDictionary<string, int> untuk menciptakan sebuah kamus yang memuat nilai-nilai int yang dikunci dengan string-string. Sekarang, kompiler dapat memeriksa dan memberitahu Anda
jika Anda mencoba menyimpan sebuah objek dengan tipe salah pada kamus. Selain
itu, karena kompiler sekarang mengetahui bahwa struktur data ini memuat
nilai-nilai int, tidak diperlukan
lagi downcast pada baris 40. Ini
memampukan baris 40 untuk menggunakan notasi inkremen prefiks (++) yang lebih
singkat.
Metode statis TampilKamus (baris 51-63) telah dimodifikasi agar menjadi generik.
Metode ini memerlukan parameter tipe K
dan V. Parameter-parameter ini
digunakan pada baris 52 untuk mengindikasikan bahwa TampilKamus memerlukan sebuah SortedDictionary
dengan kunci-kunci dengan tipe K dan
nilai-nilai dengan tipe V. Anda
menggunakan parameter tipe K kembali
pada baris 59 sebagai tipe dari kunci iterasi. Penggunaan generik ini merupakan
contoh yang menarik dari pendaur-ulangan kode. Jika Anda memutuskan untuk
mengubah aplikasi agar menghitung jumlah kemunculan dari tiap karakter yang
muncul pada sebuah string, maka
metode TampilKamus dapat menerima
sebuah argumen dengan tipe SortedDictionary<char,
int> tanpa modifikasi. Pasangan-pasangan kunci yang ditempilkan sekarang
diurutkan berdasarkan kunci, seperti ditampilkan pada Gambar 8.8.
8.5.2
Kelas LinkedList Generik
Kelas LinkedList generik merupakan sebuah senarai berantai ganda. Anda
dapat menavigasi senarai tersebut ke depan dan ke belakang dengan simpul-simpul
dari kelas LinkedListNode generik.
Setiap simpul memuat properti Value
dan properti-properti read-only Previous dan Next. Tipe
dari properti Value cocok dengan
parameter tipe pada LinkedList
karena ia memuat data yang disimpan pada sebuah simpul. Properti Previous mendapatkan sebuah referensi
yang menunjuk ke simpul sebelumnya pada senarai berantai (atau referensi null jika simpul merupakan simpul
pertama pada senarai). Sama halnya, properti Next mendapatkan sebuah referensi
yang menunjuk ke simpul berikutnya pada senarai berantai (atau referensi null jika simpul merupakan simpul
pertama pada senarai). Beberapa manipulasi terhadap senarai berantai
didemonstrasikan pada Gambar 8.9.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
// Gambar 8.9: UjiLinkedList.cs
// Menggunakan LinkedLists.
using System;
using
System.Collections.Generic;
public class UjiLinkedList
{
private static readonly string[]
warna2 = { "hitam",
"kuning",
"hijau", "biru", "violet", "perak" };
private static readonly string[] warna22 = { "emas",
"putih",
"coklat", "biru", "abu2" };
// memanipulasi objek-objek LinkedList
public static void Main( string[] args )
{
LinkedList< string >
list1 = new LinkedList< string >();
// menambahkan elemen-elemen pada senarai berantai pertama
foreach ( var warna in warna2 )
list1.AddLast( warna );
// menambahkan elemen-elemen pada senarai
berantai kedua lewat konstruktor
LinkedList< string >
list2 = new LinkedList< string >( warna22 );
Sambung( list1, list2 ); // menyambung list2 ke list1
TampilSenarai( list1 ); // menampilkan elemen-elemen list1
Console.WriteLine( "\nMengkonversi string-string list1 menjadi huruf besar\n" );
KeStringHurufBesar( list1 ); // mengkonversi
menjadi string huruf besar
TampilSenarai( list1 ); // menampilkan
elemen-elemen list1
Console.WriteLine( "\nMenghapus string-string antara HITAM dan COKLAT\n" );
HapusAntarItem( list1, "HITAM",
"COKLAT" );
TampilSenarai( list1 ); // menampilkan elemen-elemen list1
TampilSenaraiTerbalik(list1); // menampilkan
senarai dalam urutan terbalik
} // akhir Main
// menampilkan isi senarai berantai
private static void TampilSenarai< T >( LinkedList< T > list )
{
Console.WriteLine( "Senarai
berantai: " );
foreach ( T nilai in list )
Console.Write( "{0} ", nilai );
Console.WriteLine();
} // akhir metode TampilSenarai
// menyambung list kedua diujung list pertama
private static void Sambung< T >( LinkedList< T > list1,
LinkedList< T > list2 )
{
//
menyambung senarai-senarai dengan menyalin nilai-nilai elemen
// secara
berurutan dari senarai kedua ke senarai pertama
foreach
( T nilai in list2 )
list1.AddLast( nilai ); //
menambahkan simpul baru
} // akhir metode Sambung
// mencari objek-objek string dan mengkonversinya menjadi huruf besar
private static void
KeStringHurufBesar( LinkedList< string
> list )
{
// menjelajah senarai menggunakan
simpul-simpul
LinkedListNode< string > simpulSekarang = list.First;
while
( simpulSekarang != null )
{
string
warna = simpulSekarang.Value; // mendapatkan
nilai pada simpul
simpulSekarang.Value =
warna.ToUpper(); // konversi ke huruf besar
simpulSekarang = simpulSekarang.Next;
// mendapatkan simpul berikutnya
} // akhir while
} // akhir
metode KeStringHurufBesar
// menghapus item-item senarai antara dua item yang diberikan
private static void HapusAntarItem< T >( LinkedList< T > list,
T itemAwal, T itemAkhir )
{
// mendapatkan simpul-simpul yang terkait
dengan item awal dan item akhir
LinkedListNode<
T > simpulSekarang = list.Find( itemAwal );
LinkedListNode<
T > simpulAkhir = list.Find( itemAkhir );
// menghapus item-item setelah item awal
// sampai ditemukan item terakhir atau sampai akhir senarai berantai
while ( (
simpulSekarang.Next != null )
&&
( simpulSekarang.Next !=
simpulAkhir ) )
{
list.Remove(
simpulSekarang.Next ); // menghapus simpul
berikutnya
} // akhir while
} // akhir metode HapusAntarItem
// menampilkan senarai berantai secara terbalik
private static void TampilSenaraiTerbalik< T >( LinkedList< T > list
)
{
Console.WriteLine( "Senarai
terbalik:" );
// menjelajah senarai menggunakan simpul-simpul
LinkedListNode< T > simpulSekarang =
list.Last;
while ( simpulSekarang
!= null )
{
Console.Write(
"{0} ", simpulSekarang.Value );
simpulSekarang
= simpulSekarang.Previous; // simpul sebelumnya
} // akhir while
Console.WriteLine();
} // akhir metode TampilSenaraiTerbalik
} // akhir kelas UjiLinkedList
|
Senarai berantai:
hitam kuning hijau biru violet perak emas putih
coklat biru abu2
Mengkonversi string-string pada list1 menjadi huruf
besar
Senarai berantai:
HITAM KUNING HIJAU BIRU VIOLET PERAK EMAS PUTIH
COKLAT BIRU ABU2
Menghapus string-string antara HITAM dan COKLAT
Senarai berantai:
HITAM COKLAT BIRU ABU2
Senarai terbalik:
ABU2 BIRU COKLAT HITAM
|
Direktif using pada baris 4 memampukan Anda untuk menggunakan kelas LinkedList dengan nama tak-penuh. baris
16-23 menciptakan dua LinkedList, list1 dan list2, yang memuat string-string dan mengisinya dengan isi array warna2 dan warna22. LinkedList
merupakan sebuah kelas generik yang memiliki satu parameter tipe. Dua cara
untuk mengisi senarai berantai telah didemonstrasikan. Pada baris 19-20, Anda
menggunakan statemen foreach dan
metode AddLast untuk mengisi list1. Metode AddaLast menciptakan sebuah LinkedListNode
yang baru (dengan nilai yang diberikan melalui properti Value) dan menyambungkan simpul ini ke ujung akhir senarai
berantai. Metode AddFirst dipakai
untuk menyisipkan sebuah simpul di awal senarai berantai. Baris 32 memanggil
konstruktor yang mengambil sebuah parameter IEnumerable<string>.
Semua array secara implisit mewarisi
antarmuka generik, IList dan IEnumerable, dengan tipe array sebagai
argumen tipe, sehingga array string,
warna22, mengimplementasikan IEnumerable<string>. Parameter tipe
dari IEnumerable generik ini cocok
dengan parameter tipe dari objek LinkedList
generik. Pemanggilan konstruktor ini menyalin isi dari array warna22 ke list2.
Baris 25 memanggil metode Sambung generik (baris 51-58) untuk
menempatkan semua elemen dari list2
ke ujung dari list1. Baris 26
memanggil metode TampilSenarai
(baris 40-48) untuk menampilkan isi dari list1. Baris 29 memanggil metode KeStringHurufBesar (baris 61-73) untuk
mengkonversi setiap elemen string
menjadi huruf besar, kemudian baris 30 memanggil TampilSenarai kembali untuk menampilkan string-string
termodifikasi. Baris 33 memanggil metode HapusAntarItem
(baris 76-90) untuk menghapus elemen-elemen antara “HITAM” dan “COKLAT”.
Baris 35 menampilkan senarai kembali, kemudian baris 36 memanggil metode TampilSenaraiTerbalik (baris 93-107)
untuk menampilkan senarai dalam tatanan terbalik.
Metode Sambung generik (baris 51-58) beriterasi menjelajah list2 dengan sebuah statemen foreach dan memanggil metode AddLast untuk menempatkan setiap nilai
ke ujung akhir dari list1.
Enumerator dari kelas LinkedList
beriterasi menjelajah nilai-nilai pada simpul-simpul, bukan pada simpul-simpul
itu sendiri, jadi variabel iterasi bertipe T.
Perhatikan bahwa hal ini menciptakan sebuah simpul baru pada list1 untuk setiap simpul pada list2. Satu LinkedListNode tidak bisa menjadi anggota dari lebih dari satu LinkedList. Jika Anda ingin data yang
sama dimiliki oleh lebih dari satu LinkedList,
maka Anda harus melakukan penyalinan simpul pada tiap senarai untuk menghindari
eksepsi InvalidOperationException.
Metode TampilSenarai generik (baris 40-48) menggunakan sebuah statemen foreach untuk beriterasi pada
nilai-nilai di dalam sebuah LinkedList,
dan menampilkannya. Metode KeStringHurufBesar
(baris 61-73) mengambil sebuah senarai berantai yang memuat string-string dan mengkonversi setiap nilai string tersebut menjadi huruf
besar. Metode ini mengganti string-string yang disimpan pada senarai, jadi
Anda tidak dapat menggunakan enumerator (melalui statemen foreach) seperti pada dua metode sebelumnya. Melainkan, Anda
mendapatkan LinkedListNode pertama
melalui properti First (baris 64),
dan menggunakan sebuah statemen while
untuk beriterasi menjelajah senarai (baris 66-72). Setiap iterasi pada statemen
while mendapatkan dan memperbarui
isi dari simpulSekarang melalui
properti Value, menggunakan metode ToUpper dari kelas string untuk menciptakan versi huruf besar dari string warna2. Di akhir tiap iterasi, Anda memajukan simpul sekarang ke
simpul berikutnya pada senarai berantai dengan menugaskan simpulSekarang kepada simpul yang diperoleh oleh properti Next-nya sendiri (baris 71). Properti Next pada simpul terakhir bernilai null, jadi ketika statemen while
beriterasi melewati akhir senarai berantai, loop akan berhenti.
Perhatikan bahwa tidak masuk akal untuk
mendeklarasikan KeStringHurufBesar
sebagai metode generik, karena ia menggunakan metode-metode spesifik string pada nilai tiap simpul. Metode TampilSenarai (baris 48-48) dan Sambung (baris 51-58) tidak menggunakan
satupun metode spesifik string, jadi
keduanya dapat dideklarasikan dengan parameter tipe generik untuk mempromosikan
pendaur-ulangan kode.
Metode HapusAntarItem generik (baris 76-90) menghapus sebuah rentang item
antara dua simpul. Baris 80-81 mendapatkan dua simpul batas pada rentang
menggunakan metode Find. Metode ini
melakukan pencarian linier pada senarai dan menghasilkan simpul pertama yang
memuat nilai yang sama dengan argumen yang dilewatkan. Metode Find menghasilkan null jika nilai tidak ditemukan.
Statemen while pada baris 85-89 menghapus semua elemen di antara simpulSekarang dan simpulAkhir. Pada tiap iterasi loop, Anda menghapus simpul yang
berada setelah simpulSekarang dengan
memanggil metode Remove (baris 88).
Metode Remove mengambil sebuah LinkedListNode, mengeluarkan simpul
tersebut dari LinkedList, dan
memperbaiki semua referensi yang ada disekitar simpul tersebut. Setelah
pemanggilan Remove, properti Next dari simpulSekarang sekarang mendapatkan simpul yang berada setelah
simpul yang baru saja dihapus, dan bahwa properti Prevous dari simpul tersebut sekarang mendapatkan simpulSekarang. Statemen while berlanjut beriterasi sampai tidak
ada lagi simpul yang tertinggal di antara simpulSekarang
dan simpulAkhir, atau sampai simpulSekarang merupakan simpul
terakhir pada senarai berantai.
Metode TampilSenaraiTerbalik (baris 93-107) menampilkan senarai berantai
secara mundur dengan menavigasi simpul-simpul secara manual. Baris 98
mendapatkan elemen terakhir pada senarai melalui properti Last dan menyimpannya di dalam simpulSekarang.
Statemen while pada baris 100-104
menjelajah senarai secara mundur dengan memajukan referensi simpulSekarang ke simpul sebelumnya
pada akhir tiap iterasi, kemudian keluar loop ketika Anda melewati awal
senarai. Perhatikan bagaimana kode ini mirip dengan kode pada baris 64-72, yang
beriterasi menjelajah senarai berantai dimulai dari awal sampai akhir senarai.
No comments:
Post a Comment