Sunday, October 8, 2017

Kuliah 12 C++: STL (Standard Template Library)


BAB 12.
STL (Standard Template Library)






12.1 Pengantar
STL (Standard Template Library) merupakan sebuah koleksi yang terdiri-dari sejumlah kode yang dapat didaur-ulang, yang menangani pelbagai struktur data dan operasi yang umum digunakan oleh para programer. Konsep ini pertama kali dikembangkan oleh Alxender Stepanov dan Meng Lee dari Hawlett-Packard. Koleksi ini kemudian dikembangkan oleh banyak peneliti dan pakar dalam pemrograman C++. STL sekarang merupakan bagian dari pustaka standar C++.

Dengan menggunakan komponen-komponen STL, programer dapat menghemat waktu dan tenaga. Hal itu juga untuk memastikan derajat efisiensi dan akurasi dari program, karena STL ditulis dan diuji oleh para pakar. STL merupakan sekumpulan besar program, yang memiliki tiga komponen utama:
a.        Kontainer-kontainer
b.       Iterator-iterator
c.        Algoritma-algoritma

Kontainer adalah objek yang menyimpan objek-objek lain. Objek-objek yang disimpan itu dapat berupa data bertipe fundamental atau data dengan tipe yang ditentukan user. Penyimpanan, pembacaan, dan pelbagai operasi lain untuk memanipulasi data didasarkan pada kelas-kelas template, jadi kontainer mengijikan penyimpanan dan pemanipulasian sembarang tipe data.

Iterator berperan seperti pointer. Karena iterator didasarkan pada kelas-kelas template, iterator dapat dipakai pada pelbagai tipe data. Fungsi utama dari iterator adalah menyediakan akses terhadap elemen-elemen dari kontainer. Jadi, iterator dapat dipakai untuk menjelajah kontainer dan melakukan operasi-operasi pada elemen kontainer. Ada beberapa jenis iterator, yang dikategorikan berdasarkan kapabilitasnya. Detilnya akan dijelaskan lebih lanjut.

Algoritma adalah potongan-potongan kode yang bisa dipakai untuk memanipulasi data di dalam kontainer dengan bantuan iterator. Algoritma tidak hanya untuk kontainer STL, tetapi dapat pula dipakai pada objek-objek lain seperti array atau string. Pada bab ini, semua topik yang telah disebutkan tersebut akan diintroduksi, sedangkan detil pada kontainer runtun, kontainer asosiatif, dan algoritma akan dibahas terpisah.


12.2 Kontainer
Kontainer dikategorikan ke dalam tiga grup utama: (i) kontainer runtun, (ii) kontainer asosiatif, (iii) kontainer adapter seperti diilustrasikan pada diagram berikut. Ketiganya kemudian dispesialisasi menjadi kontainer-kontainer dengan fungsi-fungsi spesial, sehingga seorang programer dapat memilih mana yang terbaik untuk dipakai dalam menyelesaikan aplikasi. Gambar berikut menunjukkan relasi antara sejumlah kelas kontainer.


GAMBAR 12.1 Kontainer runtun, kontainer asosiatif, dan kontainer adapter


Kontainer runtun dan kontainer asosiatif secara kolektif disebut dengan kontainer kelas pertama karena keduanya dapat menyimpan dan memiliki kapabilitas untuk memanipulasi data dengan bantuan iterator. Kedua kontainer itu juga memiliki sejumlah fungsi pustaka. Kontainer adapter tidak mendukung keberadaan iterator dan tidak dapat memanipulasi data. Kelas adapter hanya memiliki sedikit fungsi pustaka, yang utamanya untuk menempatkan atau menghapus data dari depan atau belakang runtun.

Kontainer runtun pada dasarnya adalah runtun data linier. Elemen data individual dihubungkan dengan elemen-elemen lain berdasarkan posisinya di dalam runtun. Kontainer ini mendukung penyisipan dan penghapusan data di dalam runtun dan dapat mengalokasikan memori tambahan jika jumlah elemen bertambah melebihi kapasitas (memori) yang semula dialokasikan. Oleh karena itu, kontainer ini bersifat dinamis, tidak seperti array yang memiliki panjang tetap yang tidak bisa diubah setelah dideklarasikan. Kontainer runtun ada tiga jenis: (i) vector, (ii) deque (juga disebut dengan antrian ujung ganda, double ended queue), dan (iii) list. Tiap kontainer ini mempunyai spesialitas berbeda.
Sebagai contoh, vektor memiliki akses acak cepat terhadap elemen dan penghapusan cepat terhadap elemen di ujung belakang vektor, tetapi kontainer ini lambat dalam penyisipan dan penghapusan di tengah vektor.

List cepat dalam penyisipan dan penghapusan di tengah dan di ujung depan runtun tetapi tidak mendukung akses acak. List hanya mendukung iterator dwi-arah (bidirectional), oleh karena itu, ia lambat dalam mengakses elemen pada posisi acak. Sama halnya, deque mempunyai kapabilitas akses acak begitu pula dengan penyisipan dan penghapusan di kedua ujung, tetapi kontainer ini lambat dalam penyisipan atau penghapusan elemen di tengah list. Deque juga mendukung iterator acak. Elemen data individual dapat diakses oleh iterator dan bisa dimanipulasi. Sejumlah fitur kunci dari semua kontainer ini diberikan pada Tabel 12.1.

