Friday, December 23, 2016

Bab 12. C++ Untuk Programer



Bab. 12 STL

Tujuan Instruksional
      ·         Kontainer: vector, list, dan deque.
      ·         Kontainer asosiatif: multiset, set, multimap, dan map.
      ·         Adapter kontainer: stack, queue, dan priority_queue.
      ·         Algoritma: fill, fill_in, generate, generate_n, equal, mismatch,       lexicographical_compare, remove, remove_if,      
             remove_copyremove_copy_if, replace, replace_if, replace_copy,         replace_copy_if.

Algoritma pencarian dan pengurutan.
swap, iter_swap, swap_ranges, copy_backward, merge, unique, reverse, inplace_merge, unique_copy, dan reverse_copy.






12.1 Introduksi

Standard Template Library (STL) mendefinisikan komponen-komponen berguna, berbasis-template, dan terdaur-ulang-kan yang mengimplementasikan beberapa struktur data dan algoritma untuk memproses data.

STL dikembangkan oleh Alexander Stepanov dan Meng Lee di Hawlett-Packard dan berbasis riset pemrograman generik mereka, dengan kontribusi signifikan dari David Musser. STL didesain untuk meningkatkan kinerja dan fleksibilitas. Bab ini akan mengintroduksi STL dan mendiskusikan tiga komponen kuncinya, yaitu kontainer (struktur data tertemplatisasi populer), iterator, dan algoritma. Kontainer STL merupakan struktur data yang mampu menyimpan objek-objek bertipe apapun (meski terdapat beberapa batasan). Ada tiga jenis kontainer, yaitu kontainer kelas-pertama, adapter, dan kontainer dekat.

Setiap kontainer STL memiliki beberapa fungsi anggota. Subhimpunan dari fungsi-fungsi anggota ini didefinisikan di dalam semua kontainer STL. Beberapa fungsionalitas umum dari kontainer STL akan diilustrasikan pada contoh yang berkaitan dengan vector, list, dan deque.

Iterator STL, yang memiliki kesamaan watak dengan pointer, digunakan oleh program untuk memanipulasi elemen-elemen kontainer STL. Array standard dapat juga dimanipulasi oleh algoritma STL, menggunakan pointer standard sebagai iterator. Akan Anda lihat bahwa pemanipulasian kontainer dengan iterator sangat membantu dan sangat berguna bila dikombinasikan dengan algoritma STL, dimana pada banyak kasus dapat mereduksi puluhan atau bahkan ratusan baris kode menjadi satu statemen tunggal. Terdapat lima kategori iterator yang akan didiskusikan nanti.

Algoritma STL terdiri-dari fungsi-fungsi yang melakukan pemanipulasian data seperti pencarian, pengurutan, dan pembandingan elemen-elemen atau keseluruhan elemen. STL menyediakan beberapa algoritma. Kebanyakan algoritma tersebut menggunakan iterator untuk mengakses elemen kontainer. Setiap algoritma mempunyai persyaratan minimum untuk tipe iterator yang akan digunakan. Anda akan melihat bahwa kontainer kelas-pertama mendukung beberapa tipe iterator spesifik. Tipe iterator yang didukung oleh suatu kontainer menentukan apakah kontainer tersebut dapat digunakan dengan algoritma tertentu. Iterator mengenkapsulasi mekanisme yang digunakan untuk mengakses elemen-elemen kontainer. Enkapsulasi ini membuat algoritma-algoritma STL dapat diterapkan di berbagai kontainer. Sepanjang iterator memenuhi persyaratan minimum dari algoritma, maka algoritma tersebut dapat memproses elemen-elemen kontainer. Hal ini tentu saja memampukan Anda untuk menciptakan algoritma baru.

12.2 Pengantar Kontainer

Tipe-tipe kontainer STL ditampilkan pada Gambar 12.1. Kontainer dibagi ke dalam tiga kategori utama, yaitu kontainer runtun, kontainer asosiatif, dan kontained adapter.

Gambar 12.1 Kelas Kontainer STL

Kelas Kontainer STL
Penjelasan
kontainer runtun
vector

deque


list

kontainer asosiatif
set

multiset

map

multimap


kontainer adapter
stack

queue

priority_queue
penyisipan dan penghapusan cepat dari belakang. Akses langsung ke semua elemen.

penyisipan dan penghapusan cepat dari belakang atau dari depan. Akses langsung ke semua elemen.

list berantai ganda, penyisipan dan penghapusan cepat di semua tempat.


pencarian cepat, duplikasi tidak diperkenankan.

pencarian cepat, duplikasi diperkenankan.

pemetaan satu-ke-satu, duplikasi tidak diperkenankan, pencarian cepat berbasis-kunci.

pemetaan satu-ke-satu, duplikasi diperkenankan, pencarian cepat berbasis-kunci.


last-in, first-out (LIFO)

first-in, first-out (FIFO)

elemen berprioritas tertinggi adalah elemen yang pertama keluar

Fungsionalitas Kontainer STL
Kebanyakan kontainer STL memiliki fungsionalitas yang mirip. Banyak operasi generik, seperti fungsi anggota size, dapat diterapkan terhadap semua kontainer, dan banyak operasi lainnya dapat diterapkan terhadap subhimpunan kontainter yang mirip. Gambar 12.2 mendeskripsikan beberapa fungsi umum yang berlaku untuk semua kontainer STL. Perhatikan bahwa operator-operator teroverload <, <=, >, >=, ==, dan != tidak disediakan untuk priority_queue.

Header Kontainer STL
Header untuk tiap kontainer STL ditampilkan pada Gambar 12.3. Isi semua header ini berada di dalam namespace std.

Kontainer Kelas-Pertama typedef
Gambar 12.4 menampilkan beberapa jenis typedef (untuk menciptakan sinonim atau nama alias bagi nama tipe yang panjang) yang ada di dalam kontainer kelas-pertama. Semua typedef ini digunakan di dalam deklarasi generik dari variabel, parameter untuk fungsi dan nilai balik dari fungsi. Sebagai contoh, value_type di dalam setiap kontainer selalu merupakan sebuah typedef yang merepresentasikan tipe elemen yang disimpan di dalam kontainer.

Gambar 12.2 Beberapa Fungi Anggota Kontainer STL

Fungsi Anggota
Penjelasan
konstruktor default



konstruktor penyalin atau pengganda


destruktor


empy


insert

size

operator=

operator<

operator<=


operator>

operator>=

operator==


operator!=

swap

fungsi-fungsi yang ditemukan di dalam kontainer kelas-pertama

max_size

begin

end


rbegin


rend


sebuah konstruktor yang menginisialisasi suatu kontainer kosong. Normalnya, setiap kontainer memiliki beberapa konstruktor yang menyediakan beberapa metode inisialisasi yang berbeda bagi kontainer.

sebuah konstruktor yang menginisialisasi kontainer dengan salinan dari suatu kontainer yang sudah ada dan bertipe sama.

destruktor berfungsi untuk membersihkan setelah sebuah kontainer tidak lagi dibutuhkan.

memberikan nilai balik true jika tidak terdapat elemen di dalam kontainer; sebaliknya, menghasilkan false.

menyisipkan sebuah item ke dalam kontainer.

memberikan nilai balik berupa jumlah elemen yang saat ini berada di dalam kontainer.

menugaskan satu kontainer kepada kontainer lainnya.

menghasilkan nilai balik true jika isi dari konten pertama kurang dari isi dari konten kedua; sebaliknya, menghasilkan false.

menghasilkan nilai balik true jika isi dari konten pertama kurang dari  atau sama dengan isi dari konten kedua; sebaliknya, menghasilkan false.

menghasilkan nilai balik true jika isi dari konten pertama lebih dari isi dari konten kedua; sebaliknya, menghasilkan false.

menghasilkan nilai balik true jika isi dari konten pertama lebih dari  atau sama dengan isi dari konten kedua; sebaliknya, menghasilkan false.

menghasilkan nilai balik true jika isi dari konten pertama sama dengan isi dari konten kedua; sebaliknya, menghasilkan false.

menghasilkan nilai balik true jika isi dari konten pertama tidak sama dengan isi dari konten kedua; sebaliknya, menghasilkan false.

menukar elemen-elemen dari dua kontainer.



memberikan nilai balik berupa jumlah elemen maksimum pada sebuah kontainer.

dua versi dari fungsi ini menghasilkan nilai balik berupa sebuah iterator atau const_iteratir yang menunjuk ke elemen pertama di dalam kontainer.

dua versi dari fungsi ini menghasilkan nilai balik berupa sebuah iterator atau const_iteratir yang menunjuk ke posisi berikutnya setelah akhir dari kontainer.

dua versi dari fungsi ini menghasilkan nilai balik berupa sebuah reverse_iterator atau const_reverse_iteratir yang menunjuk ke elemen terakhir dari kontainer.

dua versi dari fungsi ini menghasilkan nilai balik berupa sebuah reverse_iterator atau const_reverse_iteratir yang menunjuk ke posisi berikutnya setelah elemen terakhir pada kontainer.

Gambar 12.3 Header Kontainer STL

<vector>

<list>

<deque>

<queue>

<stack>

<map>

<set>

<valarray>

<bitset>






memuat queue dan priority_queue


memuat map dan multimap

memuat set dan multiset

Gambar 12.4 typedef di dalam Kontainer Kelas-Pertama

typedef
Penjelasan
allocator_type
value_type
reference
const_reference

pointer
const_pointer
iterator
const_iterator

reverse_iterator


const_reverse_iterator


difference_type

size_type
tipe objek yang digunakan untuk mengalokasikan memori kontainer.

tipe elemen yang disimpan di dalam kontainer.

referensi untuk tipe elemen kontainer.

referensi konstanta untuk tipe elemen kontainer. Referensi semacam ini dapat digunakan hanya untuk membaca elemen di dalam kontainer dan untuk melakukan operasi const.

pointer untuk tipe elemen kontainer.

pointer untuk sebuah konstanta dari tipe elemen kontainer.

iterator yang menunjuk ke sebuah elemen dari tipe elemen kontainer.

iterator konstanta yang menunjuk ke sebuah elemen dari tipe elem kontainer dan dapat digunakan hanya untuk membaca elemen.

iterator terbalik yang menunjuk ke sebuah elemen dari tipe elemen kontainer. Tipe iterator ini untuk beriterasi menjelajahi kontainer dengan arah terbalik.

iterator terbalik konstanta yang menunjuk ke sebuah elemen dari tipe elemen kontainer dan hanya dapat digunakan untuk membaca elemen. Tipe iterator ini untuk beriterasi menjelajahi kontainer dengan arah terbalik.

tipe yang dihasilkan dari pengurangan atas dua iterator yang menunjuk ke kontainer yang sama (operator – tidak didefinisikan untuk iterator dari list dan kontainer asosiatif).

tipe yang digunakan untuk menghitung item di dalam sebuah kontainer dan indeks untuk kontainer runtun.

Ketika mempersiapkan penggunaan suatu kontainer STL, adalah hal penting untuk memastikan bahwa tipe elemen yang sedang disimpan di dalam kontainer mendukung fungsionalitas yang diinginkan. Ketika sebuah elemen disisipkan ke dalam suatu kontainer, salinan dari elemen tersebut yang disisipkan. Karena alasan ini, tipe elemen harus menyediakan konstruktor penyalin dan operator penugasan sendiri. Juga, kontainer asosiatif dan banyak algoritma memerlukan pembandingan elemen. Untuk itu, tipe elemen harus menyediakan operator ekualitas (==) dan operator kurang-dari (<).

12.3 Pengantar Iterator
Iterator memiliki banyak kesamaan dengan pointer dan digunakan untuk menunjuk ke elemen-elemen kontainer kelas-pertama. Iterator menyimpan informasi yang sensitif dengan kontainer tertentu; oleh karena itu, iterator diimplementasikan berdasarkan tipe kontainer tertentu. Beberapa operasi iterator seragam di semua kontainer. Misalnya, operator dereferensi (*) mendereferensi sebuah iterator sehingga Anda dapat menggunakan elemen yang ditunjuk oleh iterator tersebut. Operasi ++ diterapkan pada iterator untuk menggesernya ke elemen berikutnya di dalam kontainer (sama seperti menginkremen pointer di dalam array untuk menunjuk elemen array berikutnya).

Kontainer STL kelas-pertama menyediakan fungsi begin dan end. Fungsi begin menghasilkan nilai balik berupa sebuah iterator yang menunjuk ke elemen pertama di dalam kontainer. Fungsi end menghasilkan nilai balik berupa sebuah iterator yang menunjuk ke elemen pertama setelah elemen terakhir di dalam kontainer (elemen yang belum ada). Jika iterator i menunjuk sebuah elemen tertentu, maka ++i akan menunjuk ke elemen berikutnya dan *i akan menunjuk ke elemen yang ditunjuk oleh i. Iterator yang dihasilkan dari end secara umum digunakan di dalam suatu perbandingan ekualitas atau inekualitas untuk menentukan apakah “iterator penggerak atau penggeser” (dalam hal ini adalah i) telah mencapai akhir kontainer atau tidak.

Sebuah objek bertipe iterator menunjuk ke suatu elemen kontainer yang dapat dimodifikasi. Sebuah objek bertipe const_interator menunjuk ke suatu elemen kontainer yang tidak dapat dimodifikasi.

Menggunakan istream_iterator untuk Masukan dan ostream_iterator untuk Keluaran
Akan digunakan iterator dengan runtun. Runtun ini bisa berada di dalam kontainer, atau dapat pula berupa runtun masukan atau runtun keluaran. Program pada Gambar 12.5 mendemonstrasikan masukan dari masukan standard (runtun data untuk masukan ke dalam program) menggunakan istream_iterator, dan keluaran ke keluaran standard (runtun data untuk keluaran dari program) menggunakan ostream_iterator. Program memasukkan dua integer dari papanketik dan menampilkan hasil penjumlahan atas kedua integer tersebut. Seperti yang akan Anda lihat nanti pada bab ini, istream_iterator dan ostream_iterator dapat digunakan dengan algoritma-algoritma STL untuk menciptakan statemen berguna. Sebagai contoh, Anda dapat menggunakan ostream_iterator dengan algoritma copy untuk menyalin isi sebuah kontainer ke aliran (stream) keluaran standard dengan satu statemen tunggal.

Gambar 12.5 Mendemonstrasikan masukan dan keluaran dengan iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Gambar 12.5: gambar12_05.cpp
// Mendemonstrasikan masukan dan keluaran dengan iterator.
#include <iostream>
#include <iterator> // ostream_iterator and istream_iterator
using namespace std;

int main()
{
  cout << "Masukkan dua integer: ";

  // menciptakan istream_iterator untuk membaca nilai-nilai int dari cin
  istream_iterator< int > inputInt( cin );

  int angka1 = *inputInt; // membaca int dari masukan standard
  ++inputInt; // menggeser iterator ke nilai masukan berikutnya
  int angka2 = *inputInt; // membaca int dari masukan standard

  // menciptakan ostream_iterator untuk menuliskan nilai-nilai int ke cout
  ostream_iterator< int > outputInt( cout );

  cout << "Penjumlahan atas kedua integer adalah: ";
  *outputInt = angka1 + angka2; // mengirim hasil ke cout
  cout << endl;
} // akhir dari main

Masukkan dua integer: 12 25
Penjumlahan atas kedua integer adalah 37

Baris 12 menciptakan sebuah istream_iterator yang mampu mengekstrak nilai-nilai int dari objek masukan standard, cin. Baris 14 mendereferensi iterator inputInt untuk membaca integer pertama dari cin dan menugaskan integer itu kepada angka1. Operator dereferensi * diterapkan terhadap iterator inputInt untuk mendapatkan nilai dari aliran yang terkait dengan inputInt; hal ini mirip dengan mendereferensi sebuah pointer. Baris 15 memposisikan iterator inputInt ke nilai berikutnya di dalam aliran masukan. Baris 16 memasukkan integer berikutnya dari inputInt dan menugaskannya kepada angka2.

Baris 19 menciptakan sebuah ostream_iterator yang mampu menyisipkan nilai-nilai int ke dalam objek keluaran standard, cout. Baris 22 menyisipkan sebuah integer ke dalam cout dengan menugaskan penjumlahan atas angka1 dan angka2 kepada *outputInt. Perhatikan bahwa operator dereferensi * pada *outputInt dipakai sebagai lvalue di dalam statemen penugasan. Jika Anda ingin menyisipkan nilai lain menggunakan outputInt, maka iterator itu harus diinkremen dengan ++ (prefiks dan postfiks inkremen dapat digunakan).

Hirarki Kategori Iterator
Gambar 12.6 menampilkan beberapa kategori iterator STL. Setiap kategori menyediakan sekelompok fungsionalitas. Gambar 12.7 mengilustrasikan hirarki dari kategori iterator. Seperti Anda perhatikan dari atas ke bawah hirarki, setiap kategori iterator mendukung semua fungsionalitas kategori di atasnya. Jadi, tipe iterator “terlemah” adalah tipe iterator yang berada di atas dan yang paling “kuat” adalah yang berada di bawah. Ingat bahwa hirarki ini bukanlah hirarki pewarisan.

Kategori iterator yang didukung oleh tiap kontainer menentukan apakah kontainer itu dapat digunakan dengan algoritma tertentu di dalam STL. Kontainer yang mendukung iterator random access (akses-acak) dapat digunakan dengan semua algoritma di dalam STL. Seperti yang akan Anda lihat, pointer ke array dapat dipakai menggantikan iterator di dalam hampir semua algoritma STL, termasuk menggantikan iterator random access. Gambar 12.8 menampilkan kategori iterator untuk tiap kontainer STL. Kontainer kelas-pertama (vector, deque, list, set, multiset, map, dan multimap), string dan array semuanya dapat dijelajahi oleh iterator.

Gambar 12.6 Kategori Iterator

Kategori
Penjelasan
input



output


forward


bidirectional


random access
digunakan untuk membaca sebuah elemen dari suatu kontainer. Iterator input hanya dapat menggerakkan hanya dengan arah maju (dari awal sampai akhir kontainer) satu elemen per waktu. Iterator input hanya mendukung algoritma one-pass, iterator input yang sama tidak dapat dipakai untuk melewati suatu runtun dua kali.

digunakan untuk menulis sebuah elemen ke dalam suatu kontainer. Iterator output bisa menggerakkan hanya dengan arah maju satu elemen per waktu. Iterator output hanya mendukung algoritma one-pass, iterator input yang sama tidak dapat dipakai untuk melewati suatu runtun dua kali.

menggabungkan kapabilitas iterator input dan iterator output dan memperoleh posisisnya di dalam kontainer (sebagai informasi keadaan).

menggabungkan kapabilitas suatu iterator forward dengan kemampuan untuk bergerak ke arah mundur (dari akhir ke awal kontainer). Iterator bidirectional mendukung algoritma multipass.

menggabungkan kapabilitas suatu iterator forward dengan kemampuan untuk mengakses secara langsung sembarang elemen di dalam kontainer, untuk melompat maju atau mundur sejauh sembarang jumlah elemen.

Gambar 12.7 Hirarki kategori iterator

Gambar 12.8 Tipe Iterator yang Didukung oleh Setiap Kontainer

Kontainer
Tipe iterator yang didukung
kontainer runtun (kelas-pertama)
vector
deque
list
kontainer asosiatif (kelas pertama)
set
multiset
map
multimap
adapter kontainer
stack
queue
priority_queue

random access
random access
bidirectional

bidirectional
bidirectional
bidirectional
bidirectional


-
-
-

Iterator typedef Terdefinisi
Gambar 12.9 menampilkan beberapa iterator typedef terdefinisi yang berada di dalam definisi-definisi kelas pada kontainer STL. Tidak setiap tydef didefinisikan untuk tiap kontainer. Digunakan versi const dari iterator untuk menjelajahi kontainer read-only. Digunakan iterator terbalik untuk menjelajahi iterator dengan arah terbalik.

Gambar 12.9 Iterator typedef

typedef terdefinisi untuk tipe-tipe iterator
Arah dari ++
Kapabilitas
iterator

const_iterator

reverse_iterator

const_reverse_iterator
forward

forward

backward

backward
read/write

read

read/write

read

Operasi Iterator
Gambar 12.10 menampilkan beberapa operasi yang dapat dilakukan pada tiap tipe iterator. Untuk iterator input dan ouput, adalah hal yang tidak mungkin untuk menyimpan iterator kemudian menggunakannya nilai yang tersimpan di kemudian waktu.

Gambar 12.10 Operasi-Operasi Iterator untuk Tiap Tipe Iterator

