A - Kelompok 6
A - Kelompok 6
Search Algorithm
Oleh:
Ach Althaaf Cahya Ramadhan (220535609181)
Anissa Alifia Putri (220535600012)
Ahmad ‘Ammar Musyaffa’ (220535601431)
David Satria Alamsyah (220535610311)
Dhia Rafifah Thifal (220535601315)
Silvia Wulandari Situngkir (230535618282)
Offering A
Kelompok 6
Algoritma pencarian atau yang biasa disebut dengan Search Algorithm adalah
suatu metode atau prosedur yang digunakan untuk menemukan keberadaan atau lokasi
suatu informasi atau elemen tertentu dalam suatu kumpulan data yang diberikan.
Tujuannya adalah untuk menemukan elemen target dalam kumpulan data tersebut.
Algoritma pencarian dapat diterapkan pada berbagai jenis struktur data, seperti
array, daftar (list), graf, pohon, dan berbagai struktur data lainnya. Misalnya, dalam
konteks array, algoritma pencarian akan mencari elemen dalam array tersebut. Dalam
konteks graf, algoritma pencarian dapat digunakan untuk mencari jalur atau node
tertentu dalam graf tersebut.
1. Linear Search
Linear search adalah algoritma pencarian yang digunakan untuk menemukan nilai
tertentu dalam sebuah kumpulan data atau daftar (biasanya dalam bentuk array atau
daftar terurut). Algoritma ini bekerja dengan cara menelusuri setiap elemen satu per
satu dalam urutan sekuensial, mulai dari elemen pertama hingga elemen terakhir,
untuk mencari nilai yang dicari. Dalam linear search, tidak ada asumsi tentang
kumpulan data yang diurutkan atau tidak diurutkan sebelumnya. Ini berarti bahwa
algoritma ini dapat digunakan pada kumpulan data yang tidak terurut sekalipun.
Berikut adalah gambaran sederhana dari cara kerja linear search.
Linear search bekerja dengan cara menelusuri setiap elemen dalam kumpulan data,
dimulai dari elemen pertama hingga elemen terakhir, secara berurutan. Pada setiap
langkah, algoritma memeriksa apakah nilai yang dicari cocok dengan nilai elemen
saat ini. Jika cocok, pencarian selesai dan indeks elemen tersebut dikembalikan. Jika
tidak cocok, algoritma melanjutkan ke elemen berikutnya. Proses ini terus berlanjut
sampai nilai yang dicari ditemukan atau seluruh kumpulan data telah diperiksa, dan
jika nilai tersebut tidak ditemukan, pencarian menghasilkan hasil 'tidak ditemukan'.
Berikut dibawah ini adalah contoh implementasi kode dengan pendekatan iteratif
dengan bahasa pemrograman python.
n = len(arr) 1 1 1
for i in range(n): 1 1 1
if arr[i] == target: 1 n/2 n
return i 1 1 1
return -1 0 0 1
n = len(arr) n =1
for i in range(n): i =1
return i
return -1
Total 3
3) Kelebihan
a) Sederhana dan mudah dipahami
Algoritma ini mudah dipelajari dan diimplementasikan, bahkan bagi
programmer pemula.
b) Fleksibilitas
Linear search dapat digunakan pada berbagai jenis data, baik yang
terstruktur maupun tidak terstruktur.
c) Efisien untuk data kecil
Linear search cukup efisien untuk dataset kecil dengan jumlah elemen
yang sedikit.
d) Berlaku untuk Kumpulan Data Tidak Terurut
Linear search dapat digunakan pada kumpulan data yang tidak terurut.
Tidak perlu mengurutkan kumpulan data sebelum melakukan pencarian
sehingga dapat menghemat waktu dan usaha.
4) Kekurangan
a) Kompleksitas Waktu Linear
Pada kasus terburuk, kompleksitas waktu linear search adalah O(n),
dimana n adalah jumlah elemen dalam kumpulan data. Ini membuatnya
kurang efisien untuk kumpulan data besar karena algoritma harus
menelusuri semua elemen satu per satu.
b) Tidak Efisien untuk Kumpulan Data Besar
Karena kompleksitas waktu linear search adalah linier, algoritma ini
mungkin tidak efisien untuk kumpulan data besar.
c) Tidak Cocok untuk Kumpulan Data Terurut
Linear search tidak memanfaatkan kumpulan data yang terurut. Dalam
kasus seperti itu, algoritma pencarian biner akan lebih cepat karena
memanfaatkan sifat terurutnya kumpulan data.
2. Binary Search
Binary Search adalah salah satu metode pencarian data dalam sebuah array
yang sudah diurutkan. Proses pencarian dimulai dengan menentukan nilai tengah
(middle) dari array. Jika nilai tengah sama dengan elemen yang dicari, maka
pencarian selesai dan elemen tersebut ditemukan. Jika elemen yang dicari lebih besar
dari nilai tengah, maka pencarian dilanjutkan pada separuh kanan array. Sebaliknya,
jika elemen yang dicari lebih kecil dari nilai tengah, pencarian dilanjutkan pada
separuh kiri array. Proses ini diulangi pada setiap iterasi hingga elemen yang dicari
ditemukan atau seluruh array telah diperiksa.
Langkah perhitungan Binary Search pada data dengan urutan ascending:
1. Buat perulangan dengan menentukan posisi low, dimana posisi ini
menandakan index paling rendah untuk kemudian dapat menentukan posisi
high. Dengan begitu dapat ditemukan posisi mid = (high+low)/2.
2. Melakukan perbandingan pada data yang dicari dengan nilai pada posisi mid.
3. Jika data yang dicari sama dengan nilai mid, data ditemukan, pencarian
berhenti.
4. Jika data yang dicari lebih kecil dari nilai mid maka pencarian dilanjutkan ke
bagian kiri mid untuk membandingkan nilainya sehingga kondisi high berubah
menjadi mid-1 dan posisi low tetap.
5. Jika data yang dicari lebih besar dari nilai mid maka pencarian dilanjutkan ke
bagian kanan mid untuk membandingkan nilainya sehingga kondisi low
berubah menjadi mid+1 dan posisi high tetap.
6. Berikut merupakan contoh ilustrasi Binary Search:
Pada kode program di atas, ‘L’, ‘n’, ‘nmin’, dan ‘nmax’ adalah inisialisasi variabel ‘L’
merupakan array yang sudah diurutkan, ‘n’ adalah elemen yang dicari dalam array
‘L’, ‘nmin’ menjadi indeks paling rendah dalam array yang di proses, dan ‘nmax’
menjadi indeks paling tinggi dalam array yang diproses
Selanjutnya, dilakukan perulangan untuk mulai mencari memanfaatkan
perulangan ‘while’ yang akan terus berlangsung selama ‘nmin’ kurang dari sama
dengan ‘nmax’. Bagian ini akan memastikan bahwa selama rentang waktu yang dapat
diperiksa, pencarian akan terus dilakukan.
Pada baris berikutnya, dilakuakan pencarian posisi mid dengan menghitung
rata-rata dari ‘nmin’ dan ‘nmax’, yaitu ‘mid = (nmin + nmax) / 2’. Jika elemen yang
dicari ‘n’ lebih besar dari nilai yang ada pada posisi mid, maka rentang pencarian akan
berpindah ke bagian kanan mid dengan mengubah ‘nmin’ menjadi ‘mid + 1’.
Sebaliknya, jika elemen yang dicari lebih kecil dari nilai di posisi mid, maka rentang
pencarian akan berpindah ke kiri mid dengan mengubah ‘nmax’ menjadi ‘mid - 1’.
Terakhir, jika yang dicari sama dengan nilai diposisi mid, maka pencarian selesai dan
fungsi akan mengembalikan ‘True’. Secara keseluruhan, jika seluruh rentang telah
diperiksa dan elemen yang dicari tidak ditemukan dimanapun, maka pencarian akan
mengembalikan fungsi ‘False’.
1) Komplekasitas Waktu
Algoritma Best Average Worst
Case Case Case
def binarySearch2(self, L, n, nmin, 0 0 0
nmax):
if n > L[mid]: 1 n n
nmin = mid + 1 1 0 0
nmax = mid - 1 0 0 0
else: 0 1 0
return True
return False 0 0 1
a) Best Case
Kasus terbaik terjadi ketika pencarian berhenti karena data yang dicari,
ditemukan pada iterasi pertama. Pada program di atas hanya dibutuhkan
pemenuhan pada baris ke dua(‘while (nmin <= nmax):’) sampai baris ke
empat(‘nmin = mid + 1’) untuk memenuhi syarat iterasi pertama Binary Search.
Dimana total statement untuk pemenuhan algoritmanya adalah konstanta
bernilai empat, yang jika dikonfersikan ke notasi asimtotiknya akan menjadi
Ω(1) atau konstan.
b) Averange Case
Pada kasus averange, pencarian akan selalu dibagi dua. Pencarian ini akan
terus dilakukan hingga ditemukan data yang dicari. Pada program di atas,
ditemukan total statement kasus averange sebanyak 5(n/2)+2, bentuk ini juga
dapat ditulis menjadi T(n/2)+k dimana k adalah konstanta, maka pola
identifikasinya dapat dituliskan sebagai berikut:
T(n) = T(n/2)+O(1)
= T(n/2)/2+O(1)+O(1)
2
= T(n/2 )+2 O(1)
3
= T(n/2 )+3 O(1)
4
= T(n/2 )+4 O(1)
.
.
𝑘
=[T(n/2 )+ k * O(1)]
Sehingga didapatkan nilai T(n) sebesar:
𝑘
T(n)=[T(n/2 + k * O(1))]
𝑘
Diasumsikan: n/2 = 1
𝑘
Jika n = 2 , maka k = log n
𝑘
T(N) = [T(n / 2 ) + k * O(1)]
= T (16 / 16) + log n * O(1)
= O (log n)
c) Worst Case
Pada kasus terburuk, data yang dicari tidak dapat ditemukan, bahkan setelah
menjalankan iterasi berulang sampai keseluruhan list diakses, sehingga program akan
mengembalikan nilai statement 1 pada baris terakhir(‘return False’). Total statement
dari kasus terburuk adalah 7(n/2)+2, bentuk ini juga dapat ditulis menjadi
T(n/2)+k dimana k adalah konstanta. Pola identifikasinya untuk diubah
menjadi notasi asimtotik akan sama dengan kasus averange yang
menghasilkan O (log n).
2) Kompleksitas Ruang
Algoritma Kompleksitas Ruang
def binarySearch2(self, L, n,
nmin, nmax): n = 1,
while (nmin <= nmax): nmin = 1,
mid = (nmin + nmax) / 2 nmax = 1,
if n > L[mid]: mid = 1,
nmin = mid + 1
elif n < L[mid]:
nmax = mid - 1
else:
return True
return False
TOTAL 4
Kompleksitas ruang untuk algoritma Binary Search dalam pola iteratif adalah
pertimbangan jumlah memori yang digunakan variabel-variabel selama eksekusi
algoritma. Pada algoritma di atas, variabel-variabel yang digunakan antara lain
‘n’, ‘nmin’, ‘nmax’, dan ‘mid’, yang totalnya bernilai empat konstanta. Semuanya
menggunakan ruang konstan yang tidak bertambah seiring dengan ukuran input
sehingga dapat dinotasikan menjadi O(1).
3) Kelebihan
Kelebihan dari Binary Search adalah pembandingan data yang tidak perlu di
mulai dari awal dan tidak harus dibandingkan seluruhannya, cukup melalui titik
tengah untuk kemudian berjalan sesuai potensi keberadaan data yang dicari.
4) Kekurangan
Implementasi yang mengharuskan data array yang terurut membuat Binary
Search harus mengurutkan dulu data yang acak, sehingga butuh melakukan
sorting terlebih dulu sebelum dilakukan pencarian
3. Depth-First Search
a. Pengertian
Algoritma Depth First Search (DFS) adalah suatu metode pencarian pada
sebuah tree/pohon dengan menelusuri satu cabang sebuah tree sampai menemukan
solusi. Pencarian dilakukan pada satu node dalam setiap level dari yang paling kiri
dan dilanjutkan pada node sebelah kanan. Jika solusi ditemukan maka tidak
diperlukan proses backtracking yaitu penelusuran balik untuk mendapatkan jalur yang
diinginkan.
Cara kerja algoritma Depth First Search yaitu masukan masukan node akar
kedalam sebuah tumpukan. Kemudian ambil simpul pertama pada level paling atas,
jika simpul merupakan solusi pencarian selesai dan hasil dikembalikan. Jika simpul
bukan merupakan solusi, masukan seluruh simpul yang bertetangga dengan simpul
tersebut ke dalam tumpukan. Apabila semua simpul sudah dicek dan antrean kosong,
pencarian selesai dengan mengembalikan hasil solusi tidak ditemukan. Pencarian
diulang dari simpul awal antrean.
Kelebihan
● Depth First Search jauh lebih efisien untuk ruang pencarian dengan banyak cabang
karena tidak perlu mengeksekusi semua simpul pada suatu level tertentu pada daftar
open.
● Depth First Search memerlukan memori yang relatif kecil karena node pada lintasan
yang aktif saja yang disimpan.
Kekurangan
c. Contoh penerapan
1 0
3 1 0
4 3 1 0
3 1 0
5 3 1 0
3 1 0
2 3 1 0
3 1 0
1 0
class Graph:
def __init__(self):
self.graph = {}
4. Breadth-First Search
- Mengeksplorasi simpul pada tingkat yang sama : Algoritma ini mengeksplorasi semua
simpul yang terhubung langsung dengan simpul awal terlebih dahulu. Ini dilakukan
dengan mengeksplorasi semua simpul tetangga dari simpul awal.
- Menyimpan daftar simpul yang telah dieksplorasi : Ketika suatu simpul dieksplorasi,
ia ditandai sebagai telah "dikunjungi" atau "dieksplorasi" agar tidak dieksplorasi lagi
dalam langkah-langkah berikutnya.
- Mengulangi proses hingga target ditemukan atau semua simpul telah dieksplorasi :
Langkah-langkah di atas diulangi secara berulang hingga simpul target ditemukan
atau tidak ada lagi simpul yang tersisa untuk dieksplorasi. Hal ini memastikan bahwa
BFS mengeksplorasi semua simpul pada tingkat yang sama sebelum melanjutkan ke
tingkat yang lebih dalam dalam pohon atau graf.
tree = {"5": ["3", "7"], "3": ["2", "4"], "7": ["8"], "2": [], "4":
["8"], "8": []} #tree is m x n, where m is the number of nodes and n is
the number of edges
# Driver Code
print("Following is the Breadth-First Search")
bfs(tree, "5", '7') # function calling
Analisis Kompleksitas Waktu
visited = [] 1 1 1
queue = [] 1 1 1
visited.append(node) 1 1 1
queue.append(node) 1 1 1
while queue: 1 1 1
m = queue.pop(0) 1 ½v v
if m == value: 1 ½v v
print("Found " + m) 1 ½v v
return 1 1 1
visited.append(neighbour) 0 ½e e
queue.append(neighbour) 0 ½e e
a. Best Case
b. Average
c. Worst Case
Kasus terburuk terjadi ketika nilai yang dicari terletak pada level
terakhir dalam tree, memaksa algoritma untuk menjelajahi semua node dan
edge. Dalam konteks ini, kompleksitas waktu dalam kasus terburuk
memberikan batas atas kinerja algoritma saat menghadapi situasi yang paling
tidak menguntungkan atau ekstrem. Meskipun tidak semua kasus pada
praktiknya akan mencapai tingkat ekstrem ini, namun analisis terhadap kasus
terburuk memberikan gambaran tentang batas kinerja algoritma dalam kondisi
yang paling sulit. Jadi, kompleksitas waktu dalam kasus terburuk,
diekspresikan sebagai O(v + e), menunjukkan bahwa kompleksitas waktu
algoritma bergantung pada jumlah node (v) dan jumlah edge (e) dalam graf
yang harus diperiksa dalam situasi paling buruk. Notasi Big O O(v + e)
memberikan gambaran tentang pertumbuhan waktu eksekusi algoritma dengan
ukuran tree.
Analisis Kompleksitas Ruang
Statement Ruang
visited = [] 1
queue = [] 1
visited.append(node) 1
queue.append(node) 1
while queue: 1
m = queue.pop(0) 1
visited.append(neighbour) v
queue.append(neighbour) v
5. Interval Search
Dalam hal ini Interval searh algoritma adalah sebuah search algoritm, tetapi
fokusnya lebih dikhususkan pada search interval (pencarian interval) dalam kumpulan
interval yang mana pencarian interval tersebut memenuhi kriteria. Hal ini merupakan
perbedaan dari pencarian algoritm secara umum yang mana mencari elemen tunggal
dalam kumpulan data.
Interval search berguna Ketika kita memiliki beberapa kumpulan interval dan
perlu untuk menemukan interval yang beririsan dengan interval yang kita miliki , atau
juga mencari interval yang mencakup nilai tertentu. Contoh penggunaanya terdapat
pada pemrosesan rentang waktu, pencarian jadwal, dan pemrosesan data spasial, pada
hal ini saya akan memberikan contoh implementasi search algorithm menggunakan
pendekatan biner, serta menganalisis kompleksitas waktu dan efisiensi dari code
program tersebut
if not intervals:
return -1
min_lower_bound = intervals[0][0]
max_upper_bound = intervals[-1][1]
return left
Pada code diatas adalah code program search algoritm menggunakan pendekatan
biner, yang mana cara pengeksekusian program tersebut berawal dari pengurutan nilai
interval yang kita miliki. Setelah selesai mengurutkan, program akan melanjutkan dengan
pencarian biner dimana dalam langkah ini mencari nilai ‘x’ diantara interval, dimana nilai ‘x’
ini adalah nilai yang ingin kita cari, pencarian biner ini menggunakan metode pembagian dan
pengecekan di tengah tengah list interval. Setelah itu, setiap iterasi membagi interavl menjadi
dua bagian dan memeriksan apakah nilai ‘x’ berada dalam interval tersebut. Jika nilai ‘x’
berada dalam nilai interval yang berada ditengah, maka proses akan selesai, jika nilai’x’ tidak
terdapat pada interval tersebut pencarian akan dilanjutkan keinterval kiri atau kanan,
tergantung pada nilai ‘x’ lebih besar atau lebih kecil(dibandingkan) dengan interval tengah,
jika lebih besar maka pencarian akan dilanjutkan pada interval kanan, jka lebih kecil maka
akan dilanjutkan pada interval kiri, hingga nilai ‘x’ ditemukan pada indeks ke berapa.
Kompleksitas waktu ;
= O(n log n) + O(n) + O(1) + O(1) + O(1) + O(1) + O(1) + O(1) . O(1) . O(1) . O(1) + O(n)
= Max O(n log n) + O(n) + O(1) + O(1) + O(1) + O(1) + O(1) + O(1) + O(n)
= O(n log n)
maka code program diatas mempunyai kompleksitas waktu dalam asimtotik yaitu algoritma
n log n
kompleksitas ruang :
intervals.sort()
if not intervals:
return -1
min_lower_bound = intervals[0][0] 1
max_upper_bound = intervals[-1][1] 1
Total 4+n
6. Bidirectional Search
Penjelasan
Kompleksitas Ruang
VARIABLE JUMLAH
start 1
end 1
list n
target 1
return 1
TOTAL 4+n
Dalam algoritma yang dibuat terdapat empat variabel yang digunakan dalam bidirectional
search dalam suatu list, yaitu list dengan jumlah sebanyak n (sepanjang jumlah list), target
untuk objek yang dicari, start dan end untuk perulangan dalam algoritma ini. Sehingga total
kompleksitas ruang yang dibutuhkan adalah sebanyak n + 4.
Kompleksitas Waktu
start = 0 1 1 1
end = len(lst) - 1 1 1 1
while start <= end: 1 1 1
if lst[start] == target: 1 n/4 n/2
return start 1 1 0
elif lst[end] == target: 1 n/4 n/2
return end 1 1 0
start += 1 0 1 1
end -= 1 0 1 1
return -1 0 1 1
7 8+(n/4)^2 6+(n/2)^2
Dalam analisis kompleksitas waktu algoritma Bidirectional Search yang telah dilakukan,
diketahui bahwa algoritma tersebut memiliki 3 kondisi yaitu best-case, average-case, dan
worst-case. Kondisi pertama best-case memiliki total kompleksitas waktu 7 yang terjadi jika
operasi pencarian elemen pada suatu data terurut dilakukan, dan elemen yang dicari tepat
berada pada posisi pertama atau indeks ke-0 dari data tersebut. Dalam skenario ini, algoritma
pencarian dapat menemukan elemen target tanpa harus mengecek elemen-elemen tambahan,
sehingga mencapai kompleksitas waktu O(1), yang merupakan kasus terbaik dalam hal
efisiensi pencarian. Kemudian pada kondisi kedua average-case memiliki total 8 + (n/4)2
yang merupakan kasus rata-rata terjadi antara best case dan worst-case. Terakhir kondisi
worst-case memiliki total kompleksitas waktu 6 + (n/2)2, dalam kondisi ini terjadi ketika
operasi pencarian elemen pada suatu data terurut dilakukan, dan elemen yang dicari berada
pada posisi terakhir atau indeks ke-(n-1) dari data tersebut.
Kompleksitas Asimtotik
STATEMENT NOTASI
ASIMTOTIK
def bidirectional_search(list, target):
start = 0 O(1)
if lst[start] == target:
return start
O(1)
elif lst[end] == target:
return end
start += 1
O(1)
end -= 1
return -1 O(1)
Algoritma Bidirectional Search memiliki kompleksitas waktu asimptotik O(n) pada kasus
terburuk. Namun, pada kasus rata-rata, algoritma ini lebih efisien dengan kompleksitas waktu
asimptotik O(n/2).