TABEL 12.1 Sejumlah fitur dari semua kontainer
Kontainer
File header
Penjelasan
vector
<vector>
Kontainer ini menyediakan akses langsung terhadap sembarang elemen. Penambahan dan penghapusan cepat di ujung belakang vektor. Untuk fungsi-fungsi dan operator-operator yang didukung oleh kelas vector, lihat Bab 22.
list
<list>
Penyisipan dan penghapusan cepat pada sembarang lokasi di dalam list. Untuk fungsi-fungsi dan operasi-operasi yang didukung oleh kelas list, lihat Bab 22.
deque
<deque>
Memiliki akses langsung terhadap sembarang elemen dari kontainer deque. Penambahan dan penghapusan cepat di kedua ujung antrian. Untuk fungsi-fungsi dan operasi-operasi yang didukung oleh kelas deque, lihat Bab 22.
set
<set>
Hanya nilai-nilai unik yang diijinkan. Salinan-salinan duplikat diabaikan jika disisipkan. Nilai-nilai diurutkan dengan urutan yang ditetapkan seperti urutan menaik atau urutan menurun, dan lainnya (Lihat Bab 23).
multiset
<set>
Sejumlah salinan (duplikasi) dari sebuah nilai diijinkan. Elemen-elemen diurutkan dengan tatanan yang ditetapkan seperti pada set.
map
<map>
Kontainer ini menyimpan pasangan nilai untuk setiap elemen, nilai pertama adalah kunci dan nilai kedua adalah nilai terkait. Elemen-elemen diurutkan berdasarkan kunci dan hanya kunci-kunci unik yang diijinkan. Untuk lebih lengkapnya, lihat Bab 23.
multimap
<map>
Kontainer ini menyimpan pasangan nilai untuk setiap elemen, nilai pertama adalah kunci dan nilai kedua adalah nilai terkait. Elemen-elemen diurutkan berdasarkan kunci dan duplikasi kunci diijinkan. Untuk lebih lengkapnya, lihat Bab 23.
stack
<stack>
Tumpukan objek yang memiliki tatanan first in last out (FILO) atau dengan kata lain objek yang belakangan dimasukkan atau menjadi objek pertama yang akan dihapus. Untuk lebih detil, lihat Subbab 12.6 pada bab ini.
queue
<queue>
Sebuah antrian objek. Tatanannya adalah first in fist out (FIFO) dengan kata lain objek yang pertama dimasukkan atau menjadi objek pertama yang akan dihapus. Untuk lebih detil, lihat Subbab 12.6.2 pada bab ini.
priority queue
<queue>
Sebuah antrian objek. Elemen dengan prioritas tertinggi berada di atas antrian dan akan menjadi elemen yang pertama dihapus. Untuk lebih detil, lihat Subbab 12.6 pada bab ini.



12.3 Iterator
Iterator berperan seperti pointer, yang dipakai untuk mengakses elemen-elemen kontainer. Iterator juga dipakai untuk menjelajah dari satu elemen ke elemen lain dengan menggunakan operattor inkremen dan dekremen. Ada sejumlah tipe iterator, seperti ditampilkan berikut ini.

Iterator
Penjelasan
input_iterator
Iterator ini dapat dipakai untuk membaca nilai-nilai, yang juga dapat diinkremen dan hanya bergerak maju. Operator-operator lain yang didukung oleh input_iterator diberikan pada Tabel 12.2.
output_iterator
Iterator ini dapat dipakai untuk menulis dan dapat diinkremen dan direferensi.
forward_iterator
Iterator ini dapat dipakai untuk membaca atau menulis, yang hanya bisa bergerak maju.
bidirectional_iterator
Iterator ini dapat dipakai untuk membaca atau menulis, yang dapat bergerak maju atau mundur (dapat diinkremen maupun didekremen).
random_iterator
Iterator ini dipakai untuk mengakses secara acak terhadap suatu elemen. Iterator ini dapat pula dipakai untuk pembacaan dan penulisan. Iterator acak memiliki semua karakteristik dari iterator-iterator lain.


DEKLARASI ITERATOR
Deklarasi iterator untuk sebuah vector<int> diilustrasikan sebagai berikut:


GAMBAR 12.2 Deklarasi dan penugasan suatu iterator pada kelas vector


Deklarasi dan penugasan dapat digabungkan sebagai berikut:

vector<int> :: iterator Iter = V1.begin();

Nilai dari elemen yang ditunjuk oleh iterator didapatkan dengan menggunakan operator dereferensi (*). Sebagai contoh, nilai dari elemen pertama pada vektor V1 dari deklarasi di atas diberikan oleh *Iter dan nilai dari elemen kedua adalah *(++Iter).


OPERATOR-OPERATOR PADA ITERATOR-ITERATOR
Ada lima tipe iterator yang telah didiskusikan sebelumnya. Setiap tipe iterator mendukung sejumlah operator seperti dicantumkan pada Tabel 12.2.

TABEL 12.2 Operator-operator yang didukung oleh pelbagai iterator
Input iterator
Output iterator
Forward iterator
Bidirectional  iterator
Random iterator
Penjelasan
++itr
++itr
++itr
++itr
++itr
pra-inkremen
itr++
itr++
itr++
itr++
itr++
pasca-inkremen
*itr
hanya untuk membaca

*itr
*itr
*itr
nilai = *itr. Lihat program 12.1.

*itr
hanya untuk menulis
*itr
*itr
*itr
*itr = nilai. Lihat program 12.2.
itr1 == itr2

itr1 == itr2
itr1 == itr2
itr1 == itr2
perbandingan ekualitas
itr1 != itr2

itr1 != itr2
itr1 != itr2
itr1 != itr2
perbandingan inekualitas




itr1 = itr2
penugasan



--itr
--itr
pra-dekremen



itr--
itr--
pasca-dekremen




itr + k
bertambah sebesar int k




itr – k
berkurang sebesar int k




itr += k
bertambah sebesar int k dan penugasan




itr –= k
berkurang sebesar int k dan penugasan




[k]
operator subskript




itr1 < itr2
perbandingan kurang dari atau lebih kecil dari




itr1>itr2
perbandingan lebih dari atau lebih besar dari




itr1<=itr2
perbandingan lebih kecil dari atau sama dengan




itr1>=itr2
perbandingan lebih besar dari atau sama dengan



12.4 Kontainer Runtun
Sejumlah fitur dari kontainer telah didiskusikan pada Tabel 12.1. Kontainer runtun terdiri-dari tiga kontainer yaitu vector, list, dan deque. Di sini, akan diberikan beberapa contoh ilustratif dari ketiga kontainer tersebut. Untuk lebih detil, silahkan lihat Bab 22.

