# ==============================
# FUNGSI PENDUKUNG
# ==============================
validasi_pencarian <- function(x, target, urut = FALSE) {
if (!is.numeric(x) || length(dim(x)) > 1L ||
anyNA(x) || any(!is.finite(x))) {
stop("x harus larik numerik satu dimensi tanpa NA atau Inf")
}
if (!is.numeric(target) || length(target) != 1L ||
!is.finite(target)) {
stop("target harus satu angka berhingga")
}
if (urut && is.unsorted(x, strictly = FALSE)) {
stop("Data harus terurut menaik")
}
invisible(TRUE)
}
# Sequential search dengan Boolean
seq_boolean <- function(x, target) {
validasi_pencarian(x, target)
i <- 1L
n <- length(x)
ketemu <- FALSE
while (i <= n && !ketemu) {
if (x[i] == target) {
ketemu <- TRUE
} else {
i <- i + 1L
}
}
if (ketemu) return(i)
NA_integer_
}
# Sequential search tanpa Boolean
seq_tanpa_boolean <- function(x, target) {
validasi_pencarian(x, target)
for (i in seq_along(x)) {
if (x[i] == target) return(i)
}
NA_integer_
}
# Sequential search pada data terurut
seq_terurut <- function(x, target) {
validasi_pencarian(x, target, urut = TRUE)
i <- 1L
n <- length(x)
while (i <= n && x[i] < target) {
i <- i + 1L
}
if (i <= n && x[i] == target) return(i)
NA_integer_
}
# Sequential search dengan sentinel
seq_sentinel <- function(x, target) {
validasi_pencarian(x, target)
n <- length(x)
kerja <- c(x, target)
i <- 1L
while (kerja[i] != target) {
i <- i + 1L
}
if (i <= n) return(i)
NA_integer_
}
# Binary search dengan Boolean
bin_boolean <- function(x, target) {
validasi_pencarian(x, target, urut = TRUE)
kiri <- 1L
kanan <- length(x)
ketemu <- FALSE
posisi <- NA_integer_
while (kiri <= kanan && !ketemu) {
tengah <- kiri + (kanan - kiri) %/% 2
if (x[tengah] == target) {
ketemu <- TRUE
posisi <- tengah
} else if (x[tengah] < target) {
kiri <- tengah + 1L
} else {
kanan <- tengah - 1L
}
}
posisi
}
# Binary search tanpa Boolean
bin_tanpa_boolean <- function(x, target) {
validasi_pencarian(x, target, urut = TRUE)
kiri <- 1L
kanan <- length(x)
while (kiri <= kanan) {
tengah <- kiri + (kanan - kiri) %/% 2
if (x[tengah] == target) return(tengah)
if (x[tengah] < target) {
kiri <- tengah + 1L
} else {
kanan <- tengah - 1L
}
}
NA_integer_
}
# Binary search posisi pertama (untuk data berulang)
bin_pertama <- function(x, target) {
validasi_pencarian(x, target, urut = TRUE)
kiri <- 1L
kanan <- length(x)
posisi <- NA_integer_
while (kiri <= kanan) {
tengah <- kiri + (kanan - kiri) %/% 2
if (x[tengah] >= target) {
if (x[tengah] == target) posisi <- tengah
kanan <- tengah - 1L
} else {
kiri <- tengah + 1L
}
}
posisi
}
# Jejak binary (tabel langkah)
jejak_binary <- function(x, target) {
validasi_pencarian(x, target, urut = TRUE)
kiri <- 1L
kanan <- length(x)
jejak <- data.frame(langkah = integer(), kiri = double(),
kanan = double(), tengah = double(), nilai = double(),
keputusan = character())
while (kiri <= kanan) {
tengah <- kiri + (kanan - kiri) %/% 2
keputusan <- if (x[tengah] == target) "Ditemukan" else
if (x[tengah] < target) "Cari kanan" else "Cari kiri"
jejak <- rbind(jejak, data.frame(
langkah = nrow(jejak) + 1L, kiri = kiri, kanan = kanan,
tengah = tengah, nilai = x[tengah], keputusan = keputusan))
if (x[tengah] == target) break
if (x[tengah] < target) kiri <- tengah + 1L else
kanan <- tengah - 1L
}
jejak
}
# Hitung kunjungan sequential
kunjungan_sequential <- function(x, target) {
validasi_pencarian(x, target)
banyak <- 0L
for (i in seq_along(x)) {
banyak <- banyak + 1L
if (x[i] == target) break
}
banyak
}
# Data produk simulasi
produk <- data.frame(
kode = c(104, 101, 107, 103, 106, 102, 105),
nama = c("Telur", "Beras", "Kopi", "Minyak",
"Garam", "Gula", "Tepung"),
stok = c(25, 40, 18, 30, 50, 35, 28)
)
urutan <- order(produk$kode)
produk_urut <- produk[urutan, , drop = FALSE]
# ==============================
# LATIHAN 11
# ==============================
lat_x <- c(12, 7, 19, 7, 25)
# 11A. Sequential Boolean, target 7
print(seq_boolean(lat_x, 7)) # hasil: 2
## [1] 2
# 11B. Sequential tanpa Boolean, target 8
print(seq_tanpa_boolean(lat_x, 8)) # hasil: NA
## [1] NA
print(seq_tanpa_boolean(numeric(), 8)) # hasil: NA
## [1] NA
# 11C. Sequential terurut, cari 12
print(seq_terurut(c(5, 10, 15, 20, 25), 12)) # hasil: NA
## [1] NA
# 11D. Sentinel, target 99
lat_awal <- lat_x
print(seq_sentinel(lat_x, 99)) # hasil: NA
## [1] NA
print(identical(lat_x, lat_awal)) # TRUE = data asli tidak berubah
## [1] TRUE
# 11E. Posisi pertama vs semua posisi
print(match(7, lat_x)) # hasil: 2
## [1] 2
print(which(lat_x == 7)) # hasil: 2 4
## [1] 2 4
# 11F. Data mengandung NA
print(tryCatch(seq_boolean(c(12, NA, 19), 19),
error = function(e) conditionMessage(e)))
## [1] "x harus larik numerik satu dimensi tanpa NA atau Inf"
# ==============================
# LATIHAN 12
# ==============================
lat_urut <- seq(10, 100, by = 10)
# 12A. Jejak binary target 80
print(jejak_binary(lat_urut, 80))
## langkah kiri kanan tengah nilai keputusan
## 1 1 1 10 5 50 Cari kanan
## 2 2 6 10 8 80 Ditemukan
# 12B. Kasus batas dua varian binary
print(bin_boolean(lat_urut, 10)) # hasil: 1
## [1] 1
print(bin_tanpa_boolean(lat_urut, 100)) # hasil: 10
## [1] 10
print(bin_boolean(lat_urut, 105)) # hasil: NA
## [1] NA
print(bin_tanpa_boolean(lat_urut, 105)) # hasil: NA
## [1] NA
# 12C. Data berulang
print(bin_boolean(c(10, 20, 20, 20, 30), 20)) # hasil: 3
## [1] 3
print(bin_pertama(c(10, 20, 20, 20, 30), 20)) # hasil: 2
## [1] 2
# 12D. Cari kode 103 pada tabel produk terurut
p <- bin_tanpa_boolean(produk_urut$kode, 103)
print(c(posisi_terurut = p, baris_asli = urutan[p]))
## posisi_terurut baris_asli
## 3 4
print(produk_urut[p, , drop = FALSE])
## kode nama stok
## 4 103 Minyak 30
# 12E. Data tidak terurut ditolak
print(tryCatch(bin_boolean(c(30, 10, 20), 20),
error = function(e) conditionMessage(e)))
## [1] "Data harus terurut menaik"
# 12F. Bandingkan kunjungan sequential vs binary, target 1024
print(c(sequential = kunjungan_sequential(seq_len(1024), 1024),
binary = nrow(jejak_binary(seq_len(1024), 1024))))
## sequential binary
## 1024 11