Anda di halaman 1dari 429

Halo Dunia

Tim Olimpiade Komputer Indonesia

1/40
Pendahuluan

Melalui dokumen ini, kalian akan:


• Mengenal program, pemrograman, dan bahasa pemrograman
• Memahami bagaimana program dieksekusi
• Mengenal kompilator
• Mengenal bahasa C++
• Melakukan instalasi perangkat lunak yang dibutuhkan untuk
pemrograman C++

2/40
Bagian 1

Perkenalan Pemrograman

3/40
Apa itu Program?

Program
Serangkaian instruksi yang dieksekusi oleh mesin untuk mencapai
suatu tujuan tertentu.

• Biasanya, program dapat menerima masukan, memprosesnya,


dan menghasilkan suatu keluaran.
• Contoh: program penerjemah bahasa menerima berkas dalam
suatu bahasa sebagai masukan, menerjemahkannya, lalu
menghasilkan keluaran berupa hasil terjemahan.

4/40
Pemrograman dan Bahasa Pemrograman

• Pemrograman adalah aktivitas menulis program.


• Program ditulis dengan bahasa pemrograman, sehingga mesin
atau komputer dapat mengerti apa yang yang diinstruksikan.
• Contoh bahasa pemrograman yang populer adalah C, C++,
Pascal, Java, dan Python.
• Pada pembelajaran ini, kita akan menggunakan bahasa C++.

5/40
Bagaimana Komputer Menjalankan Program?

• Pada masa lalu, komputer diprogram dengan bahasa


Assembly.
• Bahasa Assembly mudah dimengerti oleh mesin. Oleh karena
itu, Bahasa Assembly termasuk dalam bahasa pemrograman
tingkat rendah (dekat dengan mesin).
• Meskipun begitu, membaca dan mengerti alur program
Assembly cukup sulit bagi manusia.

6/40
Bagaimana Komputer Menjalankan Program?
(lanj.)

• Pada tahun 1960-an, mulai diciptakan bahasa pemrograman


tingkat tinggi.
• Bahasa ini lebih mudah dimengerti manusia karena
menggunakan frase bahasa sehari-hari, seperti ”jika ... maka
...” dan ”lakukan ... hingga tercapai ...”.
• Sayangnya, bahasa pemrograman tingkat tinggi tidak bisa
dimengerti secara langsung oleh mesin.

7/40
Bagaimana Komputer Menjalankan Program?
(lanj.)

• Perlu ada penerjemahan bahasa pemrograman tingkat tinggi


ke tingkat rendah, sehingga mesin dapat mengerti instruksi
yang diberikan.
• Penerjemahan ini biasa dilakukan oleh program yang berperan
sebagai kompilator, intepreter, atau keduanya. Dalam hal ini
kita hanya akan membahas tentang kompilator.

8/40
Kompilator

• Merupakan program komputer yang dapat menerjemahkan


bahasa pemrograman tingkat tinggi ke bahasa mesin.
• Hasil terjemahan ini dapat dimengerti oleh mesin, sehingga
dapat dieksekusi oleh komputer denga mudah.
• Aktivitas menerjemahkan ini disebut dengan kompilasi.
• Siklus kerja jika kita menggunakan kompilator adalah:
tulis program → kompilasi → eksekusi.

9/40
Mengapa C++?

• Kompilasi berjalan dengan cepat.


• Memiliki library berupa Standard Template Library (STL)
yang lengkap, sehingga berbagai komponen pemrograman
tidak perlu Anda buat ulang.

10/40
Bagian 2

Petunjuk Mempersiapkan
Lingkungan Belajar

11/40
Instalasi Dev C++ (Windows)

• Kita akan melakukan instalasi Dev C++, yaitu perangkat


lunak gratis untuk memprogram C++.
• Seluruh petunjuk instalasi yang akan diberikan ini akan
dilakukan pada sistem operasi Windows 7.
• Proses instalasi berikut akan menghasilkan dua hal muncul
pada komputer kalian, yaitu:
• Kompilator C++ yang bernama g++.
• IDE (Integrated Development Environment) bawaan dari Dev
C++. IDE ini bisa dianggap sebagai sebuah lingkungan
tempat kalian memprogram nantinya.

12/40
Instalasi Dev C++ (Windows)

• Buka browser kalian dan kunjungi


https://sourceforge.net/projects/orwelldevcpp.
• Unduh sesuai dengan arsitektur prosesor komputer kalian,
misalnya intel dan Windows 32 bit.

13/40
Instalasi Dev C++ (Windows) (lanj.)
• Berikut ini adalah tampilan dari
https://sourceforge.net/projects/orwelldevcpp
• Tekan ”Download” untuk mendapatkan Dev C++.

14/40
Instalasi Dev C++ (Windows) (lanj.)

• Setelah selesai mengunduh, jalankan installer Dev C++ yang


baru saja diunduh.
• Akan muncul tampilan sebagai berikut:

15/40
Instalasi Dev C++ (Windows) (lanj.)
• Baca persetujuan yang ditampilkan.
• Setelah Anda menyetujui, tekan ”I Agree”.

16/40
Instalasi Dev C++ (Windows) (lanj.)

• Selanjutnya, tekan ”next” untuk melakukan instalasi.

17/40
Instalasi Dev C++ (Windows) (lanj.)
• Atur di mana Anda hendak menyimpan Dev C++.
• Ingat di mana lokasinya, lalu tekan ”install”.

18/40
Instalasi Dev C++ (Windows) (lanj.)

• Tunggu sampai proses instalasi selesai.

19/40
Instalasi Dev C++ (Windows) (lanj.)

• Jika sudah selesai, pilih next dan finish.

20/40
Instalasi Dev C++ (Windows) (lanj.)
• Jika kalian menjalankan program Dev C++, akan muncul
jendela untuk pengaturan.
• Setelah selesai mengatur, muncul tampilan berikut:

21/40
Lingkungan Pemrograman

• Sejauh ini, memprogram dengan Dev C++ sudah bisa


dilakukan.
• Untuk membiasakan diri di lingkungan memprogram yang
asing, kami memperkenalkan penggunaan text editor yang
cukup populer, yaitu Notepad++.
• Kalian akan menulis kode di Notepad++, lalu melakukan
kompilasi dan eksekusi program di command line.

22/40
Perkenalan Notepad++

• Notepad++ merupakan perangkat lunak pengolah teks gratis


yang berjalan di sistem operasi Windows.
• Sesuai dengan namanya, kalian bisa menganggap bahwa
Notepad++ merupakan versi ”plus-plus” dari Notepad, yang
mana membuatnya lebih canggih dari Notepad.
• Kalian dapat menggunakan Notepad++ untuk berbagai
keperluan, seperti menulis program dalam bahasa C, C++,
atau Pascal.

23/40
Instalasi Notepad++ (Windows)
• Buka kembali browser kalian, dan kunjungi
http://notepad-plus-plus.org/download/v6.7.html

• Unduh installer Notepad++ dengan memilih Notepad++


Installer di bagian bawah tombol download.

24/40
Instalasi Notepad++ (Windows) (lanj.)
• Jalankan installer Notepad++ yang baru kalian unduh.
• Akan muncul tampilan sebagai berikut:

• Pilih ok, lalu next sampai muncul tampilan berikut:

25/40
Instalasi Notepad++ (Windows) (lanj.)

• Pilih install, dan tunggu sampai proses instalasi selesai.


• Setelah muncul tampilan berikut, pilih finish.

26/40
Menulis Program C++ Sederhana

• Ketikkan program berikut pada Notepad++, lalu simpan


dengan nama halo.cpp di suatu direktori, misalnya di
Documents.
#include <cstdio>
int main() {
printf("halo dunia\n");
}

27/40
Catatan Tentang Penamaan Berkas

• Disarankan untuk memberi nama berkas program tanpa


menggunakan spasi.
• Apabila nama berkas terdiri dari beberapa kata, gunakan
pemisah berupa ’ ’ atau ’-’.
• Contoh: ”program-pertama.cpp”, ”if else.cpp”,
”sort versi 2.cpp”.

28/40
Kompilasi Program C++

• Buka cmd, yang bisa dilakukan dengan cara menekan tombol


winkey+r, lalu isikan ”cmd” pada kotak dialog yang muncul,
dan tekan enter.

29/40
Kompilasi Program C++ (lanj.)
• Pergi ke direktori tempat halo.cpp disimpan, gunakan perintah
”cd ..” untuk mundur ke direktori parent dan ”cd <nama
folder>” untuk maju ke direktori <nama folder>.

30/40
Kompilasi Program C++ (lanj.)
• Ketikkan perintah g++ -o prog halo.cpp.
• Perhatikan bahwa mungkin akan muncul pesan kesalahan
seperti berikut ini:

31/40
Kompilasi Program C++ (lanj.)

• Berikut pesan kesalahan yang diberikan:

’g++’ is not recognized as an internal or external


command, operable program or batch file.

• Jika ini terjadi, artinya perlu pengaturan path g++ pada


environment variable terlebih dahulu.

32/40
Pengaturan environment variable
• Klik kanan pada ”my computer”, lalu pilih properties. Akan
muncul tampilan sebagai berikut:

• Pilih advanced system settings di bagian kiri.


33/40
Pengaturan environment variable (lanj.)
• Pilih tab advance, lalu tekan tombol environment variable.

34/40
Pengaturan environment variable (lanj.)
• Kemudian akan muncul tampilan sebagai berikut:

35/40
Pengaturan environment variable (lanj.)
• Pada bagian system variables, pilih Path lalu tekan tombol
edit. Jika kalian tidak bisa menemukannya, maka tekan
tombol new.
• Isikan direktori tempat Dev C++ yang sebelumnya diatur,
ditambah dengan ”\MinGW64\bin” pada bagian akhir.

• Tekan ok hingga seluruh kotak dialog tertutup.

36/40
Pengaturan environment variable (lanj.)
• Tutup cmd yang telah terbuka, lalu buka kembali.
• Pergi ke direktori tempat halo.cpp disimpan dan ketikkan
g++ -o prog halo.cpp.
• Pastikan tidak ada lagi pesan kesalahan yang muncul:

• Selamat! Kompilasi berhasil dilaksanakan!

37/40
Kompilasi Program C++ (lanj.)
• Ketikkan ”prog” pada cmd, yang artinya menjalankan berkas
”prog” yang merupakan hasil kompilasi program ”helo.cpp”.
• Pastikan tulisan ”halo dunia” tercetak di cmd:

• Selamat! Kalian berhasil menulis dan menjalankan program


C++!

38/40
Penjelasan Cara Kompilasi

• Perintah yang digunakan untuk kompilasi adalah:


g++ -o <nama berkas> <nama program>
• <nama berkas> diisi dengan nama berkas hasil kompilasi yang
Anda inginkan.
• <nama program> diisi dengan nama berkas C++ yang hendak
Anda kompilasi.

39/40
Selanjutnya...

• Perkenalan variabel dan tipe data.


• Pemrograman C++ sederhana.

40/40
Variabel dan Tipe Data

Tim Olimpiade Komputer Indonesia

1/35
Pendahuluan

Melalui dokumen ini, kalian akan:


• Mengenal konsep variabel.
• Mempelajari berbagai tipe data.
• Mempelajari cara deklarasi variabel.
• Mengenal operasi assignment.

2/35
Kilas Balik

• Mari kita lihat kembali program halo.pas.


#include <cstdio>
int main() {
printf("halo dunia\n");
}
• Pada program tersebut, terdapat kata kunci ”int main() {”
dan ”}”.
• Kedua kata kunci tersebut blok program utama.
• Ketika halo.cpp dieksekusi, seluruh perintah di blok program
utama akan dieksekusi secara berurutan.

3/35
Baris Perintah Program

• Pada halo.cpp, satu-satunya perintah yang ada adalah


printf("halo dunia\n");
• Pada C++, printf(x) merupakan fungsi untuk mencetak x
ke layar.
• Dalam program ini, x = ’halo dunia\n’.
• ’\n’ merupakan karakter ”baris baru” atau ”enter”.

4/35
Bagian 1

Konsep Variabel

5/35
Perkenalan Variabel

Variabel
Merupakan istilah yang diadopsi dari dunia matematika, yang
memetakan sebuah nama ke suatu nilai.

6/35
Perkenalan Variabel (lanj.)

• Setiap kali suatu variabel digunakan dalam ekspresi


matematika, yang diacu sebenarnya adalah nilai yang
dipetakan oleh nama variabel tersebut.
• Contoh: jika kita menyatakan x = 5, maka hasil dari 3x 2 + x
adalah 80.
• Dalam pemrograman, kita bisa membuat variabel, mengisikan
nilai pada variabel, dan mengacu nilai yang dipetakan variabel
tersebut.

7/35
Aturan Penamaan Variabel

• Variabel bebas diberi nama apapun, tetapi terbatas pada


beberapa aturan berikut:
• Terdiri dari kombinasi karakter huruf, angka, dan underscore
( ).
• Tidak boleh dimulai dengan angka.
• Huruf kapital dan huruf kecil dianggap berbeda. Artinya ”a1”
dan ”A1” dianggap merupakan dua variabel yang berbeda.
• Tidak boleh merupakan reserved word. Contoh reserved word
pada C++: int, if, while, for, atau switch.
• Contoh penulisan variabel yang tepat: nilai, xKecil, y1,
tambahan string.
• Contoh penulisan variabel yang salah: 2kar, wow!?, while.

8/35
Aturan Penamaan Variabel (lanj.)

• Lebih jauh lagi, aturan ini berlaku pada seluruh penamaan


identifier , yaitu nama variabel dan fungsi yang akan dipelajari
selanjutnya.

9/35
Assignment

Assignment
Pengisian nilai yang diacu oleh variabel dengan suatu nilai disebut
assignment.

• Operator untuk assignment adalah =


• Isikan ruas kiri dengan nama suatu variabel, dan ruas kanan
dengan nilai yang ingin diisikan ke variabel tersebut.
• Tipe data dari variabel dan nilai yang diacu harus sesuai.

10/35
Contoh Program: assign.cpp

• Perhatikan contoh program assign.cpp berikut. Tuliskan, lalu


jalankan program ini.
#include <cstdio>
int x;
int main() {
x = 12;
printf("Nilai = %d\n", x);
}

11/35
Penjelasan Program: assign.cpp

• Keluaran yang dihasilkan dari program itu adalah sebuah baris


berisikan:
Nilai = 12
• Pada program tersebut, x merupakan suatu variabel.
• Variabel x didaftarkan terlebih dahulu dengan menuliskan int
x di luar blok program utama.
• Pada blok program utama, x diisi dengan nilai 12, lalu
perintah printf dieksekusi.

12/35
Sekilas Tentang printf

• Untuk pencetakan, digunakan perintah berikut:


printf("Nilai = %d\n", x);
• Untuk mencetak nilai dari variabel, diperlukan simbol
sementara yang akan digantikan dengan nilai variabel.
• Simbol sementara untuk variabel bertipe bilangan bulat
seperti x adalah ”%d”.
• Variabel-variabel untuk menggantikan simbol sementara perlu
dituliskan sesudah pola cetakan.

13/35
Contoh Program: assign2.pas

• Berikut adalah contoh program yang melibatkan beberapa


variabel.
#include <cstdio>
int x;
int y;
int main() {
x = 12;
y = 123456;
printf("Nilai x = %d\n", x);
printf("Nilai y = %d\n", y);
x = 15;
printf("Sekarang nilai x = %d\n", x);
}

14/35
Penjelasan Program: assign2.pas

• Keluaran yang dihasilkan dari program itu adalah:


Nilai x = 12
Nilai y = 123456
Sekarang nilai x = 15

• Apa maksud dari kata kunci int? Dijelaskan pada bagian


selanjutnya.

15/35
Bagian 2

Tipe Data Variabel

16/35
Tipe Data Variabel

• Setiap variabel pada C++ memiliki tipe data.


• Jenis tipe data dasar dari suatu variabel pada:
• Bilangan bulat.
• Bilangan riil (bilangan bulat dan pecahan).
• Karakter (merepresentasikan karakter, seperti ’a’, ’b’, ’3’, atau
’ ?’).
• Nilai kebenaran, yaitu benar (TRUE) atau salah (FALSE).

17/35
Tipe Data: Bilangan Bulat
Nama Jangkauan Ukuran
short −215 ..215 − 1 2 byte
unsigned short 0..216 − 1 2 byte
int −231 ..231 − 1 4 byte
unsigned int 0..232 − 1 4 byte
long long −263 ..263 − 1 8 byte
unsigned long long 0..264 − 1 8 byte

• C++ menawarkan beberapa tipe data bilangan bulat yang


variasinya terletak pada jangkauan nilai yang bisa
direpresentasikan dan ukurannya pada memori.
• Dalam memprogram, yang umum digunakan adalah int dan
long long.

18/35
Tipe Data: Bilangan Riil
Nama Jangkauan (magnitudo) Akurasi Ukuran
float 1.5 × 10−45 ..3.4 × 1038 7-8 digit 4 byte
double 5.0 × 10−324 ..1.7 × 10308 15-16 digit 8 byte

• Biasa disebut dengan floating point.


• Tipe data floating point bisa merepresentasikan negatif atau
positif dari magnitudonya.
• Pada pemrograman, umumnya tipe data floating point
dihindari karena kurang akurat. Representasi 3 pada floating
point bisa jadi 2.99999999999999 atau 3.000000000000001
karena keterbatasan pada struktur penyimpanan bilangan
pecahan pada komputer.
• Tipe yang umum digunakan adalah double.

19/35
Tipe Data: Karakter

• Merupakan tipe data untuk merepresentasikan karakter


menurut ASCII (American Standart Code for Information
Interchange).
• Dalam ASCII, terdapat 128 karakter yang direpresentasikan
dengan angka dari 0 sampai 127.
• Misalnya, kode ASCII untuk karakter spasi (’ ’) adalah 32,
huruf ’A’ adalah 65, ’B’ adalah 66, huruf ’a’ adalah 97, dan
huruf ’b’ adalah 98.
• Pada C++, tipe data ini dinyatakan sebagai char, dengan
ukuran 1 byte.

20/35
Tipe Data: Boolean

• Merupakan tipe data yang menyimpan nilai kebenaran, yaitu


hanya TRUE atau FALSE.
• Tipe data ini akan lebih terasa kebermanfaatannya ketika kita
sudah mempelajari struktur percabangan dan array.
• Pada Pascal, kalian dapat menggunakan tipe data boolean.

21/35
Deklarasi Variabel

• Deklarasi variabel adakah aktivitas mendaftarkan nama-nama


dan tipe variabel yang akan digunakan.
• Pada saat dideklarasi, setiap variabel perlu disertakan tipe
datanya.

22/35
Deklarasi Variabel (lanj.)

• Pada C++, variabel dapat dideklarasikan di luar atau di


dalam blok program.
• Apabila variabel dideklarasikan di luar blok program, artinya
variabel tersebut bersifat global.
• Tipe data dituliskan sebelum nama variabel, dipisahkan oleh
spasi.
Contoh: ”int nilai” atau ”double rerata”.
• Beberapa variabel juga bisa dideklarasikan secara bersamaan
jika memiliki tipe data yang sama. Contoh: ”double x, y”.

23/35
Contoh Program: tipedasar.pas

• Pahami program berikut ini dan coba jalankan!