VEKTOR
Vektor adalah array dinamis. Jumlah elemen bisa berubah selama eksekusi program. Di sini, beberapa fitur dari vektor akan diilustrasikan. Program berikut memberikan sebuah ilustrasi dari vektor, iterator, dan fungsi push_back(), begin(), end(), dan lainnya. Untuk fungsi-fungsi dan operator-operator lain yang didukung oleh kelas vector, silahkan lihat Bab 22.

Program 12.1 Mengilustrasikan aplikasi dari vektor dan input iterator dari istream

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

vector<int> V; //Deklarasi dari sebuah vektor dengan elemen-elemen int

int main()
{
   cout<<"Masukkan 5 integer: "<<endl;
   istream_iterator <int> readit(cin);  //input iterator

   /*Berikut adalah fungsi push_back() yang dipakai untuk menambahkan elemen-elemen
     di belakang sebuah vektor V.*/
   V.push_back (*readit++);
   V.push_back (*(readit++));
   V.push_back (*(readit++));
   V.push_back (*(readit++));
   V.push_back (*(readit));

   cout<<"Elemen-elemen dari V adalah: ";
   vector<int>:: iterator iter = V.begin();
   /*vector adalah nama kelas, iterator adalah katakunci. iter adalah nama iterator.
     Fungsi begin() menghasilkan iterator yang menunjuk ke elemen pertama dari V.
     Kelas vector mendukung keberadaan iterator random (acak).*/
  
   while(iter != V.end())
   //end() menghasilkan iterator yang menunjuk ke tepat setelah elemen terakhir dari vektor
      cout<<*iter++ <<" "; //menampilkan nilai-nilai elemen dari vektor

   return 0;
}
KELUARAN
Masukkan 5 integer:
20 30 40 50 60
Elemen-elemen dari V adalah: 20 30 40 50 60


Berikut adalah program lain yang menangani vektor dan menggunakan iterator untuk menjelajah vektor tersebut.

Program 12.2 Mengilustrasikan aplikasi dari vektor dan input iterator dari istream untuk menjelajah vektor

#include<iostream>
#include<vector>
#include <iterator>
using namespace std;

vector<int> V;  //Deklarasi dari sebuah vektor dengan elemen-elemen int

int main()
{
   cout<<"Masukkan 5 integer: "<<endl;
   int hitung =0;
   while (hitung <=4)
   {
      istream_iterator <int> readit(cin); //input iterator
      V.push_back (*readit);
      ++hitung;
   }

   //Vektor dikonstruksi dengan menempatkan elemen-elemen di belakang vektor.
   cout<<"\nElemen-elemen dari V adalah: ";
   vector<int>:: iterator iter = V.begin(); // iterator didefinisikan
   //iter adalah nama iterator, yang akan dipakai untuk menjelajah vektor

   while(iter != V.end())
   {
      cout<< *iter <<" ";
      iter++;
   }

   return 0;
}
KELUARAN
Masukkan 5 integer:
30 45 56 67 78

Elemen-elemen dari V adalah: 30 45 56 67 78


DEQUE
Program berikut mengilustrasikan operasi-operasi pada sebuah deque, seperti deklarasi deque, konstruksi deque, dan input iterator dan output iterator dari iostream. Deque juga mendukung random iterator sehingga semua elemen dapat diakses secara langsung. Untuk lebih detil tentang deque, silahkan lihat Bab 22.

Program 12.3 Mengilustrasikan aplikasi dari input iterator dan output iterator pada deque

#include<iostream>
#include<deque>
#include <iterator>
using namespace std;

deque<int> Dek; //deklarasi deque dengan elemene-elemen int

int main()
{
   cout<<"Masukkan 4 buah integer: "<<endl;

   int hitung =0;
   while (hitung < 4)
   {
      istream_iterator <int> readit(cin);
      Dek.push_back (*readit);
      ++hitung;
   }

   int k=0;
   cout<<"\nElemen-elemen dari Dek adalah: ";
   while (k <4)
   {
      ostream_iterator <int> writeit(cout);
      * writeit= * (Dek.begin()+k );
      cout<<" ";
      k++;
   }

   return 0;
}
KELUARAN
Masukkan 4 buah integer:
12 34 56 78

Elemen-elemen dari Dek adalah: 12 34 56 78


LIST
Program berikut mengilustrasikan kontainer list. List ini seperti senarai berantai ganda (doubly linked list). Program ini mengilustrasikan deklarasi list, konstruksinya, dan bagaimana menampilkan elemen-elemen list.

Program 12.4 Mengilustrasikan konstruksi dari list dan bagaimana mengisi dan menampilkan list

#include<iostream>
#include<list>
using namespace std;

list<char> Lc ;      //deklarasi dari sebuah list dengan nama Lc dan bertipe char
list<int> Li (7,60); //deklarasi dari sebuah list dengan Li
                     //list ini memiliki 7 elemen int dengan tiap nilai 60

int main()
{
   for (int i=0; i<6;i++)
      Lc.push_back(65+i); //Menambahkan elemen-elemen di belakang list Lc

   cout<<"Elemen pertama dari Lc adalah "<<Lc.front()<<" dan elemen akhirnya adalah "
       <<Lc.back()<<endl; //menampilkan elemen pertama dan elemen akhir

   list<double>Ld(3,2.5); //List Ld mempunyai tiga elemen masing-masing dengan nilai 2.5

   for (int j =0; j< 3; j++)
   {
      Ld.push_back( 5.5); //Menambahkan 3 elemen, dengan nilai 10.5, di belakang list
      Ld.push_front( 10.5);
   } //Menambahkan 3 elemen, dengan nilai 10.5, di depan list

   cout<<"Lc = ";
   list<double>::iterator itrd;          //iterator untuk list double
   list<int>:: iterator itri;            //deklarasi iterator untuk list int
   list <char>:: iterator itrc;          //iterator untuk list char

   for(itrc= Lc.begin(); itrc!=Lc.end(); itrc++)
      cout << *itrc <<" "; //menampilkan elemen-elemen dari list Lc.

   cout<<"\nLi = ";
   for(itri= Li.begin(); itri!=Li.end(); itri++)
      cout<<*itri<<" "; // menampilkan elemen-elemen dari list Li.

   cout<<"\n Ld = ";
   for(itrd= Ld.begin(); itrd!=Ld.end(); itrd++)
      cout<<*itrd<<" "; //menampilkan elemen-elemen dari list Ld.

   cout<<"\nElemen pertama dari Ld = " <<*(Ld.begin())<<endl;

   cout<<"\nElemen ketiga dari Ld dari awal = "<<*(++(++ Ld.begin())) ;
   //kelas list tidak mendukung akses acak

   cout<<"\nElemen ketiga dari Ld dari akhir = "<< * (--(-- Ld.end()))<<endl;

   return 0;
}
KELUARAN
Elemen pertama dari Lc adalah A dan elemen akhirnya adalah F
Lc = A B C D E F
Li = 60 60 60 60 60 60 60
 Ld = 10.5 10.5 10.5 2.5 2.5 2.5 5.5 5.5 5.5