Operasi iterator
Penjelasan
semua iterator
++p
p++
iterator input
*p
p = p1
p == p1
p != p1
iterator output
*p
p = p1

iterator forward

iterator bidirectional
--p
p—
iterator random access
p += i
p -= i
p + i atau i + p

p – i


p – p1


p[i]


p < p1

p <= p1


p > p1

p >= p1


melakukan preinkremen terhadap sebuah iterator.
melakukan postinkremen terhadap sebuah iterator.

mendereferensi sebuah iterator.

menugaskan satu iterator kepada iterator lainnya.

membandingkan iterator untuk ekualitas.

membandingkan iterator untuk inekualitas.

mendereferensi sebuah iterator.

menugaskan satu iterator kepada iterator lainnya.

iterator forward menyediakan semua fungsionalitas kedua iterator input dan iterator output.

melakukan predekremen terhadap sebuah iterator.
melakukan postdekremen terhadap sebuah iterator.

menginkreman iterator p sejauh i posisi.
mendekremen iterator p sejauh i posisi.

nilai ekspresi adalah sebuah iterator diposisikan pada p yang diinkremen sejauh i posisi.
nilai ekspresi adalah sebuah iterator diposisikan pada p yang didekremen sejauh i posisi.

nilai ekspresi merupakan sebuah integer yang merepresentasikan jarak antara dua elemen di dalam kontainer yang sama.

memberikan nilai balik berupa sebuah referensi ke elemen beroffset dari p sejauh i posisi.

memberikan nilai balik true jika iterator p kurang dari iterator p1 (iterator p berada sebelum iterator p1 di dalam kontainer); sebaliknya, menghasilkan false.

memberikan nilai balik true jika iterator p kurang dari  atau sama dengan iterator p1 (iterator p berada sebelum atau berada di lokasi yang sama dengan iterator  p1 di dalam kontainer); sebaliknya, menghasilkan false.

memberikan nilai balik true jika iterator p lebih dari iterator p1 (iterator p berada setelah iterator p1 di dalam kontainer); sebaliknya, menghasilkan false.

memberikan nilai balik true jika iterator p lebih dari  atau sama dengan iterator p1 (iterator p berada setelah atau berada di lokasi yang sama dengan iterator  p1 di dalam kontainer); sebaliknya, menghasilkan false.

12.4 Pengantar Algoritma
Algoritma STL dapat dipakai secara generik pada berbagai kontainer. STL menyediakan banyak algoritma yang seringkali akan Anda pakai untuk memanipulasi kontainer. Penyisipan, penghapusan, pencarian, pengurutan, dan lainnya merupakan sebagain dari pemanipulasian kontainer.

STL menyertakan beberapa algoritma standard. Akan ditunjukkan beberapa di antaranya pada bab ini. Algoritma STL beroperasi pada elemen-elemen kontainer hanya bisa mengakses secara tak-langsung melalui iterator. Banyak algoritma beroperasi pada runtun elemen yang didefinisikan oleh sepasang iterator, satu iterator menunjuk ke elemen pertama runtun dan satu iterator lainnya menunjuk ke satu elemen setelah elemen terakhir. Juga, adalah hal yang memungkinkan untuk menciptakan algoritma Anda sendiri yang beroperasi dengan gaya sama sehingga dapat digunakan dengan kontainer STL dan iterator.

Gambar 12.11 Beberapa Algoritma STL Pemodifikasi Runtun

Beberapa algoritma STL
copy
copy_backward
fill
fill_n
generate
generate_n
iter_swap
partition
random_shuffle
remove
remove_copy
remove_copy_if
remove_if
replace
replace_copy
replace_copy_if
replace_if
reverse
reverse_copy
rotate
rotate_copy
stable_partition
swap
swap_ranges
transform
unique
unique_copy

Algoritma seringkali menjadikan iterator sebagai nilai balik yang mengindikasikan hasil algoritma tersebut. Algoritma find, misalnya, mencari lokasi sebuah elemen dan memberikan nilai balik berupa sebuah iterator yang menunjuk ke elemen tersebut. Jika elemen yang dicari tidak ditemukan, maka find akan menghasilkan nilai balik berupa iterator yang menunjuk ke satu elemen setelah elemen terakhir, yang dilewatkan untuk mendefinisikan akhir rentang yang dicari. Algoritma find dapat digunakan dengan sembarang kontainer kelas-pertama. Algoritma STL menciptakan peluang untuk mendaur-ulang kode, sehingga Anda dapat menghemat waktu pengembangan program.

Sebuah algoritma dapat digunakan dengan kontainer yang mendukung sedikitnya persyaratan iterator minimum. Beberapa iterator menuntut iterator yang kuat; misalnya, algoritma sort menuntut iterator random-access.

Gambar 12.11 menampilkan beberapa algoritma STL, yaitu algoritma yang menghasilkan pemodifikasian kontainer.

Gambar 12.12 Beberapa Algoritma STL Non-Pemodifikasi Runtun

Beberapa algoritma STL Non-Pemodifikasi Runtun
adjacent_find
count
count_if
equal
find
find_each
find_end
find_first_of
find_if
mismatch
search
searc_n

Gambar 12.12 menampilkan beberapa algoritma STL pemodifikasi runtun, yaitu algoritma yang tidak menghasilkan pemodifikasian kontainer. Gambar 12.13 menampilkan beberapa algoritma numerik dari header <numeric>.

Gambar 12.13 Beberapa Algoritma STL Numerik dalam header <numeric>

Beberapa algoritma STL Numerik
accumulate
inner_product
partial_sum
adjacent_difference

12.5 Kontainer Runtun
STL menyediakan tiga kontainer runtun, yaitu vector, list, dan deque. Template kelas vector dan template kelas deque keduanya didasarkan pada array. Template kelas list mengimplementasikan sebuah struktur data list-berantai.

Salah satu kontainer yang paling populer di dalam STL adalah vector. Sebuah vector dapat mengubah ukurannya secara dinamis. Tidak seperti array biasa di dalam C atau C++, vector dapat ditugaskan satu sama lain. Hal ini tidak mungkin dilakukan pada array C yang berbasis pointer, karena nama array merupakan pointer konstanta sehingga tidak bisa dilakukan penugasan. Sama seperti array C, subskript dari vector tidak melakukan pengecekan rentang secara otomatis, tetapi template kelas vector menyediakan kapabilitas ini melalui fungsi anggota at.

Gambar 12.2 telah menyajikan beberapa operasi yang dapat diterapkan pada semua kontainer. Di luar operasi tersebut, secara umum setiap kontainer menyediakan berbagai kapabilitas lain. Banyak kapabilitas ini berlaku untuk beberapa kontainer, tetapi tidak semuanya sama efisiennya untuk tiap kontainer. Anda harus memilih kontainer yang paling sesuai dengan aplikasi Anda.

Selain operasi yang dideskripsikan pada Gambar 12.2, kontainer runtun mempunya beberapa operasi lainnya, seperti front untuk menghasilkan nilai balik berupa sebuah referensi ke elemen pertama di dalam suatu kontainer tak-kosong, push_back untuk menyisipkan suatu elemen baru ke ujung akhir sebuah kontainer, back untuk menghasilkan nilai balik berupa sebuah referensi ke elemen terakhir di dalam suatu kontainer tak-kosong, dan pop_back untuk menghapus elemen terakhir di dalam sebuah kontainer.

12.5.1 Kontainer Runtun vector
Template kelas vector menyediakan suatu struktur data dengan lokasi-lokasi memori yang bertetangga. Hal ini membuat akses langsung menjadi efisien ke sembarang elemen melalui sebuah vektor menggunakan operator subskript [ ], sama seperti array pada C atau C++. Template kelas vector paling banyak digunakan ketika data di dalam kontainer dapat dengan mudah diakses melalui sebuah subskript. Ketika memori vector telah penuh, vector mengalokasikan area memori bertetangga yang lebih besar, menyalin semua elemen awal ke memori baru dan membebaskan memori lama.

Bagian penting dari setiap kontainer adalah tipe iterator yang didukung. Ini menentukan algoritma mana yang dapat diterapkan terhadap kontainer. Sebuah vector mendukung iterator random-access, jadi semua operasi iterator pada Gambar 12.10 dapat diterapkan terhadap iterator vector. Semua algoritma STL dapat beropasi pada sebuah vector. Iterator untuk sebuah vector kadangkala diimplementasikan sebagai pointer yang menunjuk ke elemen-elemen vector. Setiap algoritma STL yang mengambil iterator sebagai argumen mensyaratkan bahwa iterator tersebut harus menyediakan suatu level fungsionalitas minimum. Jika suatu algoritma mensyaratkan sebuah iterator forward, misalnya, maka algoritma itu dapat beroperasi pada sembarang kontainer yang menyediakan iterator forward, iterator bidirectional, atau iterator random-access. Sepanjang kontainer mendukung fungsionalitas iterator minimum pada algoritma, maka algoritma tersebut dapat beroperasi pada kontainer tersebut.

Menggunakan Vektor dan Iterator
Gambar 21.14 mengilustrasikan beberapa fungsi dari template kelas vector. Banyak dari fungsi-fungsi ini tersedia di dalam setiap kontainer kelas-pertama. Anda harus menyertakan header <vector> untuk menggunakan template kelas vector.

Baris 14 mendefinisikan sebuah instans bernama integers dari template kelas vector yang menyimpan nilai-nilai int. Ketika objek ini diinstansiasi, maka sebuah vector kosong diciptakan dengan ukuran 0 (jumlah elemen yang disimpan di dalam vector) dan kapasitas 0 (jumlah elemen yang dapat disimpan tanpa mengalokasikan memori tambahan kepada vector).

Baris 16 dan 17 mendemonstrasikan fungsi size dan capacity; setiap fungsi awalnya memberikan nilai balik 0 untuk vector v pada contoh ini. Fungsi size, tersedia bagi setiap kontainer, memberikan nilai balik berupa jumlah elemen yang saat ini disimpan di dalam kontainer. Fungsi capacity memberikan nilai balik berupa jumlah elemen yang dapat disimpan di dalam vector sebelum vector secara dinamis perlu mengekspansi dirinya untuk mengakomodasi elemen tambahan.

Gambar 12.14 Mendemonstrasikan Template Kelas vector STL

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
// Gambar 12.14: gambar12_14.cpp
// Mendemonstrasikan template kelas vector STL.
#include <iostream>
#include <vector> // definisi tempalte-kelas vector
using namespace std;

// prototipe untuk template fungsi tampilVektor
template < typename T > void tampilVektor( const vector< T > &integers2 );

int main()
{
  const int UKURAN = 6; // mendefinisikan ukuran array
  int array[ UKURAN ] = { 1, 2, 3, 4, 5, 6 }; // menginisialisasi array
  vector< int > integers; // menciptakan vektor yang memuat nilai-nilai int

  cout << "Ukuran awal vektor adalah: " << integers.size()
    << "\nKapasitas awal vektor adalah: " << integers.capacity();

  // fungsi push_back berada di dalam setiap kontainer runtun
  integers.push_back( 2 );
  integers.push_back( 3 );
  integers.push_back( 4 );

  cout << "\nUkuran vektor adalah: " << integers.size()
    << "\nKapasitas vektor adalah: " << integers.capacity();
  cout << "\n\nMenampilkan array menggunakan notasi pointer: ";

  // menampilkan array menggunakan notasi pointer
  for ( int *ptr = array; ptr != array + UKURAN; ++ptr )
    cout << *ptr << ' ';

  cout << "\nMenampilkan vektor menggunakan notasi iterator: ";
  tampilVektor( integers );
  cout << "\nIsi vektor terbalik adalah: ";

  // dua iterator const reverse
  vector< int >::const_reverse_iterator reverseIterator;
  vector< int >::const_reverse_iterator tempIterator = integers.rend();

  // menampilkan vektor dengan urutan terbalik menggunakan reverse_iterator
  for ( reverseIterator = integers.rbegin();
    reverseIterator!= tempIterator; ++reverseIterator )
    cout << *reverseIterator << ' ';

  cout << endl;
} // akhir dari main

// template fungsi untuk menampilkan elemen-elemen vektor
template < typename T > void tampilVektor( const vector< T > &integers2 )
{               
  typename vector< T >::const_iterator constIterator; // const_iterator

  // menampilkan elemen-elemen vektor menggunakan const_iterator
  for ( constIterator = integers2.begin();
    constIterator != integers2.end(); ++constIterator )
    cout << *constIterator << ' ';
} // akhir dari fungsi tampilVektor

Ukuran awal vektor adalah: 0
Kapasitas awal vektor adalah: 0
Ukuran vektor adalah: 3
Kapasitas vektor adalah: 4

Menampilkan array menggunakan notasi pointer: 1 2 3 4 5 6
Menampilkan vektor menggunakan notasi iterator: 2 3 4
Isi vektor terbalik adalah: 4 3 2

Baris 20-22 menggunakan fungsi push_back, tersedia di dalam semua kontainer runtun, untuk menambahkan sebuah elemen ke ujung akhir vector. Jika sebuah elemen ditambahkan ke dalam sebuah vector yang telah penuh, maka vector tersebut akan menambah ukurannya, beberapa implementasi STL menggandakan dua kali lipat kapasitas vector.

Baris 24 dan 25 menggunakan size dan capacity untuk mengilustrasikan ukuran dan kapasitas baru vector setelah tiga operasi push_bach diterapkan. Fungsi size menghasilkan nilai balik 3, jumlah elemen yang ditambahkan ke dalam vector. Fungsi capacity menghasilkan nilai balik 4, mengindikasikan bahwa Anda dapat menambahkan satu elemen tambahan lagi sebelum vector mengekspansi memorinya. Ketika elemen pertama ditambahkan, vector mengalokasikan memori untuk satu elemen, dan ukuran menjadi 1 untuk mengindikasikan bahwa vector hanya memuat satu elemen. Ketika elemen kedua ditambahkan, kapasitasnya digandakan menjadi 2 dan ukuran menjadi 2. Ketika elemen ketiga ditambahkan, kapasitas dilipat-duakan lagi menjadi 4. Jadi sebenarnya Anda dapat menambahkan satu elemen lagi sebelum vector melipat-gandakan kapasitasnya. Ketika akhirnya vector memenuhi kapasitas yang teralokasi dan program mencoba untuk menambahkan satu elemen baru ke dalam vector, maka vector akan melipat-duakan kapasitasnya menjadi 8.

Baris 29-30 mendemonstrasikan bagaimana menampilkan isi sebuah array menggunakan pointer dan aritmatika pointer. Baris 33 memanggil fungsi tampilVektor (deidefinisikan pada baris 49-57) untuk menampilkan isi sebuah vector menggunakan iterator. Template fungsi tampilVektor menerima sebuah referensi const yang menunjuk kepada sebuah vector (integers2) sebagai argumennya. Baris 51 mendefinisikan sebuah const_iterator memanggil constIterator yang beriterasi menjelajahi vector dan menampilkan isinya. Perhatikan bahwa deklarasi pada baris 51 diprefiks dengan katakunci typename.

Karena tampilVektor merupakan sebuah template fungsi dan vector<T> akan dispesialisasi secara berbeda untuk tiap spesialisasi template fungsi, kompiler tidak dapat memberitahu pada saat waktu kompilasi apakah vector<T>::const_iterator sebuah tipe atau tidak. Pada suatu spesialisasi tertentu, const_iterator bisa jadi berupa sebuah variabel static. Kompiler memerlukan informasi ini untuk mengkompilasi program secara tepat. Oleh karena itu, Anda harus memberitahu kompiler bahwa nama yang dikualifikasi, ketika pengkualifikasi merupakan sebuah tipe independen, adalah sebuah tipe di dalam setiap spesialisasi.

Sebuah const_iterator memampukan program untuk membaca elemen-elemen dari vector, tetapi ia tidak mengijinkan program untuk memodifikasi elemen-elemen tersebut. Statemen for pada baris 54-56 menginisialisasi constIterator menggunakan fungsi anggota begin, yang menghasilkan nilai balik berupa sebuah const_iterator untuk elemen pertama di dalam vector. Sebuah const_iterator dijadikan nilai balik karena pengenal integers2 telah dideklarasikan const di dalam daftar parameter pada fungsi tampilVektor. Loop terus beriterasi sepanjang constIterator tidak meraih ujung akhir vector. Hal ini dilakukan dengan membandingkan constIterator dengan hasil dari integers.end(), yang menghasilkan sebuah iterator yang mengindikasikan lokasi satu elemen setelah elemen terakhir di dalam vector. Jika constIterator sama dengan nilai ini, maka ujung akhir vector telah diraih. Fungsi begin dan end tersedia untuk semua kontainer kelas-pertama. Tubuh loop melakukan dereferensi terhadap iterator constIterator untuk mendapatkan nilai di dalam elemen sekarang pada vector. Ingat bahwa iterator berperilaku seperti pointer yang menunjuk ke elemen dan bahwa operator * dioverload untuk menghasilkan sebuah referensi yang menunjuk ke elemen. Ekspresi ++constIterator (baris 55) memposisikan iterator ke elemen berikutnya di dalam vector.

Baris 37 mendeklarasikan sebuah const_reverse_iterator yang dapat digunakan untuk beriterasi dengan arah mundur di dalam vector. Baris 38 mendeklarasikan sebuah variabel const_reverse_iterator, tempIterator, dan menginisialisasinya dengan iterator yang dijadikan nilai balik oleh fungsi rend. Semua kontainer kelas-pertama mendukung tipe iterator ini. Baris 42-43 menggunakan statemen for, seperti yang ada di dalam fungsi tampilVektor untuk beriterasi menjelajahi vector. Fungsi begin dan end, rbegin dan rend dapat menghasilkan nilai balik berupa sebuah const_reverse_iterator atau berupa sebuah reverse_iterator, tergantung apakah kontainer konstanta atau tidak.

Fungsi Pemanipulas-ELemen Vektor
Gambar 12.15 mengilustrasikan beberapa fungsi yang memampukan penarikan dan pemanipulasian elemen-elemen sebuah vector. Baris 15 menggunakan konstruktor vector teroverload yang mengambil dua iterator sebagai argumen untuk menginisialisasi integers. Baris 15 menginisialisasi integers dengan isi array dari lokasi array sampai lokasi array + UKURAN.

Gambar 12.15 Menguji Fungsi Pemanipulasi Elemen

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
// Gambar 12.15: gambar12_15.cpp
// Menguji template kelas fungsi-fungsi pemanipulasi-elemen
// di dalam kelas vector STL.
#include <iostream>
#include <vector> // definisi template-kelas vector
#include <algorithm> // algoritma copy
#include <iterator> // iterator ostream_iterator
#include <stdexcept> // eksepsi out_of_range
using namespace std;

int main()
{
  const int UKURAN = 6;
  int array[ UKURAN ] = { 1, 2, 3, 4, 5, 6 };
  vector< int > integers( array, array + UKURAN );
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor integers memuat: ";
  copy( integers.begin(), integers.end(), output );

  cout << "\nElemen pertama vektor integers: " << integers.front()
   << "\nElemen terakhir vektor integers: " << integers.back();

  integers[ 0 ] = 7; // menetapkan elemen pertama menjadi 7
  integers.at( 2 ) = 10; // menetapkan elemen pada posisi 2 menjadi 10

  // menyisipkan 22 pada elemen kedua
  integers.insert( integers.begin() + 1, 22 );

  cout << "\n\nIsi vektor integers setelah perubahan: ";
  copy( integers.begin(), integers.end(), output );

  // mengakses elemen di luar rentang
  try
  {
    integers.at( 100 ) = 777;
  } // akhir dari try
  catch( out_of_range &outOfRange )// eksepsi out_of_range
  {
    cout << "\n\nEksepsi: " << outOfRange.what();
  } // akhir dari catch

  // menghapus elemen pertama
  integers.erase( integers.begin() );
  cout << "\n\nVektor integers setelah penghapusan elemen pertama: ";
  copy( integers.begin(), integers.end(), output );

  // menghapus elemen-elemen yang lain
  integers.erase( integers.begin(), integers.end() );
  cout << "\nSetelah menghapus semua elemen, vektor integers "
    <<( integers.empty() ?"menjadi" : "menjadi tidak" ) << " kosong";

  // menyisipkan elemen-elemen dari array
  integers.insert( integers.begin(), array, array + UKURAN );
  cout << "\n\nIsi vektor integers sebelum penghapusan: ";
  copy( integers.begin(), integers.end(), output );

  // vektor integers kosong; clear menghapus semuanya
  integers.clear();
  cout << "\nSetelah penghapusan, vektor integers "
   <<( integers.empty() ?"menjadi" : "menjadi tidak" ) << " kosong" << endl;
} // akhir dari main