#include <cstdio>
int p1, p2;
double x, y;
int main() {
p1 = 100;
p2 = p1;
printf("p1: %d, p2: %d\n", p1, p2);
x = 3.1418;
y = 234.432;
printf("x %lf\n", x);
printf("y %lf\n", y);
}

24/35
Penjelasan Program: tipedasar.pas

• Berikut adalah keluaran dari program tipedasar.pas:


p1: 100, p2: 100
x 3.141800
y 234.432000
• Perhatikan bahwa perintah p2 = p1 sama artinya dengan
p2 = 100, karena p1 sendiri mengacu pada nilai 100.
• Untuk mencetak variabel bertipe double, gunakan simbol
”%lf” (seperti ”long float”).

25/35
Simbol Variabel pada printf
• Sejauh ini, kita mengenal bahwa ”%d” digunakan untuk
mencetak int, dan ”%lf” untuk double.
• Berikut tabel variabel beserta simbolnya:

Variabel Simbol
short %d
unsigned short %u
int %d
unsigned int %u
long long %lld atau %I64d
unsigned long long %llu atau %I64u
float %f
double %lf
char %c

26/35
Simbol Variabel pada printf (lanj.)

• Untuk boolean, Anda dapat menggunakan %d yang akan


mencetak 1 apabila TRUE atau 0 apabila FALSE.
• Khusus untuk long long, simbolnya bergantung pada sistem
operasi yang digunakan.
• Untuk sistem operasi berbasis UNIX (Linux dan Mac),
gunakan %lld dan %llu.
• Untuk sistem operasi Windows, gunakan %I64d dan %I64u.

27/35
Tipe Data Komposit: Struct

• Kadang-kadang, kita membutuhkan suatu tipe data yang


sifatnya komposit; terdiri dari beberapa data lainnya.
• Contoh kasusnya adalah ketika kita butuh suatu representasi
dari titik. Setiap titik pada bidang memiliki dua komponen,
yaitu x dan y.

28/35
Tipe Data Komposit: Struct (lanj.)

• Memang bisa saja kita mendeklarasi dua variabel, yaitu x dan


y. Namun bagaimana jika kita hendak membuat beberapa
titik? Apakah kita harus membuat x1, y1, x2, y2, ...?
Sungguh melelahkan!
• Karena itulah C++ menyajikan suatu tipe data komposit,
yaitu struct.

29/35
Tipe Data Komposit: Struct (lanj.)

• Struct dapat dideklarasikan di luar blok program utama.


struct <nama_struct> {
<tipe_1> <variabel_1>;
<tipe_2> <variabel_2>;
...
};
• Setelah dideklarasikan, sebuah tipe data <nama struct>
sudah bisa digunakan.
• Untuk mengakses nilai dari <variabel 1> dari suatu
variabel bertipe struct, gunakan tanda titik (.).

30/35
Tipe Data Komposit: Struct (lanj.)
• Sebagai contoh, perhatikan contoh program titik.pas berikut:
#include <cstdio>
struct titik {
int x, y;
};
titik a, b;
int main() {
a.x = 5;
a.y = 3;
b.x = 1;
b.y = 2;
printf("%d %d\n", a.x, a.y);
printf("%d %d\n", b.x, b.y);
}

31/35
Konsumsi Memori Struct

• Memori yang dibutuhkan bagi sebuah tipe data struct bisa


dianggap sama dengan jumlah memori variabel-variabel yang
menyusunnya.
• Artinya, struct bernama titik pada contoh titik.pas
mengkonsumsi memori yang sama dengan dua buah longint,
yaitu 8 byte.
• Perhitungan ini hanya perkiraan saja, sebab konsumsi memori
yang sesungguhnya sulit dilakukan.

32/35
Ordinalitas

• Menurut keberurutannya, tipe data dapat dibedakan menjadi


tipe data ordinal atau non-ordinal.
• Suatu tipe data memiliki sifat ordinal jika untuk suatu
elemennya, kita bisa mengetahui secara pasti apa elemen
sebelum atau selanjutnya. Contoh:
• Diberikan bilangan bulat 6, kita tahu pasti sebelumnya adalah
angka 5 dan sesudahnya adalah angka 7.
• Diberikan karakter ’y’, kita tahu pasti sebelumnya adalah
karakter ’x’ dan sesudahnya adalah karakter ’z’.
• Dengan demikian, seluruh tipe data bilangan bulat dan
karakter adalah tipe data ordinal.

33/35
Ordinalitas (lanj.)

• Kebalikannya, suatu tipe data dinyatakan memiliki sifat


non-ordinal jika kita tidak bisa menentukan elemen sebelum
dan sesudahnya. Contohnya:
• Diberikan bilangan riil 6, apakah elemen sesudahnya 7, atau
6.1, atau 6.01, atau 6.001, atau 6.00000000001?
• Bilangan floating point termasuk dalam tipe data non-ordinal.

34/35
Yang Sudah Kita Pelajari...

• Mengenal konsep variabel.


• Mempelajari berbagai tipe data.
• Mempelajari cara deklarasi variabel.
• Mengenal operasi assignment.

35/35
Variabel dan Tipe Data: String

Tim Olimpiade Komputer Indonesia

1/12
Pendahuluan

Melalui dokumen ini, kalian akan:


• Mengenal konsep string pada C dan C++.
• Mengenal sedikit tentang STL.

2/12
Tipe Data String

• Merupakan tipe data untuk merepresentasikan untaian


karakter.
• Contohnya adalah untuk penyimpanan data berupa teks.
• Tipe data string berperilaku berbeda dengan tipe data dasar
pada C++.
• Sebab, string bukan tipe data primitif, melainkan suatu tipe
dari Standard Template Library (STL).

3/12
STL

• STL merupakan kumpulan library yang disediakan C++.


• Sebuah library dapat dianggap sebagai komponen program
yang sering digunakan, sehingga sudah disediakan dan siap
pakai.
• Contoh komponen program yang akan sering digunakan
adalah pembacaan data, pencetakan data, pengurutan,
pencarian, dan pencarian akar kuadrat.

4/12
Contoh Program String

• Sebagai contoh, perhatikan contoh program berikut:


#include <cstdio>
#include <string>
int main() {
std::string s = "ini adalah string";
printf("%s\n", s.c_str());
}

5/12
Penjelasan Contoh Program String

• Pertama, perhatikan penambahan ”#include <string>”.


• Sebuah perintah ”#include <nama library>” digunakan
untuk memberitahu C++ bahwa kita hendak menggunakan
komponen STL ”nama library”.
• Pada kasus ini, STL yang kita akan gunakan adalah string.
• Hal ini juga berlaku dengan yang sejauh ini telah dilakukan,
yaitu ”#include <cstdio>”.
• STL cstdio merupakan STL yang memberikan kemampuan
untuk membaca dan mencetak keluaran. Komponen yang
telah kita gunakan adalah ”printf”.

6/12
Penjelasan Contoh Program String (lanj.)

• Kedua, perhatikan bahwa tipe data string ditulis dengan gaya


yang berbeda, yaitu ”std::string”.
• Sebenarnya, nama tipe datanya hanya ”string”.
• Nilai yang tertera sebelum ”::” disebut dengan namespace.
• Namespace merupakan mekanisme C++ untuk menjamin
tidak adanya pertubrukan antara nama identifier yang
didefinisikan, terutama antar library.
• Namespace yang digunakan oleh STL string adalah ”std”.

7/12
Program String Tanpa std

• Berhubung terus menerus menulis ”std::” cukup merepotkan,


kita dapat menggunakan perintah ”using namespace std”
untuk memberitahu C++ bahwa kita hendak menggunakan
namespace tersebut secara standar.
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "ini adalah string";
printf("%s\n", s.c_str());
}

8/12
Penjelasan Contoh Program String (lanj.)

• Ketiga, perhatikan bahwa pencetakan string menggunakan


simbol ”%s”.
• Variabel yang dicantumkan juga diberikan ”.c str()”.
• Alasannya adalah string dari STL merupakan kepunyaan
C++, sementara printf merupakan kepunyaan bahasa C.
• Karena bahasa C lebih tua daripada C++, printf tidak
paham cara mencetak tipe data string.
• Kita perlu mengubah string C++ menjadi string bahasa C
dengan .c str()”.

9/12
String pada C++ dan C

• Lalu tipe data string seperti apa yang ada pada bahasa C?
• Pada bahasa C, string diwujudkan dengan membuat array of
char, atau biasa disebut dengan cstring.
• Pembelajaran tentang cstring akan diperdalam pada bab yang
akan datang.

10/12
Sifat String

• Memori yang digunakan adalah 1 byte dikali banyak


karakternya.
• String bukan tipe data ordinal.
• Penulisannya pada program perlu diapit oleh tanda petik (”).

11/12
Yang Sudah Kita Pelajari...

• Mengenal cara membuat variabel string.


• Mengenal sedikit tentang STL.
• Mempelajari sifat-sifat string.

12/12
Ekspresi

Tim Olimpiade Komputer Indonesia

1/26
Kilas Balik: Assignment

• Program menjadi kurang bermanfaat jika kita hanya bisa


mengisi variabel dengan nilai yang pasti.
• Kadang-kadang dibutuhkan hal yang lebih ekspresif seperti
penjumlahan:
a = 5;
b = 2;
jumlah = a + b;
• Kenyataannya, hal ini dapat diwujudkan pada pemrograman.
• Perintah ”a + b” biasa disebut sebagai ekspresi.

2/26
Mengenal Ekspresi

• Ekspresi terdiri dari dua komponen: operator dan operand.


• Operand menyatakan nilai yang akan dioperasikan, misalnya
bilangan atau suatu ekspresi lagi.
• Operator menyatakan bagaimana operand akan dioperasikan,
apakah ditambah, dikali, atau dibagi?

3/26
Mengenal Ekspresi (lanj.)

Bisa juga dibentuk ekspresi bersarang, yaitu ekspresi yang


operand-nya merupakan ekspresi lagi:

4/26
Operasi Numerik

• Operasi pada bilangan yang dapat dilakukan adalah


penjumlahan (+), pengurangan (-), perkalian (*), pembagian
(/), dan modulo (%).
• Jika kedua operand merupakan bilangan bulat, hasil
pengoperasian selalu bilangan bulat juga.
• Ketika setidaknya salah satu dari operand ada yang bertipe
data floating point, pengoperasian akan selalu menghasilkan
floating point.

5/26
Operasi Numerik (lanj.)

• Operasi pembagian pada kedua operand berupa bilangan bulat


didefinisikan sebagai: membagi, lalu dibulatkan (ke bawah
untuk hasil positif, ke atas untuk hasil negatif). Contoh:
• 7/2=3
• 10 / 2 = 5
• 3/5=0
• -5 / 2 = -2
• Operasi pembagian dengan salah satu operand berupa floating
point akan menghasilkan floating point pula. Contoh:
• 10.0 / 5 = 2.0000000
• 7 / 2.0 = 3.5000000

6/26
Operasi Numerik (lanj.)

• Operasi modulo adalah mengambil sisa bagi dari operand


pertama terhadap operand kedua. Contoh:
• 7 mod 2 = 1
• 10 mod 2 = 0
• 3 mod 5 = 3
• 8 mod 3 = 2
• Operasi mod hanya bisa dilakukan apabila kedua operand
memiliki tipe data bilangan bulat.

7/26
Contoh Program: kuadrat.cpp

• Setelah memahami tentang operasi numerik, coba perhatikan


program berikut dan cari tahu apa keluarannya!
#include <cstdio>
int a, b, c, x, hasil;
int main() {
a = 1;
b = 3;
c = -2;
x = 2;
hasil = a*x*x + b*x + c;
printf("ax^2 + bx + c = %d\n", hasil);
}

8/26
Prioritas Pengerjaan

• Seperti pada ilmu matematika, ada juga prioritas pengerjaan


pada ekspresi numerik. Tabel berikut menunjukkan
prioritasnya:
Prioritas Operasi
1 *,/,mod
2 +,-
• Jika ada beberapa operasi bersebelahan yang memiliki
prioritas sama, operasi yang terletak di posisi lebih kiri akan
dikerjakan lebih dahulu.

9/26
Contoh Program: numerik.cpp
• Kita juga bisa menggunakan tanda kurung untuk mengatur
prioritas pengerjaan suatu ekspresi.
• Perhatikan contoh berikut dan coba jalankan programnya:
#include <cstdio>
int hasil1, hasil2;
int main() {
hasil1 = 3+5 / 4;
hasil2 = (3+5) / 4;
printf("%d\n", hasil1);
printf("%d\n", hasil2);
}
• Isi dari variabel hasil1 adalah 4, karena operasi ”5 div 4”
memiliki prioritas yang lebih tinggi untuk dikerjakan, dan
menghasilkan nilai 1. Barulah ”3 + 1” dilaksanakan.

10/26
Operasi Unary

• Pada C++, terdapat pula operasi unary numerik.


• Operasi unary berarti hanya melibatkan satu operand.
• Misalnya terdapat variabel x, operasi unary tersedia berupa:
• x++, artinya tambah x dengan 1.
• x--, artinya kurangi x dengan 1.

11/26
Contoh Operasi Unary

Perhatikan dan coba eksekusi program berikut untuk memahami


operasi unary :
#include <cstdio>
int main() {
int x = 5;
x++;
printf("x: %d\n", x);
x--;
printf("x: %d\n", x);
}

12/26
Fungsi Dasar Numerik

Untuk membantu perhitungan, C++ menyediakan fungsi-fungsi


pada STL ”cmath”.
• round: membulatkan suatu bilangan pecahan bilangan bulat
terdekat (hasilnya tetap bertipe floating point). Contoh:
round(1.2) akan menghasilkan 1.0, sementara round(1.87)
akan menghasilkan 2.0.
• sqrt: mendapatkan akar kuadrat dari suatu bilangan.
Contoh: sqrt(9) akan menghasilkan 3.00, dan sqrt(3) akan
menghasilkan 1.73205....

13/26
Contoh Program: cmath.cpp

• Perhatikan contoh penggunaan STL cmath berikut:


#include <cstdio>
#include <cmath>
int main() {
printf("%lf\n", sqrt(5));
printf("%lf\n", round(5.2));
printf("%lf\n", round(5.6));
}

14/26
Operasi Relasional

• Kita juga bisa melakukan operasi relasional, yaitu:


• kurang dari (<)
• lebih dari (>)
• sama dengan (==)
• kurang dari atau sama dengan (<=)
• lebih dari atau sama dengan (>=)
• tidak sama dengan (! =)
• Operasi relasional harus melibatkan dua operand (ingat bahwa
operand bisa jadi berupa ekspresi lagi), dan menghasilkan
sebuah nilai kebenaran.
• Pada C++, nilai kebenaran dinyatakan dengan tipe data
boolean.

15/26
Contoh Program: relasional.cpp

• Perhatikan contoh berikut dan coba jalankan programnya:


#include <cstdio>
int main() {
printf("%d\n", 2 > 1);
printf("%d\n", 2 < 1);
printf("%d\n", 2 == 1);
printf("%d\n", 2 >= 1);
printf("%d\n", 1 == 1);
printf("%d\n", 1 != 1);
printf("%d\n", 1 != 2);
}

16/26
Operasi Relasional pada Floating Point

• Karena komputer tidak dapat secara sempurna menyimpan


nilai floating point, Anda perlu hati-hati saat membandingkan
dua bilangan riil.
• Ekspresi berikut mungkin saja bernilai FALSE:
(0.1 + 0.2) == 0.3

• Sebab 0.1 + 0.2 bisa saja bernilai 0.30000000000000001

17/26
Operasi Relasional pada Floating Point (lanj.)

• Untuk memeriksa kesamaan antara dua nilai floating point,


biasanya dilibatkan suatu nilai toleransi.
• Misalnya, kedua nilai dianggap sama apabila selisih mereka
kurang dari 10−8 .

18/26
Operasi Relasional (lanj.)

• Operasi relasional dapat dilakukan pada setiap tipe data


ordinal, sehingga bisa juga diterapkan pada char.
• Perbandingan karakter dilakukan dengan membandingkan
kode ASCII mereka, sehingga menjadi seperti membandingkan
angka biasa.
• Contoh:
• ’a’ < ’b’ akan bernilai TRUE
• ’a’ > ’z’ bernilai FALSE
• ’A’ < ’a’ akan bernilai TRUE

19/26
Operasi Relasional (string)

• Lebih jauh lagi, string sebenarnya merupakan untaian char.


Operasi relasional juga bisa diterapkan pada string (meskipun
string bukan tipe data ordinal).
• C++ akan membandingkan karakter demi karakter dari kiri ke
kanan. Begitu ditemukan ada perbedaan karakter, lebih kecil
atau tidaknya suatu string ditentukan oleh karakter tersebut.
• Contohnya, ”aa” < ”ab” akan bernilai TRUE.
• Jika sampai salah satu string habis dan tidak ditemukan ada
perbedaan karakter, maka stirng yang lebih pendek dianggap
lebih kecil.
• Contohnya ”a” < ”aa” bernilai TRUE.

20/26
Contoh Program: relasional2.pas

• Perhatikan contoh berikut dan coba jalankan programnya:


#include <cstdio>
int main() {
printf("%d\n", ’a’ > ’A’);
printf("%d\n", ’a’ < ’A’);
printf("%d\n", ’a’ >= ’A’);
printf("%d\n", ’a’ == ’A’);
printf("%d\n", "a" < "aa");
printf("%d\n", "abcb" > "abca");
printf("%d\n", "abc" == "abc");
printf("%d\n", "abc" <= "abc");
}

21/26
Operasi Boolean
• Operasi boolean merupakan operasi yang hanya melibatkan
nilai-nilai kebenaran. Terdiri atas: not (!), and (&&), or (||),
xor (b).
• Operasi-operasi ini sesuai dengan sebuah cabang ilmu
matematika yang bernama ”aljabar boolean”.
• Operasi not merupakan operasi unary. Gunanya untuk
membalik nilai kebenaran.
• Tabel berikut menunjukkan efek dari penggunaan not, yang
cara penulisannya dengan tanda seru (!) sebelum variabelnya.
a !a
TRUE FALSE
FALSE TRUE

22/26
Operasi Boolean (lanj.)

• Operasi boolean yang lainnya merupakan operasi binary, yang


artinya melibatkan dua operand.
• Tabel berikut menunjukkan efek dari penggunaan
operator-operator tersebut:
a b a && b a || b abb
TRUE TRUE TRUE TRUE FALSE
TRUE FALSE FALSE TRUE TRUE
FALSE TRUE FALSE TRUE TRUE
FALSE FALSE FALSE FALSE FALSE

23/26
Operasi Boolean (lanj.)

• Prioritas pengerjaan dari operator boolean secara berurutan


adalah: not, and, or, xor.
• Tanda kurung juga bisa digunakan untuk menentukan operasi
mana yang perlu dijalankan terlebih dahulu. Bahkan sangat
disarankan untuk selalu menggunakan tanda kurung untuk
kejelasan.

24/26
Contoh Program: relasional3.pas

• Perhatikan contoh berikut dan coba jalankan programnya:


#include <cstdio>
int main() {
printf("%d\n", 2 > 1);
printf("%d\n", !(2 > 1));
printf("%d\n", (2 > 1) && (3 > 1));
printf("%d\n", ((2 > 1) || (3 < 1)) && (1 == 1));
printf("%d\n", (1 != 1) ^ !(1 != 1));
}
• Perhatikan bahwa tanda kurung diperlukan dalam ekspresi
”not (2 > 1)”. Dengan tanda kurung, ”2 > 1” akan
dievaluasi terlebih dahulu, menghasilkan nilai boolean.
Barulah operator not bisa mengolah nilai boolean tersebut.

25/26
Selanjutnya...

• Kini kalian sudah mempelajari tentang variabel, ekspresi, dan


masukan/keluaran.
• Artinya, sudah waktunya untuk menulis program-program
sederhana.

26/26
Masukan/Keluaran

Tim Olimpiade Komputer Indonesia

1/28
Bagian 1

Masukan

2/28
Kilas Balik: kuadrat.cpp
• Sekarang coba lihat kembali program kuadrat.cpp:
#include <cstdio>
int a, b, c, x, hasil;
int main() {
a = 1;
b = 3;
c = -2;
x = 2;
hasil = a*x*x + b*x + c;
printf("ax^2 + bx + c = %d\n", hasil);
}
• Jika kita ingin mengganti nilai x, kode harus diganti,
dikompilasi ulang, baru dijalankan kembali.
• Untuk menghasilkan keluaran yang bervariasi, perlu ada
masukan dari luar program.

3/28
Membaca Masukan

• Diperlukan mekanisme untuk melakukan pembacaan masukan


dari luar program.
• Masukan bagi suatu program bisa berasal dari berbagai
sumber, misalnya standard input atau file.
• Kita akan mempelajari fungsi yang umum untuk membaca
masukan, yaitu scanf.

4/28
Membaca Masukan: scanf
• Modifikasi bagian x = 2 menjadi scanf("%d", &x):
#include <cstdio>
int a, b, c, x, hasil;
int main() {
a = 1;
b = 3;
c = -2;
scanf("%d", &x);
hasil = a*x*x + b*x + c;
printf("ax^2 + bx + c = %d\n", hasil);
}
• Kompilasi, dan jalankan program. Kemudian ketikkan angka
2, dan tekan enter.
• Selamat! Kalian berhasil membaca masukan!

5/28
Fungsi scanf

• Fungsi scanf berguna untuk membaca masukan, dan nilainya


dapat di-assign ke dalam variabel.
• Fungsi ini disediakan oleh STL cstdio.
• Cara kerja scanf: pada berkas masukan, cari token yang dapat
dibaca berikutnya, lalu baca ambil nilainya.
• Yang dimaksud token adalah serangkaian karakter non-spasi,
misalnya huruf atau angka.
• Pada contoh sebelumnya, token yang dimaksud adalah
bilangan yang akan menjadi nilai variabel x.

6/28
Fungsi scanf (lanj.)

• Sama dengan printf, diperlukan simbol sesuai tipe data yang


bersangkutan.
• Perbedaan paling mendasar adalah diperlukannya karakter ’&’
pada variabel yang hendak diisi.

7/28
Membaca Beberapa Variabel

• Hal ini juga berlaku apabila Anda hendak membaca beberapa


variabel pada satu baris masukan.
#include <cstdio>
int a, b, c, x, hasil;
int main() {
scanf("%d %d %d %d", &a, &b, &c, &x);
hasil = a*x*x + b*x + c;
printf("ax^2 + bx + c = %d\n", hasil);
}
• Jalankan program lalu masukkan ”1 3 -2 2”, lalu tekan enter.

8/28
Membaca Beberapa Variabel (lanj.)

• Meskipun kita memberikan pola ”%d %d %d %d”, tidak


masalah apabila masukan yang hendak Anda baca ada di baris
yang berbeda.
• Misalnya Anda dapat ketikkan ”1 3”, enter, ”-2 2”, lalu enter.
• Masukan tetap akan dibaca sesuai urutan yang diberikan.
• Alasannya adalah scanf membaca bilangan dengan cara
mencari token yang ada selanjutnya, tanpa peduli baris baru
atau spasi.

9/28
Membaca Karakter

• Terkecuali pada tipe data karakter, scanf tidak membaca


token selanjutnya.
• Scanf akan membaca 1 karakter selanjutnya, baik itu spasi,
angka, ataupun baris baru.

10/28
Membaca Karakter (lanj.)

• Perhatikan contoh program berikut.


#include <cstdio>
char c1, c2, c3;
int bil;
int main() {
scanf("%c %c", &c1, &c2);
scanf("%d", &bil);
scanf("%c", &c3);
printf("c1=’%c’ c2=’%c’ bil=%d c3=’%c’\n", c1, c2,
bil, c3);
}
• Berikan masukan berupa ”p q”, enter, 5, enter, lalu ”r”.

11/28
Membaca Karakter (lanj.)

• Berikut adalah keluaran yang dihasilkan:


c1=’p’ c2=’q’ bil=5 c3=’

• Perhatikan bahwa c3 memiliki nilai berupa karakter enter,
padahal yang kita harapkan adalah karakter ’r’.
• Hal ini disebabkan karena karakter yang selanjutnya
dimasukkan sesudah membaca bil adalah enter, yang
kemudian dibaca untuk c3.

12/28
Membaca Karakter (lanj.)
• Cara yang tepat adalah dengan menambahkan ”\n” secara
tertib di akhir pembacaan baris:
#include <cstdio>
char c1, c2, c3;
int bil;
int main() {
scanf("%c %c\n", &c1, &c2);
scanf("%d\n", &bil);
scanf("%c", &c3);
printf("c1=’%c’ c2=’%c’ bil=%d c3=’%c’\n", c1, c2,
bil, c3);
}
• Karena berpotensi membingungkan dan memperumit
penulisan kode, pembacaan tipe data karakter kurang
disarankan.

13/28
Membaca String

• Cara yang disarankan adalah membacanya dalam bentuk


string, sekalipun yang akan dibaca dipastikan hanya memiliki
1 karakter.
• Seperti printf, scanf tidak dapat berinteraksi secara langsung
dengan STL string.
• Scanf perlu membaca string dalam bentuk cstring, kemudian
mengubahnya menjadi string.

14/28
Membaca String (lanj.)
• Perhatikan program berikut:
#include <cstdio>
#include <string>
using namespace std;
char buff[1001];
int main() {
scanf("%s", buff);
string s = buff;
printf("s=’%s’\n", s.c_str());
}
• Variabel buff merupakan array of char dengan maksimal
1001 karakter (angka ini dapat Anda ubah sesuai kebutuhan).
• Array of char inilah yang merupakan cstring.

15/28
Membaca String (lanj.)

• Kita dapat membaca cstring dengan scanf, lalu mengubahnya


ke bentuk string dengan melakukan assignment ke variabel
string (string s = buff).
• Khusus untuk pembacaan cstring, tanda ’&’ tidak digunakan.
• Program tersebut akan membaca 1 token yang diberikan.
• Coba jalankan program tersebut, lalu masukkan ”abcd”, lalu
enter.

16/28
Membaca Sebaris String
• Bagaimana jika kita hendak membaca sebuah baris string,
yang mungkin mengandung spasi?
• Caranya adalah menggunakan simbol khusus ”%[ b \n]\n”.
#include <cstdio>
#include <string>
using namespace std;
char buff[1001];
int main() {
scanf("%[^\n]\n", buff);
string s = buff;
printf("s=’%s’\n", s.c_str());
}

17/28
Kesimpulan dalam Membaca Masukan

• Membaca masukan pada C++ mungkin tidak semudah yang


diharapkan.
• Anda perlu menghafal sintaks dan cara pembacaan bilangan,
karakter, dan string.
• Untungnya, hal-hal yang telah diajarkan tersebut sudah cukup
untuk membuat program yang kompleks.
• Cobalah untuk mencetak kembali nilai variabel yang telah
dibaca, untuk memastikan program Anda membaca masukan
dengan tepat!

18/28
Bagian 2

Keluaran

19/28
Mencetak Keluaran

• Seperti masukan, keluaran juga bisa disajikan dalam bentuk


langsung ke standard output atau ke file.
• Pada C++, fungsi untuk mencetak keluaran yang umum
adalah printf.
• Sejauh ini, kita sudah menggunakan printf untuk berbagai
keperluan dan Anda seharusnya telah menguasainya.

20/28
Contoh Program: jumlah.cpp
• Coba ketikkan dan jalankan program berikut:
#include <cstdio>
int main() {
int a, b;
printf("masukkan nilai a: ");
scanf("%d", &a);
printf("masukkan nilai b: ");
scanf("%d", &b);
printf("hasil dari penjumlahan a dan b: %d\n", a+b);
}
• Pada program tersebut, dicetak terlebih dahulu apa yang perlu
dimasukkan. Tentu saja, program seperti ini sangat ramah
terhadap pengguna (user-friendly ).
• Namun dalam kontes pemrograman OSN/IOI, hal seperti
ini tidak perlu dilakukan. Bahkan, tidak boleh dilakukan.

21/28
Bagian 3

Standard Input Output

22/28
Penjelasan Tentang STDIO

• Tempat kalian selama ini mengisikan masukan dan melihat


keluaran biasa disebut sebagai standard input output, atau
STDIO.
• STDIO memiliki dua saluran yang berbeda, yaitu input
(STDIN) dan output (STDOUT).

23/28
Penjelasan Tentang STDIO (lanj.)
• Masukan yang kalian masukkan, akan melewati saluran
STDIN.
• Keluaran yang kalian lihat, sebenarnya datang lewat saluran
STDOUT.
• Namun, pada command line keduanya terlihat seperti
menyatu, seakan-akan keduanya melewati jalur yang sama.

24/28
Penjelasan Tentang STDIO (lanj.)

• Untuk lebih memahami tentang hal ini, coba buat sebuah


berkas bernama input.txt pada folder yang sama dengan
program jumlah.cpp, dan berisi:
1
2

• Kemudian pada command line, saat menjalankan program


jumlah.cpp, ketikkan perintah:
jumlah < input.txt > output.txt

• Buka output.txt dan perhatikan apa yang tercetak!

25/28
Penjelasan Tentang STDIO (lanj.)
• Isi dari output.txt adalah:
masukkan nilai a:
masukkan nilai b:
hasil dari penjumlahan a dan b: 3

• Tulisan ”masukkan nilai ...” juga ikut tercetak, karena pada


kasus ini, STDOUT merupakan berkas output.txt. Segala
yang dicetak lewat saluran STDOUT akan dicetak ke
output.txt.
• Dengan pemahaman yang sama, seluruh masukan yang
diberikan adalah lewat STDIN, yang merupakan input.txt.
Sehingga masukannya perlu dimasukkan ke input.txt terlebih
dahulu.

26/28
Masukan dan Keluaran pada OSN/IOI

• Setelah kalian memahami tentang STDIN dan STDOUT,


mungkin kalian sudah bisa menebak kenapa pada OSN/IOI
tidak boleh mencetak informasi masukan seperti ”masukkan
nilai ...”.
• Hal ini dikarenakan tulisan itu akan ikut tercetak sebagai
keluaran, yang mana mengakibatkan ada keluaran yang tidak
sesuai spesifikasi soal. Hasilnya, program akan dinilai wrong
answer , alias menghasilkan jawaban yang tidak sesuai.

27/28
Selanjutnya...

• Kini kalian sudah mempelajari tentang variabel, ekspresi, dan


masukan/keluaran.
• Artinya, sudah waktunya untuk menulis program-program
sederhana.

28/28
Penunjang Pemrograman Dasar

Tim Olimpiade Komputer Indonesia

1/16
Pendahuluan

Dokumen ini berisi tambahan pengetahuan yang dapat menunjang


pemrograman dasar kalian.

Melalui dokumen ini, kalian akan:


• Mengenal komentar.
• Memahami pesan kesalahan.
• Memahami I/O redirection.

2/16
Bagian 1

Komentar

3/16
Mengenal Komentar

• Program yang pendek seperti kuadrat.cpp atau jumlah.cpp


yang sebelumnya telah kita jumpai memang sederhana dan
mudah dipahami.
• Ketika program sudah mulai panjang dan kompleks,
memahami alur kerja suatu program menjadi lebih sulit.
• Salah satu cara untuk membantu memahami alur kerja
program adalah dengan menulis komentar.

4/16
Komentar
• Merupakan bagian dari program yang diabaikan oleh compiler.
• Kita bisa menuliskan apapun di dalam komentar. Misalnya:
apa yang dilakukan oleh suatu bagian program atau catatan
tertentu.
• Pada C++, komentar dapat dituliskan dalam dua gaya:
• Satu baris, dituliskan dengan awalan dua slash
// ini adalah komentar, hanya bisa sebaris
// jika perlu baris baru, tambahkan // lagi

• Beberapa baris, dituliskan dengan mengawali dan mengakhiri


komentar dengan slash bintang (/* */).
/* ini adalah komentar, yang memungkinkan
ditulis dalam beberapa baris */

5/16
Contoh Komentar
• Perhatikan program berikut:
#include <cstdio>
int main() {
int a, b, c, x, hasil;
// Inisialisasi
a = 1;
b = 3;
c = -2;
// Baca nilai x
scanf("%d", &x);
// Hitung hasil fungsi
hasil = a*x*x + b*x + c;
// Cetak
printf("ax^2 + bx + c = %d\n", hasil);
}

6/16
Penjelasan Komentar

• Program menjadi lebih deskriptif ketika kita menuliskan


komentar.
• Ketika program yang dibuat sudah mulai panjang, komentar
menjadi efektif untuk membantu kalian ”mengingat kembali”
apa yang telah diketikkan sebelumnya.
• Komentar juga berguna ketika program kalian akan dibaca
oleh orang lain, sehingga orang lain bisa memahaminya
dengan lebih mudah.
• Gunakan komentar secukupnya, jangan terlalu berlebihan juga.

7/16
Bagian 2

Pesan Kesalahan (Error)

8/16
Dua Jenis Error

Compilation Error
Kesalahan yang terjadi ketika program dikompilasi.
Contoh: terdapat kesalahan dalam pengetikan nama variabel,
kurang tanda titik koma (;), atau salah penggunaan tipe data.

Runtime Error
Kesalahan yang terjadi ketika program dieksekusi.
Contoh: saat program dieksekusi, tiba-tiba ada operasi pembagian
dengan 0.

Mampu memahami pesan kesalahan yang disampaikan dapat


membantu kita memperbaiki program secara lebih efisien.

9/16
Compilation Error

• Pada kompilator g++, pesan kesalahan saat kompilasi


biasanya disampaikan dengan format:
<nama berkas>:<nomor baris>:<nomor kolom>: error:
<jenis error>

Contoh:
tes.cpp:18:34: error: hasil was not declared in
this scope

• Artinya pada berkas tes.cpp, baris 4, kolom 13, terdapat


kesalahan berupa: sebuah variabel bernama ”nilai” tidak
ditemukan. Untuk memperbaikinya, ”nilai” harus
dideklarasikan terlebih dahulu.

10/16
Compilation Error (lanj.)

• Ketika suatu program memiliki compilation error, kompilasi


akan dibatalkan.
• Program tidak bisa dikompilasi sampai kesalahannya
diperbaiki.

11/16
Runtime Error
• Ketika program sudah berhasil dikompilasi, belum tentu
program luput dari error ketika dieksekusi.
• Program dapat mengalami error ketika sedang dieksekusi
karena berbagai hal:
• Melakukan pembagian dengan angka 0.
• Mengakses memori di luar yang telah dialokasikan.
• Mengalami stack overflow.
• Pesan error akan langsung diberikan dalam bentuk kalimat,
contohnya ”Floating point exception”.
• Sebagian besar dari istilah dan masalah yang dijelaskan di atas
mungkin kalian hadapi ketika sudah mempelajari tentang
array dan rekursi.

12/16
Bagian 3

IO Redirection

13/16
IO Redirection
• Penjelasan tentang saluran input dan output sempat
dijelaskan pada bagian sebelumnya. Kali ini, kita akan
memperdalamnya.
• Pada contoh yang lalu, kita sempat melakukan hal ini:
jumlah < input.txt > output.txt

• Ada dua hal yang dilakukan di sini:


• Memberikan STDIN kepada program jumlah yang akan
dieksekusi dengan input.txt. Hal ini dilakukan dengan operator
<.
• Memberikan STDOUT kepada program jumlah yang akan
dieksekusi dengan output.txt. Hal ini dilakukan dengan
operator >.

14/16
IO Redirection (lanj.)
• Kita bisa melakukan hanya salah satu dari keduanya. Misalnya
jika kita melakukan:
jumlah < input.txt

• Artinya program jumlah akan dijalankan dengan STDIN dari


berkas input.txt, dan STDOUT ke layar.
• Hal ini akan membantu dalam mengurangi pengetikan berkas
masukan terus menerus secara manual.
• Demikian pula dengan:
jumlah > output.txt

• Artinya program jumlah akan dijalankan dengan STDIN dari


layar (kalian dapat mengetikkannya), dan STDOUT ke berkas
output.txt.

15/16
Selanjutnya...

• Memasuki bagian yang menarik, yaitu struktur percabangan.

16/16
Percabangan

Tim Olimpiade Komputer Indonesia

1/20
Pendahuluan

Melalui dokumen ini, kalian akan:


• Mengenal percabangan.
• Analisa kasus dan mengimplementasikannya pada C++.

2/20
Motivasi

• Bebek-bebek Pak Dengklek sedang belajar tentang


membedakan bilangan positif, nol, atau negatif.
• Karena bebek-bebek kebingungan, mereka memberikan kalian
sebuah bilangan dan meminta kalian menentukan apakah
bilangan itu positif atau bukan positif!
• Jika positif, cetak ”positif”. Jika tidak, jangan cetak apa-apa.

3/20
Motivasi (lanj.)

• Sebuah bilangan dinyatakan positif apabila bilangan tersebut


lebih dari nol.
• Dengan begitu, kita memerlukan suatu struktur yang
memungkinkan ”jika bilangan itu lebih dari 0, maka cetak
positif”.
• Pada C++, hal ini bisa diwujudkan dengan struktur
kondisional if.

4/20
Struktur ”if ... then ...”

• Struktur dari penulisan ”if ... then ...” adalah:


if (<kondisi>) {
<perintah 1>;
<perintah 2>;
...
}
• Dengan <kondisi> adalah suatu boolean.
• Jika nilai <kondisi> adalah TRUE, seluruh perintah yang ada
di antara blok ”{” dan ”}” akan dilaksanakan.
• Jika FALSE, seluruh perintah yang ada di antara blok ”begin”
dan ”end” akan dilewati.

5/20
Blok ”{ ... }”

• Struktur yang sebenarnya dari penulisan ”if ... then ...”


adalah:
if (<kondisi>)
<perintah>;
• Jika nilai <kondisi> adalah TRUE, <perintah> akan
dilaksanakan.
• Jika nilai <kondisi> adalah FALSE, <perintah> tidak
dilaksanakan.
• Lalu di mana bedanya?

6/20
Blok ”{ ... }” (lanj.)

• Setelah kondisi dari if, sebenarnya hanya satu perintah yang


dapat dieksekusi jika <kondisi> bernilai TRUE.
• Perhatikan contoh berikut:
if (nilai == 10)
printf("masuk\n");
printf("lagi\n");