Elemen pertama dari Ld = 10.5

Elemen ketiga dari Ld dari awal = 10.5
Elemen ketiga dari Ld dari akhir = 5.5



12.5 Kontainer Asosiatif
Kontainer asosiatif mendukung pembacaan cepat atas elemen-elemen melalui kunci-kunci. Kontainer asosiatif ini terdiri-diri (i) set, (ii) multiset, (iii) map, dan (iv) multimap. Ukuran kontainer dapat berubah selama eksekusi program. Elemen-elemen dari set asosiatif bertipe value_type. Setiap elemen memiliki kunci yang bertipe key-type. Pada kasus set dan multiset, nilai elemen itu sendiri adalah kunci. Pada kasus map dan multimap, kunci berbeda dari nilai elemen. Jadi, pada set dan multiset, sebuah elemen terdiri-dari satu nilai, sedangkan pada map dan multimap, sebuah elemen terdiri-dari sepasang kunci dan nilai.

Set hanya mengijinkan kunci-kunci unik, sedangkan multiset mengijinkan adanya kunci-kunci duplikat. Sama halnya, map hanya mengijinkan kunci-kunci unik, sedangkan multimap mengijinkan adanya kunci-kunci duplikat. Program berikut mengilustrasikan konstruksi dan pembacaan/penampilan dari sebuah map. 

Program 12.5 Mengilustrasikan konstruksi dari map dan cara menampilkan elemen-elemennya

#include<iostream>
using namespace std;
#include<map>
#include<string>

typedef map <string, int> Mint;
/*typedef digunakan untuk menghindari penulisan map<string, int> berulangkali.
Pada deklarasi, kunci adalah sebuah string dan nilai int.*/

int main()
{
   string Nama;
   int Skor;

   Mint Nilai; //Nilai adalah nama map

   for (int i = 0; i<4; i++)
   {
      cout<<"Masukkan Nama: ";
      cin>>Nama;
      cout<<"Masukkan Skor: ";
      cin>>Skor;

      Nilai[Nama] = Skor;
   } //membuat pasangan-pasangan nilai

   Mint :: iterator iter; // deklarasi iterator

   for(iter = Nilai.begin(); iter != Nilai.end(); iter++)
      cout<<(*iter).first<<"\t"<<(*iter).second<<"\n";
      /*first adalah kunci dan second adalah nilai. Operator dot dipakai
           untuk memilih first dan second.*/

   return 0;
}
KELUARAN
Masukkan Nama: Kristof
Masukkan Skor: 78
Masukkan Nama: John
Masukkan Skor: 89
Masukkan Nama: Vivian
Masukkan Skor: 99
Masukkan Nama: Marolop
Masukkan Skor: 98
John    89
Kristof 78
Marolop 98
Vivian  99



12.6 Kontainer Adapter: Tumpukan (stack), Antrian (queue), dan Antrian Prioritas (priority queue)
Tumpukan, antrian, dan antrian prioritas adalah kontainer-kontainer adapter di dalam STL. Ketiganya tidak mendukung adanya iterator dan tidak memiliki struktur implementasi data sendiri seperti vektor, list, dan lainnya. Namun ketiga kontainer adapter ini dapat beradaptasi dengan struktur data dari kontainer lain. Oleh karena itu, programer dapat memilih kontainer yang cocok dengan permasalahan yang akan ditangani.

TUMPUKAN
Tumpukan memiliki kapabilitas penyisipan dan penghapusan data di awal (atas) tumpukan, dengan tatanan LIFO (last in first out). Hal ini diilustrasikan pada Gambar 12.3, yang menunjukkan bahwa piring-piring ditumpuk satu di atas yang lain. Untuk mengambil sebuah piring, hal itu dilakukan dengan mengambilnya dari atas tumpukan. Jadi, piring yang terakhir kali ditempatkan akan diambil pertama kali. Ada banyak aplikasi tumpukan, sebagai contoh, kompiler membuat tumpukan kode mesin dari kode sumber. Fungsi-fungsi yang didukung oleh kelas stack dicantumkan pada Tabel 12.3.


GAMBAR 12.3 Tatanan LIFO (last in first out)


TABEL 12.3 Fungsi-fungsi yang berkaitan dengan tumpukan
Fungsi
Penjelasan
empty()
Fungsi ini menghasilkan true jika tumpukan kosong.
pop()
Fungsi ini menghapus sebuah elemen dari atas tumpukan.
push()
Fungsi ini menempatkan sebuah elemen di atas tumpukan.
size()
Fungsi ini menghasilkan jumlah elemen pada tumpukan.
top()
Fungsi ini menghasilkan elemen teratas pada tumpukan.


Program berikut mengilustrasikan implementasi dari sebuah tumpukan. Fungsi push() dipakai untuk mengisi tumpukan.

Program 12.6 Mengilustrasikan aplikasi dari beberapa fungsi pada tumpukan

#include<iostream>
#include<stack>
using namespace std;