Vektor integers memuat: 1 2 3 4 5 6
Elemen pertama vektor integers: 1
Elemen terakhir vektor integers: 6

Isi vektor integers setelah perubahan: 7 22 2 10 4 5 6

Eksepsi: invalid vector<T> subscript

Vektor integers setelah penghapusan elemen pertama: 22 2 10 4 5 6
Setelah menghapus semua elemen, vektor integers menjadi kosong
Isi vektor integers sebelum penghapusan: 1 2 3 4 5 6
Setelah penghapusan vektor integers menjadi kosong

Baris 16 mendefinisikan sebuah ostream_iterator, dinamakan output, yang dapat digunakan untuk menampilkan integer-integer dipisahkan oleh spasi melalui cout. Sebuah ostream_iterator merupakan mekanisme yang hanya menampilkan nilai-nilai tipe int atau tipe kompatibelnya. Argumen pertama dari konstruktor menspesifikasi aliran keluaran, dan argumen kedua adalah sebuah string yang menspesifikasi separator atau pemisah keluaran (nilai-nilai integer), dalam kasus ini, string memuat karakter spasi. Digunakan ostream_iterator (yang didefinisikan di dalam header <iterator>) untuk menampilkan isi vector pada contoh ini.

Baris 19 menggunakan algoritma copy dari STL untuk menampilkan keseluruhan isi vector integers. Algoritma copy menyalin setiap elemen di dalam kontainer mulai dari lokasi yang dispesifikasi oleh iterator di dalam argumen pertamanya dan berlanjut sampai lokasi yang dispesifikasi di dalam argumen keduanya. Elemen-elemen disalin ke lokasi yang dispesifikasi oleh iterator output pada argumen terakhir. Untuk menggunakan algoritma-algoritma STL, Anda harus menyertakan header <algorithm>.

Baris 21-22 menggunakan fungsi front dan back (tersedia untuk semua kontainer runtun) untuk menentukan elemen pertama dan terakhir dari vector. Perhatikan bahwa perbedaan antara fungsi front dan begin. Fungsi front menghasilkan sebuah referensi ke elemen pertama di dalam vector, sedangkan fungsi begin menghasilkan sebuah iterator random access yang menunjuk ke elemen pertama di dalam vector. Perhatikan pula perbedaan antara fungsi back dan end. Fungsi back menghasilkan sebuah referensi ke elemen terakhir di dalam vector, sedangkan fungsi end menghasilkan sebuah iterator random access yang menunjuk ke ujung akhir vector (lokasi satu elemen setelah elemen terakhir).

Baris 24-25 mengilustrasikan dua cara untuk mensubskript sebuah vector (yang juga dapat dilakukan terhadap deque). Baris 24 menggunakan operator yang telah dioverload untuk menghasilkan sebuah referensi ke nilai pada lokasi tertentu atau menghasilkan sebuah referensi konstanta yang menunjuk ke nilai tersebut, tergantung dari apakah kontainer konstanta atau tidak. Fungsi at (baris 25) melakukan operasi yang sama, tetapi dengan pemeriksaan rentang. Fungsi at pertama-tama memeriksa nilai yang disuplai sebagai argumen dan menentukan apakah ia berada di dalam rentang vector atau tidak. Jika tidak, fungsi at akan melempar sebuah eksepsi out_of_range yang didefinisikan di dalam header <stdexcept> (seperti didemonstrasikan pada baris 34-41). Gambar 12.16 menunjukkan beberapa tipe eksepsi STL.

Gambar 12.16 Beberapa Tipe Eksepsi STL

Tipe Eksepsi STL
Penjelasan
out_of_range

invalid_argument

length_error

bad_alloc
mengindikasikan bahwa subskript di luar rentang, misalnya, ketika sebuah subskript tak-valid dispesifikasi untuk vector pada fungsi anggota at.

mengindikasikan sebuah argumen tak-valid yang dilewatkan ke suatu fungsi.

mengindikasikan sebuah percobaan untuk menciptakan kontainer, string, atau lainnya yang terlalu panjang.

mengindikasikan bahwa sebuah percobaan untuk mengalokasikan memori menggunakan new (atau dengan sebuah alokator) telah gagal karena tidak tersedia memori yang cukup.

Baris 28 menggunakan salah satu dari tiga fungsi insert teroverload yang disediakan oleh setiap kontainer runtun. Baris 28 menyisipkan nilai 22 di depan elemen pada lokasi yang dispesifikasikan oleh iterator pada argumen pertamanya. Pada contoh ini, iterator menunjuk ke elemen kedua vector, jadi 22 disisipkan sebagai elemen kedua dan elemen kedua yang asli menjadi elemen ketiga di dalam vector. Versi lain dari insert memampukan penyisipan salinan jamak dari nilai yang sama dimulai pada posisi tertentu di dalam kontainer, atau menyisipkan rentang nilai dari kontainer (atau array) lain, dimulai dari posisi tertentu.

Baris 44 dan 49 menggunakan dua fungsi erase yang tersedia bagi semua kontainer kelas-pertama. Baris 44 mengindikasikan bahwa elemen pada lokasi yang dispesifikasi oleh argumen iterator harus dibuang dari kontainer (pada contoh ini, elemen pada awal vector). Baris 49 menspesifikasi bahwa semua elemen di dalam rentang, mulai dari lokasi argumen pertama sampai lokasi argumen kedua (tetapi tidak termasuk elemen pada lokasi yang dispesifikasi oleh argumen kedua) harus dihapus dari kontainer. Baris 51 menggunakan fungsi empty (tersedia bagi semua kontainer dan adapter) untuk memastikan apakah vector kosong atau tidak.

Baris 54 mendemonstrasikan versi fungsi insert yang menggunakan argumen kedua dan ketiga untuk menspesifikasi lokasi awal dan lokasi akhir di dalam sebuah runtun nilai (bisa saja dari kontainer lain; pada kasus ini, dari array yang memuat integer, array)  yang harus disisipkan ke dalam vector. Ingat bahwa lokasi akhir menspesifikasi posisi, di dalam runtun, setelah elemen terakhir disisipkan. Terakhir, baris 59 menggunakan fungsi clear (yang berada di dalam semua kontainer kelas-pertama) untuk mengosongkan vector. Fungsi ini memanggil versi erase yang digunakan pada baris 51 untuk mengosongkan vector.

12.5.2 Kontainer Runtun list
Kontainer runtun list menyediakan implementasi efisien untuk operasi penyisipan dan penghapusan pada sembarang lokasi di dalam kontainer. Jika kebanyakan penyisipan dan penghapusan terjadi di ujung akhir kontainer, maka struktur data deque lah yang dipakai karena menyediakan implementasi yang lebih efisien. Template kelas list diimplementasikan sebagai list-berantai ganda, dimana setiap simpul di dalam list memuat sebuah pointer ke simpul sebelumnya di dalam list dan ke simpul berikutnya di dalam list. Hal ini memampukan template kelas list untuk mendukung iterator bidrectional (dua-arah) sehingga kontainer dapat dijelalahi dengan arah maju dan arah mundur. Setiap algoritma yang memerlukan iterator input, iterator output, atau iterator bidirectional dapat beroperasi pada sebuah list. Tersedia banyak fungsi anggota list yang dapat memanipulasi elemen-elemen kontainer sebagai himpunan elemen terurut.

Template kelas list juga menyediakan sembilan fungsi anggota, yaitu splice, push_front, pop_front, remove, remove_if, unique, merge, reverse, dan sort. Beberapa dari fungsi anggota ini diimplementasikan dengan teroptimasi-list. Gambar 12.17 mendemonstrasikan beberap fitur kelas list. Ingat bahwa beberapa fungsi yang disajikan pada Gambar 12.14 - 12.15 dapat dipakai dengan kelas list. Header <list> harus dicantumkan untuk mengunakan kelas list.

Gambar 12.17 Menguji Template Kelas list STL

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
// Gambar 12.17: gambar12_17.cpp
// Menguji template kelas list STL.
#include <iostream>
#include <list> // definisi template kelas list
#include <algorithm> // algoritma copy
#include <iterator> // ostream_iterator
using namespace std;

// prototipe untuk fungsi tampilList
template < typename T > void tampilList( const list< T > &listRef );

int main()
{
  const int UKURAN = 4;
  int array[ UKURAN ] = { 2, 6, 4, 8 };
  list< int > nilai2; // menciptakan list yang memuat nilai-nilai int
  list< int > nilai2Lain; // menciptakan list yang memuat nilai-nilai int

  // menyisipkan beberapa item ke dalam nilai2
  nilai2.push_front( 1 );
  nilai2.push_front( 2 );
  nilai2.push_back( 4 );
  nilai2.push_back( 3 );

  cout << "nilai2 memuat: ";
  tampilList( nilai2 );

  nilai2.sort(); // mengurutkan nilai2
  cout << "\nnilai2 setelah pengurutan memuat: ";
  tampilList( nilai2 );

  // menyisipkan elemen-elemen array ke dalam nilai2Lain
  nilai2Lain.insert( nilai2Lain.begin(), array, array + UKURAN );
  cout << "\nSetelah penyisipan, nilai2Lain memuat: ";
  tampilList( nilai2Lain );

  // menghapus elemen-elemen nilai2Lain dan menyisipkannya di ujung nilai2
  nilai2.splice( nilai2.end(), nilai2Lain );
  cout << "\nSetelah splice, nilai2 memuat: ";
  tampilList( nilai2 );

  nilai2.sort(); // mengurutkan nilai2
  cout << "\nSetelah pengurutan, nilai2 memuat: ";
  tampilList( nilai2 );

  // menyisipkan elemen-elemen array ke dalam nilai2Lian
  nilai2Lain.insert( nilai2Lain.begin(), array, array + UKURAN );
  nilai2Lain.sort();
  cout << "\nSetelah penyisipan dan pengurutan, nilai2Lain memuat: ";
  tampilList( nilai2Lain );

  // menghapus elemen-elemen nilai2Lain dan menyisipkan ke nilai2 dengan terurut
  nilai2.merge( nilai2Lain );
  cout << "\nSetelah merge:\n nilai2 memuat: ";
  tampilList( nilai2 );
  cout << "\n nilai2Lain memuat: ";
  tampilList( nilai2Lain );

  nilai2.pop_front(); // menghapus elemen dari depan
  nilai2.pop_back(); // menghapus elemen dari belakang
  cout << "\nSetelah pop_front dan pop_back:\n nilai2 memuat: ";
  tampilList( nilai2 );

  nilai2.unique(); // menghapus elemen duplikat
  cout << "\nSetelah unique, nilai2 memuat: ";
  tampilList( nilai2 );

  // menukar elemen-elemen nilai2 dan nilai2Lain
  nilai2.swap( nilai2Lain );
  cout << "\nSetelah swap:\n nilai2 memuat: ";
  tampilList( nilai2 );
  cout << "\n nilai2Lain memuat: ";
  tampilList( nilai2Lain );

  // menggantikan isi nilai2 dengan elemen-elemen nilai2Lain
  nilai2.assign( nilai2Lain.begin(), nilai2Lain.end() );
  cout << "\nSetelah assign, nilai2 memuat: ";
  tampilList( nilai2 );

  // menghapus elemen-elemen nilai2Lain dan menyisipkannya ke nilai2 dengan terurut
  nilai2.merge( nilai2Lain );
  cout << "\nSetelah merge, nilai2 memuat: ";
  tampilList( nilai2 );

  nilai2.remove( 4 ); // menhapus keempat isi nilai2
  cout << "\nSetelah remove( 4 ), nilai2 memuat: ";
  tampilList( nilai2 );
  cout << endl;
} // akhir dari main

// definisi template fungsi tampilList; menggunakan
// ostream_iterator dan algoritma copy untuk menampilkan elemen-elemen list
template < typename T > void tampilList( const list< T > &listRef )
{
  if ( listRef.empty() ) // list kosong
    cout << "List kosong";
  else
  {
    ostream_iterator< T > output( cout, " " );
    copy( listRef.begin(), listRef.end(), output );
  } // akhir dari else
} // akhir dari fungsi tampilList

nilai2 memuat: 2 1 4 3
nila2 setelah pengurutan memuat: 1 2 3 4
Setelah penyisipan, nilai2Lain memuat: 2 6 4 8
Setelah splice, nilai2 memuat: 1 2 3 4 2 6 4 8
Setelah penyisipan dan pengurutan, nilai2Lain memuat: 2 4 6 8
Seteleh merge:
   nilai2 memuat: 1 2 2 2 3 4 4 4 6 6 8 8
   nilai2Lain memuat: List kosong
Setelah pop_front dan pop_back:
nilai2 memuat: 2 2 2 3 4 4 4 6 6 8
Setelah unique, nilai2 memuat: 2 3 4 6 8
Setelah swap:
  nilai2 memuat: List kosong
  nilai2Lain memuat: 2 3 4 6 8
Setelah assign, nilai2 memuat: 2 3 4 6 8
Setelah merge, nilai2 memuat: 2 2 3 3 4 4 6 6 8 8
Setelah remove(4), nilai2 memuat: 2 2 3 3 6 6 8 8

Baris 16-17 menginstansiasi dua objek list yang mampu menyimpan integer-integer. Baris 20-21 menggunakan fungsi push_front untuk menyisipkan integer pada awal nilai2. Fungsi push_front spesifik untuk kelas list dan deque (bukan untuk vector). Baris 22-23 menggunakan fungsi push_back untuk menyisipkan integer-integer di akhir nilai2. Ingat bahwa fungsi push_back tersedia untuk semua kontainer runtun.

Baris 28 menggunakan fungsi anggota list, sort, untuk menata elemen-elemen di dalam list dalam urutan menaik. Versi kedua dari fungsi sort mengijinkan Anda untuk menyuplai sebuah fungsi predikat biner yang mengambil dua argumen (nilai-nilai di dalam list), melakukan perbandingan dan menghasilkan nilai balik bool untuk mengindikasikan hasil. Fungsi ini menentukan urutan dari elemen-elemen di dalam list.

Baris 38 menggunakan fungsi anggota list, splice, untuk menghapus elemen-elemen di dalam nilai2Lain dan menyisipkannya sebelum posisi iterator yang dispesifikasi sebagai argumen pertama. Ada dua versi dari fungsi ini. Fungsi splice dengan tiga argumen membolehkan satu elemen dihapus dari kontainer yang dispesifikasi sebagai argumen kedua dari lokasi yang dispesifikasi oleh iterator pada argumen ketiga. Fungsi splice dengan empat argumen menggunakan dua argumen terakhir untuk menentukan suatu rentang lokasi yang harus dihapus dari kontainer dalam argumen kedua dan menempatkannya di argumen pertama.

Setelah penyisipan elemen-elemen lain di dalam nilai2Lain dan pengurutan nilai2 dan nilai2Lain, baris 53 menggunakan fungsi anggota list, merge, untuk menghapus semua elemen nilai2Lain dan menyisipkannya dalam tatanan terurut ke dalam nilai2. Kedua list harus diurutkan sebelum operasi ini dilakukan. Versi kedua dari merge memampukan Anda untuk menyuplai sebuah fungsi predikat yang mengambil dua argumen (nilai-nilai di dalam list) dan menghasilkan nilai balik bool. Fungsi predikat tersebut menentukan tatanan pengurutan yang dipakai oleh merge.

Baris 59 menggunakan fungsi anggota list, pop_front, untuk menghapus elemen pertama di dalam list. Baris 60 menggunakan fungsi pop_back (tersedia bagi semua kontainer runtun) untuk menghapus elemen terakhir di dalam list.

Baris 64 menggunakan fungsi anggota list, unique, untuk menghapus elemen-elemen duplikat di dalam list. list harus dalam tatanan terurut (sehingga semua duplikat berada berdampingan) sebelum operasi ini dilakukan, untuk menjamin semua duplikat tereliminasi. Versi kedua dari unique memampukan Anda untuk menyuplai sebuah fungsi predikat yang mengambil dua argumen (nilai-nilai di dalam list) dan menghasilkan nilai balik bool, yang menspesifikasi apakah kedua elemen sama atau tidak.

Baris 69 menggunakan fungsi swap (tersedia bagi semua kontainer kelas-pertama) untuk menukar elemen-elemen nilai2 dengan elemen-elemen nilai2Lain.

Baris 76 menggunakan fungsi anggota list, assign, (yang tersedia bagi semua kontainer runtun) untuk menggantikan isi nilai2 dengan isi nilai2Lain dalam rentang yang dispesifikasi oleh dua argumen iterator. Versi kedua dari assign mengganti isi asli dengan salinan dari nilai yang dispesifikasi dalam argumen kedua. Argumen pertama dari fungsi itu menspesifikasi jumlah salinan. Baris 58 menggunakan fungsi anggota list, remove, untuk menghapus semua salinan nilai 4 dari list.

12.5.3 Kontainer Runtun deque
Kelas deque menyediakan keuntungan dari vector dan list dalam satu kontainer. Istilah deque berasal dari singkatan “double-ended queue” atau “antrian ujung-ganda”. Kelas deque diimplementasikan untuk menyediakan akses berindeks secara efisien (menggunakan subskript) dalam membaca dan memodifikasi elemen-elemennya. Kelas deque juga diimplementasikan untuk operasi penyisipan dan penghapusan secara efisien di ujung depan dan di ujung belakang.  Kelas deque menyediakan dukungan untuk iterator random access, sehingga deque dapat dipakai dengan semua algoritma STL.

Memori tambahan untuk deque dapat dialokasikan di salah satu ujung deque. Karena tata letak memori yang tidak bertetangga dari sebuah deque, iterator deque harus lebih cerdas dari pointer yang digunakan untuk mengiterasi menjelajahi vector.

Kelas deque menyediakan operasi-operasi dasar yang sama dengan kelas vector, tetapi sama seperti list yang memiliki fungsi anggota push_front dan push_back untuk membolehkan penyisipan dan penghapusan di awal deque.

Gambar 12.18 mendemonstrasikan beberapa fitur kelas deque. Ingat bahwa banyak fungsi yang disajikan pada Gambar 12.14, Gambar 12.15, dan Gambar 12.17 juga dapat dipakai menggunakan kelas deque.

Baris 11 menginstansiasi sebuah deque yang dapat menyimpan nilai-nilai double. Baris 15-17 menggunakan fungsi push_front dan push_back untuk menyisipkan elemen-elemen di ujung awal dan ujung akhir deque.

Gambar 12.18 Program Menguji Kelas deque STL

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
// Gambar 12.18: gambar12_18.cpp
// Program menguji kelas deque STL.
#include <iostream>
#include <deque> // definisi template-kelas deque
#include <algorithm> // algoritma copy
#include <iterator> // ostream_iterator
using namespace std;

int main()
{
  deque< double > nilai2; // menciptakan deque yang memuat double
  ostream_iterator< double > output( cout, " " );

  // menyisipkan elemen-elemen di nilai2
  nilai2.push_front( 2.2 );
  nilai2.push_front( 3.5 );
  nilai2.push_back( 1.1 );

  cout << "nilai2 memuat: ";

  // menggunakan operator subskript untuk mendapatkan elemen-elemen nilai2
  for ( unsigned int i = 0; i < nilai2.size() ;++i )
    cout << nilai2[ i ] << ' ';

  nilai2.pop_front(); // menghapus elemen pertama
  cout << "\nSetelah pop_front, nilai2 memuat: ";
  copy( nilai2.begin(), nilai2.end(), output );

  // menggunakan operator subskript untuk memodifikasi elemen pada lokasi 1
  nilai2[ 1 ] = 5.4;
  cout << "\nSetelah nilai2[ 1 ] = 5.4, nilai2 memuat: ";
  copy( nilai2.begin(), nilai2.end(), output );
  cout << endl;
} // akhir dari main

nilai2 memuat: 3.5 2.2 1.1
Setelah pop_front, nilai2 memuat: 2.2 1.1
Setelah nilai2[1], nilai2 memuat: 2.2 5.4

Ingat bahwa push_back tersedia bagi semua kontainer runtun, tetapi push_front hanya tersedia bagi kelas list dan deque.

Statemen for pada baris 22-23 menggunakan operator subskript untuk mengambil nilai setiap elemen deque untuk ditampilkan. Kondisi menggunakan fungsi size untuk memastikan bahwa Anda tidak mencoba untuk mengakses elemen di luar rentang deque.

Baris 25 menggunakan fungsi pop_front untuk mendemonstrasikan penghapusan elemen pertama deque. Ingat bahwa pop_front hanya tersedia bagi kelas list dan deque (tidak bagi kelas vector).