7/20
Blok ”{ ... }” (lanj.)

• Meskipun perintah printf("masuk\n") hanya dieksekusi


ketika nilai sama dengan 10, printf("lagi\n") akan selalu
dilaksanakan tanpa peduli isi variabel nilai.
• Blok ”{ ... }”, akan berperan sebagai ”pembungkus”
beberapa perintah menjadi ”satu” perintah, sehingga
berapapun perintah di dalam blok tersebut, akan dilihat oleh
C++ sebagai ”satu” perintah.

8/20
Blok ”{ ... }” (lanj.)

• Menulis ”{ ... }” setiap sesudah if merupakan kebiasaan yang


bagus, meskipun isi dari if itu hanya satu perintah.
• Dengan cara ini, ketika ada tambahan perintah yang perlu
dimasukkan ke dalam if, kalian tidak perlu menuliskan lagi ”{
... }”.
• Konsisten dengan selalu menulis ”{ ... }” juga menjaga
program tetap rapi.

9/20
Contoh Program: kondisi.cpp
• Ketikkan dan jalankan program berikut:
#include <cstdio>
int main() {
int x;
scanf("%d", &x);
if (x > 0) {
printf("positif\n");
}
}
• Perhatikan bahwa ekspresi ”x > 0” akan merupakan operasi
relasional yang menghasilkan nilai boolean. Sehingga tepat
untuk digunakan pada if.
• Bagaimana jika ingin dibuat jika bilangan itu bukan positif,
cetak ”non-positif”?

10/20
Struktur ”if ... then ... else ...”
• Kita juga bisa membuat percabangan jika nilai pada
<kondisi> adalah FALSE, yaitu dengan kata kunci else.
• Struktur dari penulisan ”if ... then ... else ...” adalah:
if (<kondisi>) {
<perintah 1>;
<perintah 2>;
...
} else {
<perintah a>;
<perintah b>;
...
}
• Jika nilai <kondisi> adalah TRUE, <perintah 1>, <perintah
2>, ..., akan dilaksanakan.
• Jika FALSE, <perintah a>, <perintah b>, ..., akan
dilaksanakan.

11/20
Contoh Program: kondisi2.cpp

• Dengan ”if ... then ... else ...”, kita bisa memodifikasi
kondisi.cpp menjadi kondisi2.cpp:
#include <cstdio>
int main() {
int x;
scanf("%d", &x);
if (x > 0) {
printf("positif\n");
} else {
printf("non-positif\n");
}
}

12/20
Persoalan Sebenarnya

Ketika bebek-bebek memberikan kalian sebuah bilangan, sebut


saja x, mereka ingin tahu:
• Jika x positif, cetak ”positif”.
• Jika x sama dengan nol, cetak ”nol”.
• Jika x negatif, cetak ”negatif”.
Pada kasus ini, diperlukan struktur if yang lebih dari dua cabang!

13/20
Struktur ”if ... then ... else if ...”

• C++ menyediakan struktur yang memungkinkan kita


memilah-milah untuk cabang yang lebih dari dua, yaitu
dengan struktur ”if ... then ... else if ...”.
• Struktur dari penulisan ”if ... then ... else if ...” adalah:
if (<kondisi 1>) {
<perintah 1>;
<perintah 2>;
...
} else if (<kondisi 2>) {
<perintah a>;
<perintah b>;
...
} else if (<kondisi 3>) {
...
}

14/20
Struktur ”if ... then ... else if ...” (lanj.)
• Jika nilai <kondisi 1> TRUE, <perintah 1>, <perintah 2>,
..., akan dilaksanakan.
• Jika nilai <kondisi 1> FALSE, diperiksa apakah <kondisi 2>
bernilai TRUE. Jika ya, <perintah a>, <perintah b>, ...,
akan dilaksanakan.
• Jika nilai <kondisi 2> FALSE, diperiksa apakah <kondisi 3>
bernilai TRUE. Hal ini akan terus diulang sampai seluruh
percabangan habis.
• Kalian juga bisa mengakhiri struktur ini dengan ”else ...”,
yaitu ketika seluruh kondisi yang diberikan tidak terpenuhi,
maka perintah-perintah di bawah else ini yang akan
dilaksanakan.

15/20
Contoh Program: kondisi3.cpp

• Dengan ”if ... then ... else if ...”, kita bisa memodifikasi
kondisi2.cpp menjadi kondisi3.cpp:
#include <cstdio>
int main() {
int x;
scanf("%d", &x);
if (x > 0) {
printf("positif\n");
} else if (x == 0) {
printf("nol\n");
} else if (x < 0) {
printf("negatif\n");
}
}

16/20
Contoh Program: kondisi4.cpp
• Pada kondisi3.cpp, sebenarnya ”else if ...” yang terakhir tidak
diperlukan.
• Ketika suatu bilangan bukan positif dan bukan nol, sudah
pasti bilangan itu negatif. Sehingga bisa didapatkan
kondisi4.cpp:
#include <cstdio>
int main() {
int x;
scanf("%d", &x);
if (x > 0) {
printf("positif\n");
} else if (x == 0) {
printf("nol\n");
} else {
printf("negatif\n");
}
}

17/20
Kombinasi dengan Ekspresi Boolean

• Kalian juga bisa menggabungkan struktur if dengan ekspresi


boolean:
if ((x > 0) && (x % 2 == 1)) {
printf("positif dan ganjil\n");
} else if ((x > 0) && (x % 2 == 0)) {
printf("positif dan genap\n");
} else if ((x < 0) && (x % 2 == 1)) {
printf("negatif dan ganjil\n");
} else if ((x < 0) && (x % 2 == 0)) {
...

18/20
If Bersarang

• Solusi yang lebih rapi dicapai dengan menggunakan if secara


bersarang:
if (x > 0) {
if (x % 2 == 1) {
printf("positif dan ganjil\n");
} else {
printf("positif dan genap\n");
}
} else if (x < 0) {
...

19/20
Selanjutnya...

• Ke bagian yang lebih menarik lagi, yaitu perulangan!


• Pastikan kalian menguasai materi percabangan terlebih
dahulu.

20/20
Perulangan

Tim Olimpiade Komputer Indonesia

1/21
Pendahuluan

Melalui dokumen ini, kalian akan:


• Memahami konsep perulangan.
• Mempelajari struktur for, while, dan repeat pada Pascal.

2/21
Motivasi

• Hari ini, Pak Dengklek ingin menyambut N ekor bebeknya


yang baru lahir dari telur.
• Diberikan N, cetak tulisan ”halo dunia!” sebanyak N kali!
• Contoh untuk N = 3:
halo dunia!
halo dunia!
halo dunia!

3/21
Motivasi (lanj.)

• Solusi ”if (N = 1) <cetak satu kali>, else if (N = 2) <cetak


dua kali>, ...” tidak mungkin digunakan, karena N bisa jadi
sangat besar.
• Kita membutuhkan suatu struktur yang memungkinkan untuk
mengulangi serangkaian pekerjaan!
• C++ menyediakan struktur perulangan berupa for dan while.

4/21
Perulangan: for
• Biasanya digunakan ketika kita tahu berapa kali perulangan
perlu dilakukan.
• Pada C++, strukturnya:
for (<kondisi_awal>; <kondisi_ulang>; <perubahan>) {
<perintah 1>;
<perintah 2>;
...
}
• <kondisi awal> dapat diisi dengan inisialisasi variabel untuk
perulangan.
• <kondisi ulang> biasanya berupa ekspresi yang menghasilkan
boolean, untuk menandakan apakah perulangan sudah patut
diberhentikan.
• <perubahan> merupakan bagian yang dieksekusi pada akhir
setiap siklus perulangan.
• Penjelasan berikutnya dengan contoh akan meningkatkan
pemahaman kalian.
5/21
Contoh Program: for.cpp

• Ketikkan program berikut dan coba jalankan:


#include <cstdio>
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
printf("tulisan ini dicetak saat i = %d\n", i);
}
printf("akhir dari program\n");
}
• Masukkan berbagai nilai N, misalnya 1, 2, 10, dan 0.

6/21
Penjelasan Program: for.cpp
• Misalnya kita memasukkan N = 5.
• Pertama kali dijalankan, i dibuat dan diisi nilai 0.
• Kedua, C++ memeriksa apakah kondisi ulang tercapai.
Berhubung i kurang dari N, maka bagian dalam for
dilaksanakan dan tulisan dicetak saat i = 0.
• Setelah itu, akhir dari struktur for ditemukan. C++ akan
mengeksekusi bagian perubahan, yakni menambah i dengan
1, lalu kembali ke awal dari for.
• Jika i masih kurang dari N, maka perintah di dalamnya akan
kembali dilaksanakan.
• Dengan demikian, tercetaklah tulisan saat i = 1, 2, dan
seterusnya hingga N-1.

7/21
Penjelasan Program: for.cpp (lanj.)

• Jika i sudah lebih dari N, perulangan akan berhenti dan C++


akan menjalankan perintah sesudah for tersebut.
• Pada contoh ini, mencetak tulisan ”akhir dari program”.

8/21
Masa Hidup Variabel

• Variabel i hanya memiliki masa hidup di dalam lingkungan


for.
• Di luar for berikut { dan }, variabel tersebut sudah tidak ada.
• Anda boleh saja mendeklarasikan variabel i lagi, tanpa
mendapatkan error bahwa nama variabel telah terdefinisi.
• Variabel yang hanya hidup dalam suatu cakupan { } disebut
dengan variabel lokal.

9/21
Contoh Program: fordownto.cpp

• Struktur for cukup luwes untuk kasus-kasus lainnya.


• Berikut ini contoh dari penggunaan for yang bekerja secara
terbalik:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
for (int i = N-1; i >= 0; i--) {
printf("tulisan ini dicetak saat i = %d\n", i);
}
printf("akhir dari program\n");
}

10/21
Contoh Program: forskip.cpp

• Sementara berikut contoh dari penggunaan for yang


lompatannya 2:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i += 2) {
printf("tulisan ini dicetak saat i = %d\n", i);
}
printf("akhir dari program\n");
}
• Ekspresi i += 2 setara dengan i = i + 2, yang mengisikan
i dengan dirinya ditambah 2.

11/21
Contoh Program: forskip2.cpp

• Tidak terbatas pada penjumlahan, hal semacam ini pun bisa


dilakukan:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i *= 2) {
printf("tulisan ini dicetak saat i = %d\n", i);
}
printf("akhir dari program\n");
}
• Ekspresi i *= 2 setara dengan i = i * 2, yang mengisikan
i dengan dirinya dikali 2.

12/21
Contoh Program: forsum.cpp

• Berikut contoh program untuk menjumlahkan seluruh


bilangan di antara dua bilangan:
#include <cstdio>
int main() {
int awal, akhir;
scanf("%d %d", &awal, &akhir);
int jumlah = 0;
for (int i = awal; i <= akhir; i++) {
jumlah += i;
}
printf("jumlah bilangan bulat di antara %d dan %d
(inklusif) adalah %d\n", awal, akhir, jumlah);
}

13/21
Perulangan: while
• Selain for, terdapat pula struktur while.
• Biasa digunakan ketika tidak diketahui harus berapa kali
serangkaian perintah dilaksanakan, tetapi diketahui
perintah-perintah itu perlu dilaksanakan selama suatu kondisi
terpenuhi.
• Pada C++, strukturnya:
while (<kondisi>) {
<perintah 1>;
<perintah 2>;
...
}
• Seperti pada if, <kondisi> adalah suatu nilai boolean. Selama
nilainya TRUE, seluruh <perintah x> di dalamnya akan
dieksekusi secara berurutan.

14/21
Contoh Program: while.cpp

• Berikut adalah contoh penggunaan while untuk kasus yang


sama dengan for.cpp:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int i = 0;
while (i < N) {
printf("tulisan ini dicetak saat i = %d\n", i);
i++;
}
printf("akhir dari program\n");
}

15/21
Penjelasan Program: while.cpp

• Alur programmnya sangat mirip dengan for.


• Perbedaannya hanya pada gaya penulisan.
// Bentuk for
for (<kondisi_awal>; <kondisi_ulang>; <perubahan>) {
<perintah 1>;
<perintah 2>;
...
// Bentuk while
<kondisi_awal>;
while (<kondisi_ulang>) {
<perintah 1>;
<perintah 2>;
...
<perubahan>;
}

16/21
Perulangan: while (lanj.)

• Perhatikan bahwa perintah ”i++” diperlukan, supaya suatu


saat nanti <kondisi> pada while akan tidak dipenuhi.
• Sekarang coba hapus perintah ”i++” pada while.cpp, dan
jalankan kembali programnya.
• Apa yang terjadi? Program akan terjebak dalam infinite loop,
atau perulangan yang tidak akan pernah berhenti! Gunakan
tombol CTRL+C pada keyboard untuk memberhentikan
program secara paksa.
• Dengan demikian, pastikan suatu saat ”kondisi pada while”
tidak dipenuhi, atau program tidak akan pernah berhenti :)

17/21
Contoh Program: whilesum.cpp
• Berikut ini contoh program dengan while yang melakukan hal
serupa dengan forsum.cpp:
#include <cstdio>
int main() {
int awal, akhir;
scanf("%d %d", &awal, &akhir);
int jumlah = 0;
int i = awal;
while (i <= akhir) {
jumlah += i;
i++;
}
printf("jumlah bilangan bulat di antara %d dan %d
(inklusif) adalah %d\n", awal, akhir, jumlah);
}

18/21
Perulangan: while (lanj.)
• Terdapat variasi lain dari while, yang biasa disebut ”do ...
while”.
• Pada C++, strukturnya:
do {
<perintah 1>;
<perintah 2>;
...
} while (<kondisi>);
• Perbedaannya adalah, seluruh perintah akan dilakukan dulu,
baru diperiksa apakah kondisi masih terpenuhi. Bila ya, maka
seluruh perintah akan diulang.
• Hal ini menjamin seluruh perintah dijalankan paling sedikit
satu kali.

19/21
Contoh Program: dowhile.cpp

• Berikut ini adalah contoh program dengan repeat yang


menjalankan tugas serupa dengan for.cpp dan while.cpp.
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int i = 0;
do {
printf("tulisan ini dicetak saat i = %d\n", i);
i++;
} while (i < N);
printf("akhir dari program\n");
}

20/21
Sejauh ini...

Kalian sudah belajar tentang:


• Konsep perulangan pada pemrograman.
• Struktur for dan while, beserta kegunaan dan perbedaannya.
Selanjutnya kita akan memasuki tentang:
• Penggunaan perulangan yang lebih kompleks, yaitu
perulangan bersarang.
• Membuat program dengan apa yang telah dipelajari sejauh ini.

21/21
Perulangan Lanjut

Tim Olimpiade Komputer Indonesia

1/30
Pendahuluan

Melalui dokumen ini, kalian akan:


• Memahami penggunaan perulangan yang bersarang.
• Memecahkan beberapa persoalan dengan perulangan.

2/30
Bagian 1

Perulangan Bersarang

3/30
Motivasi: Pola 0

• Pak Dengklek akan memberikan sebuah bilangan, misalnya N.


• Anda diminta untuk mencetak karakter bintang (*) yang
tersusun N baris.
• Contoh untuk N = 3:
*
*
*

4/30
Motivasi (lanj.)

• Tentu saja solusinya sederhana, cukup gunakan salah satu


struktur perulangan yang kalian kuasai.
• Misalnya menggunakan for:
for (int i = 0; i < N; i++) {
printf("\n");
}

5/30
Motivasi: Pola 1

• Kemudian Pak Dengklek memberikan persoalan yang sedikit


lebih sulit.
• Diberikan dua bilangan, misalnya N dan M.
• Cetak karakter bintang (*) yang tersusun N baris dan M
kolom!
• Contoh untuk N = 3 dan M = 5:
*****
*****
*****
• Kali ini, untuk setiap barisnya kita perlu melakukan
perulangan untuk mencetak M karakter bintang!

6/30
Contoh Program: pola1 1.cpp

• Kita bisa membuat ”for di dalam for”, sehingga membentuk


struktur yang bersarang.
#include <cstdio>
int main() {
int N, M;
scanf("%d %d", &N, &M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
printf("*");
}
printf("\n");
}
}

7/30
Contoh Program: pola1 2.cpp
• Tentu saja kita bisa melakukannya dengan struktur
perulangan yang lain:
#include <cstdio>
int main() {
int N, M;
scanf("%d %d", &N, &M);
int i = 0;
while (i < N) {
int j = 0;
while (j < M) {
printf("*");
j++;
}
i++;
printf("\n");
}
}

8/30
Contoh Lain: Pola 2

• Soal ”Pola 1” dapat diselesaikan dengan mudah. Dengan


demikian Pak Dengklek memberikan soal yang lebih
menantang.
• Diberikan sebuah bilangan, misalnya N.
• Cetak ”struktur segitiga rata kiri” yang terdiri dari N baris.
• Misalnya untuk N = 5, hasilnya adalah:
*
**
***
****
*****

9/30
Contoh Solusi: pola2.cpp

• Berikut ini adalah contoh solusinya, dimodifikasi dari


pola1 1.cpp:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
printf("*");
}
printf("\n");
}
}

10/30
Latihan: Pola 3

• Pak Dengklek kemudian memberikan tugas yang lebih sulit


lagi, yang kali ini perlu Anda kerjakan sendiri.
• Diberikan sebuah bilangan, misalnya N.
• Cetak ”struktur segitiga rata kanan” yang terdiri dari N baris.
• Misalnya untuk N = 5, hasilnya adalah:
*
**
***
****
*****
• Petunjuk: cetak bagian kiri terlebih dahulu!

11/30
Bagian 2

Break & Continue

12/30
Break & Continue

• Kadang kala, kita membutuhkan suatu perulangan untuk


diberhentikan secara paksa atau lompat ke iterasi berikutnya.
• C++ menyediakan kedua fitur tersebut, yaitu dengan kata
kunci break dan continue.

13/30
Break & Continue (lanj.)

Break
Penggunaan break akan membuat program keluar dari perulangan
yang mengandung kata kunci tersebut.

Continue
Penggunaan continue akan membuat program kembali ke baris
awal perulangan, yaitu baris ”for”, atau ”while”.

14/30
Contoh Soal: Berhitung 1
• Setelah mahir dalam menggambar pola, kini Pak Dengklek
ingin mengajar tentang berhitung.
• Pak Dengklek akan memberikan dua bilangan, yaitu N dan M.
• Anda diminta untuk menuliskan bilangan dari 1 sampai
dengan N. Namun, ketika bilangan yang hendak ditulis adalah
M, jangan cetak bilangan itu dan jangan cetak bilangan
apapun lagi.
• Setelah selesai mencetak bilangan, cetak ”selesai”.
• Contoh untuk N = 10 dan M = 5:
1
2
3
4
selesai

15/30
Contoh Program: break.cpp

• Berikut ini adalah contoh solusi dari soal ”Berhitung 1”.


#include <cstdio>
int main() {
int N, M;
scanf("%d %d", &N, &M);
for (int i = 1; i <= N; i++) {
if (i == M) {
break;
}
printf("%d\n", i);
}
printf("selesai\n");
}

16/30
Penjelasan Program: break.cpp

• Ketika break ditemui, perulangan ”for” akan diberhentikan


