Gulir untuk membalik halaman
Computer Science A · AP Computer Science A
if, while, dan for
Program menjalankan pernyataannya satu demi satu, berurutan. Dua hal mengubah urutan itu: seleksi memilih pernyataan mana yang dijalankan, dan iterasi menjalankan pernyataan lagi.
Program pada gambar dimulai dengan n = 5. Selama n bukan 1, program membagi dua n jika genap, atau mengalikannya tiga lalu menambah 1 jika ganjil, dan menghitung satu langkah. Belah ketupat di atas adalah pertanyaan perulangan; belah ketupat di bawahnya milik if. Token merah adalah titik eksekusi, dan kode di sampingnya menyalakan baris yang sedang berjalan.
int n = 5; int steps = 0; while (n != 1) { if (n % 2 == 0) { n = n / 2; } else { n = 3 * n + 1; } steps++; } System.out.println(steps); n berubah 5, 16, 8, 4, 2, 1. Kondisi perulangan diperiksa 6 kali: true 5 kali, lalu false sekali, dan program mencetak 5.
Bab ini adalah AP Computer Science A Unit 2, 25–35% dari nilai pilihan ganda: ekspresi Boolean dan pernyataan if (2.1–2.6), perulangan while dan for (2.7–2.8), algoritma standar yang dibangun darinya (2.9–2.10), perulangan di dalam perulangan (2.11), dan menghitung seberapa sering sebuah pernyataan berjalan (2.12).
tiga blok pembangun
Setiap algoritma dibangun dari tiga hal: sekuensial (langkah berurutan), seleksi (keputusan), dan pengulangan (perulangan).
Seleksi terjadi ketika kelanjutan sebuah algoritma bergantung pada keputusan benar atau salah. Pengulangan adalah proses yang berulang sampai hasil yang diinginkan tercapai. Keduanya muncul dalam petunjuk sehari-hari: “jika hujan, bawa payung” adalah seleksi; “aduk sampai gula larut” adalah pengulangan.
Algoritma dapat ditulis dengan kata-kata atau digambar sebagai diagram alir: kotak untuk setiap langkah, belah ketupat untuk setiap keputusan benar-atau-salah, dan panah yang kembali ke atas untuk pengulangan. Gambar sekarang menuliskan algoritma yang sama dengan kata-kata: “apakah n genap?”, “bagi dua”, “hitung satu langkah”. Kode mengatakan hal yang persis sama dalam Java.
Urutan langkah mengubah hasilnya. Kedua segmen ini memuat pernyataan yang sama:
int x = 3; x = x * 2; x = x + 1;
int x = 3; x = x + 1; x = x * 2;
Yang pertama menyisakan x pada 7; yang kedua, pada 8. Pada gambar, menghitung satu langkah setelah perulangan, bukan di dalamnya, akan mencetak 1, seberapa lama pun perulangan berjalan.
operator relasional
Ekspresi Boolean bernilai salah satu dari dua nilai, true atau false. Yang paling sederhana membandingkan dua nilai dengan operator relasional.
== dan != menguji apakah dua nilai sama atau berbeda. <, >, <=, dan >= membandingkan bilangan. Dengan tipe primitif seperti int, double, dan boolean, == membandingkan nilai sebenarnya. Dengan tipe referensi, operator ini membandingkan referensinya: apakah dua variabel merujuk ke objek yang sama (2.6).
Pada gambar a menyimpan 7 dan b mengambil nilai 4, 7, 9. Setiap perbandingan menghasilkan sebuah blok, merah untuk true:
| b = 4 | b = 7 | b = 9 | |
|---|---|---|---|
a == b | false | true | false |
a != b | true | false | true |
a < b | false | false | true |
a > b | true | false | false |
a <= b | false | true | true |
a >= b | true | true | false |
= menugaskan; == membandingkan. Hasil Boolean dapat disimpan seperti nilai lainnya: boolean same = a == b;
seleksi satu arah dan dua arah
Pernyataan seleksi mengubah eksekusi pernyataan yang berurutan. Pernyataan if menjalankan segmen kode yang berbeda bergantung pada nilai ekspresi Boolean.
Seleksi satu arah (sebuah if) memiliki satu segmen, yang dijalankan hanya ketika kondisinya true:
if (temp >= 30) { System.out.println("hot"); } System.out.println("done"); Dengan temp bernilai 34 program mencetak hot then done; pada 22, hanya done. Baris terakhir berada setelah if, sehingga selalu dijalankan.
Seleksi dua arah (if-else) memiliki dua segmen: badan if ketika kondisinya true, badan else ketika false. Tepat satu di antaranya dijalankan.
if (temp >= 30) { System.out.println("hot"); } else { System.out.println("mild"); } System.out.println("done"); Gambar mengirim dua suhu melewatinya. Pada 34 token mengambil jalur true dan mencetak hot; pada 22 jalur false, mild. Keduanya kemudian mencetak done.
if, else if, else
Seleksi berganda (if-else-if) menguji serangkaian kondisi secara berurutan. Kondisi pertama yang true menjalankan segmennya, dan tidak lebih dari satu segmen yang dijalankan.
if (score >= 90) { grade = "A"; } else if (score >= 80) { grade = "B"; } else if (score >= 70) { grade = "C"; } else { grade = "F"; } Gambar menjatuhkan tiga nilai ke sepanjang rantai ini. 83 gagal pada score >= 90, lolos pada score >= 80, dan tertangkap: grade "B". Kondisi di bawahnya tidak pernah diperiksa. 95 tertangkap oleh gerbang pertama, "A". 64 gagal di ketiganya, sehingga else penutup dijalankan: "F". Tanpa else penutup, nilai yang gagal di setiap kondisi tidak menjalankan segmen apa pun.
Karena kondisi true pertama yang menang, urutan berpengaruh. Uji score >= 70 lebih dulu dan 95 mendapat "C": setiap nilai 70 atau lebih berhenti di gerbang pertama. Taruh uji yang paling ketat lebih dulu.
if di dalam if
Pernyataan if bersarang adalah pernyataan if, if-else, atau if-else-if di dalam pernyataan if, if-else, atau if-else-if lainnya.
if (age >= 16) { if (hasPermit) { System.out.println("may drive"); } else { System.out.println("needs a permit"); } } System.out.println("done"); Kondisi dalam dievaluasi hanya jika kondisi luar true. Gambar menjalankan tiga orang. Usia 17 dengan izin lolos keduanya dan mencetak may drive. Usia 17 tanpa izin lolos uji luar dan gagal pada uji dalam: needs a permit. Usia 14 gagal pada uji luar, sehingga token berputar mengelilingi seluruh kotak: hasPermit bahkan tidak pernah dilihat, dan hanya done yang dicetak.
Kurung kurawal menentukan if mana yang memiliki else tersebut. Di sini else berada di dalam kurung kurawal luar, sehingga berpasangan dengan if (hasPermit): seseorang di bawah 16 sama sekali tidak mendapat pesan tentang izin.
!, &&, dan ||
Operator logika ! (not), && (and), dan || (or) menggabungkan ekspresi Boolean menjadi satu ekspresi yang juga bernilai true atau false.
!a bernilai true ketika a false, dan false jika tidak. a && b bernilai true hanya ketika keduanya true. a || b bernilai true ketika a true, b true, atau keduanya. Gambar mengerjakan setiap kombinasi, satu baris pada satu waktu:
| a | b | a && b | a || b | !a |
|---|---|---|---|---|
| true | true | true | true | false |
| true | false | false | true | false |
| false | true | false | true | true |
| false | false | false | false | true |
Urutan prioritasnya adalah ! lebih dulu, lalu &&, kemudian ||. Jadi dengan a = false, b = true, c = false, ekspresi !a || b && c berarti (!a) || (b && c): true. Mengelompokkannya sebagai (!a || b) && c justru menghasilkan false. Tanda kurung membuat urutannya jelas.
Operator relasional didahulukan daripada operator logika, sehingga x > 0 && x < 10 membandingkan lebih dulu dan menggabungkan sesudahnya: bernilai true untuk setiap x yang berada tepat di antara 0 dan 10.
sisi kanan mungkin tidak pernah dijalankan
Ketika operan kiri dari && atau || sudah menentukan hasilnya, Java tidak mengevaluasi operan kanan. Inilah evaluasi hubung singkat.
false && anything bernilai false, dan true || anything bernilai true, apa pun yang dikatakan sisi kanan. Jadi sisi kanan dilewati. Gambar mengevaluasi dua ekspresi, pertama dengan x = 4, lalu dengan x = 0:
x != 0 && 10 / x > 2 x == 0 || 10 / x > 2
Dengan x = 4 kedua sisi dari keduanya dijalankan. 10 / 4 adalah 2 (pembagian bilangan bulat), tidak lebih dari 2, sehingga yang pertama false dan yang kedua juga.
Dengan x = 0, x != 0 bernilai false, sehingga yang pertama langsung false; dan x == 0 bernilai true, sehingga yang kedua langsung true. Pada keduanya 10 / x tidak dijalankan, dan itu justru baik: membagi sebuah int dengan nol melempar ArithmeticException.
Itu menjadikan operan kiri sebagai penjaga. Jika ditulis dengan urutan terbalik, 10 / x > 2 && x != 0 membagi lebih dulu dan macet ketika x bernilai 0.
tabel kebenaran dan hukum De Morgan
Dua ekspresi Boolean ekuivalen jika keduanya bernilai sama dalam semua kasus. Tabel kebenaran, dengan satu baris untuk setiap kombinasi masukan, dapat membuktikannya.
Hukum De Morgan memberikan dua ekuivalensi:
!(a && b) ekuivalen dengan !a || !b !(a || b) ekuivalen dengan !a && !b
Untuk memasukkan ! ke dalam tanda kurung, negasikan setiap bagian dan tukar && dengan ||, atau || dengan &&. Pada gambar setiap kolom ekspresi kedua bergeser ke ekspresi pertama: warnanya cocok di setiap baris.
| a | b | !(a && b) | !a || !b | !(a || b) | !a && !b |
|---|---|---|---|---|---|
| true | true | false | false | false | false |
| true | false | true | true | false | false |
| false | true | true | true | false | false |
| false | false | true | true | true | true |
Lupa menukar operatornya merusak ekuivalensi: !(a && b) dan !a && !b berbeda pada 2 dari 4 baris. Perbandingan yang dinegasikan membalik operatornya: !(x > 5) adalah x <= 5. Jadi !(x >= 1 && x <= 10) ekuivalen dengan x < 1 || x > 10.
== melawan equals
Dua variabel berbeda dapat menyimpan referensi ke objek yang sama. == dan != pada referensi menanyakan apakah keduanya merujuk ke objek yang sama, bukan apakah dua objek memiliki isi yang sama.
String s1 = new String("atlas"); String s2 = s1; String s3 = new String("atlas"); String s4 = null; s2 = s1 menyalin referensi, sehingga s1 dan s2 menunjuk satu objek: s1 == s2 bernilai true. s3 merujuk ke objek kedua dengan huruf yang sama: s1 == s3 bernilai false.
Kelas sering mendefinisikan metode equals yang menyatakan kapan dua objek dianggap sama, biasanya dengan membandingkan atributnya. Milik Tali membandingkan karakternya, sehingga s1.equals(s3) bernilai true. Bandingkan string dengan equals, jangan pernah ==.
Referensi dapat dibandingkan dengan null memakai == atau !=, untuk mengetahui apakah referensi itu merujuk ke suatu objek sama sekali: s4 == null bernilai true. (Meng-override metode equals berada di luar cakupan kursus.)
periksa, jalankan, periksa lagi
Iterasi adalah bentuk pengulangan: pernyataan iterasi mengulang segmen kode nol kali atau lebih, selama ekspresi Boolean-nya true.
Pada perulangan while, ekspresi Boolean dievaluasi sebelum setiap putaran melewati badan, termasuk yang pertama. Selama true, badan dijalankan; ketika false, perulangan berakhir dan program melanjutkan setelahnya.
int sum = 0; int k = 1; while (k <= 4) { sum += k; k++; } System.out.println(sum); Tabel jejak mencatat variabel setiap kali kondisi diperiksa. Gambar mengisinya baris demi baris:
| k | sum | k <= 4 |
|---|---|---|
| 1 | 0 | true |
| 2 | 1 | true |
| 3 | 3 | true |
| 4 | 6 | true |
| 5 | 10 | false |
Kondisi diperiksa 5 kali dan badan dijalankan 4 kali: pemeriksaan terakhir adalah yang false. Perulangan berakhir dengan k = 5, dan 10 dicetak.
tidak pernah, selamanya, kurang satu
Sebagian besar bug perulangan adalah satu dari tiga: perulangan tidak pernah berjalan, tidak pernah berhenti, atau berjalan satu kali terlalu banyak atau terlalu sedikit.
Jika ekspresi Boolean false pada pemeriksaan pertama, badan tidak pernah dieksekusi. while (k < 5) dengan k bernilai 10 memeriksa sekali lalu lanjut (baris teratas).
Perulangan tak hingga terjadi ketika ekspresi Boolean selalu bernilai true. Pada baris tengah k berubah 1, 3, 5, 7, 9, … dan tidak pernah 6, sehingga while (k != 6) tidak pernah menjadi false. Perulangan yang badannya tidak pernah mengubah variabel dalam kondisinya melakukan hal yang sama.
Kesalahan selisih satu (off-by-one) adalah perulangan yang berjalan satu kali terlalu banyak atau satu kali terlalu sedikit. Dimaksudkan untuk mencetak 1 sampai 5, perulangan paling bawah mencetak 1234: while (k < 5) berhenti sebelum 5. k <= 5 memperbaikinya.
int k = 1; while (k < 5) { System.out.print(k); k++; } Periksa perulangan di tepinya: putaran pertama, putaran terakhir, dan pemeriksaan yang mengakhirinya.
inisialisasi, ekspresi Boolean, pembaruan
Perulangan for menaruh tiga bagian perulangan penghitung di header-nya: inisialisasi, ekspresi Boolean, dan pembaruan.
for (int i = 0; i < 3; i++) { System.out.println(i); } Inisialisasi berjalan sekali, sebelum pemeriksaan pertama. Variabel yang diatur olehnya adalah variabel kendali perulangan. Ekspresi Boolean dievaluasi tepat setelah inisialisasi, lalu lagi setelah setiap pembaruan, sampai false. Pada setiap putaran, pembaruan berjalan setelah seluruh badan dan sebelum pemeriksaan berikutnya.
Token pada gambar bergerak inisialisasi → pemeriksaan → badan → pembaruan → pemeriksaan …. Hitungan di bawah setiap stasiun: inisialisasi 1, pemeriksaan 4, badan 3, pembaruan 3. Perulangan mencetak 0, 1, 2, masing-masing di barisnya sendiri.
Perulangan for dapat ditulis ulang sebagai perulangan while yang ekuivalen, dan sebaliknya:
int i = 0; while (i < 3) { System.out.println(i); i++; } Satu perbedaan: i yang dideklarasikan di header for hanya ada di dalam perulangan; jika dideklarasikan sebelum perulangan while, variabel itu masih ada sesudahnya.
% 10, / 10, dan % k
Dua algoritma standar memakai operator sisa bagi: memecah bilangan bulat digit demi digit, dan menguji apakah satu bilangan bulat habis dibagi oleh bilangan bulat lain.
Untuk int n positif, n % 10 adalah digit terakhirnya dan n / 10 (pembagian bilangan bulat) adalah n dengan digit itu dihapus. Ulangi sampai n bernilai 0:
| n | n % 10 | n / 10 |
|---|---|---|
| 3725 | 5 | 372 |
| 372 | 2 | 37 |
| 37 | 7 | 3 |
| 3 | 3 | 0 |
int n = 3725; int sum = 0; int max = 0; int odd = 0; while (n > 0) { int d = n % 10; sum += d; if (d > max) { max = d; } if (d % 2 == 1) { odd++; } n /= 10; } Gambar mengupas digit-digit 3725 dari kanan, 5, 2, 7, 3, dan masing-masing melewati d.
a % b == 0 bernilai true tepat ketika a habis dibagi b. 3725 % 5 adalah 0, sehingga 3725 habis dibagi 5; 3725 % 3 adalah 2, sehingga tidak habis dibagi 3. Uji yang sama dengan 2 memisahkan genap dari ganjil, seperti yang dilakukan d % 2 == 1 dalam perulangan.
terakumulasi saat perulangan berjalan
Tiga algoritma standar lagi menyimpan nilai yang berjalan dalam variabel yang dideklarasikan sebelum perulangan dan diperbarui di dalamnya: jumlah, nilai minimum atau maksimum, dan hitungan.
Sebuah jumlah dimulai dari 0 dan menambahkan setiap nilai: sum += d. Untuk 3725, sum berakhir pada 17.
Rata-rata adalah jumlah dibagi banyaknya nilai. Waspadai pembagian bilangan bulat:
double avg = (double) sum / 4; int avgInt = sum / 4;
avg bernilai 4.25; avgInt bernilai 4, pecahannya dibuang. Lakukan casting sebelum membagi, bukan sesudahnya.
Sebuah maksimum menyimpan nilai terbesar sejauh ini dan menggantinya setiap kali muncul nilai yang lebih besar: if (d > max). Di sini max berakhir pada 7. Mulailah dari nilai pertama, atau dari nilai yang tidak mungkin lebih kecil dari nilai sebenarnya mana pun: 0 berfungsi hanya karena angka digit tidak pernah negatif; secara umum gunakan Integer.MIN_VALUE. Sebuah minimum adalah bayangan cerminnya, dimulai dari Integer.MAX_VALUE dan menguji <; digit terkecil adalah 2.
Sebuah hitungan seberapa sering suatu kriteria terpenuhi dimulai dari 0 dan menambahkan 1 di dalam if: if (d % 2 == 1) menghitung digit ganjil, yaitu 3 digit.
membalik, dan menghitung substring
Algoritma String menelusuri indeks sepanjang sebuah string dan mengambil substring pada setiap posisi: untuk membangun string baru, atau untuk menguji atau menghitung substring yang memiliki suatu sifat.
Untuk membalik sebuah string, letakkan setiap karakter di depan apa yang sudah dibangun sejauh ini. substring(i, i + 1) adalah karakter tunggal pada indeks i:
String word = "drawer"; String rev = ""; for (int i = 0; i < word.length(); i++) { rev = word.substring(i, i + 1) + rev; } rev bertambah "d", "rd", "ard", "ward", "eward", "reward". (rev = rev + word.substring(i, i + 1) akan menyalin kata itu tanpa perubahan.)
Untuk menghitung substring yang memenuhi suatu kriteria, geser sebuah jendela sepanjang string dan uji tiap jendela:
String s = "banana"; int count = 0; for (int i = 0; i < s.length() - 1; i++) { if (s.substring(i, i + 2).equals("an")) { count++; } } Jendela substring(i, i + 2) melihat "ba", "an", "na", "an", "na": 2 cocok, sehingga count adalah 2. Jendela terakhir dimulai pada indeks 4, jadi i harus berhenti di bawah s.length() - 1; satu langkah lebih jauh, substring(5, 7) melewati ujung string dan melempar StringIndexOutOfBoundsException.
Bandingkan substring dengan equals. Untuk mencari apakah ada substring yang memiliki sifat itu, perulangan yang sama dapat berhenti pada substring pertama yang ditemukan, atau indexOf mengembalikan posisi pertama kemunculan substring tertentu, −1 jika tidak ada.
perulangan di dalam perulangan
Iterasi bersarang adalah perulangan di dalam badan perulangan lain. Perulangan dalam menjalankan semua iterasinya sebelum perulangan luar lanjut ke iterasi berikutnya.
for (int r = 0; r < 3; r++) { for (int c = 0; c < 4; c++) { System.out.print(r * c + " "); } System.out.println(); } Untuk r = 0 perulangan dalam menjalankan c dari 0 sampai 3; lalu println mengakhiri baris, dan baru setelah itu r menjadi 1. Gambar menyalakan kisi sel demi sel, baris demi baris: badan dalam dijalankan 3 × 4 = 12 kali dan mencetak
0 0 0 0 0 1 2 3 0 2 4 6
Batas perulangan dalam dapat bergantung pada variabel luar. Di sini perulangan dalam dijalankan r + 1 kali, sehingga putarannya adalah 1, 2, 3, 4:
int count = 0; for (int r = 0; r < 4; r++) { for (int c = 0; c <= r; c++) { count++; } } count berakhir pada 10, sebuah segitiga, bukan persegi panjang.
menghitung seberapa sering sebuah pernyataan dijalankan
Jumlah eksekusi pernyataan adalah banyaknya sebuah pernyataan dijalankan. Biasanya ditemukan secara informal, dengan menelusuri beberapa putaran dan bernalar tentang perulangannya.
for (int i = 0; i < n; i++) { count++; } Dengan i dari 0 sampai n − 1, count++ dijalankan n kali. Pemeriksaan i < n dijalankan n + 1 kali: sekali lebih banyak, untuk mengakhiri perulangan.
for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { count++; } } Pada perulangan bersarang, setiap dari n putaran luar menjalankan perulangan dalam n kali: count++ dijalankan n × n kali. Untuk n = 6 itu 6 berbanding 36; untuk n = 8, 8 berbanding 64. Gambar tumbuh pada keduanya seiring n naik: menggandakan n menggandakan yang satu dan melipatempatkan yang lain.
Hitung dari batas perulangan. for (int i = 1; i <= n; i++) juga dijalankan n kali; i < n yang dimulai dari 1 dijalankan n − 1; segitiga seperti pada halaman terakhir dijalankan 1 + 2 + … + n kali. Membandingkan hitungan seperti ini adalah cara mengatakan satu perulangan lebih cepat daripada yang lain tanpa stopwatch.