Baris 30 menggunakan operator subskript untuk menciptakan sebuah lvalue. Ini memampukan nilai-nilai ditugaskan secara langsung ke sembarang elemen deque.

12.6 Kontainer Asosiatif
Kontainer asosiatif STL menyediakan akses langsung dalam menyimpan mengambil elemen melalui kunci (seringkali disebut juga dengan kunci pencarian).  Ada empat kontainer asosiatif, yaitu multiset, set, multimap, dan map. Setiap kontainer asosiatif mempunyai kunci dalam tatanan terurut. Kelas multiset dan set menyediakan beberapa operasi untuk memanipulasi sehimpunan nilai dimana nilai-nilai tersebut merupakan kuncinya. Perbedaan utama antara multiset dan set adalah bahwa multiset membolehkan adanya kunci duplikat sedangkan set tidak mengijinkan adanya kunci duplikat.

Kelas multimap dan map menyediakan beberapa operasi untuk memanipulasi nilai yang berkaitan dengan kunci. Perbedaan utama antara multimap dan map adalah bahwa multimap mengijinkan adanya kunci duplikat dengan nilai berkaitan yang akan disimpan dan map tidak mengijinkannya. Selain fungsi anggota untuk semua kontainer yang disajikan pada Gambar 12.2, semua kontainer asosiatif juga mendukung beberapa fungsi anggota lain, termasuk find, lower_bound, upper_bound, dan count.




12.6.1 Kontainer Asosiatif multiset
Kontainer asosiatif multiset menyediakan mekanisme penyimpanan dan penarikan kunci secara cepat dan membolehkan adanya kunci duplikat. Pengurutan elemen ditentukan oleh sebuah objek fungsi komparator. Sebagai contoh, di dalam sebuah multiset integer, elemen-elemen dapat diurutkan secara menaik dengan mengurutkan kunci menggunakan objek fungsi komparator less<int>. Tipe data kunci semua kontainer asosiatif harus mendukung perbandingan berbasis objek fungsi komparator yang dispesifikasi, yaitu less<T> harus mendukung perbandirngan dengan operator<. Jika kunci yang digunakan di dalam kontainer asosiatif adalah tipe data yang didefinisikan oleh pengguna, maka tipe tersebut harus menyuplai operator perbandingan yang sesuai. Sebuah multiset mendukung iterator bidirectional (tetapi tidak mendukung iterator random access).

Gambar 12.19 mendemonstrasikan kontainer asosiatif multiset untuk sebuah multiset yang memuat integer-integer terurut secara menaik. Header <set> harus dicantumkan untuk menggunakan kelas multiset. Kontainer multiset dan set menyediakan fungsionalitas dasar yang sama.

Baris 10 menggunakan typedef untuk menciptakan nama alias bagi sebuah multiset yang memuat integer-integer terurut secara menaik, menggunakan objek fungsi less<int>. Urutan menaik adalah kondisi default untuk multiset, jadi less<int> dapat diabaikan pada baris 10. Tipe baru ini (Ims) kemudian digunakan untuk menginstansiasi objek multiset integer, intMultiset, pada baris 16.

Gambar 12.19 Menguji Template Kelas multiset STL

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
// Gambar 12.19: gambar12_19.cpp
// Menguji template kelas multiset STL
#include <iostream>
#include <set> // definisi template-kelas multiset
#include <algorithm> // algoritma copy
#include <iterator> // ostream_iterator
using namespace std;

// mendefinisikan nama alias untuk tipe multiset
typedef multiset< int, less< int > > Ims;

int main()
{
  const int UKURAN = 10;
  int a[ UKURAN ] = { 7, 22, 9, 1, 18, 30, 100, 22, 85, 13 };
  Ims intMultiset; // Ims adalah typedef untuk "multiset integer"
  ostream_iterator< int > output( cout, " " );

  cout << "Sekarang terdapat " <<  intMultiset.count( 15 )
    << " buah nilai 15 di dalam multiset\n";

  intMultiset.insert( 15 ); // menyisipkan 15 di dalam intMultiset
  intMultiset.insert( 15 ); // menyisipkan 15 di dalam intMultiset
  cout << "Setelah insert, terdapat " << intMultiset.count( 15 )
    << " buah nilai 15 di dalam multiset\n\n";

  // iterator yang tidak bisa dipakai untuk mengubah nilai elemen
  Ims::const_iterator hasil;

  // mencari 15 di dalam intMultiset; find menghasilkan iterator
  hasil = intMultiset.find( 15 );

  if ( hasil != intMultiset.end() ) // jika iterator tidak di ujung
    cout << "Ditemukan nilai 15\n"; // nilai 15 ditemukan

  // mencari 20 di dalam intMultiset; find menghasilkan iterator
  hasil = intMultiset.find( 20 );

  if ( hasil == intMultiset.end() )
    cout << "Nilai 20 tidak ditemukan\n"; // nilai 20 tidak ditemukan

  // menyisipkan elemen array ke intMultiset
  intMultiset.insert( a, a + UKURAN );
  cout << "\nSetelah insert, intMultiset memuat:\n";
  copy( intMultiset.begin(), intMultiset.end(), output );

  // menentukan batas bawah dan batas atas 22 di dalam intMultiset
  cout << "\n\nBatas bawah dari 22: "
    << *( intMultiset.lower_bound( 22 ) );
  cout << "\nBatas atas dari 22: " << *( intMultiset.upper_bound( 22 ) );

  // p merepresentasikan sepasang const_iterator
  pair< Ims::const_iterator, Ims::const_iterator > p;

  // menggunakan equal_range untuk menentukan batas atas dan batas bawah
  // dari 22 di dalam intMultiset
  p = intMultiset.equal_range( 22 );

  cout << "\n\nequal_range dari 22:" << "\n Batas bawah: "
    << *( p.first ) << "\n Batas atas: " << *( p.second );
  cout << endl;
} // akhir dari main

Sekarang terdapat 0 buah nilai 15 di dalam multiset
Setelah insert, terdapat 2 buah nilai 15 di dalam multiset


Ditemukan nilai 15
Nilai 20 tidak ditemukan

Setelah insert, intMultiset memuat:
1 7 9 13 15 15 18 22 22 30 85 100

Batas bawah dari 22: 22
Batas atas dari 22: 30

equal_range dari 22:
   Batas bawah: 22
   Batas atas: 30

Statemen keluaran pada baris 19 menggunakan fungsi count (tersedia bagi semua kontainer asosiatif) untuk menghitung jumlah kemunculan nilai 15 yang saat ini berada di dalam multiset. Baris 22-23 menggunakan salah satu dari tiga versi fungsi insert untuk menambahkan nilai 15 ke dalam multiset dua kali. Versi kedua dari insert mengambil sebuah iterator dan sebuah nilai sebagai argumen dan memulai pencarian titik penyisipan dari posisi iterator yang dispesifikasi. Versi ketiga dari insert mengambil dua iterator sebagai argumen yang menspesfikasi rentang nilai yang ditambahkan ke dalam multiset dari kontainer lain.

Baris 31 menggunakan fungsi find (tersedia bagi semua kontainer asosiatif) untuk mencari lokasi nilai 15 di dalam multiset. Fungsi find menghasilkan sebuah iterator atau sebuah const_iterator yang menunjuk ke lokasi nilai yang dicari. Jika nilai yang dicari tidak ditemukan, find menghasilkan iterator atau const_iterator yang sama dengan nilai yang dijadikan nilai balik oleh pemanggilan fungsi end. Baris 40 mendemonstasikan hal itu.

Baris 43 menggunakan fungsi insert untuk menyisipkan elemen array ke dalam multiset. Pada baris 45, algoritma copy menyalin elemen-elemen multiset ke keluaran standard dalam urutan menaik.

Baris 49 dan 50 menggunakan fungsi lower_bound dan upper_bound (tersedia bagi semua kontainer asosiatif) untuk mencari lokasi kemunculan pertama dari nilai 22 di dalam multiset dan lokasi elemen setelah kemunculan terakhir dari nilai 22 di dalam multiset. Kedua fungsi ini menghasilkan nilai balik berupa iterator atau const_iterator yang menunjuk ke lokasi tertentu atau berupa iterator yang dijadikan nilai balik oleh fungsi end jika nilai yang dicari tidak ditemukan di dalam multiset.

Baris 53 menciptakan sebuah objek pair, yang dinamakan p. Objek semacam itu memuat pasangan-pasangan nilai. Pada contoh ini, isi sebuah pair adalah dua const_iterator untuk multiset integer. Tujuan adanya p adalah untuk menyimpan nilai balik dari fungsi equal_range yang menghasilkan sebuah pair yang memuat hasil dari operasi lower_bound dan upper_bound.

Baris 57 menggunakan fungsi equal_range untuk menentukan lower_bound dan upper_bound dari nilai 22 di dalam multiset. Baris 60 menggunakan p.first dan p.second untuk mengakses lower_bound dan upper_bound. Kedua iterator tersebut kemudian didereferensi untuk menampilkan nilai-nilai pada lokasi-lokasi yang dihasilkan dari equal_range.



12.6.2 Kontainer Asosiatif set
Kontainer asosiatif set digunakan untuk penyimpanan dan penarikan kunci-kunci unik. Implementasi atas sebuah set identik dengan implementasi atas sebuah multiset, kecuali bahwa sebuah set harus memiliki kunci-kunci unik. Oleh karena itu, jika suatu percobaan untuk menyisipkan kunci duplikat ke dalam sebuah set dilakukan, maka kunci duplikat tersebut diabaikan. Sebuah set mendukung iterator bidirectional (tetapi tidak mendukung iterator random access). Gambar 12.20 mendemonstrasikan sebuah set yang memuat nilai-nilai double. Header <set> harus disertakan untuk menggunakan kelas set.

Gambar 12.20 Menguji Template Kelas set STL

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
// Gambar 12.20: gambar12_20.cpp
// Program menguji set STL.
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator> // ostream_iterator
using namespace std;

// mendefinisikan nama alias untuk set
typedef set< double, less< double > > DoubleSet;

int main()
{
  const int UKURAN = 5;
  double a[ UKURAN ] = { 2.1, 4.2, 9.5, 2.1, 3.7 };
  DoubleSet doubleSet( a, a + UKURAN );
  ostream_iterator< double > output( cout, " " );

  cout << "doubleSet memuat: ";
  copy( doubleSet.begin(), doubleSet.end(), output );
 
  // p merepresentasikan pair memuat const_iterator dan bool
  pair< DoubleSet::const_iterator, bool > p;

  // menyisipkan 13.8 ke dalam doubleSet; penyisipan menghasilkan pair
  // dimana p.first merepresentasikan lokasi dari 13.8 di dalam doubleSet dan
  // p.second merepresentasikan apakah 13.8 telah disisipkan atau belum
  p = doubleSet.insert( 13.8 );
  cout << "\n\n" << *( p.first )
    << ( p.second ? " telah" : " tidak" ) << " disisipkan";
  cout << "\ndoubleSet memuat: ";
  copy( doubleSet.begin(), doubleSet.end(), output );
 
  // menyisipkan 9.5 ke dalam doubleSet
  p = doubleSet.insert( 9.5 ); // nilai telah berada di dalam set
  cout << "\n\n" << *( p.first )
    << ( p.second ? " telah" : " tidak" ) << " disisipkan";
  cout << "\ndoubleSet memuat: ";
  copy( doubleSet.begin(), doubleSet.end(), output );
  cout << endl;
} // akhir dari main

doubleSet memuat: 2.1 3.7 4.2 9.5
13.8 telah disisipkan
doubleSet memuat: 2.1 3.7 4.2 9.5 13.8
19.5 tidak disisipkan
doubleSet memuat: 2.1 3.7 4.2 9.5 13.8

Baris 10 menggunakan typedef untuk menciptakan nama alias (DoubleSet) untuk sehimpunan nilai double yang tersusun secara menaik, menggunakan objek fungsi less<double>.

Baris 16 menggunakan DoubleSet untuk menginstansiasi objek doubleSet. Pemanggilan konstruktor mengambil elemen-elemen di dalam array a di antara a dan a + SIZE (keseluruhan array) dan menyisipkannya ke dalam set. Baris 20 menggunakan algoritma copy untuk menampilkan isi set. Perhatikan bahwa nilai 2.1, yang muncul dua kali di dalam array a, hanya muncul sekali saja di dalam doubleSet. Hal ini karena kontainer set yang tidak mengijinkan duplikasi.

Baris 23 mendefinisikan sebuah pair yang memuat const_iterator untuk DoubleSet dan sebuah nilai double. Objek ini menyimpan hasil dari pemanggilan fungsi insert. Baris 28 menggunakan fungsi insert untuk menempatkan nilai 13.8 di dalam set. Nilai balik pair dari fungsi insert, p, memuat sebuah iterator p.first yang menunjuk ke nilai 13.8 di dalam set dan sebuah iterator p.second yang menunjuk ke nilai bool yang bernilai true jika nilai telah disisipkan dan false jika nilai tidak disisipkan (karena sudah ada di dalam set). Keluaran dari baris 36-37 menunjukkan bahwa 9.5 tidak disisipkan, karena sudah ada sebelumnya di dalam set.

12.6.3 Kontainer Asosiatif multimap
Kontainer asosiatif multimap digunakan untuk penyimpanan dan penarikan kunci dan nilai terkait (sering disebut dengan pasangan kunci/nilai). Banyak fungsi yang digunakan dengan multiset dan set dapat pula dipakai dengan multimap dan map. Elemen-elemen multimap dan map adalah pasangan-pasangan kunci dan nilai, bukan nilai saja. Ketika menyisipkan ke dalam multimap atau map, sebuah objek pair yang memuat kunci dan nilai digunakan. Pengurutan kunci ditentukan oleh sebuah objek fungsi komparator. Sebagai contoh, di dalam multimap yang menggunakan integer sebagai tipe kunci, kunci-kunci dapat disimpan dalam urutan menaik dengan mengurutkannya menggunakan objek fungsi komparator less<int>. Kunci duplikat diijinkan di dalam multimap, jadi banyak nilai bisa diasosiasikan dengan sebuah kunci. Hal ini dikenal dengan relasi satu-ke-banyak. Sebagai contoh, di dalam sistem pemrosesan traksaksi kartu kredit, satu akun kartu kredit dapat memiliki banyak transaksi; di universitas, seorang mahasiswa dapat mengambil banyak matakuliah, dan seorang guru besar dapat mengajar banyak mahasiswa. Sebuah multimap mendukung iterator bidirectional, tetapi tidak mendukung iterator random access. Gambar 12.21 mendemonstrasikan kontainer asosiatif. Header <map> harus dicantumkan untuk menggunakan kelas multimap.

Baris 8 menggunakan typedef untuk mendefinisikan alias Mmid untuk suatu tipe multimap dimana di dalamnya tipe kunci adalah integer, tipe nilai yang terasosiasi dengan kunci adalah double dan elemen-elemen diurutkan dengan tatanan menaik. Baris 12 menggunakan Mmid untuk menginstansiasi sebuah multimap, yang dinamakan sepasang. Baris 14 menggunakan fungsi count untuk menentukan jumlah pasangan kunci/nilai dengan sebuah kunci 15.

Gambar 12.21 Menguji Template Kelas multimap STL

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
// Gambar 12.21: gambar21_21.cpp
// Program untuk menguji kelas multimap STL.
#include <iostream>
#include <map> // definisi template kelas multimap
using namespace std;

// mendefinisikan nama alias untuk tipe multimap
typedef multimap< int, double, less< int > > Mmid;

int main()
{
  Mmid sepasang; // mendeklarasikan pasangan multimap

  cout << "Sekarang terdapat " << sepasang.count( 15 )
    << " buah pasangan dengan kunci 15 di dalam multimap\n";

  // menyisipkan dua objek value_type objects di dalam sepasang
  sepasang.insert( Mmid::value_type( 15, 2.7 ) );
  sepasang.insert( Mmid::value_type( 15, 99.3 ) );

  cout << "Setelah insert, terdapat " << sepasang.count( 15 )
    << " buah pasangan dengan kunci 15\n\n";

  // menyisipkan lima objek value_type di dalam sepasang
  sepasang.insert( Mmid::value_type( 30, 111.11 ) );
  sepasang.insert( Mmid::value_type( 10, 22.22 ) );
  sepasang.insert( Mmid::value_type( 25, 33.333 ) );
  sepasang.insert( Mmid::value_type( 20, 9.345 ) );
  sepasang.insert( Mmid::value_type( 5, 77.54 ) );

  cout << "Multimap sepasang memuat:\nKunsi\tNilai\n";

  // menggunakan const_iterator untuk menjelajahi elemen-elemen sepasang
  for ( Mmid::const_iterator iter = sepasang.begin();
    iter != sepasang.end(); ++iter )
  cout << iter->first << '\t' << iter->second << '\n';

  cout << endl;
} // akhir dari main

Sekarang terdapat 0 buah pasangan dengan kunci 15 di dalam multimap
Setelah insert, terdapat 2 buah pasangan dengan kunci 15

Multimap sepasang memuat:
5       77.54
10      22.22
15      2.7
15      99.3
20      9.345
25      33.333
30      111.11

Baris 18 menggunakan fungsi insert untuk menambahkan sepasang kunci/nilai baru ke dalam multimap. Ekspresi Mmid::value_type (15, 2.7) menciptakan sebuah objek sepasang dimana di dalamnya first adalah kunci (15) bertipe int dan second adalah nilai (2.7) bertipe double. Tipe Mmid::value_type didefinisikan sebagai bagian dari typedef untuk multimap. Baris 19 menyisipkan objek sepasang lainnya dengan kunci 15 dan nilai 99.3. Statemen for pada baris 34-36 menampilkan isi multimap, termasuk kunci dan nilai. Baris 36 menggunakan const_iterator, dinamakan iter, untuk mengakses anggota-anggota dari sepasang di setiap elemen multimap. Perhatikan bahwa keluaran menunjukkan kunci-kunci dalam tatanan terurut menaik.

12.6.4 Kontainer Asosiatif map
Kontainer asosiatif map melakukan operasi penyimpanan dan penarikan kunci unik dan nilai terkait. Kunci duplikat tidak diijinkan, jadi sebuah nilai hanya bisa diasosiasikan dengan sebuah kunci. Ini dikenal dengan relasi satu-ke-satu. Sebagai contoh, sebuah perusahaan menggunakan nomor pegawai, seperti 101, 203, dan 309, yang memiliki sebuah map yang mengasosiasikannya dengan ekstensi telepon sebagai kunci, seperti 3421, 5435, dan 8273. Dengan map, Anda menspesifikasi dapat kunci dan memperoleh data (nilai) dengan cepat. Sebuah map juga dikenal dengan array asosiatif. Penyediaan kunci di dalam operator subskript [ ] pada sebuah map dapat mencari lokasi nilai yang diasosiasikan dengan nilai di dalam map. Penyisipan dan penghapusan dapat dilakukan di sembarang tempat di dalam map.

Gambar 12.22 mendemonstrasikan sebuah map dan menggunakan beberapa fitur yang sama pada Gambar 12.21 untuk mendemonstrasikan operator subskript. Header <map> harus dicantumkan untuk menggunakan kelas map. Baris 31-32 menggunakan operator subskript dari kelas map. Ketika subskript merupakan sebuah kunci yang sebelumnya telah ada di dalam map (baris 31), operator menghasilkan sebuah referensi ke nilai terasosiasi. Ketika subskript merupakan sebuah kunci yang belum ada di dalam map (baris 32), operator menyisipkan kunci tersebut di dalam map dan menghasilkan nilai balik berupa sebuah referensi yang dapat dipakai untuk mengasosiasikan sebuah nilai dengan kunci tersebut. Baris 31 mengganti nilai untuk kunci 35 (sebelumnya 33.333 seperti yang dispesifikasikan pada baris 19) dengan sebuah nilai baru, 9999.99. Baris 32 menyisipkan sepasang kunci/nilai baru di dalam map (yang disebut dengan penciptaan sebuah asosiasi).

Gambar 12.22 Menguji Template Kelas map STL

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
// Gambar 12.22: gambar12_22.cpp
// Program menguji map STL.
#include <iostream>
#include <map> // definisi template kelas map
using namespace std;

// mendefinisikan nama alias untuk tipe map
typedef map< int, double, less< int > > Mid;