void main()
{
   stack<int> St1 ; //St1 dideklarasikan sebagai tumpukan integer

   for (int i =1; i< 7; i++) // konstruksi tumpukan oleh fungsi push()
      St1.push (10* i);

   //Elemen-elemen yang diisikan adalah 10, 20, 30, 40, 50, 60
   //Pada tumpukan, tatanannya adalah LIFO
   cout <<"Elemen teratas pada St1 = "<<St1.top()<<endl;

   cout<<"Ukuran dari tumpukan adalah = "<<St1.size()<<endl;

   cout<<"Elemen-elemen dari St1 adalah: ";
   while(!St1.empty()) //statemen untuk menampilkan elemen-elemen tumpukan
   {
      cout<<St1.top()<<" ";
      St1.pop() ;
   } //menghapus elemen teratas
}
KELUARAN
Elemen teratas pada St1 = 60
Ukuran dari tumpukan adalah = 6
Elemen-elemen dari St1 adalah: 60 50 40 30 20 10


Pada program di atas, tumpukan dikonstruksi dengan menempatkan nilai-nilai. Pada statemen keluaran, elemen teratas ditempatkan lebih dahulu ke aliran keluaran, kemudian, elemen teratas itu dihapus dengan fungsi pop(). Elemen berikutnya setelah elemen teratas tersebut ditempatkan ke aliran keluaran, dan kemudian dihapus. Proses berlanjut sampai elemen terakhir dihapus. Dari keluaran program dapat dilihat bahwa elemen pertama pada aliran keluaran adalah elemen terakhir yang ditempatkan pada tumpukan. Program berikut menyajikan contoh lain dari tumpukan.

Program 12.7 Mengilustrasikan contoh lain dari tumpukan dengan beberapa tipe elemen berbeda

#include<iostream>
#include<stack>
#include <string>
using namespace std;

void main()
{
   stack<int> Ski ;        //deklarasi tumpukan integer
   stack<char> Sch;        //deklarasi tumpukan char
   stack<string> Skt ;     //deklarasi tumpukan string

   string Nama[4]={"Jakarta", "Medan", "Surabaya", "Bandung"};
   char ch[4] = {'B', 'A', 'C', 'T'};
   int Array[5] = { 10, 40, 60,20,10 };

   for (int i = 0;i < 4; i++)
   {
      Ski.push (Array[i]); //menempatkan 4 elemen pada tumpukan Ski
      Sch.push (ch[i]);           //menempatkan 4 elemen pada tumpukan Sch
      Skt.push (Nama[i]);  //menempatkan 4 elemen pada tumpukan Skt
   }

   cout<<"Elemen teratas pada Skt = "<<Skt.top()<<endl;
   cout<<"Elemen teratas pada Sch = "<<Sch.top()<<endl;
   cout<<"Elemen teratas pada Ski = "<<Ski.top()<<endl;

   cout<<"Ukuran dari tumpukan Skt adalah = "<<Skt.size()<<endl;

   cout<<"Elemen-elemen dari ketiga tumpukan adalah sebagai berikut: "<<endl;
   for (int j = 0;j < 4; j++)
   {
      cout<<Skt.top()<<"\t"<< Sch.top()<<"\t"<<Ski.top()<<"\n";
      Skt.pop() ;    //menghapus elemen teratas pada Skt
      Sch.pop();     //menghapus elemen teratas pada Sch
      Ski.pop();     //menghapus elemen teratas pada Ski
   }
}
KELUARAN
Elemen teratas pada Skt = Bandung
Elemen teratas pada Sch = T
Elemen teratas pada Ski = 20
Ukuran dari tumpukan Skt adalah = 4
Elemen-elemen dari ketiga tumpukan adalah sebagai berikut:
Bandung    T       20
Surabaya   C       60
Medan      A       40
Jakarta    B       10



Program 12.8 Mengilustrasikan tumpukan dengan memanfaatkan kontainer vektor

#include<iostream>
#include<stack>
using namespace std;

#include <vector>

int main()
{
   stack <int, vector <int> > Tumpukan1, Tumpukan2, Tumpukan3;
   //Deklarasi tumpukan int
   //Kontainer yang digunakan adalah vektor

   int Array1[] = {12, 13, 14, 15, 16};
   int Array2[] = {40, 60, 20, 10, 50};

   for (int i = 0;i < 5; i++)
   {
      Tumpukan1.push (Array1[i]);
      Tumpukan2 .push (Array2[i]);
   }
     
   Tumpukan3 = Tumpukan2; // Tumpukan2 ditugaskan kepada Tumpukan3

   cout<<"Ukuran dari Tumpukan3 adalah = "<<Tumpukan3 .size()<<endl;

   if ( Tumpukan2 == Tumpukan3 ) // relational == operator
      cout<< "Tumpukan3 dan Tumpukan2 sama.\n";
   else
      cout<<"Tumpukan3 dan Tumpukan2 tidak sama.\n";

   Tumpukan3.push(80); //menambahkan elemen lain pada tumpukan

   cout <<"Sekarang ukuran dari Tumpukan3 = "<<Tumpukan3.size()<<endl;

   for (int j = 0;j < 6; j++) //untuk menampilkan elemen-elemen tumpukan
   {
      cout<<Tumpukan3.top()<<" " ; //menampilkan elemen teratas pada Tumpukan3
      Tumpukan3.pop(); // menghapus elemen teratas dari Tumpukan3
   }
   cout<<endl;

   return 0;
}
KELUARAN
Ukuran dari Tumpukan3 adalah = 5
Tumpukan3 dan Tumpukan2 sama.
Sekarang ukuran dari Tumpukan3 = 6
80 50 10 20 60 40


ANTRIAN
Pada antrian, elemen-elemen data disisipkan di belakang antrian dan dihapus dari depan antrian. Urutan yang sama terjadi pada antrian di kehidupan nyata, dengan tatanan FIFO (first in first out). Hal ini diilustrasikan pada gambar berikut. Antrian dapat diisi dengan memanfaatkan fungsi push().


GAMBAR 12.4 Ilustrasi dari antrian