secara paksa dan lanjut mengeksekusi perintah selanjutnya,
yaitu mencetak tulisan ”selesai”.

17/30
Contoh Soal: Berhitung 2

• Kali ini Pak Dengklek mengubah soalnya: diberikan dua


bilangan, yaitu N dan M.
• Anda diminta untuk menuliskan bilangan dari 1 sampai
dengan N. Namun, ketika bilangan yang hendak ditulis adalah
kelipatan dari M, jangan cetak bilangan itu.
• Setelah selesai mencetak bilangan, cetak ”selesai”.
• Contoh untuk N = 10 dan M = 2:
1
3
5
7
9
selesai

18/30
Contoh Program: continue.cpp

• Berikut ini adalah contoh solusi dari soal ”Berhitung 2”.


#include <cstdio>
int main() {
int N, M;
scanf("%d %d", &N, &M);
for (int i = 1; i <= N; i++) {
if (i % M == 0) {
continue;
}
printf("%d\n", i);
}
printf("selesai\n");
}

19/30
Penjelasan Program: continue.cpp

• Ketika continue ditemui, eksekusi perintah di dalam ”for”


untuk i tersebut langsung dilewati dan lanjut ke bagian
perubahan.
• Artinya, untuk N = 10 dan M = 2, ketika nilai i = 2 dan
”continue” ditemui, eksekusi akan dilewati langsung ke bagian
perubahan i++.
• Selanjutnya, perulangan dilanjutkan pada i = 3.

20/30
Contoh Soal: Tes Keprimaan

• Diberikan sebuah bilangan positif yang lebih dari 1, misalnya


N.
• Suatu bilangan N dikatakan prima apabila N positif dan hanya
habis dibagi oleh 1 dan dirinya sendiri.
• Jika N prima, cetak ”<N> adalah bilangan prima” dan jika
tidak, cetak ”<N> bukan bilangan prima”.
Bagaimanakah kalian akan menyelesaikan persoalan ini?

21/30
Solusi 1

• Salah satu solusi yang sederhana adalah: periksa semua


bilangan di antara 2 sampai dengan N-1.
• Jika ada setidaknya satu bilangan yang habis membagi N,
artinya N bukan prima.

22/30
Solusi 1: prima1 1.cpp
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
bool prima = true;
for (int i = 2; i <= N-1; i++) {
if (N % i == 0) {
prima = false;
}
}
if (prima) {
printf("%d adalah bilangan prima\n", N);
} else {
printf("%d bukan bilangan prima\n", N);
}
}

23/30
Solusi 2

• Solusi 1 melakukan pemeriksaan dari 2 sampai dengan N-1,


artinya dibutuhkan pemeriksaan sebanyak N-2 kali.
• Sebetulnya pemeriksaan bisa dihentikan ketika ditemukan
setidaknya satu saja bilangan yang habis membagi N.
• Dengan demikian bisa digunakan break untuk
memberhentikan perulangan begitu ditemukan bilangan yang
habis membagi N.

24/30
Solusi 2: prima1 2.cpp
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
bool prima = true;
for (int i = 2; i <= N-1; i++) {
if (N % i == 0) {
prima = false;
break;
}
}
if (prima) {
printf("%d adalah bilangan prima\n", N);
} else {
printf("%d bukan bilangan prima\n", N);
}
}

25/30
Contoh Soal: Pembangkit Prima

• Diberikan sebuah bilangan bulat N. Pak Dengklek meminta


Anda untuk menuliskan N bilangan prima pertama.
• Contoh untuk N = 5:
2
3
5
7
11

26/30
Solusi: Pembangkit Prima

• Salah satu strategi yang dapat kalian gunakan adalah ”selama


belum ditemukan N bilangan prima, cari bilangan prima!”.
• Bagaimana mencari bilangan prima? Coba saja dari 2, 3, 4,
dan seterusnya sampai ditemukan N bilangan prima.

27/30
Contoh Solusi: prima2.cpp
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int count = 0; // Banyaknya prima yang sudah ditemukan
int cur = 2; // nilai yang akan diperiksa keprimaannya
while (count < N) {
bool prima = true;
for (int i = 2; i <= cur-1; i++) {
if (cur % i == 0) {
prima = false;
break;
}
}

28/30
Contoh Solusi: prima2.cpp (lanj.)

if (prima) {
// Ditemukan prima!
// Cetak dan tambahkan prima yg sudah ditemukan
printf("%d\n", cur);
count++;
}
// Entah ini prima atau bukan, lanjut untuk
// memeriksa bilangan berikutnya
cur++;
}
// Keluar dari while, dipastikan count = N
}

29/30
Penutup

• Percabangan dan perulangan merupakan dua struktur kontrol


yang sangat penting pada pemrograman.
• Kalian diharapkan berlatih sampai lancar di kedua hal
tersebut, baru lanjut untuk mempelajari materi selanjutnya.

30/30
Analisis Kompleksitas

Tim Olimpiade Komputer Indonesia

1/37
Pendahuluan

Melalui dokumen ini, kalian akan:


• Memahami konsep analisis kompleksitas.
• Mampu menganalisis kompleksitas untuk memperkirakan
runtime eksekusi program.

2/37
Bagian 1

Perkenalan Analisis Algoritma

3/37
Analisis Algoritma

• Diberikan dua algoritma untuk menyelesaikan permasalahan


yang sama. Algoritma mana yang lebih cepat?
• Pengukuran seberapa cepatnya suatu algoritma biasa
dinyatakan dalam kompleksitas waktu.
• Kompleksitas waktu: banyaknya komputasi yang perlu
dilakukan dari awal eksekusi sampai berakhirnya algoritma.

4/37
Contoh Soal: Membajak Sawah
Deskripsi:
• Pak Dengklek memiliki N bibit tanaman yang akan ia semai di
sawahnya.
• Untuk itu, ia akan membajak sawahnya supaya sawahnya bisa
memuat N tanaman.
• Sawah yang akan dibajak harus memiliki bentuk persegi
panjang, tersusun atas R baris dan C kolom petak-petak.
Setiap petak bisa memuat maksimal sebuah tanaman.
• Tentukan nilai R dan C supaya semua petak yang ada
ditanami tanaman!
• Jika ada lebih dari satu kemungkinan jawaban, minimalkan
selisih R dengan C.
• Jika masih ada lebih dari satu kemungkinan jawaban, cetak
yang mana saja.

5/37
Contoh Soal: Membajak Sawah (lanj.)

Batasan:
• 1 ≤ N ≤ 109 .

Format Masukan:
• Sebuah baris berisi bilangan bulat, yaitu N.

Format Keluaran:
• Sebuah baris berisi dua bilangan bulat, yaitu R dan C .

6/37
Contoh Soal: Membajak Sawah (lanj.)

Contoh Masukan
35

Contoh Keluaran
75

7/37
Solusi 1: Coba Semua Kemungkinan

• Untuk setiap R dan C yang mungkin, coba hitung apakah


R × C sama dengan N.
• Jika ya, cari yang selisih |R − C | minimal.
• Cukup mencoba untuk 1 ≤ R ≤ N dan 1 ≤ C ≤ N.

8/37
Solusi 1: Coba Semua Kemungkinan (lanj.)
Berikut implementasinya:
#include <cstdio>
#include <cmath>
using namespace std;
int main() {
int N, R, C;
scanf("%d", &N);
R = 1;
C = N;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (i*j == N) {
if (abs(R-C) > abs(i-j)) {
R = i;
C = j;
}
}
}
}
printf("%d %d\n", R, C);
}
9/37
Solusi 1: Coba Semua Kemungkinan (lanj.)

• Fungsi abs adalah fungsi yang disediakan STL cmath untuk


mengambil harga mutlak.
• Misalkan untuk N = 100, secara kasar diperlukan 100 × 100
komputasi untuk mencari nilai R dan C yang tepat.
• Jadi secara umum bisa diperkirakan bahwa untuk suatu nilai
N, diperlukan N 2 komputasi.
• Solusi ini dikatakan memiliki kompleksitas waktu sebesar
O(N 2 ) (dibaca ”O-N-kuadrat”).
• Pertanyaan: apakah solusi ini cukup cepat? Bagaimana jika
N = 109 ?

10/37
Cerita Sampingan: Meramal Waktu Eksekusi

• Terdapat sebuah perkiraan kasar bahwa komputer mampu


melakukan 100 juta (108 ) komputasi dalam 1 detik.
• Tentu saja, perkiraan ini masih sangat kasar. Waktu untuk
melakukan 108 operasi penjumlahan tidak sama dengan waktu
untuk melakukan 108 operasi modulo.
• Jenis bahasa pemrograman juga mempengaruhi waktu
eksekusi algoritma, misalnya bahasa C cenderung lebih cepat
daripada Java.
• Bagaimanapun juga, konvensi ini umum digunakan pada
dunia pemrograman kompetitif dan sesuai untuk bahasa
Pascal, C, dan C++.

11/37
Solusi 1: Terlalu lambat!

• Untuk N yang bisa mencapai 109 , diperlukan sekitar


1018 /108 = 1010 detik.
• Waktu tersebut setara dengan sekitar 317 tahun!
• Adakah solusi lebih efisien?

12/37
Solusi 2: Coba Semua Kemungkinan R

• Tidak perlu memeriksa semua R dan C , cukup coba saja


semua kemungkinan R untuk 1 ≤ R ≤ N.
• Jika untuk suatu nilai R, diketahui N habis dibagi R, maka C
dipastikan ada, yaitu N/R.

13/37
Solusi 2: Coba Semua Kemungkinan R (lanj.)

Bagian implementasi:
scanf("%d", &N);
R = 1;
C = N;
for (int i = 1; i <= N; i++) {
if (N % i == 0) {
int j = N / i;
if (abs(R-C) > abs(i-j)) {
R = i;
C = j;
}
}
}

14/37
Solusi 2: Coba Semua Kemungkinan R (lanj.)

• Solusi ini bekerja dengan lebih cepat.


• Untuk suatu nilai N, kasarnya cukup dilakukan N komputasi
untuk mencari nilai R dan C yang tepat.
• Solusi ini dikatakan memiliki kompleksitas waktu sebesar
O(N).
• Untuk N = 109 , diperlukan sekitar 10 detik eksekusi
algoritma.

15/37

Solusi 3: Batasi R sampai N
• Persoalan ini sebenarnya meminta kita memfaktorkan N,
supaya dua bilangan hasil faktorisasi sedekat mungkin.
• Untuk memeriksa
√ seluruh faktor bilangan, cukup batasi
sampai N saja.
• Contoh: untuk N = 100, faktorisasi yang mungkin adalah:
• 1 × 100
• 2 × 50
• 4 × 25
• 5 × 20
• 10 × 10
• 20 × 5
• 25 × 4
• ... (faktorisasi selanjutnya hanya mengulang yang sudah ada)

16/37

Solusi 3: Batasi R sampai N (lanj.)
Bagian implementasi:
scanf("%d", &N);
R = 1;
C = N;
int i = 1;
while (i*i <= N) {
if (N % i == 0) {
int j = N / i;
if (abs(R-C) > abs(i-j)) {
R = i;
C = j;
}
}
i++;
}
printf("%d %d\n", R, C);

17/37

Solusi 3: Batasi R sampai N (lanj.)


• Kompleksitas solusi menjadi hanya O( N).
• Untuk N = 109 , hanya diperlukan sekitar 32.000 komputasi,
jauh di bawah 100 juta.
• Solusi ini bekerja dengan cepat bahkan untuk N yang besar.

18/37
Ulasan Contoh Soal

• Untuk menyelesaikan suatu permasalahan, bisa jadi ada


beberapa solusi, masing-masing dengan kompleksitasnya
tersendiri.
• Dari ketiga solusi yang telah dijelaskan, solusi ketiga sudah
pasti paling diharapkan untuk bisa menyelesaikan
permasalahan.
• Untuk mengukur seberapa efisien suatu algoritma, bisa
digunakan notasi Big-Oh untuk kompleksitas waktu.

19/37
Notasi Big-Oh

• Biasa digunakan pada ilmu komputer untuk menyatakan


pertumbuhan nilai suatu fungsi terhadap ukuran masukan
yang diberikan.
• Dalam kasus ini, fungsi yang dimaksud adalah fungsi
banyaknya komputasi yang diperlukan jika diberikan suatu
ukuran masukan.
• Kita tidak akan menggali terlalu dalam tentang hal-hal
matematis di balik notasi Big-Oh ini, hanya kulit luarnya saja.

20/37
Aturan Sederhana Notasi Big-Oh

1. Konstanta bisa diabaikan.


Contoh: O(3N 2 ) bisa ditulis O(N 2 ) saja.
Alasan: kita hanya tertarik dengan pertumbuhan fungsinya,
bukan nilai fungsi sebenarnya.

2. Cukup ambil suku yang mendominasi.


Contoh: O(N 3 + N 2 ) bisa ditulis O(N 3 ) saja.
Alasan: untuk N yang besar, suku N 3 akan jauh lebih besar
daripada suku N 2 , sehingga N 2 menjadi tidak signifikan.

21/37
Kelompok Kompleksitas

Biasanya kompleksitas dikelompokkan menurut kelasnya sebagai


berikut:
• Constant: O(1)
Komputasi yang dilakukan tidak bergantung pada besarnya
input. Contoh: program untuk mencari nilai harga mutlak
suatu angka.
• Logarithmic: O(log N)
Komputasi yang dilakukan proporsional terhadap nilai
logaritma dari input.

22/37
Kelompok Kompleksitas (lanj.)

• Linear : O(N)
Komputasi yang dilakukan proporsional secara linier terhadap
input.

• Polynomial: O( N), O(N 2 ), O(N 3 ), ...
Komputasi yang dilakukan proporsional secara polinomial
terhadap input.
• Exponential: O(N!), O(2N ), O(N N ), ...
Komputasi yang dilakukan proporsional secara eksponensial
terhadap input. Biasanya dihindari karena terlalu lambat.

23/37
Kelompok Kompleksitas (lanj.)

24/37
Bagian 2

Menghitung Kompleksitas

25/37
Menghitung Kompleksitas

• Wajib dilakukan sebelum mengimplementasikan suatu


algoritma.
• Tujuannya untuk memperkirakan apakah solusi ini cukup
efisien untuk menyelesaikan persoalan yang ada.
• Dengan sedikit latihan, Anda dapat menghitung kompleksitas
dari algoritma sederhana.

26/37
Contoh 1: Soal

Hitung kompleksitas waktu potongan program berikut:

total = 0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
total++;
}
}

27/37
Contoh 1: Jawaban

• Sederhana, jawabannya adalah O(N 2 ).

28/37
Contoh 2: Soal

Hitung kompleksitas waktu potongan program berikut:

total = 0;
for (int i = 1; i <= N; i++) {
for (int j = i; j <= N; j++) { // j dimulai dari i
total++;
}
}

29/37
Contoh 2: Jawaban

• Banyaknya operasi ”total := total + 1” yang dilakukan adalah


N + (N − 1) + (N − 2) + ... + 2 + 1 = N(N+1)
2 .
 
N(N+1)
• Kompleksitasnya O 2 , tetapi cukup ditulis O(N 2 )
saja.

30/37
Contoh 3: Soal

Hitung kompleksitas waktu potongan program berikut:

total = 0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= M; j++) {
total++;
}
}

31/37
Contoh 3: Jawaban

• Kali ini terdapat dua variabel pada input, yaitu N dan M.


• Kompleksitasnya adalah O(NM).

32/37
Contoh 4: Soal

Hitung kompleksitas waktu potongan program berikut:

val = N;
while (val > 0) {
val /= 3; // Setara "val = val / 3"
}

33/37
Contoh 4: Jawaban

• Banyaknya operasi yang dilaksanakan setara dengan panjang


N N N
dari barisan 3 , 9 , 27 , ..., 1.
• Panjang dari barisan tersebut sebenarnya adalah logaritma
basis 3 dari N, atau bisa dituliskan kompleksitasnya
O(log3 N).
• Namun sebenarnya log3 N = log N 1
log 3 = log 3 log N.
• Berhubung log1 3 adalah konstanta, jadi cukup ditulis O(log N)
saja.

34/37
Contoh 5: Soal

Hitung kompleksitas waktu potongan program berikut:

counter = 1;
while (counter*counter < N) {
counter++;
}

35/37
Contoh 5: Jawaban

• Nilai variabel counter akan terus bertambah, hingga


kuadratnya lebih dari N.
• Misalkan jika N = 81, maka counter akan berhenti setelah
nilainya melebihi 9.

• Kompleksitas sebenarnya adalah O( N).

36/37
Penutup

• Pelajari lebih lanjut tentang perhitungan kompleksitas melalui


latihan yang diberikan.
• Terdapat notasi lainnya yang tidak kita bahas di sini, seperti
Big-Theta (Θ), Big-Omega (Ω), Little-Oh (o), dan
sebagainya. Silakan Anda pelajari jika tertarik untuk
mengetahui lebih lanjut.

37/37
Array

Tim Olimpiade Komputer Indonesia

1/38
Pendahuluan

Melalui dokumen ini, kalian akan:


• Memahami konsep array.
• Mengimplementasikan array pada bahasa Pascal.
• Menggunakan array untuk penyelesaian beberapa contoh
masalah.

2/38
Bagian 1

Konsep Array

3/38
Motivasi

• Pak Dengklek memiliki sebuah tumpukan berisi N kartu, yang


dipenuhi 1 ≤ N ≤ 100.
• Setiap kartu bertuliskan suatu bilangan bulat.
• Sekarang Pak Dengklek ingin tahu urutan angka-angka pada
kartu tersebut bila tumpukan kartu itu dibalik.
• Contoh: jika diberikan 5 kartu dengan angka-angka dari
atasnya [1, 5, 3, 20, 4], maka setelah dibalik urutannya
menjadi: [4, 20, 3, 5, 1].
• Bantulah Pak Dengklek menentukan urutan angka-angka
tersebut setelah tumpukan kartu dibalik!

4/38
Solusi?

• Sederhana, idenya adalah dengan menampung seluruh


bilangan terlebih dahulu, baru dicetak dalam urutan terbalik.
• Misalnya jika N selalu 3, kita bisa membuat 3 variabel
(misalnya a, b, c), lalu:
scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);
printf("%d\n", c);
printf("%d\n", b);
printf("%d\n", a);
• Sayangnya nilai N tidak tetap! Dibutuhkan suatu mekanisme
lain untuk menggunakan dan mengakses variabel!

5/38
Pengertian Array

Array
Variabel dengan satu nama, tetapi mengandung banyak nilai.
Akses nilai-nilainya dilakukan dengan indeks.

Perhatikan contoh berikut!


indeks 1 2 3 4 5 6 7 8 9 10
A 3 10 11 23 35 12 31 53 0 19
• A[1] = 3
• A[2] = 10
• A[5] = 35

6/38
Penjelasan

• Pada contoh sebelumnya, kita memiliki sebuah variabel


bernama A.
• A memiliki 10 nilai, yang masing-masing dapat diakses dengan
indeks.
• Untuk mengakses nilai A yang ke-x, digunakan A[x].
• Lebih jauh lagi, sebenarnya A[x] bisa dianggap sebagai sebuah
variabel yang berdiri sendiri.
• Konsep inilah yang disebut sebagai array!

7/38
Bagian 2

Implementasi Array pada C++