int main()
{
  Mid sepasang;

  // menyisipkan delapan objek value_type di dalam sepasang
  sepasang.insert( Mid::value_type( 15, 2.7 ) );
  sepasang.insert( Mid::value_type( 30, 111.11 ) );
  sepasang.insert( Mid::value_type( 5, 1010.1 ) );
  sepasang.insert( Mid::value_type( 10, 22.22 ) );
  sepasang.insert( Mid::value_type( 25, 33.333 ) );
  sepasang.insert( Mid::value_type( 5, 77.54 ) ); // diabaikan
  sepasang.insert( Mid::value_type( 20, 9.345 ) );
  sepasang.insert( Mid::value_type( 15, 99.3 ) ); // diabaikan

  cout << "sepasang memuat:\nKunci\tNilai\n";

  // menggunakan const_iterator untuk menjelajahi elemen-elemen sepasang
  for ( Mid::const_iterator iter = sepasang.begin();
    iter != sepasang.end(); ++iter )
  cout << iter->first << '\t' << iter->second << '\n';

  sepasang[ 25 ] = 9999.99; // menggunakan subskript untuk mengubah nilai kunci 25
  sepasang[ 40 ] = 8765.43; // menggunakan subskript untuk mengubah nilai kunci 40

  cout << "\nSetelah operasi subskript, sepasang memuat:\nKunci\tNilai\n";

  // menggunakan const_iterator untuk menjelajahi elemen-elemen sepasang
  for ( Mid::const_iterator iter2 = sepasang.begin();
    iter2 != sepasang.end(); ++iter2 )
  cout << iter2->first << '\t' << iter2->second << '\n';

 cout << endl;
 } // end main

sepasang memuat:
5       1010.1
10      22.22
15      2.7
20      9.345
25      33.333
30      111.11

Setelah operasi subskript, sepasang memuat:
5       1010.1
10      22.22
15      2.7
20      9.345
25      9999.99

12.7 Adapter Kontainer
STL menyediakan tiga adapter kontainer, yaitu stack, queue, dan prioriy_queue. Adapter bukan kontainer kelas-pertama, karena ia tidak menyediakan implementasi struktur data aktual dimana di dalamnya elemen-elemen dapat disimpan dan karena adapter tidak mendukung iterator. Keuntungan dari kelas adapter adalah bahwa Anda dapat memilih struktur data yang cocok untuk aplikasi Anda. Ketiga kelas adapter menyediakan fungsi anggota push dan pop yang menyisipkan sebuah elemen ke dalam setiap struktur data adapter dan menghapus sebuah elemen dari setiap struktur data adapter.

12.7.1 Adapter stack
Kelas stack memampukan penyisipan ke dalam dan penghapusan dari  ujung struktur data (yang sering dikenal dengan struktur data last-in, first-out). Sebuah stack dapat diimplementasikan dengan sembarang kontainer runtun: vector, list, dan deque. Contoh ini menciptakan tiga tumpukan integer, menggunakan ketiga kontainer runtun STL sebagai struktur data untuk merepresentasikan stack. Secara default, stack diimplementasikan dengan deque. Beberapa operasi stack adalah push untuk menyisipkan sebuah elemen teratas stack (diimplementasikan dengan pemanggilan fungsi push_back), pop untuk menghapus elemen teratas stack, top untuk mendapatkan sebuah referensi ke elemen teratas stack (diimplementasikan dengan pemanggilan fungsi back), empty untuk menentukan apakah stack kosong atau tidak (diimplementasikan dengan pemanggilan fungsi empty), dan size untuk mendapatkan jumlah elemen di dalam stack (diimplementasikan dengan pemanggilan fungsi size).

Gambar 12.23 mendemonstrasikan kelas adapter stack. Header <stack> harus dicantumkan untuk memakai kelas stack. Baris 18, 21, dan 24 menginstansiasi tiga tumpukan integer. Baris 18 menspesifikasi sebuah stack integer yang menggunakan kontainer deque default sebagai struktur data. Baris 21 menspesifikasi sebuah stack integer yang menggunakan vector integer sebagai struktur data. Baris 24 menspesifikasi sebuah stack integer yang menggunakan list integer sebagai struktur data.
Fungsi pushElemen (baris 46-53) mendorong elemen ke atas setiap stack. Baris 50 menggunakan fungsi push (tersedia bagi setiap kelas adapter) untuk menempatkan sebuah integer di atas stack. Baris 51 menggunakan fungsi top untuk menarik elemen teratas stack untuk ditampilkan. Fungsi top tidak membuang elemen teratas stack.

Fungsi popElemen (baris 56-63) membuang elemen dari setiap stack. Baris 60 menggunakan fungsi top untuk menarik elemen teratas stack untuk ditampilkan. Baris 61 menggunakan fungsi pop (tersedia bagi setiap kelas adapter) untuk menghapus elemen teratas stack. Fungsi pop tidak menghasilkan nilai balik apapun.

Gambar 12.23 Menguji Adapter stack STL

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
// Gambar 12.23: gambar12_23.cpp
// Program menguji adapter stack STL.
#include <iostream>
#include <stack> // definisi adapter stack
#include <vector> // definisi template kelas vector
#include <list> // definisi template kelas list
using namespace std;

// prototipe template-fungsi pushElemen
template< typename T > void pushElemen( T &stackRef );

// prototipe template-fungsi popElements
template< typename T > void popElemen( T &stackRef );

int main()
{
  // stack dengan deque default
  stack< int > intDequeStack;

  // stack dengan struktur-data vector
  stack< int, vector< int > > intVectorStack;

  // stack dengan struktur data list
  stack< int, list< int > > intListStack;

  // mendorong nilai 0-9 ke atas tiap stack
  cout << "Mendorong ke atas intDequeStack: ";
  pushElemen( intDequeStack );
  cout << "\nMendorong ke atas  intVectorStack: ";
  pushElemen( intVectorStack );
  cout << "\nMendorong ke atas  intListStack: ";
  pushElemen( intListStack );
  cout << endl << endl;

  // menampilkan dan menghapus elemen dari setiap stack
  cout << "Menghapus dari intDequeStack: ";
  popElemen( intDequeStack );
  cout << "\nMenghapus dari intVectorStack: ";
  popElemen( intVectorStack );
  cout << "\nMenghapus dari intListStack: ";
  popElemen( intListStack );
  cout << endl;
} // akhir dari main

// mendorong elem ke atas objek stack yang ditunjuk oleh stackRef
template< typename T > void pushElemen( T &stackRef )
{
  for ( int i = 0; i < 10; ++i )
  {
    stackRef.push( i ); // mendorang elemen ke atas stack
    cout << stackRef.top() << ' '; // menampilkan elemen teratas
  } // akhir dari for
} // akhir dari fungsi pushElemen

// menghapus elemen dari objek stack yang ditunjuk oleh stackRef
template< typename T > void popElemen( T &stackRef )
{
  while( !stackRef.empty() )
  {
    cout << stackRef.top() << ' '; // menampilkan elemen teratas
    stackRef.pop(); // menghapus elemen teratas
  } // akhir dari while
} // akhir dari fungsi popElemen

Mendorong ke atas intVectorStack: 0 1 2 3 4 5 6 7 8 9
Mendorong ke atas intListStack: 0 1 2 3 4 5 6 7 8 9
Menghapus dari intDequeStack: 9 8 7 6 5 4 3 2 1 0
Menghapus dari intVectorStack: 9 8 7 6 5 4 3 2 1 0
Menghapus dari intListStack: 9 8 7 6 5 4 3 2 1 0

12.7.2 Adapter queue
Kelas queue memampukan penyisipan di belakang struktur data dan penghapusan dari depan struktur data (yang sering dikenal dengan struktur data first-in, first-out). Sebuah queue dapat diimplementasikan dengan list atau deque. Secara default, sebuah queue diimplementasikan dengan deque. Beberapa operasi umum queue adalah push untuk menyisipkan sebuah elemen di belakang queue (diimplementasikan dengan pemanggilan fungsi push_back), pop untuk menghapus elemen di depan queue (diimplementasikan dengan pemanggilan fungsi pop_front), front untuk mendapatkan sebuah referensi ke elemen pertama di dalam queue (diimplementasikan dengan pemanggilan fungsi front), back untuk memperoleh sebuah referensi ke elemen terakhir di dalam queue (diimplementasikan dengan pemanggilan fungsi back), empty untuk menentukan apakah queue kosong atau tidak (diimplementasikan dengan pemanggilan fungsi empty), dan size untuk mendapatkan jumlah elemen di dalam queue (diimplementasikan dengan pemanggilan fungsi size).
Gambar 12.24 mendemonstrasikan kelas adapter queue. Header <queue> harus dicantumkan untuk menggunakan sebuah queue. Baris 9 menginstansiasi sebuah queue yang menyimpan nilai-nilai double. Baris 12-14 menggunakan fungsi push untuk menambahkan elemen ke dalam queue. Statemen while pada baris 19-23 menggunakan fungsi empty (tersedia untuk semua kontainer) untuk menentukan apakah queue kosong atau tidak (baris 19). Jika masih ada elemen di dalam queue, baris 21 menggunakan fungsi front untuk membaca (tetapi tidak menghapus) elemen pertama di dalam queue untuk ditampilkan. Baris 22 menghapus elemen pertama di dalam queue menggunakan fungsi pop (tersedia di dalam semua kelas adapter).

Gambar 12.24 Menguji Adapter queue STL

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
// Gambar 12.24: gambar12_24.cpp
// Program menguji adapter queue STL.
#include <iostream>
#include <queue> // definisi adapter queue
using namespace std;

int main()
{
  queue< double > nilai2; // queue berisi nilai-nilai double

  // mendorong elemen ke atas queue
  nilai2.push( 3.2 );
  nilai2.push( 9.8 );
  nilai2.push( 5.4 );

  cout << "Menghapus dari nilai2: ";

  // menghapus elemen dari queue
  while(!nilai2.empty())
  {
    cout << nilai2.front() << ' '; // menampilkan elemen depan
    nilai2.pop(); // menghapus elemen
  } // akhir dari while

  cout << endl;
} // akhir main

Menghapus dari nilai2: 3.2 9.8 5.4

12.7.3 Adapter priority_queue
Kelas priority_queue menyediakan fungsionalitas yang memampukan penyisipan dalam tatanan terurut ke dalam struktur data dan penghapusan dari depan struktur data. Sebuah priority_queue dapat diimplementasikan dengan kontainer runtun STL vector atau deque. Secara default, priority_queue diimplementasikan dengan vector. Ketika elemen-elemen ditambahkan ke priority_queue, elemen-elemen tersebut disisipkan dalam urutan prioritas, sehingga elemen dengan prioritas tertinggi akan dihapus pertama kali dari priority-queue. Hal ini dilakukan dengan menata elemen-elemen dalam suatu struktur pohon biner yang disebut dengan heap, dimana nilai terbesar (elemen dengan prioritas tertinggi) berada di depan struktur data. Perbandingan elemen dilakukan dengan objek fungsi komparator less<T> secara deault, tetapi Anda bisa menyuplai komparator yang berbeda.

Terdapat beberapa operasi yang umum pada priority_queue. Operasi push menyisipkan sebuah elemen ke suatu lokasi tertentu berdasarkan urutan prioritas dari priority_queue (diimplementasikan oleh pemanggilan fungsi push_back, kemudian mengurutkan-ulang elemen-elemen menggunakan heap). Operasi pop menghapus elemen dengan prioritas tertinggi (diimplementasikan dengan pemanggilan fungsi pop_back setelah menghapus elemen teratas heap). Operasi top memperoleh sebuah referensi ke elemen teratas priority_queue (diimplementasikan dengan pemanggilan fungsi front). Operasi empty menentukan apakah priority_queue kosong atau tidak (diimplementasikan dengan pemanggilan fungsi empty). Operasi size mendapatkan jumlah elemen di dalam priority_queue (diimplementasikan dengan pemanggilan fungsi size).

Gambar 12.25 mendemonstrasikan kelas adapter priorty_queue. Header <queue> harus dicantumkan untuk menggunakan priority_queue. Baris 9 menginstansiasi sebuah priority_queue yang menyimpan nilai-nilai double dan menggunakan sebuah vector sebagai struktur data. Baris 12-14 menggunakan fungsi push untuk menambahkan elemen ke dalam priority_queue. Statemen while pada baris 19-23 menggunakan fungsi empty (tersedia bagi semua kontainer) untuk menentukan apakah priority_queue kosong atau tidak (baris 19). Ketika masih ada elemen, baris 21 menggunakan fungsi top untuk menarik elemen dengan prioritas tertinggi di dalam priority_queue agar ditampilkan. Baris 22 menghapus elemen dengan prioritas tertinggi di dalam priority_queue dengan fungsi pop (tersedia bagi semua kelas adapter).

Gambar 12.25 Menguji Adapter priority_queue STL

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
// Gambar 12.25: gambar12_25.cpp
// Standard Library adapter priority_queue test program.
#include <iostream>
#include <queue> // definisi adapter priority_queue
using namespace std;

int main()
{
  priority_queue< double > prioritas; // menciptakan priority_queue

  // mendorong elemen ke atas prioritas
  prioritas.push( 3.2 );
  prioritas.push( 9.8 );
  prioritas.push( 5.4 );

  cout << "Menghapus dari prioritas: ";

  // menghapus elemen dari priority_queue
  while(!prioritas.empty())
  {
    cout << prioritas.top() << ' '; // menampilkan elemen teratas
    prioritas.pop(); // menghapus elemen teratas
  } // akhir dari while

  cout << endl;
} // akhir main

Menghapus dari prioritas: 9.8 5.4 3.2

12.8 Algoritma
Sebelum adanya STL, pustaka kelas kontainer dan algoritma saling tidak kompatibel di antara vendor. Pustaka kontainer, pada awal pembentukannya, menggunakan pewarisan dan polimorfisme untuk membangun algoritma ke dalam kelas kontainer. STL memisahkan algoritma dari kontainer. Hal ini membuat penambahan algoritma baru menjadi lebih mudah. Dengan STL, elemen kontainer dapat diakses melalui iterator.

12.8.1 fill, fill_n, generate, dan generate_n
Gambar 12.26 mendemonstrasikan algoritma fill, fill_n, generate, dan generate_n. Fungi fill dan fill_n menetapkan sebuah nilai spesifik terhadap elemen-elemen di dalam suatu rentang elemen kontainer. Fungei generate dan generate_n menggunakan suatu fungsi pembangkit dalam menciptakan nilai-nilai untuk setiap elemen di dalam suatu rentang elemen kontainer. Fungsi pembangkit tidak memerlukan argumen apapun dan menghasilkan nilai balik berupa suatu nilai yang dapat ditempatkan di dalam sebuah elemen kontainer.

Gambar 12.26 Algoritma fill, fill_n, generate, dan generate_n

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
// Gambar 21.26: gambar21_26.cpp
// Algoritma fill, fill_n, generate dan generate_n dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // ostream_iterator
using namespace std;

char nextHuruf(); // prototipe fungsi pembangkit

int main()
{
  vector< char > karakter( 10 );
  ostream_iterator< char > output( cout, " " );
  fill( karakter.begin(), karakter.end(), '5' ); // mengisi karakter dengan 5

   cout << "Vektor karakter setelah diisi dengan 5:\n";
   copy( karakter.begin(), karakter.end(), output );

   // mengisi lima elemen pertama karakter dengan A
   fill_n( karakter.begin(), 5, 'A' );

   cout << "\n\nVektor karakter setelah diisi lima elemen pertama dengan A:\n";
   copy( karakter.begin(), karakter.end(), output );

  // membangkitkan nilai-nilai untuk semua elemen karakter dengan nextHuruf
  generate( karakter.begin(), karakter.end(), nextHuruf );

  cout << "\n\nVektor karakter setelah pembangkitan huruf A-J:\n";
  copy( karakter.begin(), karakter.end(), output );

  // membangkitkan nilai-nilai untuk lima elemen pertama karakter dengan nextHuruf
  generate_n( karakter.begin(), 5, nextHuruf );

  cout << "\n\nVektor karakter setelah pembangkitan K-O untuk"
    << " lima elemen pertama:\n";
   copy( karakter.begin(), karakter.end(), output );
   cout << endl;
} // akhir dari main

// fungsi pembangkit menghasilkan huruf berikutnya (mulai dari A)
char nextHuruf()
{
  static char huruf = 'A';
  return ++huruf;
} // akhir dari fungsi nextHuruf

Vektor karakter setelah diisi dengan 5:
5 5 5 5 5 5 5 5 5 5

Vektor karakter setelah diisi lima elemen pertama dengan A:
A A A A A 5 5 5 5 5

Vektor karakter setelah pembangkitan huruf A-J:
A B C D E F G H I J

Vektor karakter setelah pembangkitan K-O untuk lima elemen pertama:
K L M N O F G H I J

Baris 13 mendefinisikan 10 elemen vector yang menyimpan nilai-nilai char. Baris 15 menggunakan fungsi fill untuk menempatkan karakter ‘5’ di semua elemen vector, karakter, mulai dari karakter.begin() sampai ke karakter.end(). Iterator yang disuplai sebagai argumen pertama dan argumen kedua harus setidaknya berupa iterator forward (yang dapat digunakan untuk masukan dari kontainer dan mengeluarkan ke sebuah kontainer dalam arah maju).

Baris 21 menggunakan fungsi fill_n untuk menempatkan karakter ‘A’ di dalam lima elemen pertama vectorkarakter. Iterator yang disuplai sebagai argumen pertama harus setidaknya berupa iterator output (yang dapat digunakan untuk mengeluarkan ke sebuah kontainer dalam arah maju). Argumen kedua menspesifikasi jumlah elemen yang akan diisi. Argumen ketiga menspesifikasi nilai yang akan ditempatkan di setiap elemen.

Baris 27 menggunakan fungsi generate untuk menempatkan hasil dari pemanggilan fungsi pembangkit nextHuruf di setiap elemen vector karakter mulai dari karakter.begin() sampai ke karakter.end().Iterator yang disuplai sebagai argumen pertama dan argumen kedua harus setidaknya berupa iterator forward. Fungsi nextHuruf (baris 42-46) membangkitkan karakter mulai dari ‘A’ yang disimpan di dalam sebuah variabel lokal static. Statemen pada baris 45 melakukan postinkremen terhadap nilai huruf dan memberikan nilai balik berupa nilai lama dari huruf setiap kali nextHuruf dipanggil.

Baris 33 menggunakan fungsi generate_n untuk menempatkan hasil dari pemanggilan fungsi pembangkit nextHuruf di dalam lima elemen vector karakter, mulai dari karakter.begin(). Iterator yang disuplai sebagai argumen pertama harus setidaknya berupa iterator output.

12.8.2 equal, mismatch, dan lexicographical_compare
Gambar 12.27 mendemonstrasikan perbandingan ekualitas atas runtun-runtun nilai menggunakan  algoritma equals, mismatch, dan lexicographical_compare.

Gambar 12.27 Algoritma equal, mismatch, dan lexicographical_compare

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
// Gambar 12.27: gambar12_27.cpp
// Algoritma equal, mismatch dan lexicographical_compare di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // ostream_iterator
using namespace std;