Sejumlah fungsi yang berkaitan dengan antrian dicantumkan pada Tabel 12.4.

TABEL 12.4 Fungsi-fungsi yang berkaitan dengan antrian
Fungsi
Penjelasan
back()
Fungsi ini menghasilkan sebuah referensi yang menunjuk ke elemen terakhir di dalam antrian.
empty()
Fungsi ini menghasilkan true jika antrian kosong.
front()
Fungsi ini menghasilkan sebuah referensi yang menunjuk ke elemen pertama di dalam antrian.
pop()
Fungsi ini menghapus sebuah elemen dari depan antrian.
push()
Fungsi ini menambahkan sebuah elemen di akhir antrian.
size()
Fungsi ini menghasilkan jumlah elemen di dalam antrian.


Program berikut mengilustrasikan sejumlah operasi pada antrian.

Program 12.9 Mengilustrasikan aplikasi dari sejumlah fungsi pada antrian

#include<iostream>
#include<queue>
using namespace std;

void main()
{
   queue <int> Q ;

   for (int i =1; i<7; i++)
      Q.push (10* i);

   //Pada antrian, tidak ada fungsi top(), tetapi yang dimiliki
   //adalah fungsi front().
   //Penampilan elemen-elemen dari depan antrian diilustrasikan
   //di bawah ini.

   cout<<"Elemen di depan antrian Q adalah = "<<Q.front()<<endl;

   cout<<"Ukuran dari antrian Q adalah = "<<Q.size()<<endl;

   cout<<"Elemen-elemen dari Q adalah: ";
   while(!Q.empty()) //statemen keluaran untuk antrian
   {
      cout<<Q.front()<<" ";
      Q.pop();
   }
   cout<<endl;
}
KELUARAN
Elemen di depan antrian Q adalah = 10
Ukuran dari antrian Q adalah = 6
Elemen-elemen dari Q adalah: 10 20 30 40 50 60


Program berikut mengilustrasikan sejumlah operator yang didukung oleh kelas queue.

Program 12.10 Mengilustrasikan aplikasi dari sejumlah operator pada antrian

#include<iostream>
#include<queue>
using namespace std;

int main()
{
   queue<int> q2,q3 ;
   queue<double> q1;

   for (int i =0; i< 6; i++)
   {
      q1.push (1.5*i);
      q2.push (i*i);
   }

   q3 = q2; //operator penugasan

   if( q2 == q3)
      cout<<"Sekarang antrian q2 dan q3 sama."<<endl;
   else
      cout<<"Sekarang antrian q2 dan q3 tidak sama."<<endl;

   cout<<"Elemen-elemen antrian q2 adalah: ";
   while(!q2.empty())
   {
      cout<<q2.front()<<" " ;
      q2.pop();
   }
   cout<<"\n";

   cout<<"Elemen-elemen antrian q3 adalah: ";
   while(!q3.empty())
   {
      cout<<q3.front()<<" " ;
      q3.pop();
   }
   cout<<"\n";

   if( q2 == q3)
      cout<<"Antrian q2 dan q3 sama."<<endl;
   else
      cout<<"Antrian q2 dan q3 tidak sama."<<endl;

   cout<<"menempatkan elemen lain, 10, ke dalam q3 \n";
   q3.push (10);

   cout<<"Elemen-elemen antrian q3 adalah: ";
   while(!q3.empty())
   {
      cout<<q3.front()<<" " ;
      q3.pop();
   }
   cout <<"\n";

   cout<<"Elemen-elemen antrian q1 adalah: ";
   while(!q1.empty())
   {
      cout<<q1.front()<<" " ;
      q1.pop();
   }
   cout <<"\n";

   return 0;
}
KELUARAN
Sekarang antrian q2 dan q3 sama.
Elemen-elemen antrian q2 adalah: 0 1 4 9 16 25
Elemen-elemen antrian q3 adalah: 0 1 4 9 16 25
Antrian q2 dan q3 sama.
menempatkan elemen lain, 10, ke dalam q3
Elemen-elemen antrian q3 adalah: 10
Elemen-elemen antrian q1 adalah: 0 1.5 3 4.5 6 7.5


Pada program tersebut, tiga antrian dideklarasikan, yaitu dua antrian int dan satu antrian double. Antrian q1 dan q2 dikonstruksi dengan fungsi push() sedangkan antrian q3 dibuat sebagai salinan dari antrian q2. Elemen-elemen ditambahkan di belakang antrian dan dihapus dari depan antrian. Aplikasi dari fungsi empty() dan front() dan operator ++ diilustrasikan. Setelah penugasan q3 = q2;, kedua antrian menjadi sama. Setelah elemen-elemen dihapus, kedua antrian itu tetap sama karena tidak ada lagi elemen di dalam kedua antrian. Kemudian sebuah elemen (10) ditambahkan ke dalam q3. Sekarang, elemen di dalam q3 adalah 10. Pada baris terakhir dari keluaran program, elemen-elemen dari q1 ditampilkan. Setelah ditampilkan, tidak ada lagi elemen di dalam q1 karena semua elemen dihapus saat penampilan.


ANTRIAN PRIORITAS
Antrian prioritas merupakan antrian dimana di dalamnya elemen-elemen diurutkan menggunakan sebuah predikat. Secara default, elemen dengan nilai tertinggi berada di depan antrian. Sejumlah fungsi yang berkaitan dengan antrian prioritas dicantumkan pada Tabel 12.5. Di sini, fungsi top() dipakai untuk menunjuk elemen yang ada di ujung depan antrian, menggantikan fungsi front() yang digunakan pada antrian biasa.

TABEL 12.5 Fungsi-fungsi yang berkaitan dengan antrian prioritas
Fungsi
Penjelasan
empty()
Fungsi ini menghasilkan true jika antrian prioritas kosong.
top()
Fungsi ini menghasilkan elemen pertama di dalam antrian prioritas.
pop()
Fungsi ini menghapus sebuah elemen dari depan antrian prioritas.
push()
Fungsi ini menambahkan sebuah elemen di akhir antrian prioritas.
size()
Fungsi ini menghasilkan jumlah elemen di dalam antrian prioritas.