8/38
Deklarasi

• Karena array merupakan variabel, diperlukan deklarasi seperti


variabel lainnya.
• Format deklarasi array adalah:
<tipe> <nama>[<ukuran>];
• Dengan:
• <nama> adalah nama dari array (aturan penamaan sama
seperti variabel biasanya)
• <ukuran> adalah ukuran dari array, yang terdefinisi dari 0
sampai dengan ukuran-1.
• <tipe> adalah tipe data dari array.
• Tentu saja, tipe data di sini bisa berupa int, double, string,
bool atau suatu struct.

9/38
Contoh Deklarasi
Berikut ini adalah contoh deklarasi array pada C++:
bool tabel[101];
int frekuensi[1000];

• Untuk contoh array tabel, hanya tabel[0], tabel[1], tabel[2],


..., tabel[100] yang terdefinisi.
• Untuk contoh array frekuensi, hanya frekuensi[0], frekuensi[1],
frekuensi[2], ..., frekuensi[999] yang terdefinisi.
• Mengakses nilai tabel[-1], tabel[-2], atau tabel[500] dapat
menyebabkan runtime error.
• Untuk itu, tentukan rentang indeks yang akan kalian gunakan
saat deklarasi dengan tepat (sesuai kebutuhan).

10/38
Array dan Variabel

• Karena suatu elemen dari array juga bisa dianggap variabel,


tentu saja kita bisa melakukan perintah scanf padanya.
• Sebagai contoh, jika kita memiliki array int bernama tabel
yang terdefinisi dari 1 sampai dengan 100, kita bisa
melakukan:
scanf("%d", &tabel[2]);

11/38
Array dan Variabel (lanj.)

• Jika diberikan 5 bilangan, dan kita perlu menyimpan


masing-masing bilangan di tabel, kita bisa melakukan:
scanf("%d", &tabel[0]);
scanf("%d", &tabel[1]);
scanf("%d", &tabel[2]);
scanf("%d", &tabel[3]);
scanf("%d", &tabel[4]);
• Tentu saja hal ini sangat tidak efisien!
• Untungnya, kita sudah mempelajari sebuah teknik yang
sangat penting, yaitu perulangan.

12/38
Array dan Variabel (lanj.)

• Proses membaca 5 bilangan pada 5 baris kini bisa dilakukan


dengan cara:
for (int i = 0; i < 5; i++) {
scanf("%d", &tabel[i]);
}
• Untuk kasus umum, yaitu ketika diberikan N bilangan, cukup
ganti angka 5 dengan variabel N.
for (int i = 0; i < N; i++) {
scanf("%d", &tabel[i]);
}

13/38
Array dan Variabel (lanj.)

• Demikian pula untuk pencetakan secara terbalik, kita bisa


menggunakan perulangan sebagai berikut:
for (int i = N-1; i >= 0; i--) {
printf("%d\n", tabel[i]);
}
• Sekarang masalah Pak Dengklek terpecahkan!

14/38
Contoh Solusi: balik.pas

Berikut contoh solusi lengkap untuk permasalahan motivasi:


#include <cstdio>
int main() {
int N;
int tabel[100];
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%d", &tabel[i]);
}
for (int i = N-1; i >= 0; i--) {
printf("%d\n", tabel[i]);
}
}

15/38
Array dan Memori

• Setiap elemen pada array membutuhkan memori, bergantung


pada tipe data yang digunakan.
• Total memori yang dibutuhkan untuk sebuah array sama
dengan banyaknya elemennya dikali ukuran memori satu
elemennya.
• Sebagai contoh, array dengan 100 elemen dan memiliki tipe
int membutuhkan memori sebesar 100 × 4 byte = 400 byte,

16/38
Rentang Array
• Pada program membalik array, dideklarasikan array sebesar
100 elemen (dari 0 sampai dengan 99), padahal bisa jadi
hanya digunakan sebagian saja.
• Cara ini memang ”boros” memori, tetapi merupakan cara
yang paling mudah adalah mendeklarasikannya sebesar nilai N
maksimal yang mungkin.
• Bisa juga kita deklarasikan sesudah N diketahui sebagai
berikut:
...
int N;
scanf("%d", &N);
int tabel[N];
...

17/38
Contoh Soal: Ujian Harian

Deskripsi:
• Pak Dengklek menyelenggarakan ujian harian setelah selesai
mengajarkan N ekor bebeknya mengenai konsep array.
• Setiap bebek ke-i mendapatkan nilai sebesar hi , yang
merupakan bilangan bulat.
• Tentukan banyaknya bebek yang memiliki nilai tidak kurang
dari rata-rata seluruh bebek!
Batasan:
• 1 ≤ N ≤ 100
• 1 ≤ hi ≤ 100, untuk 1 ≤ i ≤ N

18/38
Contoh Soal: Ujian Harian (lanj.)

Format masukan:
• Baris pertama berisi sebuah bilangan bulat N.
• N baris berikutnya berisi nilai ujian bebek. Baris ke-i ini
merupakan hi .
Format keluaran:
• Sebuah baris yang menyatakan banyaknya bebek yang lulus
ujian.

19/38
Contoh Soal: Ujian Harian (lanj.)

Contoh masukan:
3
5
6
7

Contoh keluaran:
2

Penjelasan
Nilai rata-rata dari seluruh bebek adalah 6, dan terdapat 2 ekor
bebek yang nilainya tidak kurang dari 6.

20/38
Petunjuk

• Salah satu solusinya adalah melalui dua tahap:


1. Hitung rata-ratanya.
2. Hitung banyaknya bebek yang nilainya tidak kurang dari
rata-rata.
• Sebisa mungkin, hindari penggunaan floating-point!
• Ingat bahwa tipe data floating-point kurang bisa menyatakan
bilangan secara akurat; nilai 1/3*3 bisa jadi
0.999999999999999 atau 1.0000000000001.
• Pengoperasian tipe data bilangan bulat oleh komputer jauh
lebih cepat daripada pengoperasian tipe data floating-point!

21/38
Contoh Solusi: lulus.pas

#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int nilai[N];
for (int i = 0; i < N; i++) {
scanf("%d", &nilai[i]);
}
int total = 0;
for (int i = 0; i < N; i++) {
total += nilai[i];
}

22/38
Contoh Solusi: lulus.pas (lanj.)

int lulus = 0;
for (int i = 0; i < N; i++) {
// Trik menghindari pembagian
if (nilai[i]*N >= total) {
lulus++;
}
}
printf("%d\n", lulus);
}

23/38
Bagian 3

Penggunaan Array Lanjutan

24/38
Array Dua Dimensi

• Struktur array bisa juga membentuk sebuah tabel dua dimensi.


• Perhatikan contoh deklarasi berikut:
int matriks[2][5];
• Kini kita mendapatkan variabel bernama matriks[a][b], yang
terdefinisi untuk 0 ≤ a ≤ 1 dan 0 ≤ b ≤ 4.

25/38
Array Dua Dimensi (lanj.)

• Akses suatu elemen dapat dilakukan dengan matriks[a][b].


• Tabel berikut menunjukkan struktur dari array matriks:
1 2 3 4 5
1
2
• Aturan perhitungan memori tetap sama; banyaknya elemen
dikali memori per elemennya.
Pada kasus ini: 2 × 5 × 4 byte = 40 byte.

26/38
Contoh Soal:
Cokelat Bebek
Deskripsi:
• Pak Ganesh datang bertamu ke peternakan bebek Pak
Dengklek.
• Pada peternakan bebek Pak Dengklek, terdapat kandang
bebek yang tersusun atas petak-petak N baris dan N kolom.
• Pak Dengklek memberi di,j gram cokelat* ke kandang di baris
ke-i dan kolom ke-j.
• Pak Ganesh memberi gi,j gram cokelat* ke kandang di baris
ke-i dan kolom ke-j.
• Tentukan berapa gram cokelat yang diperoleh setiap bebek di
kandangnya!
Batasan:
• 1 ≤ N ≤ 100
• 0 ≤ di,j , hi,j ≤ 10, untuk 1 ≤ i, j ≤ N
*Catatan: bebek-bebek suka cokelat!
27/38
Contoh Soal:
Cokelat Bebek (lanj.)
• Sebagai contoh, misalkan N = 3.
• Kemudian berikut adalah cokelat yang diberikan Pak
Dengklek (D) dan Pak Ganesh (G ):
   
1 3 0 2 1 7
D = 6 2 4 G = 0 0 1
2 1 5 1 1 2
• Maka total cokelat yang didapatkan setiap kandang adalah:
 
3 4 7
6 2 5
3 2 7

28/38
Contoh Soal:
Cokelat Bebek (lanj.)
Format masukan:
• Baris pertama berisi sebuah bilangan bulat N.
• N baris berikutnya berisi N bilangan. Bilangan di baris ke-i
dan kolom ke-j ini adalah di,j .
• N baris sisanya berisi N bilangan. Bilangan di baris ke-i dan
kolom ke-j ini adalah gi,j .
Format keluaran:
• N baris yang berisi N bilangan. Bilangan di baris ke-i dan
kolom ke-j ini adalah total makanan yang ada di kandang
baris ke-i dan kolom ke-j.

29/38
Contoh Soal:
Cokelat Bebek (lanj.)

Contoh masukan:
3
1 3 0
6 2 4
2 1 5
2 1 7
0 0 1
1 1 2

Contoh keluaran:
3 4 7
6 2 5
3 2 7

30/38
Petunjuk

• Salah satu cara yang mudah adalah membuat tiga array dua
dimensi, masing-masing untuk menampung makanan yang
diberikan Pak Dengklek (D), Pak Ganesh (G ), dan hasil
akhirnya (hasil).
• Tentu saja hubungannya adalah hasil[i][j] = D[i][j] + G [i][j],
untuk 1 ≤ i, j ≤ N.

31/38
Solusi: cokelat.pas
Pertama, mari kita deklarasikan variabel dan baca masukan:
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int D[N][N], G[N][N], hasil[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
scanf("%d", &D[i][j]);
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
scanf("%d", &G[i][j]);
}
}

32/38
Solusi: cokelat.pas (lanj.)
Lakukan penjumlahan, lalu cetak hasilnya:
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
hasil[i][j] = D[i][j] + G[i][j];
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%d", hasil[i][j]);
if (j+1 < N) {
printf(" ");
}
}
printf("\n");
}
}

33/38
Solusi: cokelat 2.pas
Nilai array D dan G sebenarnya tidak perlu disimpan, kita bisa
menghemat memori dengan langsung menjumlahkannya.
#include <cstdio>
int main() {
int N;
scanf("%d", &N);
int hasil[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int temp;
scanf("%d", &temp);
hasil[i][j] = temp;
}
}

34/38
Solusi: cokelat 2.pas (lanj.)
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int temp;
scanf("%d", &temp);
hasil[i][j] += temp;
}
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%d", hasil[i][j]);
if (j+1 < N) {
printf(" ");
}
}
printf("\n");
}
}

35/38
Array Multidimensi

• Tidak hanya sampai dua dimensi, dimensi tiga, empat, atau


lebih pun bisa.
• Sebagai contoh:
int data[2][50][50];
• Kita akan mendapatkan variabel data[i][j][k] yang terdefinisi
untuk 0 ≤ i ≤ 1, dan 0 ≤ j, k ≤ 49.

36/38
Catatan

• Pada saat array dideklarasi, nilai yang ada di dalam array bisa
jadi tidak tentu.
• Sebagai contoh, program berikut akan mencetak angka yang
tidak tentu:
#include <cstdio>
int main() {
int arr[10];
printf("%d\n", arr[0]);
}
• Pastikan Anda melakukan inisialisasi pada array dengan tepat.

37/38
Selanjutnya...

• Mempelajari tentang fungsi dan prosedur.

38/38
Subprogram

Tim Olimpiade Komputer Indonesia

1/42
Motivasi-1
• Ketika menulis program, kadang-kadang kita memerlukan
suatu rutinitas yang sama di beberapa tempat.
• Sebagai gambaran, perhatikan contoh soal berikut:
• Pak Dengklek menancapkan tiga buah tiang pancang di
halaman rumahnya untuk membangun sebuah kandang bebek.
• Setiap tiang pancang bisa dianggap terletak di suatu sistem
koordinat Kartesius, yaitu di (Ax , Ay ), (Bx , By ), dan (Cx , Cy ).
• Pagar akan dibentangkan menurut garis lurus antar setiap
tiang pancang.
• Sekarang Pak Dengklek ingin tahu berapa luas kandang
bebeknya.
• Persoalan yang kita hadapi adalah menghitung luas dari
segitiga, jika hanya diberikan titik-titik sudutnya.

2/42
Motivasi-1 (lanj.)

Salah satu penyelesaian untuk soal tersebut adalah menggunakan


rumus Heron:

Jika sebuah segitiga memiliki panjang sisi sebesar a, b, dan c,


makapluas segitiga tersebut adalah:
L = S(S − a)(S − b)(S − c), dengan S = a+b+c 2

Bagaimana implementasinya pada program?

3/42
Motivasi-1 (lanj.)
• Kita perlu menghitung jarak antar titik terlebih dahulu, baru
bisa menghitung luasnya.
• Kita dapat menuliskannya:
// tA, tB, tC merupakan ketiga titik yang diberikan
a = sqrt((tA.x - tB.x)*(tA.x - tB.x) + (tA.y -
tB.y)*(tA.y - tB.y));
b = sqrt((tA.x - tC.x)*(tA.x - tC.x) + (tA.y -
tC.y)*(tA.y - tC.y));
c = sqrt((tB.x - tC.x)*(tB.x - tC.x) + (tB.y -
tC.y)*(tB.y - tC.y));
• Perhatikan bahwa hal yang sama, yaitu menghitung jarak
titik, dituliskan secara berulang-ulang.
• Bagaimana jika pada salah satunya terdapat kesalahan
pengetikan? Atau suatu ketika rumusnya perlu diubah?
Sungguh merepotkan!

4/42
Motivasi-2
• Seringkali ketika kita menulis program yang panjang, program
menjadi lebih sulit dipahami, meskipun telah ditulis komentar
sekalipun.
• Alangkah baiknya jika kita bisa membuat subprogram untuk
suatu rutinitas tertentu dan menyatukannya di akhir, seperti:
bacaMasukan(N);
cariPrimaSampai(N);
printf("faktorisasi:\n");
temp = N;
while (!cekPrima(temp)) {
d = cariPembagiTerkecil(temp);
temp = temp / d;
printf("%d\n", d);
}
if (temp > 1) {
printf("%d\n", temp);
}

5/42
Bagian 1

Konsep Subprogram

6/42
Konsep Subprogram

• Sesuai dengan namanya, subprogram adalah bagian dari


program.
• Jika program merupakan serangkaian instruksi untuk
mencapai suatu tujuan tertentu, maka subprogram bisa
dianggap sebagai serangkaian instruksi untuk mencapai suatu
tujuan tertentu, sebagai bagian dari tujuan program.
• Subprogram bisa dipanggil di bagian manapun pada program.
• Pada C++, subprogram disebut dengan fungsi.

7/42
Contoh Subprogram
• Kita bisa memindahkan serangkaian kode menjadi sebuah
fungsi, lalu memanggilnya pada program utama.
• Perhatikan contoh pesan.cpp berikut!
#include <cstdio>
#include <string>
using namespace std;
char buff[1001];
string pesan;
// Subprogram
void bacaPesan() {
printf("masukkan pesan: \n");
scanf("%s", buff);
pesan = buff;
}
// Program utama
int main() {
bacaPesan();
printf("pesan = %s\n", pesan.c_str());
}
8/42
Penjelasan

• Pada pesan.cpp, terdapat sebuah fungsi bernama bacaPesan


yang melakukan perintah untuk membaca masukan.
• Ketika bacaPesan dipanggil pada program utama, bisa
dianggap seluruh instruksi yang ada di dalam fungsi tersebut
dipindahkan ke program utama yang memanggilnya.
• Sehingga, program utama seakan-akan menjadi:
int main() {
printf("masukkan pesan: \n");
scanf("%s", buff);
pesan = buff;
printf("pesan = %s\n", pesan.c_str());
}

9/42
Penjelasan (lanj.)

• Tentu saja, sebuah fungsi bisa dipanggil berkali-kali, dan hal


yang dilakukan tetap sama.
• Coba modifikasi blok progam utama pesan.cpp menjadi:
int main() {
bacaPesan();
printf("pesan = %s\n", pesan.c_str());
bacaPesan();
printf("sekarang pesan berisi = %s\n",
pesan.c_str());
}

10/42
Bagian 2

Implementasi pada C++

11/42
Fungsi

Pada C++, fungsi bisa ditulis dengan format berikut:


<tipe> <nama>(<parameter...>) {
<instruksi...>
}

• <tipe>: nilai kembalian yang dihasilkan fungsi. Untuk fungsi


yang tidak menghasilkan nilai kembalian, kita gunakan tipe
void. Fungsi yang menghasilkan nilai kembalian akan
dipelajari di bagian selanjutnya.
• <nama>: nama dari fungsi.
• <parameter>: informasi yang hendak diberikan ke fungsi.

12/42
Konsep Parameter

Parameter merupakan tempat untuk ”memberi masukan” bagi


fungsi, sehingga fungsi bisa berperilaku berdasarkan masukan yang
diterima.

Perhatikan contoh berikut:


void gambar(int x) {
for (int i = 0; i < x; i++) {
printf("*");
}
printf("\n");
}

13/42
Konsep Parameter (lanj.)

• Fungsi gambar berfungsi untuk menuliskan karakter ’*’ pada


sebuah baris sebanyak x kali.
• Lalu apa x pada fungsi tersebut?
• Untuk menjawabnya, perhatikan blok program utama berikut:
// Program utama
int main() {
gambar(3);
gambar(5);
}
• Yang akan tercetak adalah:
***
*****

14/42
Konsep Parameter (lanj.)

• Pada pemanggilan pertama, angka 3 pada gambar(3)


mengakibatkan nilai x untuk fungsi gambar bernilai 3.
Sehingga tercetak 3 karakter ’*’.
• Pada pemanggilan kedua, nilai x yang diterima adalah 5.
Sehingga tercetak 5 karakter ’*’.
• Variabel x pada fungsi gambar disebut sebagai parameter.
• Melalui contoh ini, kalian dapat memahami bahwa nilai
parameter dapat digunakan untuk mengatur perilaku fungsi.

15/42
Konsep Parameter (lanj.)

• Tentu saja, pemanggilan juga bisa dilakukan dengan variabel


seperti contoh berikut:
int main() {
int n;
scanf("%d", &n);
gambar(n);
}

16/42
Parameter

• Parameter dituliskan dengan format tipe dan namanya.


• Suatu fungsi boleh memiliki beberapa parameter.
• Contoh:
// Tanpa parameter
void baca()
// Satu parameter
void tes(int x)
// Dua parameter
void sama(int x, int y)
// Dua parameter, berbeda tipe data
void berbeda(int x, string y)

17/42
Lingkup Variabel

• Perhatikan kembali fungsi gambar berikut:


void gambar(int x) {
for (int i = 0; i < x; i++) {
printf("*");
}
printf("\n");
}
• Variabel i dan x pada fungsi tersebut hanya terdefinisi di
antara blok { dan } fungsi gambar saja.
• Artinya jika pada program utama terdapat pula variabel
bernama x atau i, maka variabel tersebut bukan mengacu
pada x dan i pada fungsi gambar.