int main()
{
  const int UKURAN = 10;
  int a1[ UKURAN ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int a2[ UKURAN ] = { 1, 2, 3, 4, 1000, 6, 7, 8, 9, 10 };
  vector< int > v1( a1, a1 + UKURAN ); // salinan dari a1
  vector< int > v2( a1, a1 + UKURAN ); // salinan dari a1
  vector< int > v3( a2, a2 + UKURAN ); // salinan dari a2
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v1 memuat: ";
  copy( v1.begin(), v1.end(), output );
  cout << "\nVektor v2 memuat: ";
  copy( v2.begin(), v2.end(), output );
  cout << "\nVektor v3 memuat: ";
  copy( v3.begin(), v3.end(), output );

  // membandingkan vektor v1 dan v2 untuk ekualitas
  bool hasil = equal( v1.begin(), v1.end(), v2.begin() );
  cout << "\n\nVektor v1 " << ( hasil ? "sama" : "tidak sama" )
    << " dengan vektor v2.\n";

  // membandingkan vektor v1 dan v3 untuk ekualitas
  hasil = equal( v1.begin(), v1.end(), v3.begin() );
  cout << "Vektor v1 " << ( hasil ? "sama" : "tidak sama" )
   << " dengan vektor v3.\n";

  // lokasi merepresentasikan sepasang iterator vector
  pair< vector< int >::iterator, vector< int >::iterator > lokasi;

  // memeriksa ketidakcocokan antara v1 dan v3
  lokasi = mismatch( v1.begin(), v1.end(), v3.begin() );
  cout << "\nTerdapat ketidakcocokan antara v1 dan v3 pada lokasi "
    <<( lokasi.first - v1.begin() )<< "\ndimana v1 memuat "
    << *lokasi.first << " dan v3 memuat " << *lokasi.second
    << "\n\n";

  char c1[ UKURAN ] = "SELAMAT";
  char c2[ UKURAN ] = "JALAN";

  // melakukan perbandingan leksikografikal atas c1 dan c2
  hasil = lexicographical_compare( c1, c1 + UKURAN, c2, c2 + UKURAN );
  cout << c1 << ( hasil ? " kurang dari " :
    " lebih dari atau sama dengan " ) << c2 << endl;
 } // akhir dari main

Vektor v1 memuat: 1 2 3 4 5 6 7 8 9 10
Vektor v2 memuat: 1 2 3 4 5 6 7 8 9 10
Vektor v3 memuat: 1 2 3 4 1000 6 7 8 9 10

Vektor v1 sama dengan vektor v2.
Vektor v1 tidak sama dengan vektor v3.

Terdapat ketidakcocokan antara v1 dan v3 pada lokasi 4
dimana v1 memuat 5 dan v3 memuat 1000
SELAMAT lebih dari atau sama dengan JALAN

Baris 27 menggunakan fungsi equal untuk membandingkan dua runtun nilai untuk ekualitas. Setiap runtun tidak perlu memuat jumlah elemen yang sama. Fungsi ini menghasilkan false jika runtun tidak sama panjang. Operator == melakukan perbandingan elemen. Pada contoh ini, elemen-elemen di dalam vector v1 mulai dari v1.begin() sampai v1.end() dibandingkan dengan elemen-elemen di dalam vector v2 mulai dari v2.begin() sampai v2.end(). Pada contoh ini, v1 dan v2 sama. Tiga argumen iterator harus sedikitnya berupa iterator input (yang dapat digunakan untuk masukan dari sebuah runtun dengan arah maju). Baris 32 menggunakan fungsi equal untuk membandingkan vector v1 dan vector v3, yang tidak sama.

Ada versi lain dari fungsi equal yang mengambil sebuah fungsi predikat biner sebagai prameter keempat. Fungsi predikat biner menerima dua elemen yang sedang dibandingkan dan menghasilkan nilai balik bool yang mengindikasikan apakah kedua elemen sama atau tidak. Hal ini berguna di dalam runtun untuk menyimpan objek-objek atau pointer-pointer yang menunjuk ke nilai, karena Anda dapat mendefinisikan satu atau lebih perbandingan. Sebagai contoh, Anda dapat membandingkan objek-objek Pegawai untuk perbandingan usia, nomor KTP, atau alamat. Anda dapat membandingkan apa yang ditunjuk oleh pointer, bukan membandingkan nilai-nilai pointer (alamat yang disimpan di dalam pointer).

Baris 37-40 dimulai dengan menginstansiasi sebuah objek pair yang dinamakan lokasi untuk vector yang memuat integer-integer. Objek ini menyimpan hasil dari pemanggilan mismatch (baris 40). Fungsi mismatch membandingkan dua runtun nilai dan menghasilkan nilai balik berupa objek pair yang mengindikasikan lokasi di dalam setiap runtun yang memuat elemen-elemen tak-cocok. Jika semua elemen cocok, dua iterator di dalam pair sama dengan iterator terakhir untuk tiap runtun. Tiga argumen iterator sedikitnya harus berupa iterator input. Baris 42 menentukan lokasi aktual dari ketidakcocokan di dalam vector dengan ekspresi lokasi.first - v1.begin(). Hasil dari kalkulasi ini adalah jumlah elemen di antara dua iterator.

Baris 50 menggunakan fungsi lexicographical_compare untuk membandingkan isi dari dua array karakter. Empat argumen iterator pada fungsi ini harus sedikitnya berupa iterator input. Seperti yang Anda ketahui, pointer ke array adalah iterator random access. Dua argumen iterator pertama menspesifikasi rentang lokasi di dalam runtun pertama. Dua argumen iterator terakhir menentukan rentang lokasi di dalam runtun kedua. Ketika beriterasi menjelajahi runtun, lexicographical_compare memeriksa apakah elemen di dalam runtun pertama kurang dari elemen terkait di dalam runtun kedua. Jika ya, fungsi ini menghasilkan true. Jika elemen di dalam runtun pertama lebih dari atau sama dengan elemen terkait di dalam runtun kedua, maka fungsi ini menghasilkan false. Fungsi ini dapat digunakan untuk menata runtun secara leksikografikal.

12.8.3 remove, remove_if, remove_copy dan remove_copy_if
Gambar 12.28 mendemonstrasikan penghapusan nilai dari sebuah runtun menggunakan algoritma remove, remove_if, remove_copy, dan remove_copy_if.

Gambar 12.28 Algoritma remove, remove_if, remove_copy, dan remove_copy_if

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
// Gambar 12.28: gambar12_28.cpp
// Fungsi remove, remove_if,
// remove_copy dan remove_copy_if di dalam STL
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // ostream_iterator
using namespace std;

bool lebihDari9( int ); // prototipe

int main()
{
  const int UKURAN = 10;
  int a[ UKURAN ] = { 10, 2, 10, 4, 16, 6, 14, 8, 12, 10 };
  ostream_iterator< int > output( cout, " " );
  vector< int > v( a, a + UKURAN ); // salinan dari a
  vector< int >::iterator newElemenTerakhir;

  cout << "Vektor v sebelum dihapus semua 10:\n ";
  copy( v.begin(), v.end(), output );

  // menghapus semua 10 daro v
  newElemenTerakhir = remove( v.begin(), v.end(), 10 );
  cout << "\nVektor v setelah dihapus semua 10:\n ";
  copy( v.begin(), newElemenTerakhir, output );

  vector< int > v2( a, a + UKURAN ); // salinan dari a
  vector< int > c( UKURAN, 0 ); // menginstansiasi vektor c
  cout << "\n\nVektor v2 sebelum dihapus dan disalin semua 10s:\n ";
  copy( v2.begin(), v2.end(), output );

  // menyalin dari v2 ke c, menghapus semua 10
  remove_copy( v2.begin(), v2.end(), c.begin(), 10 );
  cout << "\nVektor c setelah dihapus semua 10 dari v2:\n ";
  copy( c.begin(), c.end(), output );

  vector< int > v3( a, a + UKURAN ); // copy of a
  cout << "\n\nVektor v3 sebalum dihapus semua elemen"
    << "\nyang lebih dari 9:\n ";
  copy( v3.begin(), v3.end(), output );

  // menghapus elemen yang lebih dari 9 dari v3
  newElemenTerakhir = remove_if( v3.begin(), v3.end(), lebihDari9 );
  cout << "\nVektor v3 setelah dihapus semua elemen"
    << "\nyang lebih dari 9:\n ";
  copy( v3.begin(), newElemenTerakhir, output );
  
  vector< int > v4( a, a + UKURAN ); // salinan dari a
  vector< int > c2( UKURAN, 0 ); // menginstansiasi vektor c2
  cout << "\n\nVektor v4 sebelum disalin dan dihapus semua elemen"
   << "\nyang lebih dari 9:\n ";
  copy( v4.begin(), v4.end(), output );

  // menyalin elemen dari v4 ke c2, menghapus semua elemen yang lebih dari
  // 9 di dalam prosesnya
  remove_copy_if( v4.begin(), v4.end(), c2.begin(), lebihDari9 );
  cout << "\nVektor c2 setelah dihapus semua elemen"
    << "\nyang lebih dari 9 dari v4:\n ";
  copy( c2.begin(), c2.end(), output );
  cout << endl;
} // akhir dari main

// menentukan apakah argumen lebih dari 9 atau tidak
bool lebihDari9( int x )
{
  return x > 9;
} // akhir dari fungsi lebihDari9

Vektor v sebelum dihapus semua 10:
  10 2 10 4 16 6 14 8 12 10
Vektor v setelah dihapus semua 10:
  2 4 16 6 14 8 12

Vektor v2 sebelum dihapus dan disalin semua 10:
  10 2 10 4 16 6 14 8 12 10
Vektor c setelah semua 10 dihapus dari v2:
   2 4 16 6 14 8 12 0 0 0

Vektor v3 sebelum dihapus semua elemen
yang lebih dari 9:
   10 2 10 4 16 6 14 8 12 10
Vektor v3 setelah dihapus semua elemen
yang lebih dari 9:
   2 4 6 8

Vektor v4 sebelum disalin dan dihapus semua elemen
yang lebih dari 9:
   10 2 10 4 16 6 14 8 12 10
Vektor c2 setelah dihapus semua elemen
yang lebih dari 9 dari v4:
   2 4 6 8 0 0 0 0 0 0

Baris 24 menggunakan fungsi remove untuk mengeliminasi semua elemen dengan nilai 10 di dalam rentang dari v.begin() sampai v.end(). Dua argumen iterator pertama harus berupa iterator forward sehingga algoritma ini dapat memodifikasi elemen di dalam runtun. Fungsi ini tidak memodifikasi jumlah elemen di dalam vector atau menghancurkan semua elemen tereliminasi, tetapi hanya memindahkan semua elemen yang tidak dieliminasi ke awal vector. Fungsi ini menghasilkan nilai balik berupa suatu iterator yang diposisikan satu elemen setelah elemen vector yang tidak tereliminasi. Elemen-elemen mulai dari posisi iterator sampai ke akhir vector memiliki nilai tak-terdefinisi (pada contoh ini, setiap posisi “tak-terdefinisi” memiliki nilai 0).

Baris 34 menggunakan fungsi remove_copy untuk menyalin semua elemen yang tidak memiliki nilai 10 di dalam rentang mulai dari v2.begin() sampai v2.end(). Elemen-elemen tersebut kemudian ditempatkan di dalam c, mulai dari posisi c.begin(). Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator input. Iterator yang disuplai sebagai argumen ketiga harus berupa sebuah iterator output sehingga semua elemen yang sedang disalin dapat disisipkan ke dalam lokasi penyalinan. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan satu elemen setelah elemen terakhir yang disalin ke dalam vector c. Perhatikan pada baris 29 penggunaan konstruktor vector dan nilai-nilai awal untuk elemen-elemen tersebut.

Baris 44 menggunakan fungsi remove_if untuk menghapus semua elemen di dalam rentang mulai dari v3.begin() sampai v3.end() bila fungsi predikat (yang didefinisikan oleh pengguna) bernilai true. Fungsi lebihDari9 (didefinisikan pada baris 65-68) menghasilkan true jika nilai yang dilewatkan kepadanya bernilai lebih dari 9; sebaliknya, menghasilkan false. Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator forward sehingga algoritma ini dapat memodifikasi elemen-elemen di dalam runtun. Fungsi ini tidak memodifikasi jumlah elemen di dalam vector, tetapi ia hanya memindahkan semua elemen yang tidak tereliminasi ke awal vector. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan satu elemen setelah elemen terakhir di dalam vector yang tidak dihapus. Semua elemen mulai dari posisi iterator sampai ke akhir vector memiliki nilai tak-terdefinisi.

Baris 57 menggunakan fungsi remove_copy_if untuk menyalin semua elemen di dalam rentang mulai dari v4.begin() sampai v4.end() bila fungsi predikat (lebihDari9) bernilai true. Elemen-elemen yang ditempatkan di dalam c2 mulai dari posisi c2.begin(). Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator input. Iterator yang disuplai sebagai argumen ketiga harus berupa iterator output sehingga elemen yang sedang disalin dapat disisipkan ke lokasi penyalinan. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan satu elemen setelah elemen terakhir yang disalin ke dalam c2.

12.8.4 replace, replace_if, replace_copy dan replace_copy_if
Gambar 12.29 mendemonstrasikan penggantian nilai-nilai dari sebuah runtun menggunakan algoritma replace, replace_if, replace_copy, dan replace_copy_if.

Gambar 12.29 Algoritma replace, replace _if, replace _copy, dan replace _copy_if

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 12.29: gambar12_29.cpp
// Fungsi replace, replace_if,
// replace_copy dan replace_copy_if di dalam STL.
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator> // ostream_iterator
using namespace std;

bool lebihDari9( int ); // prototipe fungsi predikat

int main()
{
  const int SIZE = 10;
  int a[ SIZE ] = { 10, 2, 10, 4, 16, 6, 14, 8, 12, 10 };
  ostream_iterator< int > output( cout, " " );

  vector< int > v1( a, a + SIZE ); // salinan dari a
  cout << "Vektor v1 sebelum diganti semua 10:\n ";
  copy( v1.begin(), v1.end(), output );

  // mengganti semua 10 di dalam v1 dengan 100
  replace( v1.begin(), v1.end(), 10, 100 );
  cout << "\nVektor v1 setelah diganti semua 10 dengan 100:\n ";
  copy( v1.begin(), v1.end(), output );

  vector< int > v2( a, a + SIZE ); // copy of a
  vector< int > c1( SIZE ); // instantiate vector c1
  cout << "\n\nVektor v2 sebelum diganti dan disalin semua 10:\n ";
  copy( v2.begin(), v2.end(), output );

  // menyalin dari v2 ke v1, mengganti 10 dengan 100
  replace_copy( v2.begin(), v2.end(), c1.begin(), 10, 100 );
  cout << "\nVektor c1 setelah diganti semua 10 di dalam v2:\n ";
  copy( c1.begin(), c1.end(), output );

  vector< int > v3( a, a + SIZE ); // copy of a
  cout << "\n\nVektor v3 sebelum diganti nilai yang lebih dari 9:\n ";
  copy( v3.begin(), v3.end(), output );

  // mengganti semua nilai yang lebih dari 9 di dalam v3 dengan 100
  replace_if( v3.begin(), v3.end(), lebihDari9, 100 );
  cout << "\nVektor v3 setelah diganti semua elemen"
    << "\nyang lebih dari 9 dengan 100:\n ";
  copy( v3.begin(), v3.end(), output );

  vector< int > v4( a, a + SIZE ); // salinan dari a
  vector< int > c2( SIZE ); // menginstansiasi vektor c2
  cout << "\n\nVektor v4 sebelum diganti dan disalin semua elemen "
    << "yang lebih dari 9:\n ";
  copy( v4.begin(), v4.end(), output );

  // menyalin v4 ke c2, mengganti elemen-elemen yang lebih dari 9 dengan 100
  replace_copy_if( v4.begin(), v4.end(), c2.begin(), lebihDari9, 100 );
  cout << "\nVektor c2 setelah diganti semua elemen "
    << "yang lebih dari 9 di dalam v4:\n ";
  copy( c2.begin(), c2.end(), output );
  cout << endl;
} // akhir dari main

// menentukan apakah argumen lebih dari 9 atau tidak
bool lebihDari9( int x )
{
  return x > 9;
} // akhir dari fungsi lebihDari9

Vektor v1 sebelum diganti semua 10:
   10 2 10 4 16 6 14 8 12 10
Vektor v1 setelah diganti semua 10 dengan 100:
   100 2 100 4 16 6 14 8 12 100

Vektor v2 sebelum diganti dan disalin semua 10:
   10 2 10 4 16 6 14 8 12 10
Vektor c1 setelah diganti semua 10 di dalam v2:
   100 2 100 4 16 6 14 8 12 100

Vektor v3 sebelum diganti nilai yang lebih dari 9:
   10 2 10 4 16 6 14 8 12 10
Vektor v3 setelah diganti semua elemen
yang lebih dari 9 dengan 100:
   100 2 100 4 16 6 14 8 12 100

Vektor v4 sebelum diganti dan disalin semua elemen yang lebih dari 9:
   10 2 10 4 16 6 14 8 12 10
Vektor c2 setelah diganti semua elemen yang lebih dari 9 di dalam v4:
   100 2 100 4 16 6 14 8 12 100

Baris 23 menggunakan fungsi replace untuk mengganti semua elemen dengan nilai 10 di dalam rentang dari v1.begin() sampai v1.end(). Dua argumen iterator pertama harus berupa iterator forward sehingga algoritma ini dapat memodifikasi elemen di dalam runtun.

Baris 33 menggunakan fungsi replace_copy untuk menyalin semua elemen yang tidak memiliki nilai 10 di dalam rentang mulai dari v2.begin() sampai v2.end(), mengganti semua elemen bernilai 10 dengan nilai baru 100. Elemen-elemen tersebut kemudian ditempatkan di dalam c1, mulai dari posisi c1.begin(). Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator input. Iterator yang disuplai sebagai argumen ketiga harus berupa sebuah iterator output sehingga semua elemen yang sedang disalin dapat disisipkan ke dalam lokasi penyalinan. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan satu elemen setelah elemen terakhir yang disalin ke dalam vector c1.

Baris 42 menggunakan fungsi replace_if untuk menghapus semua elemen di dalam rentang mulai dari v3.begin() sampai v3.end() bila fungsi predikat (yang didefinisikan oleh pengguna) bernilai true. Fungsi lebihDari9 (didefinisikan pada baris 62-65) menghasilkan true jika nilai yang dilewatkan kepadanya bernilai lebih dari 9; sebaliknya, menghasilkan false. Nilai 100 menggantikan setiap nilai yang lebih dari 9. Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator forward sehingga algoritma ini dapat memodifikasi elemen-elemen di dalam runtun.

Baris 54 menggunakan fungsi replace_copy_if untuk menyalin semua elemen di dalam rentang mulai dari v4.begin() sampai v4.end() bila fungsi predikat (lebihDari9) bernilai true. Jika fungsi predikat bernilai true (elemen bernilai lebih dari 9), maka setiap nilai yang lebih dari 9 akan digantikan dengan nilai baru 100. Elemen-elemen yang ditempatkan di dalam c2 mulai dari posisi c2.begin(). Iterator yang disuplai sebagai dua argumen pertama harus berupa iterator input. Iterator yang disuplai sebagai argumen ketiga harus berupa iterator output sehingga elemen yang sedang disalin dapat disisipkan ke lokasi penyalinan. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan satu elemen setelah elemen terakhir yang disalin ke dalam c2.

12.8.5 Algoritma Matematik
Gambar 12.30 mendemonstrasikan beberapa algoritma matematik di dalam STL, termasuk random_shuffle, count, count_if, min_element, max_element, accumulate, for_each, dan transform.

Gambar 12.30 Beberapa Algoritma Matematik di dalam STL

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
// Gambar 12.30: gambar12_30.cpp
// Beberapa algoritma matematik di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <numeric> // accumulate didefinisikan di sini
#include <vector>
#include <iterator>
using namespace std;

bool lebihDari9( int ); // prototipe fungsi predikat
void tampilKuadrat( int ); // menampilkan kuadrat atas suatu nilai
int hitungKubik( int ); // menghitung kubik atas suatu nilai

int main()
{
  const int UKURAN = 10;
  int a1[ UKURAN ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  vector< int > v( a1, a1 + UKURAN ); // salinan dari a1
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v sebelum random_shuffle: ";
  copy( v.begin(), v.end(), output );

  random_shuffle( v.begin(), v.end() ); // mengacak elemen-elemen di dalam v
  cout << "\nVektor v setelah random_shuffle: ";
  copy( v.begin(), v.end(), output );

  int a2[ UKURAN ] = { 100, 2, 8, 1, 50, 3, 8, 8, 9, 10 };
  vector< int > v2( a2, a2 + UKURAN ); // copy of a2
  cout << "\n\nVektor v2 memuat: ";
  copy( v2.begin(), v2.end(), output );

  // menghitung jumlah elemen di dalam v2 yang bernilai 8
  int hasil = count( v2.begin(), v2.end(), 8 );
  cout << "\nJumlah elemen yang cocok dengan 8: " << hasil;

  // menghitung jumlah elemen di dalam v2 yang bernilai lebih dari 9
  hasil = count_if( v2.begin(), v2.end(), lebihDari9 );
  cout << "\nJumlah elemen yang bernilai lebih dari 9: " << hasil;

  // mencari lokasi elemen minimum di dalam v2
  cout << "\n\nElemen minimum di dalam vektor v2 adalah: "
    << *( min_element( v2.begin(), v2.end() ) );

  // mencari lokasi elemen maksimum di dalam v2
  cout << "\nElemen maksimum di dalam vektor v2 adalah: "
    << *( max_element( v2.begin(), v2.end() ) );

  // menghitung jumlah dari elemen-elemen di dalam v
  cout << "\n\nTotal elemen di dalam vektor v adalah: "
    << accumulate( v.begin(), v.end(), 0 );

  // menampilkan kuadrat atas setiap elemen di dalam v
  cout << "\n\nKuadrat atas setiap integer di dalam vektor v adalah:\n";
  for_each( v.begin(), v.end(), tampilKuadrat );

  vector< int > kubik( UKURAN ); // menginstansiasi vektor kubik

  // menghitung kubik atas setiap elemen di dalam v; menempatkan hasilnya di dalam kubik
  transform( v.begin(), v.end(), kubik.begin(), hitungKubik );
  cout << "\n\nKubik atas setiap integer di dalam vektor v adalah:\n";
  copy( kubik.begin(), kubik.end(), output );
  cout << endl;
} // akhir dari main

// menentukan apakah argumen lebih dari 9 atau tidak
bool lebihDari9( int nilai )
{
  return nilai > 9;
} // akhir dari fungsi lebihDari9

// menampilkan kuadrat atas argumen
void tampilKuadrat( int nilai )
{
  cout << nilai * nilai << ' ';
} // akhir dari fungsi tampilKuadrat

// menghasilkan kubik atas argumen
int hitungKubik( int nilai )
{
  return nilai * nilai * nilai;
} // akhir dari fungsi hitungKubik

Vektor v sebelum random_shuffle: 1 2 3 4 5 6 7 8 9 10
Vektor v setelah random_shuffle: 5 4 1 3 7 8 9 10 6 2

Vektor v2 memuat: 100 2 8 1 50 3 8 8 9 10
Jumlah elemen yang cocok dengan 8: 3
Jumlah elemen yang bernilai lebih dari 9: 3

Elemen minimum di dalam vektor v2 adalah: 1
Elemen maksimum di dalam vektor v2 adalah: 100

Total elemen di dalam vektor v adalah: 55

Kuadrat atas setiap elemen di dalam vektor v adalah:
25 16 1 9 49 64 81 100 36 4

Kubik atas setiap elemen di dalam vektor v adalah:
125 64 1 27 343 512 729 1000 216 8

Baris 24 menggunakan fungsi random_shuffle untuk menata-ulang secara acak elemen-elemen di dalam rentang mulai dari v.begin() sampai v.end() di dalam v. Fungsi ini mengambil dua argumen iterator random access.

Baris 34 menggunakan fungsi count untuk menghitung elemen bernilai 8 di dalam rentang dari v2.begin() sampai v2.end() di dalam v2. Fungsi ini memerlukan dua agumen iterator yang sedikitnya berupa iterator input.

Baris 38 menggunakan fungsi count_if untuk menghitung elemen-elemen di dalam rentang dari v2.begin() sampai v2.end() di dalam v2 jika fungsi predikat lebihDari9 bernilai true. Fungsi ini memerlukan dua argumen iterator yang sedikitnya berupa iterator input.

Baris 43 menggunakan fungsi min_element untuk mencari lokasi elemen terkecil di dalam rentang dari v2.begin() sampai v2.end(). Fungsi ini menghasilkan nilai balik berupa sebuah iterator forward yang ditempatkan di elemen terkecil atau di v2.end() jika rentang kosong. Dua argumen iterator sedikitnya harus berupa iterator input. Versi kedua dari fungsi ini mengambil sebuah fungsi biner sebagai argumen ketiga yang membandingkan dua elemen di dalam runtun. Fungsi ini menghasilkan true jika argumen pertama kurang dari argumen kedua.

Baris 47 menggunakan fungsi max_element untuk mencari lokasi elemen terbesar di dalam rentang dari v2.begin() sampai v2.end(). Fungsi ini menghasilkan nilai balik berupa sebuah iterator input yang ditempatkan di elemen terbesar. Dua argumen iterator sedikitnya harus berupa iterator input. Versi kedua dari fungsi ini mengambil sebuah fungsi biner sebagai argumen ketiga yang membandingkan dua elemen di dalam runtun. Fungsi ini menghasilkan true jika argumen pertama kurang dari argumen kedua.

Baris 51 menggunakan fungsi accumulate (templatenya berada di dalam header <numeric>) untuk menjumlahkan nilai-nilai di dalam rentang mulai dari v.begin() sampai v.end() di dalam v. Dua argumen iterator sedikitnya harus berupa iterator input dan argumen ketiganya merepresentasikan nilai awal dari total. Versi kedua dari fungsi ini mengambil sebuah fungsi umum sebagai argumen keempat yang menentukan bagaimana elemen diakumulasikan. Fungsi umum itu mengambil dua argumen dan memberikan nilai balik hasil penjumlahan. Argumen pertama fungsi ini adalah nilai terkini dari akumulasi. Argumen keduanya adalah nilai elemen di dalam runtun yang akan diakumulasikan.

Baris 55 menggunakan fungsi for_each untuk menerapkan suatu fungsi umu terhadap setiap elemen di dalam rentang mulai dari v.begin() sampai v.end(). Fungsi umum itu mengambil elemen sekarang sebagai argumen dan memodifikasinya. Fungsi for_each memerlukan dua argumen iterator yang sedikitnya berupa iterator input.

Baris 60 menggunakan fungsi transform untuk menerapkan suatu fungsi umum terhadap setiap elemen di dalam rentang mulai dari v.begin() sampai v.end(). Fungsi umum itu mengambil elemen sekarang sebagai argumen, tidak memodifikasinya, dan mengembalikan nilai yang telah ditransformasi. Fungsi transform memerlukan dua argumennya sedikitnya berupa iterator input. Argumen ketiga fungsi ini menspesifikasi dimana nilai yang telah ditransformasi harus ditempatkan.

12.8.6 Algoritma Pencarian dan Pengurutan
Gambar 12.31 mendemonstrasikan beberapa kapabilitas pencarian dan pengurutan di dalam STL, termasuk find, find_if, sort dan binary_search.

Gambar 12.31 Beberapa Algoritma Pencarian dan Pengurutan di dalam STL

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
// Gambar 12.31: gambar12_31.cpp
// Algoritma pencarian dan pengurutan STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator>
using namespace std;

bool lebihDari10( int ); // prototipe fungsi predikat

int main()
{
  const int UKURAN = 10;
  int a[ UKURAN ] = { 10, 2, 17, 5, 16, 8, 13, 11, 20, 7 };
  vector< int > v( a, a + UKURAN ); // salinan dari a
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v memuat: ";
  copy( v.begin(), v.end(), output ); // menampilkan vector

  // mencari lokasi kemunculan pertama dari 16 di dalam v
  vector< int >::iterator lokasi;
  lokasi = find( v.begin(), v.end(), 16 );

  if ( lokasi != v.end() ) // ditemukan 16
    cout << "\n\nDitemukan 16 pada lokasi " << ( lokasi - v.begin() );
  else // 16 tidak ditemukan
    cout << "\n\n16 tidak ditemukan";

  // mencari lokasi kemunculan pertama dari 100 di dalam v
  lokasi = find( v.begin(), v.end(), 100 );

  if ( lokasi != v.end() ) // found 100
    cout << "\nDitemukan 100 pada lokasi " << ( lokasi - v.begin() );
  else // 100 tidak ditemukan
    cout << "\n100 tidak ditemukan";

  // mencari lokasi kemunculan pertama nilai yang lebih dari 10 di dalam v
  lokasi = find_if( v.begin(), v.end(), lebihDari10 );

  if ( lokasi != v.end() ) // ditemukan nilai lebih dari 10
    cout << "\n\nNilai pertama yang lebih dari 10 adalah " << *lokasi
      << "\nditemukan pada lokasi " << ( lokasi - v.begin() );
  else // nilai yang lebih dari 10 tidak ditemukan
    cout << "\n\n Tidak adal nilai yang lebih dari 10 ditemukan";

  // mengurutkan elemen-elemen di dalam v
  sort( v.begin(), v.end() );
  cout << "\n\nVektor v setelah sort: ";
  copy( v.begin(), v.end(), output );

  // menggunakan binary_search untuk mencari lokasi 13 di dalam v
  if(binary_search( v.begin(), v.end(), 13 ))
    cout << "\n\n13 ditemukan di dalam v";
  else
    cout << "\n\n13 tidak ditemukan di dalam v";

  // menggunakan binary_search untuk mencari lokasi 100 di dalam v
  if(binary_search( v.begin(), v.end(), 100 ))
    cout << "\n100 ditemukan di dalam v";
  else
    cout << "\n100 tidak ditemukan di dalam v";

  cout << endl;
} // end main

// menentukan apakah argumen bernilai lebih dari 10
bool lebihDari10( int nilai )
{
  return nilai > 10;
} // akhir dari fungsi lebihDari10

Vektor v memuat: 10 2 17 5 16 8 13 11 20 7
Ditemukan 16 pada lokasi 4
100 tidak ditemukan

Nilai pertama yang lebih dari 10 adalah 17
ditemukan pada lokasi 2

Vektor v setelah sort: 2 5 7 8 10 11 13 16 17 20

13 ditemukan di dalam v
100 tidak ditemukan di dalam v

Baris 23 menggunakan fungsi find untuk mencari lokasi nilai 16 di dalam rentang mulai dari v.begin() sampai v.end(). Fungsi ini memerlukan dua argumen iterator yang sedikitnya harus berupa iterator input dan memberikan nilai balik berupa sebuah iterator input yang diposisikan pada  elemen pertama yang memuat nilai yang dicari atau elemen yang mengindikasikan akhir suatu runtun (seperti kasus pada baris 31).

Baris 39 menggunakan fungsi find_if untuk mencari lokasi nilai pertama di dalam rentang mulai dari v.begin() sampai v.end() dimana fungsi predikat lebihDari10 bernilai true. Fungsi lebihDari10 (didefinisikan pada baris 68-71) mengambil sebuah integer sebagai argumen dan menghasilkan sebuah nilai bool yang mengindikasikan apakah argumen integer tersebut bernilai lebih dari 10. Fungsi find_if mensyaratkan bahwa dua argumen iteratornya sedikitnya harus berupa iterator input. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan di elemen pertama yang memuat nilai dimana fungsi predikat bernilai true atau di elemen yang mengindikasikan akhir runtun.

Baris 48 menggunakan fungsi sort untuk menata elemen-elemen di dalam rentang mulai dari v.begin() sampai v.end() dengan urutan menaik. Fungsi ini mensyaratkan bahwa kedua argumen iteratornya harus berupa sedikitnya iterator random access. Versi kedua dari fungsi ini mengambil sebuah argumen ketiga, yang merupakan sebuah fungsi predikat biner yang memerlukan dua argumen (nilai di dalam runtun), dan menghasilkan nilai bool yang mengindikasikan hasil pengurutan. Jika nilai baliknya true, maka dua elemen yang sedang dibandingkan tertata secara terurut.

Baris 53 menggunakan fungsi binary_search untuk menentukan apakah nilai 13 berada di dalam rentang mulai dari v.begin() sampai v.end(). Runtun nilai harus sudah diurutkan secara menaik terlebih dahulu. Fungsi ini mensyaratkan bahwa kedua argumen iteratornya sedikitnya harus berupa iterator forward. Nilai baliknya adalah sebuah bool yang mengindikasikan apakah nilai yang dicari ditemukan di dalam runtun atau tidak. Baris 59 mendemonstrasikan pemanggilan terhadap fungsi binary_search dimana di dalamnya nilai yang dicari tidak ditemukan. Versi kedua dari fungsi ini mengambil argumen keempat, yang merupakan sebuah  fungsi predikat biner yang memerlukan dua argumen (nilai di dalam runtun), dan menghasilkan nilai bool yang mengindikasikan hasil pengurutan. Jika nilai baliknya true, maka dua elemen yang sedang dibandingkan tertata secara terurut. Untuk mendapatkan lokasi kunci pencarian di dalam kontainer, digunakan algoritma lower_bound atau find.

12.8.7 Algoritma swap, iter_swap, dan swap_ranges
Gambar 12.32 mendemonstrasikan algoritma swap, swap_iter, dan swap_ranges untuk menukar elemen. Baris 18 menggunakan fungsi swap untuk menukar dua elemen. Pada contoh ini, elemen pertama dan elemen kedua dari sebuah array a dipertukarkan. Fungsi ini mengambil referensi ke dua nilai yang sedang dipertukarkan sebagai argumen.

Gambar 12.32 Algoritma swap, iter_swap, dan swap_ranges

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
// Gambar 12.32: gambar12_32.cpp
// Algoritma iter_swap, swap dan swap_ranges di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <iterator>
using namespace std;

int main()
{
  const int UKURAN = 10;
  int a[ UKURAN ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  ostream_iterator< int > output( cout, " " );

  cout << "Array a memuat:\n ";
  copy( a, a + UKURAN, output ); // menampilkan array a

  // menukar elemen pada lokasi 0 dengan elemen pada lokasi 1 di dalam array a
  swap( a[ 0 ], a[ 1 ] );

  cout << "\nArray a setelah menukar a[0] dan a[1] menggunakan swap:\n ";
  copy( a, a + UKURAN, output ); // menampilkan array a

  // menggunakan iterator untuk menukar elemen lokasi 0 dengan elemen lokasi 1 array a
  iter_swap( &a[ 0 ], &a[ 1 ] ); // menukar dengan iterator
  cout << "\nArray a setelah menukar a[0] dan a[1] menggunakan iter_swap:\n ";
  copy( a, a + UKURAN, output );

  // menukar lima elemen pertama dari a dengan
  // lima elemen terakhir dari a
  swap_ranges( a, a + 5, a + 5 );

  cout << "\nArray a setelah menukar lima elemen pertama\n"
    << "dengan lima elemen terakhir:\n ";
  copy( a, a + UKURAN, output );
  cout << endl;
} // akhir dari main

Array a memuat:
   1 2 3 4 5 6 7 8 9 10
Array a setelah menukar a[0] dan a[1] menggunakan swap:
   2 1 3 4 5 6 7 8 9 10
Array a setelah menukar a[0] dan a[1] menggunakan iter_swap:
   1 2 3 4 5 6 7 8 9 10
Array a setelah menukar lima elemen pertama
dengan lima elemen terakhir:
   6 7 8 9 10 1 2 3 4 5

Baris 24 menggunakan fungsi iter_swap untuk mempertukarkan dua elemen. Fungsi ini mengambil dua argumen iterator forward (pada kasus ini, pointer yang menunjuk ke elemen suatu array) dan mempertukarkan nilai-nilai di dalam elemen yang ditunjuk oleh iterator.

12.8.8 Algoritma copy_backward, merge, unique, dan reverse
Gambar 12.33 mendemonstrasikan algoritma STL copy_backward, merge, unique, dan reverse. Baris 26 menggunakan fungsi copy_backward untuk menyalin elemen-elemen di dalam rentang mulai dari v1.begin() sampai dengan v1.end(), dengan menempatkan elemen-elemen di dalam hasil mulai dari elemen sebelum hasil.end() dan bergerak ke arah awal vector. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan di elemen terakir yang disalin ke hasil (awal hasil, karena penyalinan mundur). Fungsi ini mensyaratkan bahwa ketiga argumen iterator bidirectional dapat diinkremen dan didekremen dengan arah maju dan arah mundur di dalam suatu runtun. Satu perbedaan antara copy_backward dan copy adalah bahwa iterator yang dijadikan nilai balik oleh copy diposisikan setelah elemen terakhir yang disalin dan iterator yang dijadikan nilai balik oleh copy_backward diposisikan di elemen terakhir yang disalin (elemen pertama di dalam runtun). Juga, bahwa copy_backward dapat memanipulasi rentang elemen yang tumpang-tindih di dalam suatu kontainer sepanjang elemen pertama yang akan disalin bukan destinasi rentang elemennya.

Gambar 12.33 Algoritma copy_backward, merge, unique, dan reverse

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
// Gambar 12.33: gambar12_33.cpp
// Algoritma copy_backward, merge, unique dan reverse di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // ostream_iterator
using namespace std;

int main()
{
  const int UKURAN = 5;
  int a1[ UKURAN ] = { 1, 3, 5, 7, 9 };
  int a2[ UKURAN ] = { 2, 4, 5, 7, 9 };
  vector< int > v1( a1, a1 + UKURAN ); // salinan dari a1
  vector< int > v2( a2, a2 + UKURAN ); // salinan dari a2
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v1 memuat: ";
  copy( v1.begin(), v1.end(), output ); // menampilkan vektor
  cout << "\nVektor v2 mamuat: ";
  copy( v2.begin(), v2.end(), output ); // menampilkan vektor

  vector< int > hasil( v1.size() );

  // menempatkan elemen-elemen dari v1 ke hasil dengan arah terbalik
  copy_backward( v1.begin(), v1.end(), hasil.end() );
  cout << "\n\nSetelah copy_backward, hasil memuat: ";
  copy( hasil.begin(), hasil.end(), output );

  vector< int > hasil2( v1.size() + v2.size() );

  // menggabung elemen-elemen dari v1 dan v2 ke hasil2 dalam tatanan terurut
  merge( v1.begin(), v1.end(), v2.begin(), v2.end(), hasil2.begin() );

  cout << "\n\nSetelah merge dari v1 dan v2 hasil2 memuat:\n";
  copy( hasil2.begin(), hasil2.end(), output );

  // mengeliminasi nilai-nilai duplikat dari hasil2
  vector< int >::iterator endLokasi;
  endLokasi = unique( hasil2.begin(), hasil2.end() );

  cout << "\n\nSetelah unique hasil2 memuat:\n";
  copy( hasil2.begin(), endLokasi, output );

  cout << "\n\nVektor v1 setelah reverse: ";
  reverse( v1.begin(), v1.end() ); // membalik elemen-elemen dari v1
  copy( v1.begin(), v1.end(), output );
  cout << endl;
} // akhir dari main

Vektor v1 memuat: 1 3 5 7 9
Vektor v1 memuat: 2 4 5 7 9
Setelah copy_backward, hasil memuat: 1 3 5 7 9
Setelah merge dari v1 dan v2 hasil2 memuat:
1 2 3 4 5 5 7 7 9 9
Setelah unique hasil2 memuat:
1 2 3 4 5 7 9
Vektor v1 setelah reverse: 9 7 5 3 1

Baris 33 menggunakan fungsi merge untuk menggabungkan dua runtun nilai terurut menaik menjadi sebuah runtun ketiga  terurut menaik. Fungsi ini memerlukan lima argumen iterator. Keempat argumen pertama harus sedikitnya berupa iterator input dan argumen terakhir harus berupa sedikitnya berupa iterator output. Dua argumen pertama menspesifikasi rentang elemen di dalam runtun terurut pertama (v1), dua argumen kedua menspesifikasi rentang elemen di dalam runtun terurut kedua (v2) dan argumen terakhir menspesifikasi lokasi awal di dalam runtun ketiga (hasil2) dimana elemen-elemen akan digabungkan. Versi kedua dari fungsi ini mengambil sebuah fungsi predikat biner sebagai argumen keenamnya yang menspesifikasi tatanan pengurutan.

Baris 30 menciptakan vektor hasil2 dengan jumlah elemen v1.size() + v2.size(). Penggunaan fungsi merge di sini mensyaratkan bahwa runtun dimana hasil penggabungan disimpan harus mempunyai ukuran sedikitnya total ukuran penggabungan dua runtun. Jika Anda tidak ingin mengalokasikan jumlah elemen untuk runtun yang dihasilkan sebelum operasi merge, Anda dapat menggunakan statemen berikut ini:

vector< int > hasil2;
merge( v1.begin(), v1.end(), v2.begin(), v2.end(),
back_inserter(hasil2) );

Argumen back_inserter(hasil2) menggunakan template fungsi back_inserter (header <iterator>) untuk kontainer hasil2. Sebuah back_inserter memanggil fungsi push_back default untuk menyisipkan sebuah elemen di ujung akhir kontainer. Jika sebuah elemen disisipkan ke suatu kontainer yang tidak lagi memiliki ruang, maka kontainer itu akan mengekspansi ukurannya. Jadi, jumlah elemen di dalam kontainer tidak perlu diketahui sebelumnya.

Baris 40 menggunakan fungsi unique pada runtun elemen terurut di dalam rentang mulai dari hasil2.begin() sampai hasil2.end() di dalam hasil2. Jika fungsi ini diterapkan terhadap sebuah runtun terurut yang memuat nilai-nilai duplikat, maka hanya satu salinan atas tiap nilai yang akan tersisa di dalam runtun tersebut. Fungsi ini mengambil dua argumen yang sedikitnya harus berupa iterator forward. Fungsi ini menghasilkan nilai balik berupa sebuah iterator yang diposisikan setelah elemen terakhir di dalam runtun dengan nilai-nilai unik. Nilai semua elemen di dalam kontainer setelah nilai unik terakhir tidak terdefinisi.

Baris 46 menggunakan fungsi reverse untuk membalik urutan semua elemen di dalam rentang dimulai dari v1.begin() sampai v1.end() di dalam v1. Fungsi ini mengambil dua argumen yang sedikitnya harus berupa iterator bidirectional.

12.8.9 Algoritma inplace_merge, unique_copy, dan reverse_copy
Gambar 12.34 mendemonstrasikan algoritma inplace_merge, unique_copy, dan reverse_copy. Baris 22 menggunakan fungsi inplace_merge untuk menggabungkan dua runtun terurut di dalam kontainer yang sama. Pada contoh ini, elemen-elemen dari v1.begin() sampai v1.begin() + 5 - 1 digabungkan dengan elemen-elemen dari v1.begin() + 5 sampai v1.end(). Fungsi ini mensyaratkan bahwa ketiga argumen iteratornya harus berupa sedikitnya iterator bidirectional.

Gambar 12.34 Algoritma inplace_merge, unique_copy, dan reverse_copy

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
// Gambar 12.34: gambar12_34.cpp
// Algoritma inplace_merge,
// reverse_copy dan unique_copy di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // definisi back_inserter
using namespace std;

int main()
{
  const int UKURAN = 10;
  int a1[ UKURAN ] = { 1, 3, 5, 7, 9, 1, 3, 5, 7, 9 };
  vector< int > v1( a1, a1 + UKURAN ); // salinan dari a
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v1 memuat: ";
  copy( v1.begin(), v1.end(), output );

  // menggabungkan setengah bagian pertama dari v1 dengan setengah bagian
  // kedua dari v1 sehingga v1 memuat sehimpunan elemen terurut setelah merge
  inplace_merge( v1.begin(), v1.begin() + 5, v1.end() );

  cout << "\nSetelah inplace_merge, v1 memuat: ";
  copy( v1.begin(), v1.end(), output );

  vector< int > hasil1;

  // menyalin hanya elemen-elemen unik dari v1 ke hasil1
  unique_copy( v1.begin(), v1.end(), back_inserter( hasil1 ) );
  cout << "\nSetelah unique_copy hasil1 memuat: ";
  copy( hasil1.begin(), hasil1.end(), output );

  vector< int > hasil2;

  // menyalin elemen-elemen dari v1 ke hasil2 dengan urutan terbalik
  reverse_copy( v1.begin(), v1.end(), back_inserter( hasil2 ) );
  cout << "\nSetelah reverse_copy, hasil2 memuat: ";
  copy( hasil2.begin(), hasil2.end(), output );
  cout << endl;
} // akhir dari main

Vektor v1 memuat: 1 3 5 7 9 1 3 5 7 9
Setelah inplace_merge, v1 memuat: 1 1 3 3 5 5 7 7 9 9
Setelah unique_copy hasil memuat: 1 3 5 7 9
Setelah reverse_copy, hasil2 memuat: 9 9 7 7 5 5 3 3 1 1

Baris 30 menggunakan fungsi unique_copy untuk membuat salinan dari semua elemen unik di dalam runtun nilai terurut mulai dari v1.begin() sampai v1.end(). Elemen-elemen yang disalin ditempatkan ke vector hasil1. Dua argumen pertama sedikitnya harus berupa iterator input dan argumen terakhir harus sedikitnya berupa sebuah argumen output. Pada contoh ini, Anda tidak perlu sebelumnya mengalokasikan memori yang cukup untuk menampung elemen-elemen yang disalin dari v1, karena digunakan fungsi back_inserter (yang didefinisikan di dalam header <iterator>).

Baris 37 menggunakan fungsi reverse_copy untuk membuat salinan terbalik atas elemen-elemen di dalam rentang mulai dari v1.begin() sampai v1.end(). Elemen-elemen yang disalin disisipkan ke dalam hasil2 menggunakan objek back_inserter untuk memastikan bahwa vector dapat mengekspansi ukurannya untuk mengakomodasi jumlah elemen yang disalin. Fungsi reverse_copy mensyaratkan bahwa dua argumen iterator pertama sedikitnya harus berupa iterator bidirectional dan argumen ketiganya harus berupa sedikitnya sebuah iterator output.

12.8.10 Operasi-Operasi set
Gambar 12.35 mendemonstrasikan fungsi includes, set_difference, set_intersection, set_symmetric, dan set_union untuk memanipulasi sehimpunan nilai terurut. Untuk mendemonstrasikan bahwa fungsi-fungsi STL dapat diterapkan pada array dan kontainer, contoh ini hanya menggunakan array (ingat bahwa pointer ke array adalah iterator random access).

Baris 25 dan 31 memanggil fungsi includes. Fungsi ini membandingkan dua himpunan nilai terurut untuk menentukan apakah setiap elemen dari himpunan kedua berada di dalam himpunan pertama. Jika ya, includes menghasilkan true; sebaliknya menghasilkan false. Dua argumen iterator pertama sedikitnya harus berupa iterator input. Pada baris 25, himpunan pertama memuat elemen-elemen dari a1 sampai a1 + UKURAN. Dua argumen iterator terakhir sedikitnya harus berupa iterator input. Pada contoh ini, himpunan kedua memuat elemen-elemen dari a2 sampai a2 + UKURAN2.

Gambar 12.35 Algoritma includes, set_difference, set_intersection, set_symmetric_difference, dan set_union STL

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
// Gambar 12.35: gambar12_35.cpp
// Algoritma includes, set_difference,
// set_intersection, set_symmetric_difference dan set_union di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <iterator> // ostream_iterator
using namespace std;

int main()
{
  const int UKURAN1 = 10, UKURAN2 = 5, UKURAN3 = 20;
  int a1[ UKURAN1 ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  int a2[ UKURAN2 ] = { 4, 5, 6, 7, 8 };
  int a3[ UKURAN2 ] = { 4, 5, 6, 11, 15 };
  ostream_iterator< int > output( cout, " " );

  cout << "a1 memuat: ";
  copy( a1, a1 + UKURAN1, output ); // menampilkan array a1
  cout << "\na2 memuat: ";
  copy( a2, a2 + UKURAN2, output ); // menampilkan array a2
  cout << "\na3 memuat: ";
  copy( a3, a3 + UKURAN2, output ); // menampilkan array a3

  // menentukan apakah himpunan a2 secara utuh dimuat di dalam a1
  includes( a1, a1 + UKURAN1, a2, a2 + UKURAN2 )
    cout << "\n\na1 mencakup a2";
  else
    cout << "\n\na1 tidak mencakup a2";

  // menentukan apakah himpunan a3 secara utuh dimuat di dalam a1
  includes( a1, a1 + UKURAN1, a3, a3 + UKURAN2 )
    cout << "\na1 mencakup a3";
  else
    cout << "\na1 tidak mencakup a3";

  int difference[ UKURAN1 ];

  // menentukan elemen-elemen a1 yang tidak di dalam a2
  int *ptr = set_difference( a1, a1 + UKURAN1,
    a2, a2 + UKURAN2, difference );
  cout << "\n\nset_difference dari a1 dan a2 adalah: ";
  copy( difference, ptr, output );

  int intersection[ UKURAN1 ];

  // menentukan elemen-elemen di dalam kedua a1 dan a2
  ptr = set_intersection( a1, a1 + UKURAN1,
    a2, a2 + UKURAN2, intersection );
  cout << "\n\nset_intersection dari a1 dan a2 adalah: ";
  copy( intersection, ptr, output );

  int symmetric_difference[ UKURAN1 + UKURAN2 ];

  // menentukan elemen-elemen dari a1 yang tidak di dalam a2 dan
  // elemen-elemen dari a2 yang tidak di dalam a1
  ptr = set_symmetric_difference( a1, a1 + UKURAN1,
    a3, a3 + UKURAN2, symmetric_difference );
  cout << "\n\nset_symmetric_difference dari a1 dan a3 adalah: ";
  copy( symmetric_difference, ptr, output );

  int unionSet[ UKURAN3 ];

  // menentukan elemen-elemen yang  berada di salah satu atau kedua himpunan
  ptr = set_union( a1, a1 + UKURAN1, a3, a3 + UKURAN2, unionSet );
  cout << "\n\nset_union dari a1 dan a3 adalah: ";
  copy( unionSet, ptr, output );
  cout << endl;
} // akhir dari main

a1 memuat: 1 2 3 4 5 6 7 8 9 10
a2 memuat: 4 5 6 7 8
a3 memuat: 4 5 6 11 15

a1 mencakup a2
a1 tidak mencakup a3

set_difference dari a1 dan a2 adalah: 1 2 3 9 10
set_intersection dari a1 dan a2 adalah: 4 5 6 7 8
set_symmetric_difference dari a1 dan a3 adalah: 1 2 3 7 8 9 10 11 15
set_union dari a1 dan a3 adalah: 1 2 3 4 5 6 7 8 9 10 11 15

Baris 39-40 menggunakan fungsi set_difference untuk menemukan elemen-elemen dari himpunan pertama yang memuat nilai-nilai terurut yang tidak berada di dalam himpunan kedua nilai-nilai terurut (kedua himpunan nilai harus dalam tatanan urutan menaik). Elemen-elemen tersebut disalin ke argumen kelima (pada kasus ini, array difference). Dua argumen iterator pertama sedikitnya harus berupa iterator input untuk himpunan pertama. Dua argumen iterator berikutnya sedikitnya harus berupa iterator input untuk himpunan kedua. Argumen kelima sedikitnya harus berupa iterator output yang mengindikasikan tempat dimana untuk menyimpan salinan nilai-nilai yang berbeda. Fungsi ini menghasilkan nilai balik berupa sebuah iterator output yang diposisikan satu elemen setelah nilai terakhir yang disalin ke lokasi yang ditunjukkan oleh argumen kelima.

Baris 47-48 menggunakan fungsi set_intersection untuk menentukan elemen-elemen dari himpunan pertama yang memuat nilai-nilai terurut yang berada di dalam himpunan kedua yang memuat nilai-nilai terurut (kedua himpunan nilai harus dalam tatanan urutan menaik). Elemen-elemen tersebut disalin ke argumen kelima (pada kasus ini, array intersection). Dua argumen iterator pertama sedikitnya harus berupa iterator input untuk himpunan pertama. Dua argumen iterator berikutnya sedikitnya harus berupa iterator input untuk himpunan kedua. Argumen kelima sedikitnya harus berupa iterator output yang mengindikasikan tempat dimana untuk menyimpan salinan nilai-nilai yang berbeda. Fungsi ini menghasilkan nilai balik berupa sebuah iterator output yang diposisikan satu elemen setelah nilai terakhir yang disalin ke lokasi yang ditunjukkan oleh argumen kelima.

Baris 56-57 menggunakan fungsi set_symmetric_difference untuk menentukan elemen-elemen dari himpunan pertama yang memuat nilai-nilai terurut yang tidak berada di dalam himpunan kedua yang memuat nilai-nilai terurut (kedua himpunan nilai harus dalam tatanan urutan menaik). Fungsi ini juga untuk memastikan bahwa elemen-elemen dari himpunan pertama tidak berada di dalam himpunan kedua. Elemen-elemen tersebut disalin ke argumen kelima (pada kasus ini, array symmetric_difference). Dua argumen iterator pertama sedikitnya harus berupa iterator input untuk himpunan pertama. Dua argumen iterator berikutnya sedikitnya harus berupa iterator input untuk himpunan kedua. Argumen kelima sedikitnya harus berupa iterator output yang mengindikasikan tempat dimana untuk menyimpan salinan nilai-nilai yang berbeda. Fungsi ini menghasilkan nilai balik berupa sebuah iterator output yang diposisikan satu elemen setelah nilai terakhir yang disalin ke lokasi yang ditunjukkan oleh argumen kelima.
Baris 64 menggunakan fungsi set_union untuk menciptakan sebuah himpunan yang memuat semua elemen yang berada di dalam salah satu atau kedua himpunan (kedua himpunan nilai harus dalam tatanan urutan menaik). Elemen-elemen tersebut disalin ke argumen kelima (pada kasus ini, array unionSet). Dua argumen iterator pertama sedikitnya harus berupa iterator input untuk himpunan pertama. Dua argumen iterator berikutnya sedikitnya harus berupa iterator input untuk himpunan kedua. Argumen kelima sedikitnya harus berupa iterator output yang mengindikasikan tempat dimana untuk menyimpan salinan nilai-nilai yang berbeda. Fungsi ini menghasilkan nilai balik berupa sebuah iterator output yang diposisikan satu elemen setelah nilai terakhir yang disalin ke lokasi yang ditunjukkan oleh argumen kelima.

12.8.11 Algoritma lower_bound, upper_bound, dan equal_range
Gambar 12.36 mendemonstrasikan fungsi lower_bound, upper_bound, dan equal_range. Baris 22 menggunakan fungsi lower_bound untuk menemukan lokasi pertama di dalam runtun nilai terurut dimana argumen ketiga dapat disisipkan di dalam runtun tersebut sehingga runtun itu masih tertata terurut secara menaik. Dua argumen iterator pertama sedikitnya harus berupa iterator forward. Argumen ketiga merupakan sebuah nilai untuk menentukan batas bawah. Nilai balik fungsi adalah sebuah iterator forward yang menunjuk ke posisi dimana penyisipan dapat dilakukan. Versi kedua dari fungsi lower_bound mengambil fungsi predikat biner sebagai argumen keempat, yang mengindikasikan tatanan pengurutan elemen.

Baris 28 menggunakan upper_bound untuk menemukan lokasi terakhir di dalam runtun nilai terurut dimana argumen ketiga dapat disisipkan di dalam runtun tersebut sehingga runtun itu masih tertata terurut secara menaik. Dua argumen iterator pertama sedikitnya harus berupa iterator forward. Argumen ketiga merupakan sebuah nilai untuk menentukan batas atas. Nilai balik fungsi adalah sebuah iterator forward yang menunjuk ke posisi dimana penyisipan dapat dilakukan. Versi kedua dari fungsi upper_bound mengambil fungsi predikat biner sebagai argumen keempat, yang mengindikasikan tatanan pengurutan elemen.

Gambar 12.36 Algoritma lower_bound, upper_bound, dan equal_range STL

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 12.36: gambar12_36.cpp
// Algoritma lower_bound, upper_bound dan
// equal_range di dalam STL.
#include <iostream>
#include <algorithm> // definisi algoritma
#include <vector> // definisi template kelas vector
#include <iterator> // ostream_iterator
using namespace std;

int main()
{
  const int UKURAN = 10;
  int a1[ UKURAN ] = { 2, 2, 4, 4, 4, 6, 6, 6, 6, 8 };
  vector< int > v( a1, a1 + UKURAN ); // salinan dari a1
  ostream_iterator< int > output( cout, " " );

  cout << "Vektor v memuat:\n";
  copy( v.begin(), v.end(), output );

  // menentukan batas-bawah titik penyisipan untuk 6 di dalam v
  vector< int >::iterator bawah;
  bawah = lower_bound( v.begin(), v.end(), 6 );
  cout << "\n\nBatas bawah untuk 6 adalah elemen "
    << ( bawah - v.begin() ) << " di vektor v";

  // menentukan batas-atas titik penyisipan untuk 6 di dalam v
  vector< int >::iterator atas;
  atas = upper_bound( v.begin(), v.end(), 6 );
  cout << "\nBatas atas untuk 6 adalah elemen "
   << ( atas - v.begin() ) << " di vektor v";

  // menggunakan equal_range untuk menentukan batas atas dan
  // batas bawah titik penyisipan untuk 6
  pair< vector< int >::iterator, vector< int >::iterator > eq;
  eq = equal_range( v.begin(), v.end(), 6 );
  cout << "\nMenggunakan equal_range:\n Batas bawah dari 6 adalah elemen "
    << ( eq.first - v.begin() ) << " di vektor v";
  cout << "\n Batas atas dari 6 adalah elemen "
    << ( eq.second - v.begin() ) << " di vektor v";
  cout << "\n\nMenggunakan lower_bound untuk melokasi titik pertama\n"
    << "dimana 6 bisa disisipkan";

  // menentukan batas bawah titik penyisipan untuk 5 di dalam v
  bawah = lower_bound( v.begin(), v.end(), 5 );
  cout << "\n Batas bawah untuk 5 adalah elemen "
    << ( bawah - v.begin() ) << " di vektor v";
  cout << "\n\nMenggunakan upper_bound untuk melokasi titik akhir\n"
    << "dimana 7 dapat disisipkan";

  // menentukan batas atas titik penyisipan untuk 7 di dalam v
  atas = upper_bound( v.begin(), v.end(), 7 );
  cout << "\n Batas atas untuk 7 adalah elemen "
    << ( atas - v.begin() ) << " di vektor v";
  cout << "\n\nMenggunakan equal_range untuk melokasi titik pertama dan\n"
   << "titik akhir dimana 5 dapat disisipkan";

  // menggunakan equal_range untuk menentukan batas atas dan
  // batas bawah titik penyisipan untuk 5
  eq = equal_range( v.begin(), v.end(), 5 );
  cout << "\n Batas bawah untuk 5 adalah elemen "
    << ( eq.first - v.begin() ) << " di vektor v";
  cout << "\n Batas atas untuk 5 adalah elemen "
    << ( eq.second - v.begin() ) << " di vektor v" << endl;
} // akhir dari main

Vektor v memuat: 2 2 4 4 4 6 6 6 6 8
Batas bawah untuk 6 adalah elemen 5 di vektor v
Batas atas untuk 6 adalah elemen 9 di vektor v

Menggunakan equal_range:
Batas bawah untuk 6 adalah elemen 5 di vektor v
Batas atas untuk 6 adalah elemen 9 di vektor v

Menggunakan lower_bound untuk melokasi titik pertama
dimana 5 bisa disisipkan
   Batas bawah untuk 5 adalah elemen 5 di vektor v

Menggunakan upper_bound untuk melokasi titik akhir
dimana 7 bisa disisipkan
   Batas atas untuk 7 adalah elemen 9 di vektor v

Menggunakan equal_range untuk melokasi titik pertama dan
titik akhir dimana 5 bisa disisipkan
   Batas bawah untuk 5 adalah elemen 5 di vektor v
   Batas atas untuk 5 adalah elemen 5 di vektor v

Kesimpulan
*      Kontainer dibagi ke dalam tiga kategori utama, yaitu kontainer runtun, kontainer asosiatif, dan kontained adapter.

*      Kontainer STL kelas-pertama menyediakan fungsi begin dan end. Fungsi begin menghasilkan nilai balik berupa sebuah iterator yang menunjuk ke elemen pertama di dalam kontainer. Fungsi end menghasilkan nilai balik berupa sebuah iterator yang menunjuk ke elemen pertama setelah elemen terakhir di dalam kontainer (elemen yang belum ada).

*      STL menyediakan tiga kontainer runtun, yaitu vector, list, dan deque. Template kelas vector dan template kelas deque keduanya didasarkan pada array. Template kelas list mengimplementasikan sebuah struktur data list-berantai.

*      Kontainer asosiatif STL menyediakan akses langsung dalam menyimpan mengambil elemen melalui kunci (seringkali disebut juga dengan kunci pencarian).  Ada empat kontainer asosiatif, yaitu multiset, set, multimap, dan map. Setiap kontainer asosiatif mempunyai kunci dalam tatanan terurut. Kelas multiset dan set menyediakan beberapa operasi untuk memanipulasi sehimpunan nilai dimana nilai-nilai tersebut merupakan kuncinya. Perbedaan utama antara multiset dan set adalah bahwa multiset membolehkan adanya kunci duplikat sedangkan set tidak mengijinkan adanya kunci duplikat.
*      STL menyediakan tiga adapter kontainer, yaitu stack, queue, dan prioriy_queue. Adapter bukan kontainer kelas-pertama, karena ia tidak menyediakan implementasi struktur data aktual dimana di dalamnya elemen-elemen dapat disimpan dan karena adapter tidak mendukung iterator. Keuntungan dari kelas adapter adalah bahwa Anda dapat memilih struktur data yang cocok untuk aplikasi Anda. Ketiga kelas adapter menyediakan fungsi anggota push dan pop yang menyisipkan sebuah elemen ke dalam setiap struktur data adapter dan menghapus sebuah elemen dari setiap struktur data adapter.

*       STL memisahkan algoritma dari kontainer. Hal ini membuat penambahan algoritma baru menjadi lebih mudah. Dengan STL, elemen kontainer dapat diakses melalui iterator.

Latihan

1.      Tulislah sebuah template fungsi palindrome yang mengambil sebuah parameter vector dan menghasilkan nilai balik true atau false tergantung dari apakah vector membaca atau tidak membaca sebuah palindrome. ( Misalnya, vector yang memuat 1 2 3 2 1 adalah sebuah palindrome, tetapi vector yang memuat 1 2 3 4 bukan sebuah palindrome).



No comments:

Post a Comment