Program berikut mengilustrasikan aplikasi dari sejumlah fungsi ini.

Program 12.11 Mengilustrasikan antrian prioritas

#include<iostream>
#include<queue>
using namespace std;

void main()
{
   priority_queue <int> PQ ; //deklarasi antrian prioritas
   int Array[6] = {10, 80, 90, 20, 40, 70};

   for (int i =0; i<6; i++)
      PQ.push (Array[i]);

   //pada antrian prioritas, tidak ada front(), tetapi yang ada top()
   cout<<"Elemen di atas (depan) antrian PQ = "<<PQ.top()<<endl;

   cout<<"Ukuran dari antrian PQ adalah = "<<PQ.size()<<endl;

   cout<<"Elemen-elemen dari PQ adalah: ";
   while(!PQ.empty())
   {
      cout<<PQ.top()<<" ";
      PQ.pop();
   }
   cout<<endl;
}
KELUARAN
Elemen di atas (depan) antrian PQ = 90
Ukuran dari antrian PQ adalah = 6
Elemen-elemen dari PQ adalah: 90 80 70 40 20 10



12.7 Objek Fungsi (Predikat)
Objek fungsi adalah sebuah objek kelas yang berperan sebagai sebuah fungsi dan menghasilkan nilai bool, yang didasarkan pada argumen (yang bisa berupa elemen kontainer) memenuhi fungsi atau tidak. Pada beberapa algoritma, elemen-elemen dari sebuah kontainer dipilih berdasarkan apakah elemen memenuhi sebuah predikat atau tidak. Algoritma diimplementasikan untuk menghasilkan nilai balik. Jika nilai balik adalah true, maka algoritma diimplementasikan. Sebaliknya jika nilai balik false, maka algoritma tidak diimplementasikan. Sebelum mendemonstrasikan objek fungsi, berikut akan disajikan sebuah fungsi biasa yang berperan sebagai predikat.

Program 12.12 Mengilustrasikan fungsi global sebagai predikat di dalam algoritma

#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;

bool Ganjil(int n) //definisi dari fungsi untuk nilai-nilai ganjil
{
   return n%2 ? true : false;
}

bool Genap(int m ) //definisi dari fungsi untuk nilai-nilai genap
{
   return !(m%2) ? true: false;
}

int main()
{
   int S[] = {5, 6, 8, 7, 4, 3, 8, 10, 11, 12};
   int n = count_if(S, S+10, Genap);

   /*count_if() adalah sebuah algoritma. Genap adalah alamat dari
     (pointer yang menunjuk ke) fungsi Genap(). Fungsi count_if diimplementasikan
        jika elemen memenuhi fungsi Genap*/

   cout<<"Jumlah elemen genap pada S adalah = "<<n<<endl;

   int K = count_if(S, S+10, Ganjil);
   /*Ganjil adalah alamat dari
     (pointer yang menunjuk ke) fungsi Ganjil(). Fungsi count_if diimplementasikan
        jika elemen memenuhi fungsi Ganjil*/

   cout<<"Jumlah elemen ganjil pada S adalah = "<<K<<endl;

   return 0;
}
KELUARAN
Jumlah elemen genap pada S adalah = 6
Jumlah elemen ganjil pada S adalah = 4


Pada kasus di atas, elemen-elemen diperiksa apakah dapat dibagi dengan 2 (divisibel, tanpa sisa) atau tidak dan sesuai dengan nilai balik bool, true atau false, elemen tersebut akan dihitung atau ditolak. Salah satu fungsi (Ganjil) menguji apakah elemen merupakan nilai ganjil sedangkan fungsi kedua (Genap) menguji apakah elemen merupakan nilai genap. Meskipun sebenarnya hanya satu fungsi yang diperlukan, kedua fungsi dicantumkan untuk mengilustrasikan kedua bentuk fungsi. Pemilihan genap atau ganjil didasarkan pada nilai balik dari kedua fungsi tersebut.

Sama halnya, Anda dapat mendefinisikan sebuah fungsi untuk menentukan apakah integer tertentu divisibel (dapat dibagi tanpa menghasilkan sisa) oleh integer lain atau tidak. Pada kasus semacam itu, jika pembagi diubah, maka, untuksetiap pembagi baru, program juga perlu diubah. Adalah lebih baik mendefinisikan sebuah kelas dengan fungsi sebagai objek dari kelas itu. Hal ini lebih mudah karena objek kelas dapat memuat data (pembagi, pada kasus itu). Dengan skema semacam itu, fungsi tersebut dinamakan dengan objek fungsi, yang diilustrasikan berikut ini.

Program 12.13 Mengilustrasikan definisi predikat sebagai kelas template

#include<iostream>
#include<algorithm>
using namespace std;

template <class T>
class LBS { // LBS = Lebih Besar atau Sama dengan
   private :
      T x;
   public :
      LBS (T A){x = A;} //konstruksi fungsi
      bool operator() (T y)
         {return y >= x ? true :false;}
}; // akhir kelas

int main()
{
   LBS <int> lbs(30);                    //lbs dideklarasikan sebagai objek dari LBS untuk int
   LBS <double> lbs2(25.0);       //lbs2 adalah objek untuk double 25.0

   int S[] = {10, 20, 30, 36, 44, 60, 70};
   double SD[] = {3.5, 27.5, 22.6, 56.7, 80.0, 90.7, 65.5, 35.5};

   //count_if() adalah sebuah algoritma
   int m = count_if(S, S+7, lbs);        //di sini lbs adalah predikat

   cout<<"Jumlah elemen dengan S >= 30 adalah = "<<m<<endl;

   int n = count_if(SD, SD+8, lbs2);     //di sini lbs2 adalah predikat

   cout<<"Jumlah elemen dengan SD >= 25.0 adalah = "<<n<<endl;

   return 0;
}
KELUARAN
Jumlah elemen dengan S >= 30 adalah = 5
Jumlah elemen dengan SD >= 25.0 adalah = 6