18/42
Lingkup Variabel (lanj.)

• Variabel yang dideklarasikan di dalam fungsi biasa disebut


sebagai variabel lokal.
• Sementara variabel yang dideklarasikan di luar fungsi atau
program utama disebut sebagai variabel global.
• Variabel global dapat diakses di mana saja, bahkan di dalam
subprogram sekalipun.
• Variabel lokal hanya bisa diakses pada subprogram yang
mendeklarasikannya.

19/42
Fungsi dengan Nilai Kembalian

• Setelah kalian memahami tentang fungsi, mari kita bahas


tentang nilai kembalian.
• Perhatikan fungsi berikut:
int kubik(int x) {
return x*x*x;
}

20/42
Penjelasan

• Pada program utama, kita bisa melakukan:


int main() {
int volume = kubik(3);
int selisih = volume - kubik(2);
printf("4 kubik adalah %d\n", kubik(4));
}
• Teringat dengan sesuatu?
• Fungsi kubik kini terlihat seperti fungsi yang biasa kalian
gunakan, seperti sqrt, round, atau abs!

21/42
Nilai Kembalian

• Ketika fungsi mengembalikan nilai, nilai ini bisa dioperasikan


ke dalam ekspresi atau assignment.
• Sebagai ilustrasi, perhatikan ekspresi berikut:
x = 2;
y = 3*kubik(x) - 1;
• Pada saat dijalankan, fungsi kubik(x) akan dieksekusi dan
mengembalikan nilai 8.
y := 3*8 - 1;
• Setelah ekspresi itu dievaluasi, y bernilai 23.

22/42
Nilai Kembalian (lanj.)

• Hal semacam ini tidak berlaku ketika fungsi tidak


mengembalikan nilai.
• Hal ini juga membedakan cara pemanggilannya:
// Tidak mengembalikan nilai
kerja1()
// Mengembalikan nilai
x = kerja2();

23/42
Fungsi

• Untuk mengembalikan nilai, isikan tipe data nilai kembalian


pada deklarasi fungsi.
• Selanjutnya, kembalikan nilai dengan cara menuliskan
”return” diikuti dengan nilai kembaliannya.
• Perintah return akan menghentikan eksekusi, keluar dari
fungsi, dan mengembalikan nilai ke pemanggilnya.
• Perintah return boleh dipanggil di baris fungsi manapun.

24/42
Contoh Fungsi Lain
• Perhatikan fungsi yang memeriksa keprimaan berikut:
bool prima(int x) {
if (x < 2) {
return false;
}
for (int i = 2; i*i <= x; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
• Pertama, periksa apakah bilangan yang diberikan kurang dari
dua. Bila ya, langsung kembalikan nilai FALSE.

• Kedua, periksa apakah ada angka di antara 2 dan x yang
habis membali x. Bila ada, langsung kembalikan FALSE.
• Selain daripada itu, dijamin x prima.

25/42
Return pada Fungsi void
• Sebenarnya, return juga dapat dilakukan pada fungsi yang
tidak mengembalikan nilai.
• Perintah return akan menghentikan eksekusi dan keluar dari
program.
• Pada contoh berikut, gambar ’*’ tidak akan dicetak apabila x
lebih dari 1000.
void gambar(int x) {
if (x > 1000) {
return;
}
for (int i = 0; i < x; i++) {
printf("*");
}
printf("\n");
}

26/42
Bagian 3

Passing Parameter

27/42
Passing Parameter

• Passing parameter merupakan aktivitas menyalurkan nilai


pada parameter saat memanggil subprogram.
• Umumnya, dikenal dua macam passing parameter :
• By value, yaitu mengirimkan nilai dari setiap parameter yang
diberikan.
• By reference, yaitu mengirimkan alamat dari setiap parameter
yang diberikan.

28/42
Passing Parameter by Value

• Sebagai penjelasan, perhatikan program berikut:


#include <cstdio>
void tukar(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1;
int y = 2;
tukar(x, y);
printf("x=%d y=%d\n", x, y);
}

29/42
Passing Parameter by Value (lanj.)

• Jika dijalankan, apa keluaran dari program tersebut? Apakah


”x=2 y=1”?
• Jawabannya tidak, yang tercetak adalah ”x=1 y=2”.
• Ketika fungsi tukar dipanggil, nilai dari x dan y dikirim ke
parameter a dan b pada fungsi tukar.
• Jadi hanya dilakukan assignment nilai dari x dan y ke a dan b.
• Apapun yang terjadi pada a dan b selanjutnya tidak
mempengaruhi x dan y karena mereka tidak berhubungan.

30/42
Passing Parameter by Reference

• Lain halnya ketika kita menambahkan lambang & pada


penulisan parameter:
void tukar(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}

31/42
Passing Parameter by Reference (lanj.)

• Dengan cara ini, ketika tukar(x, y ) dipanggil, alamat memori


variabel x dan y dikirimkan ke parameter a dan b.
• Kini, x dan a mengacu pada alamat memori yang sama.
• Apabila dilakukan perintah ”a = 3”, maka nilai x juga ikut
menjadi 3. Sebab x dan a mengacu pada alamat memori yang
sama.
• Demikian pula untuk y dan b.
• Sehingga keluaran program menjadi ”x=2 y=1”!

32/42
Passing Parameter by Reference (lanj.)

• Jika tukar ditulis dengan passing parameter by reference, kita


tidak bisa melakukan:
tukar(2, 3);
• Mengirimkan alamat memori dari variabel memang bisa
dilakukan, tetapi angka 2 atau 3 jelas bukan variabel dan jelas
tidak punya alamat memori.
• Jika kita mengembalikan kedua parameter fungsi tukar untuk
menggunakan passing parameter by value, barulah hal ini bisa
dilakukan.

33/42
Penulisan pada C++

• Untuk melakukan passing parameter by reference, cukup


tambahkan & di depan parameter yang akan
di-pass-by-reference.
• Sebuah subprogram bisa juga menerima parameter dengan
cara passing parameter yang campuran:
void bagi(int a, int b, int &hasil, int &sisa) {
hasil = a / b;
sisa = a % b;
}

34/42
Bagian 4

Studi Kasus Subprogram

35/42
Fungsi Pangkat (int)

Berikut ini adalah fungsi untuk menghitung ab :


int pangkat(int a, int b) {
int hasil = 1;
for (int i = 0; i < b; i++) {
hasil *= a;
}
return hasil;
}

36/42
Fungsi Pangkat (void)

Berikut ini adalah fungsi untuk menghitung ab , hasil ditampung


pada variabel hasil:
void pangkat(int a, int b, int &hasil) {
hasil = 1;
for (int i = 0; i < b; i++) {
hasil *= a;
}
}

37/42
Mengembalikan Nilai atau Tidak

• Baik dengan kedua cara, kita bisa mencapai hal yang sama.
• Pertanyaannya adalah: mana yang lebih tepat?

38/42
Mengembalikan Nilai atau Tidak (lanj.)

• Dengan mengembalikan nilai, menghitung y = 3x 5 bisa


dilakukan dengan:
y = 3 * pangkat(x, 5);
• Tanpa mengembalikan nilai, sedikit lebih rumit:
pangkat(x, 5, y);
y = 3 * y;
• Untuk kasus ini, mengembalikan nilai lebih tepat.

39/42
Kilas Balik: Fungsi tukar

• Sekarang coba ingat kembali fungsi tukar yang kita bahas


sebelumnya.
• Kurang masuk akal apabila kita menggunakan mengembalikan
nilai saat melakukan penukaran.
• Sehingga untuk kasus penukaran isi variabel, tanpa
mengembalikan nilai lebih tepat.

40/42
Penggunaan Subprogram

• Dari sini kita mempelajari bahwa ada subprogram yang lebih


cocok diimplementasikan mengembalikan nilai atau tidak.
• Biasanya, yang mengembalikan nilai bersifat:
• Menghasilkan suatu nilai berdasarkan parameter.
• Tidak mengakibatkan efek samping, misalnya adanya
perubahan nilai pada parameter yang diberikan seperti pada
fungsi tukar.
• Sementara yang tidak mengembalikan nilai bersifat:
• Tidak menghasilkan suatu nilai berdasarkan parameter.
• Boleh jadi mengakibatkan perubahan pada variabel global atau
parameter yang dikirimkan.

41/42
Manfaat Subprogram

• Meningkatkan daya daur ulang kode (reusability ).


Satu kali saja kita mendefinisikan subprogram untuk menukar
isi variabel, berapa kali pun penukaran isi variabel bisa
dilakukan tanpa perlu menuliskan algoritma penukaran lagi.
• Memecah program menjadi beberapa subprogram yang lebih
kecil.
Keuntungannya adalah didapatkan kumpulan subprogram
yang:
• Fokus pada suatu tujuan tertentu.
• Tersusun atas kode yang cenderung pendek.
• Karena kedua hal di atas, lebih mudah dibaca dan ditelusuri.

42/42
Pendalaman String
(C++)

Tim Olimpiade Komputer Indonesia

1/24
Bagian 1

Pengolahan String

2/24
String pada C++

Seperti yang disinggung sebelumnya, terdapat dua macam string


yang dapat digunakan di C++.
1. cstring: string yang diwariskan dari bahasa C, yang
merupakan leluhur bahasa C++.
2. std string: string yang dimiliki oleh C++.
Kita akan membahasnya satu per satu.

3/24
Bagian 2

cstring

4/24
Pengenalan cstring

• Dalam bahasa C dan C++, cstring dibuat menggunakan ”null


terminated array of char ”.
• Penggunaannya sesederhana membuat array char.
• Karena berasal dari bahasa C, cstring dapat berinteraksi
dengan scanf dan printf secara langsung.
#include <cstdio>
char s[1001];
int main() {
scanf("%s", s);
printf("%s\n", s);
}

5/24
Representasi cstring

• Misalkan kita memasukkan ”Pak Dengklek” pada program


sebelumnya.
• Array s akan berisi karakter-karakter penyusun ”Pak
Dengklek”, diakhiri dengan karakter ’\0’.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...
P a k D e n g k l e k \0 ...

• Karakter ’\0’ digunakan oleh C/C++ untuk menandai akhir


dari string.
• Jadi, meskipun terdapat 1001 elemen pada s, C/C++ tahu
string yang direpresentasikan hanya sampai elemen ke-11 saja.

6/24
Representasi cstring

• Perhatikan bahwa s hanya dapat menampung paling banyak


1000 karakter.
• Meskipun memiliki 1001 elemen, sebuah elemen sudah
dipesan untuk menempatkan karakter \0.
• Apabila string yang dibaca lebih dari 1000 karakter, program
tidak mengalami error. Namun, program akan bekerja dengan
tidak terprediksi.
• Pastikan ukuran array dibuat sebesar ukuran maksimal
masukan yang mungkin.

7/24
Pengolahan cstring

• Seperti array pada umumnya, Anda dapat mengolah setiap


elemennya secara independen.
• Sebagai contoh, program berikut mengubah setiap karakter
dari string yang dibaca menjadi ’a’.
int main() {
scanf("%s", s);
for (int i = 0; s[i] != ’\0’; i++) {
s[i] = ’a’;
}
printf("%s\n", s);
}

8/24
Mencari Panjang cstring

• Kita dapat menggunakan fungsi strlen untuk mencari


panjang suatu cstring.
• Fungsi ini disediakan oleh STL ”cstring”.

Contoh:
#include <cstdio>
#include <cstring>
char s[1001];
int main() {
scanf("%s", s);
printf("%d\n", strlen(s));
}

9/24
Penggunaan strlen
• Fungsi strlen memiliki kompleksitas O(N), dengan N adalah
panjang dari string masukan.
• Penyebabnya adalah strlen sebenarnya mencari di indeks
keberapakah \0 berada.
• Apabila hendak digunakan dalam perulangan, simpan dulu
panjangnya ke dalam suatu variabel untuk menghindari
pemanggilan yang berulang-ulang.
Contoh:
// Buruk, O(N^2)
for (int i = 0; i < strlen(s); i++) {
printf("%c", s[i]);
}
// Baik, O(N)
int len = strlen(s);
for (int i = 0; i < len; i++) {
printf("%c", s[i]);
}
10/24
Membandingkan cstring
• Untuk membandingkan 2 cstring s dan t secara leksikografis,
gunakan strcmp(s,t).
• Nilai kembaliannya memiliki arti sebagai berikut:
• Negatif, artinya s lebih awal dari t.
• Nol, artinya s sama dengan t.
• Positif, artinya s lebih akhir dari t.
• Kompleksitasnnya O(N), dengan N adalah panjang string
terkecil yang dibandingkan.
Contoh penggunaan:
#include <cstdio>
#include <cstring>
char s[1001];
char t[1001];
int main() {
scanf("%s %s", s, t);
printf("%d\n", strcmp(s, t));
}
11/24
Mengisi Array
• Untuk mengisi array arr dengan x, gunakan memset(arr,
x, sizeof(arr)).
• Nilai x terbatas pada tipe data char, atau angka di antara
-128 sampai 127 saja.
• Fungsi ini biasanya juga dimanfaatkan untuk menginisialisasi
array bilangan dengan 0 atau -1.
Contoh:
#include <cstdio>
#include <cstring>
char s[1001];
int arr[101];
int main() {
memset(s, ’x’, sizeof(s));
memset(arr, -1, sizeof(arr));
printf("%c %d\n", s[0], arr[0]);
}

12/24
Fungsi cstring Lainnya

• Terdapat beberapa fungsi cstring lain seperti strcpy,


strncpy, dan strstr.
• Fungsi-fungsi tersebut tidak dibahas pada materi ini.
• Anda dapat mempelajarinya di dokumentasi C/C++ lebih
lanjut, seperti di http://www.cplusplus.com.

13/24
Bagian 3

std string

14/24
Representasi string

• String pada C++ direpresentasikan dengan struktur array


dinamis.
• Ukurannya dapat berubah sesuai dengan ukuran string.
• Oleh sebab itu, Anda tidak perlu mendeklarasikan ukuran
terbesar yang mungkin.
• Anda dapat mengakses dan mengubah nilai karakter dari
suatu indeks string secara independen.

15/24
Mencari Panjang string

• Untuk mencari panjang dari string s, cukup panggil


s.length().
• Kompleksitas pemanggilannya adalah O(1).
// O(N)
for (int i = 0; i < s.length(); i++) {
printf("%c", s[i]);
}

16/24
Mencari Substring
• Untuk mencari posisi suatu substring t dari string s, gunakan
s.find(t).
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "Pak Dengklek berternak";
string t1 = "Dengklek";
string t2 = "pak";
string t3 = "klek";
printf("%d\n", s.find(t1)); // 4
printf("%d\n", s.find(t2)); // -1 (tak ditemukan)
printf("%d\n", s.find(t3)); // 8
}

17/24
Mengambil Substring

• Untuk mengambil substring dari indeks i sebanyak n karakter


dari string s, gunakan s.substr(i, n).
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "Pak Dengklek berternak";
printf("%s\n", s.substr(0, 6).c_str()); // Pak De
printf("%s\n", s.substr(2, 1).c_str()); // k
}

18/24
Menghapus Substring

• Untuk menghapus substring dari indeks i sebanyak n karakter


dari string s, gunakan s.erase(i, n).
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "Pak Dengklek berternak";
s.erase(1, 3);
printf("%s\n", s.c_str()); // PDengklek berternak
}

19/24
Menyisipkan String

• Untuk menyisipkan string t ke string s bermula di indeks i,


gunakan s.insert(i, t).
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "Pak Dengklek berternak";
string t = "dan Bu ";
s.insert(4, t);
printf("%s\n", s.c_str()); // Pak dan Bu Dengklek
berternak
}

20/24
Operasi Tambahan: Penempelan String

• Pada std string, hal ini dapat dilakukan cukup dengan operasi
’+’, layaknya operasi numerik.
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "Pak";
string t = "Dengklek";
string gabung = s + t;
printf("%s\n", gabung.c_str()); // PakDengklek
}

21/24
Operasi Char
• Setiap karakter dari string memiliki tipe char.
• Kita dapat melakukan operasi penambahan atau pengurangan
pada char, yang akan dioperasikan pada kode ASCII-nya.
Contoh:
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "abc";
s[0]++;
s[1] += 2;
s[2] -= 2;
printf("%s\n", s.c_str()); // bda
}

22/24
Operasi Char (lanj.)
• Operasi ini dapat digunakan untuk mengubah karakter suatu
string.
• Operasi yang umum adalah mengubah dari huruf kecil ke
besar, dengan cara mengurangkan char dengan selisih antara
ASCII ’a’ dengan ’A’.
• Cara sebaliknya akan mengubah dari huruf besar ke huruf
kecil.
• Hafalkan ASCII ’a’ adalah 97, dan ’A’ adalan 65.
#include <cstdio>
#include <string>
using namespace std;
int main() {
string s = "toki";
for (int i = 0; i < s.size(); i++) {
s[i] -= ’a’ - ’A’;
}
printf("%s\n", s.c_str()); // TOKI
}
23/24
Selanjutnya...

• Pembelajaran kalian tentang C++ sudah cukup untuk bisa


menuliskan algoritma-algoritma kompleks.
• Berikutnya kita akan mempelajari hal-hal yang lebih berkaitan
dengan algoritma, bukan sekedar belajar bahasa.

24/24
Pengenalan rekursi

Tim Olimpiade Komputer Indonesia

1/24
Pengenalan Rekursi

• Rekursi adalah keadaan yang mana sebuah fungsi


menyelesaikan sebuah permasalahan dengan cara memanggil
diri sendiri secara berulang kali.
• Jika masalah sudah cukup kecil, maka fungsi rekursi dapat
langsung menghasilkan jawaban.
• Jika masalah terlalu besar, maka fungsi akan memanggil diri
sendiri dengan cakupan masalah yang lebih kecil.

2/24
Mengapa Perlu Ada Rekursi

• Banyak permasalahan yang lebih mudah diselesaikan dan


pendek kodenya jika menggunakan pendekatan rekursif.
• Pada dasarnya, strategi iteratif (misalnya dengan for loop) dan
rekursif sama-sama melakukan sesuatu yang berulang-ulang.
• Namun, terkadang solusi iteratif untuk suatu masalah sangat
sulit untuk dipikirkan dan memerlukan teknik khusus.
• Dengan solusi rekursif, mungkin saja lebih mudah untuk
melihat dan merancang alur penyelesaiannya.

3/24
Strategi Rekursif

Terdapat dua hal yang perlu dipikirkan ketika menggunakan


strategi rekursif:
• Base case
Apa kasus paling sederhana dari permasalahan ini?
• Recurrence relation
Bagaimana hubungan rekursif dari persoalan ini dengan
persoalan serupa yang lebih kecil?

4/24
Contoh Soal: Faktorial

Deskripsi:
• Pak Dengklek baru mempelajari konsep matematika baru,
yaitu faktorial.
• Operasi faktorial pada N, atau ditulis dengan notasi N!,
adalah operasi mengalikan bilangan dari 1 sampai dengan N.
• Contoh: Jika N = 4, maka 4! = 1 × 2 × 3 × 4 = 24
• Diberikan N, bantu Pak Dengklek mencari hasil N!

5/24
Contoh Soal: Faktorial (lanj.)

Format masukan:
• Sebuah baris berisi sebuah bilangan N
Format keluaran:
• Sebuah baris berisi hasil N!
Batasan:
• 1 ≤ N ≤ 10

6/24
Solusi

• Ide 1:
• Cukup gunakan for loop biasa
• Solusi ini bekerja secara iteratif.
• Ide 2: Rekursi

7/24
Contoh Solusi Iteratif

Implementasi solusi secara iteratif cukup sederhana:


int faktorial(int x) {
int jawaban = 1;
for (int i = 2; i <= x; i++) {
jawaban *= i;
}
return jawaban;
}

8/24
Solusi Rekursif

Base Case
• Pada batasan soal, nilai N berkisar antara 1 sampai dengan
10.
• Dari batasan tersebut, kasus terkecilnya adalah N = 1.
• Jadi N = 1 adalah base case, dan memang jelas diketahui
bahwa 1! = 1.

9/24
Solusi Rekursif (lanj.)

Recurrence Relation
• Bagaimana jika N > 1?
• Untuk mencari N!, kita bisa mencari (N − 1)! dan
mengalikannya dengan N.
• Jadi persoalan mencari N! bisa diselesaikan dengan mudah
jika diketahui (N − 1)!.
• Dengan observasi ini, kita mengetahui hubungan rekursif dari
N!.

10/24
Contoh Solusi: faktorial rekursif.cpp

Berikut implementasi pencarian faktorial secara rekursif:


int faktorial(int x) {
if (x == 1) {
return 1;
} else {
return x * faktorial(x-1);
}
}

11/24
Contoh Solusi: faktorial rekursif.cpp (lanj.)

Pemanggilan pada program utama bisa dilakukan seperti


memanggil fungsi biasa:
...
int main() {
printf("4! = %d\n", faktorial(4));
}

12/24
Contoh Eksekusi Fungsi

• Pada awalnya, program utama


dijalankan. Misalkan hendak
dicari nilai 4!.

program utama

13/24
Contoh Eksekusi Fungsi (lanj.)

• Dari program utama, dipanggil


fungsi faktorial(4).
• Pada saat ini, status program
utama adalah ”tidak aktif”, dan
faktorial(4) akan ”aktif” kembali setelah
fungsi faktorial(4) selesai.
program utama

14/24
Contoh Eksekusi Fungsi (lanj.)

• faktorial(4) mengeksekusi
”return x *
faktorial(x-1)”, yang pada
kasus ini x = 4.
faktorial(3)
• Akibatnya, dipanggil fungsi
faktorial(4) faktorial(3).
program utama • Kini yang ”aktif” adalah
faktorial(3).

15/24
Contoh Eksekusi Fungsi (lanj.)

faktorial(2)
faktorial(3) • Hal serupa terjadi untuk mencari
nilai faktorial(3).
faktorial(4)
program utama

16/24
Contoh Eksekusi Fungsi (lanj.)

faktorial(1)
faktorial(2)
faktorial(3) • Terjadi juga untuk mencari nilai
faktorial(2).
faktorial(4)
program utama

17/24
Contoh Eksekusi Fungsi (lanj.)

faktorial(1)
• Pada saat ini, faktorial(1) tidak
faktorial(2) lagi melakukan pemanggilan
rekursif, berhubung ditemui base
faktorial(3) case.
• Sebaliknya, langsung
faktorial(4)
dikembalikan nilai 1 sebagai
program utama jawaban atas faktorial(1).

18/24
Contoh Eksekusi Fungsi (lanj.)

• faktorial(1) selesai, kini kembali


faktorial(2) ke faktorial(2).
• Nilai faktorial(2) kini ditemukan,
faktorial(3) yaitu 2 × faktorial(1).
faktorial(4) • Fungsi faktorial(2)
mengembalikan nilai 2 ke
program utama pemanggilnya, lalu selesai.

19/24
Contoh Eksekusi Fungsi (lanj.)

• Setelah menerima nilai kembalian


faktorial(2), faktorial(3)
kembali aktif.
faktorial(3) • Hasilnya dapat ditemukan, yaitu
3 × faktorial(2).
faktorial(4) • Fungsi faktorial(3)
program utama mengembalikan nilai 6 ke
pemanggilnya, lalu selesai.

20/24
Contoh Eksekusi Fungsi (lanj.)

• Kini faktorial(4) kembali aktif.


• Hasilnya dapat ditemukan, yaitu
4 × faktorial(3).
• Fungsi faktorial(4)
faktorial(4) mengembalikan nilai 24 ke
program utama pemanggilnya, lalu selesai.

21/24
Contoh Eksekusi Fungsi (lanj.)

• Program utama yang memanggil


faktorial(4) menerima nilai
kembaliannya, yaitu 24.
• Program utama kembali
menjalankan perintah-perintah
program utama berikutnya.

22/24
Kompleksitas Solusi

• Baik secara iteratif maupun rekursif, kompleksitasnya adalah


O(N).
• Setiap pemanggilan rekursif membutuhkan alokasi memori,
sehingga jika pemanggilannya semakin dalam, semakin banyak
tambahan memori yang digunakan.
• Waktu untuk mengalokasikan memori juga menyebabkan
solusi rekursif cenderung bekerja lebih lambat dibandingkan
solusi iteratif.

23/24
Materi Selanjutnya

• Pada pembelajaran ini, rekursi yang digunakan masih sangat


sederhana.
• Bahkan belum terasa bahwa solusi rekursi lebih mudah dan
pendek kodenya dibandingkan solusi iteratif.
• Pembelajaran selanjutnya tentang rekursi yang lebih kompleks
akan menunjukkan hal tersebut.

24/24
Rekursi Lanjut

Tim Olimpiade Komputer Indonesia

1/36
Bagian 1

Fibonacci

2/36
Soal: Fibonacci
Deskripsi:
• Deret Fibonacci merupakan deret yang mana suatu anggota
adalah penjumlahan dari dua anggota sebelumnya, kecuali dua
anggota pertama.
• Jika fN adalah bilangan Fibonacci ke-N, maka f0 = 0, f1 = 1,
dan fN = fN−1 + fN−2 untuk N > 1.
• Beberapa bilangan pertama dari deret Fibonacci adalah 0, 1,
1, 2, 3, 5, 8, 13, 21, . . . .
• Carilah bilangan Fibonacci ke-N.
• Contoh: Bilangan Fibonacci ke-6 adalah 8. Perhatikan bahwa
indeks dimulai dari 0.

3/36
Soal: Fibonacci (lanj.)

Format masukan:
• Sebuah baris berisi sebuah bilangan N.
Format keluaran:
• Sebuah baris berisi bilangan Fibonacci ke-N.
Batasan:
• 0 ≤ N ≤ 20

4/36
Solusi

• Bagaimana cara mendapatkan nilai dari dua bilangan


Fibonacci sebelum bilangan Fibonacci ke-N?
• Apakah kita bisa melakukan rekursi untuk mencari bilangan
Fibonacci ke-(N − 1) dan ke-(N − 2)?

5/36
Penjelasan Solusi Rekursif

Base Case
• Pada batasan soal, nilai N berkisar antara 0 sampai 20.
• Dari batasan tersebut, kasus terkecil yang sudah pasti
diketahui jawabannya adalah f0 dan f1 .
• Nilai dari f0 = 0 dan f1 = 1, atau dapat dituliskan fN = N,
untuk 0 ≤ N ≤ 1.
• Sehingga, N = 0 dan N = 1 adalah base case.

6/36
Penjelasan Solusi Rekursif (lanj.)
Recurrence Relation
• Bagaimana jika N > 1?
• Seperti yang sudah didefinisikan, fN = fN−1 + fN−2 untuk
N>1
• Contoh: f5 = f4 + f3 .
• Mencari f4 dan f3 sendiri juga memunculkan permasalahan
yang lebih kecil, yaitu:
• f4 = f3 + f2
• f3 = f2 + f1
• Hal ini akan terus diulang sampai tercapai base case, yaitu f0
atau f1 .
• Dengan ini, kita menemukan hubungan rekursif dari fN .

7/36
Contoh Solusi: fibonacci rekursi.cpp

Perhatikan contoh berikut:


int fibonacci(int N) {
if (N <= 1) {
return N;
} else {
return fibonacci(N-1) + fibonacci(N-2);
}
}

8/36
Penjelasan Solusi Rekursif
Alur eksekusi rekursi dapat dimodelkan dengan pohon rekursi.
Berikut adalah contoh pohonnya untuk f4 .
f4

f3 f2

f2 f1 f1 f0

f1 f0

9/36
Penjelasan Solusi Rekursif (lanj.)

Yang terjadi pada program ketika menghitung f4 :


• Panggil fibonacci(4).
• fibonacci(4) akan memeriksa, apakah N = 4 adalah base case.
• Ternyata bukan, karena baru base case jika N ≤ 1.
• Dijalankanlah ”return fibonacci(3) + fibonacci(2)”.
• Alur rekursi berjalan berurutan, sehingga fibonacci(3)
dieksekusi lebih dulu.

10/36
Penjelasan Solusi Rekursif (lanj.)

• fibonacci(3) akan menjalankan ”return fibonacci(2) +


fibonacci(1)”.
• fibonacci(2) akan menjalankan ”return fibonacci(1) +
fibonacci(0)”.
• Ternyata ketika fibonacci(1), 1 termasuk base case sehingga
fibonacci(1) = 1.
• Ternyata ketika fibonacci(0), 0 termasuk base case sehingga
fibonacci(0) = 0.
• Kembali ke fibonacci(2), nilai dari fibonacci(2) menjadi 1 + 0
= 1.

11/36
Penjelasan Solusi Rekursif (lanj.)

• Kembali ke fibonacci(3), nilai fibonacci(2) sudah ada nilainya


tetapi fibonacci(1) belum sehingga akan dipanggil dan
langsung menghasilkan 1 (karena sudah base case). Nilai dari
fibonacci(3) menjadi 1 + 1 = 2.
• Kembali ke fibonacci(4), nilai fibonacci(3) sudah ada nilainya
tetapi fibonacci(2) belum sehingga akan dipanggil dan akan
menghasilkan 1 (alur yang terjadi sama seperti sebelumnya).
Nilai dari fibonacci(4) menjadi 2 + 1 = 3.
Tantangan: Cobalah membuat pohon rekursi dan alurnya untuk
menghitung f5 !

12/36
Kompleksitas Solusi

• Perhatikan pohon rekursi yang sebelumnya. Berapa kali fungsi


akan dipanggil?
• Setiap pemanggilan fungsi akan bercabang 2 dan kedalaman
maksimalnya adalah N.
• Sebagai pendekatan, bisa dikatakan fungsi dipanggil 2N kali.
• Kompleksitasnya menjadi O(2N ).

13/36
Masalah

• Perhatikan kembali pohon rekursi yang sebelumnya. Terlihat


f2 dihitung dua kali.
• Ketika fN cukup besar, ada banyak fungsi dengan parameter
yang sama namun dihitung berkali-kali. Hal ini berakibat
program berjalan lambat.
• Kita dapat mereduksi kompleksitas rekursi Fibonacci menjadi
O(N) dengan teknik yang akan kita pelajari pada
pemrograman lanjut.
• Kita juga bisa membuat solusi O(N) dengan menghitung nilai
Fibonacci secara iteratif. Dapatkah Anda membuatnya?

14/36
Bagian 2

Permutasi

15/36
Soal: Permutasi

Deskripsi:
• Pak Dengklek lupa password akun TLX-nya!
• Yang ia ingat hanyalah passwordnya terdiri dari N angka, dan
mengandung masing-masing angka dari 1 sampai N.
• Misalnya N = 3, bisa jadi password Pak Dengklek adalah 123,
132, 312, dst
• Bantu Pak Dengklek menuliskan semua kemungkinan
passwordnya!

16/36
Soal: Permutasi (lanj.)

Format masukan:
• Sebuah baris berisi sebuah bilangan N.
Format keluaran:
• Beberapa baris yang merupakan semua kemungkinan
password, satu pada setiap barisnya.
• Urutkan keluaran secara leksikografis (seperti pada kamus).
Batasan:
• 1≤N≤8

17/36
Soal: Permutasi (lanj.)

Contoh masukan:
3

Contoh keluaran:
123
132
213
231
312
321

18/36
Solusi

• Sebelum merancang solusi untuk persoalan sebenarnya, mari


kita sederhanakan persoalan.
• Misalkan digit-digit boleh berulang, sehingga untuk N = 3,
keluarannya adalah:
111
112
113
121
122
123
131
...
333

19/36
Solusi (lanj.)

• Jika N selalu 3, terdapat solusi iteratif yang sederhana:


for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
for (int k = 1; k <= 3; k++) {
printf("%d%d%d\n",i, j, k);
}
}
}

20/36
Solusi (lanj.)

• Namun bagaimana jika N = 2? Atau N = 4?


• Kedalaman for loop tidak bisa diatur untuk memenuhi
kebutuhan N yang beragam!
• Untuk itu, solusi rekursif lebih mudah digunakan untuk
persoalan yang disederhanakan ini.

21/36
Ide Rekursif
• Setiap kedalaman loop bisa diwujudkan oleh sebuah
pemanggilan rekursif.

for 1..N
for 1..N
for 1..N
...
end
end
end

• Dengan menambahkan parameter ”kedalaman” pada


pemanggilan rekursif, kedalaman dari loop dapat diatur.

22/36
Ide Rekursif (lanj.)

void tulis(int kedalaman) {


if (kedalaman >= N) {
// Cetak password
...
} else {
// Masuk ke lapisan lebih dalam
for (int i = 1; i <= N; i++) {
tulis(kedalaman + 1);
}
}
}

23/36
Ide Rekursif (lanj.)

• Prosedur tulis dapat dipanggil dengan perintah:


N = 3;
tulis(0);
• Nilai kedalaman akan terus bertambah selama kedalaman
saat ini belum mencapai N.
• Hal ini menjadi memicu pemanggilan rekursif lebih dalam.
• Setelah kedalaman melebihi N, artinya tidak perlu lagi
menambah ”lapisan loop”, sehingga dicapai base case dan
dicetak password.

24/36
Ide Rekursif (lanj.)

• Masalah berikutnya adalah bagaimana mencatat password


yang sejauh ini telah dibentuk.
• Salah satu solusinya adalah membuat array global yang
mencatat digit password dari 1 sampai kedalaman.
• Ketika base case tercapai, kita bisa mencetak isi array
tersebut.
• Kita namakan array tersebut catat.

25/36
Ide Rekursif (lanj.)

void tulis(int kedalaman) {


if (kedalaman >= N) {
// Cetak password
for (int i = 0; i < N; i++) {
printf("%d", catat[i]); // Cetak
}
printf("\n");
} else {
// Masuk ke lapisan lebih dalam
for (int i = 1; i <= N; i++) {
catat[kedalaman] = i; // Catat di sini
tulis(kedalaman + 1);
}
}
}

26/36
Solusi untuk Permutasi

• Kita berhasil menyelesaikan masalah yang disederhanakan,


saatnya menarik solusi tersebut ke masalah sebenarnya.
• Perbedaan dari masalah yang baru kita selesaikan dengan
yang sebenarnya adalah: tidak boleh ada digit yang berulang.
• Sebagai contoh, 122, 212, 311 bukan password yang benar,
sementara 123, 213, dan 321 merupakan password yang benar.
• Artinya, jika kita bisa menghindari mencetak password dengan
digit berulang, masalah selesai.

27/36
Menghindari Digit Berulang

Solusi yang mungkin:


• Sebelum mencetak, periksa apakah ada digit yang berulang.
• Sebelum melakukan pemanggilan rekursif yang lebih dalam,
periksa apakah ada digit berulang yang tercatat.

28/36
Menghindari Digit Berulang (lanj.)

• Solusi pertama kurang cocok digunakan.


• Misalkan untuk N = 8, dan kedalaman saat ini adalah 2.
• Diketahui bahwa array catat sejauh ini berisi [1, 1, ...].
• Tidak ada gunanya untuk meneruskan pemanggilan rekursif
lebih dalam, sebab kemungkinan ini sudah pasti tidak dicetak
(ada digit ’1’ berulang).

29/36
Menghindari Digit Berulang (lanj.)

• Mengindari perulangan digit sebelum pemanggilan rekursif


lebih efisien untuk digunakan.
• Oleh karena itu kita akan menggunakan cara kedua.
• Hal ini dapat dilakukan dengan menandai digit-digit yang
sudah pernah digunakan, dan jangan mencatat digit-digit
tersebut.

30/36
Menghindari Digit Berulang (lanj.)

• Kita akan menggunakan array global bertipe boolean, yaitu


pernah.
• Awalnya, seluruh isi array pernah adalah false.
• pernah[i] bernilai true jika digit i berada di dalam array
catat.
• Setiap sebelum masuk ke kedalaman rekursif berikutnya,
periksa apakah digit yang akan digunakan sudah pernah
digunakan.
• Jika belum pernah, baru boleh digunakan.

31/36
Implementasi
void tulis(int kedalaman) {
if (kedalaman >= N) {
// Cetak password
for (int i = 0; i < N; i++) {
printf("%d", catat[i]); // Cetak
}
printf("\n");
} else {
// Masuk ke lapisan lebih dalam
for (int i = 1; i <= N; i++) {
if (!pernah[i]) { // i belum pernah?
pernah[i] = true; // Gunakan
catat[kedalaman] = i; // Catat di sini
tulis(kedalaman + 1);
pernah[i] = false; // Selesai menggunakan
}
}
}
}

32/36
Menghindari Digit Berulang (lanj.)

• Setelah perintah ”tulis(kedalaman + 1)”, nilai pernah[i] perlu


dikembalikan menjadi false.
• Sebab setelah keluar dari pemanggilan rekursif tersebut, digit i
dianggap tidak lagi ada pada catat.
• Namun digit i bisa saja digunakan untuk beberapa
pemanggilan rekursif ke depannya.
• Dengan cara ini, kita memastikan tidak ada digit berulang
yang dicetak.

33/36
Kompleksitas
• Jika N = 3, maka berikut pohon rekursif yang
menggambarkan pemilihan i untuk setiap pemanggilan:

tulis(1)

i=1 i=2 i=3

tulis(2) tulis(2) tulis(2)

i=2 i=3 i=1 i=3 i=1 i=2

tulis(3) tulis(3) tulis(3) tulis(3) tulis(3) tulis(3)

i=3 i=2 i=3 i=1 i=2 i=1

tulis(4) tulis(4) tulis(4) tulis(4) tulis(4) tulis(4)

34/36
Kompleksitas

• Dapat diperhatikan bahwa pada kedalaman pertama, terdapat


N cabang rekursif.
• Pada kedalaman kedua, terdapat N − 1 cabang rekursif.
• Seterusnya hingga kedalaman terakhir yang tidak lagi
bercabang.
• Kompleksitasnya adalah N × (N − 1) × (N − 2) × ... × 1, atau
dengan kata lain O(N!).

35/36
Penutup

• Rekursi merupakan topik yang luas untuk dibicarakan.


• Jika Anda belum terbiasa dengan berpikir rekursif, maka
latihan yang banyak adalah solusinya.
• Selamat berlatih dengan soal-soal yang ada!

36/36

Anda mungkin juga menyukai