Pada program tersebut, objek lbs dan lbs2 berperilaku seperti fungsi. Nilai-nilai inisialisasi untuk kedua objek itu, 30 dan 25.0, menjadi argumen fungsi. Hal ini merupakan pilihan yang lebih baik daripada fungsi predikat pada program sebelumnya.

Ada sejumlah predikat pustaka di dalam C++, seperti dicantumkan padan Tabel 12.6 berikut. Seperti yang telah didemonstrasikan sebelumnya, user dapat mengembangkan predikatnya sendiri.



12.8 Predikat-Predikat Pustaka dalam C++
Ada sembilan predikat relasional dan logikal yang didefinisikan di dalam file header <functional>. Sejumlah predikat yang disediakan di dalam file header itu dicantumkan pada Tabel 12.6.

TABEL 12.6 Predikat-predikat pustaka di dalam file header <functional>
Predikat
Unary/binary
Operasi ekivalen
plus
binary
x + y
minus
binary
x – y
multiplies
binary
x * y
divides
binary
x / y
modulus
binary
x % y
negate
unary
-x
equal_to
binary
x==y
not_equal_to
binary
x!=y
greater
binary
x>y
greater_equal
binary
x>=y
less
binary
x<y
less_equal
binary
x<=y
logical_and
binary
x&&y
logical_or
binary
x||y
logical_not
unary
!x

Ilustrasi kegunaan dari beberapa predikat diberikan oleh program 12.14 berikut ini.

Program 12.14 Mengilustrasikan aplikasi predikat greater dan less dengan algoritma sort()

#include<iostream>
#include<algorithm>
#include<functional> //file header untuk predikat-predikat pustaka
using namespace std;

int main()
{
   int S[8] = {5, 6, 8, 7, 4, 3, 8, 9};
   char ch[] = {'A', 'Z', 'C', 'M', 'G', 'K', 'T'};

   sort(S, S+8, less<int>());            //menata dengan urutan menaik

   sort(ch, ch+7, greater<int>()); //menata dengan urutan menurun

   for (int i =0; i<8;i++)
      cout<<S[i]<<" ";
   cout <<endl;

   for (int j =0; j< 7 ; j++)
      cout << ch[j]<<" ";
   cout<<endl;

   return 0;
}
KELUARAN
3 4 5 6 7 8 8 9
Z T M K G C A

Pada baris pertama dari keluaran, elemen-elemen array diurutkan dengan tatanan menaik. Pada baris kedua dari keluaran, karakter-karakter diurutkan dengan tatanan menurun.



12.9 Fungsi Binder
Ketika setiap elemen runtun dibandingkan dengan suatu nilai untuk kepentingan aksi selanjutnya, adalah lebih baik mengikat nilai itu dengan predikat menggunakan fungsi binder. Dua fungsi biner didefinisikan berikut.

bind1st(x)    //memanggil atau mengikat fungsi dengan x sebagai argumen pertama.
bind2nd(y)    //memanggil atau mengikat fungsi dengan x sebagai argumen kedua.

Aplikasi dari bind2nd() diilustrasikan pada program berikut.

Program 12.15 Mengilustrasikan aplikasi dari bind2nd()

#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;

template <class T>
struct LbhBesar: binary_function< T, T, bool> {
   bool operator ()(const T & x, const T& y) const
   {
      return ( x >y );
   }
};

int main()
{
   int S[10] = {5, 6, 8, 7, 4, 3, 8, 9, 12, 14};
  
   int n = count_if( S, S +10, bind2nd(LbhBesar<int>(), 7));

   cout<<"Jumlah elemen yang lebih besar dari 7 adalah: "<<n<<endl;

   return 0;
}
KELUARAN
Jumlah elemen yang lebih besar dari 7 adalah: 5

Program berikut menggunakan objek fungsi pustaka greater dan less.

Program 12.16 Mengilustrasikan aplikasi dari predikat greater dan less dengan fungsi bind2nd()

#include<iostream>
#include<algorithm>
using namespace std;
#include<functional>

int main()
{
   int S[] = {5, 6, 8, 7, 8, 3, 8, 10, 8, 12};

   int n = count_if(S, S+10, bind2nd(greater<int>(),7));
   cout<<"Jumlah elemen yang lebih besar dari 7 adalah: "<<n<<endl;

   int m = count_if(S, S+10, bind2nd(less<int>(),10));
   cout<<"Jumlah elemen yang lebih kecil dari 10 adalah: "<<m <<endl;

   return 0;
}
KELUARAN
Jumlah elemen yang lebih besar dari 7 adalah: 6
Jumlah elemen yang lebih kecil dari 10 adalah: 8



LATIHAN
1.       Apa itu STL?
2.       Apa komponen-komponen utama dari STL?
3.       Apa itu iterator?
4.       Kontainer-kontainer manakah yang dikatakan sebagai kontainer-kontainer kelas pertama dan mengapa?
5.       Bagaimana kontainer asosiatif berbeda dari kontainer runtun?
6.       Bagaimana iterator dideklarasikan? Berikan beberapa contoh deklarasi iterator untuk tiap kasus berikut:
a.        vektor dengan elemen-elemen int.
b.       deque dengan elemen-elemen double.
c.        list dengan elemen-elemen berupa nama-nama.
7.       Apakah tumpukan mendukung iterator?
8.       Apa perbedaan antara antrian dan antrian prioritas?
9.       Tuliskan sebuah program untuk mengilustrasikan aplikasi dari tiap fungsi berikut:
a.        push()
b.       top()
c.        size()
10.    Tuliskan sebuah program untuk mengilustrasikan aplikasi dari tiap fungsi berikut:
a.        size()
b.       push()
c.        pop()
11.    Bagaimana tumpukan berbeda dari vektor?
12.    Apa itu predikat?
13.    Definisikanlah predikat fungsi untuk mengurutkan sebuah array dengan ururtan menaik.
14.    Apa itu fungsi binder?
15.    Tulislah sebuah program untuk memilih nilai-nilai genap dari sebuah runtun integer.












No comments: