0Pricing
Coding Interview Prep · Pelajaran

Penyisipan dan Pencarian BST

Implementasikan penyisipan dan pencarian secara rekursif serta iteratif, telusuri jalur dalam pohon untuk berbagai kunci, dan analisis kompleksitas kasus terburuk pada pohon yang tidak seimbang.

Penyisipan dan Pencarian BST adalah pelajaran Coding Interview Prep gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Coding Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Coding Interview Prep mencakup 4 pelajaran total.

Definisi Properti BST

Sebuah Pohon Pencarian Biner memenuhi satu invarian: untuk setiap simpul, semua nilai di subpohon kiri lebih kecil secara ketat daripada nilai simpul tersebut, sedangkan semua nilai di subpohon kanan lebih besar secara ketat. Properti pengurutan ini dipertahankan di seluruh subpohon, bukan hanya pada anak langsung, sehingga memungkinkan pencarian, penyisipan, dan penghapusan dalam O(log n) pada pohon seimbang serta membedakan BST dari pohon biner umum.

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

# Valid BST:
#       4
#      / \
#     2   6
#    / \ / \
#   1  3 5  7
# For node 4: left subtree {1,2,3} < 4 < right subtree {5,6,7}
# This holds recursively for EVERY node in the tree.
print('BST property: left < node < right at every level')

Pencarian BST Rekursif

Pencarian BST bekerja seperti pencarian biner: bandingkan target dengan nilai simpul saat ini, lalu lakukan rekursi ke subpohon yang sesuai. Jika target sama dengan nilai saat ini, kembalikan simpul tersebut. Jika target lebih kecil, bergeraklah ke kiri; jika lebih besar, bergeraklah ke kanan. Kembalikan nilai kosong jika mencapai simpul kosong. Kompleksitas waktunya adalah O(h) — O(log n) untuk pohon seimbang dan O(n) untuk pohon miring.

def search_bst(root, val):
    if not root:
        return None  # not found
    if root.val == val:
        return root  # found
    if val < root.val:
        return search_bst(root.left, val)
    else:
        return search_bst(root.right, val)

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)

result = search_bst(root, 2)
print(result.val if result else 'Not found')  # 2
result = search_bst(root, 5)
print(result.val if result else 'Not found')  # Not found

Pencarian BST Iteratif

Pencarian iteratif menghindari overhead tumpukan pemanggilan dan lebih disukai dalam kode produksi. Gunakan penunjuk curr yang bergerak menuruni pohon ke kiri atau kanan berdasarkan perbandingan. Ini adalah perulangan sederhana dengan tiga kasus: kosong (tidak ditemukan), cocok (ditemukan), atau menyesuaikan arah. Pencarian iteratif juga memiliki kompleksitas O(h), tetapi menggunakan ruang O(1), dibandingkan O(h) pada versi rekursif.

def search_bst_iterative(root, val):
    curr = root
    while curr:
        if val == curr.val:
            return curr
        elif val < curr.val:
            curr = curr.left
        else:
            curr = curr.right
    return None  # not found

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)

node = search_bst_iterative(root, 3)
print(node.val if node else 'Not found')  # 3
print(search_bst_iterative(root, 9))     # None

Penyisipan BST Rekursif

Penyisipan BST menemukan posisi yang tepat dengan mengikuti keputusan kiri/kanan yang sama seperti pada pencarian, lalu menambahkan simpul baru pada posisi null pertama yang dicapai. Pendekatan rekursif mengembalikan akar setiap subpohon (yang mungkin merupakan akar baru): jika simpul saat ini kosong, kembalikan TreeNode baru; jika tidak, perbarui root.left atau root.right dengan hasil pemanggilan rekursif. Pola ini rapi dan umum digunakan dalam solusi wawancara teknis.

def insert_bst(root, val):
    if not root:
        return TreeNode(val)  # create new node here
    if val < root.val:
        root.left = insert_bst(root.left, val)
    elif val > root.val:
        root.right = insert_bst(root.right, val)
    # val == root.val: duplicate, do nothing (or handle as needed)
    return root

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root = insert_bst(root, 1)
root = insert_bst(root, 5)
# Tree is now: 4, left=2(left=1), right=7(left=5)
print(root.right.left.val)  # 5

Penyisipan BST Iteratif

Penyisipan iteratif menggunakan penunjuk parent untuk melacak simpul terakhir yang tidak kosong sebelum mencapai titik penyisipan. Telusuri pohon seperti pada pencarian, sambil melacak induk dan arah terakhir yang diambil. Saat mencapai nilai kosong, tambahkan simpul baru ke sisi yang sesuai dari induk. Selalu tangani kasus khusus pohon kosong (akar kosong) secara terpisah.

def insert_bst_iterative(root, val):
    new_node = TreeNode(val)
    if not root:
        return new_node
    curr = root
    while True:
        if val < curr.val:
            if curr.left is None:
                curr.left = new_node
                break
            curr = curr.left
        else:  # val > curr.val
            if curr.right is None:
                curr.right = new_node
                break
            curr = curr.right
    return root

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root = insert_bst_iterative(root, 3)
print(root.left.right.val)  # 3

BST Kasus Terburuk: Pohon Miring

Jika Anda menyisipkan urutan terurut ke dalam BST, hasilnya adalah pohon miring yang merosot menjadi daftar tertaut. Pencarian, penyisipan, dan penghapusan semuanya menjadi O(n). Inilah alasan pohon BST seimbang seperti pohon AVL dan pohon merah-hitam dibuat. Dalam wawancara, selalu sebutkan kasus terburuk ini ketika ditanya tentang kompleksitas BST — mengatakan 'O(log n) rata-rata, O(n) kasus terburuk untuk pohon yang tidak seimbang' menunjukkan pemahaman yang mendalam.

# Inserting 1, 2, 3, 4, 5 into a BST:
# 1
#  \
#   2
#    \
#     3
#      \
#       4
#        \
#         5
# This is a right-skewed tree: search is O(n) not O(log n)

root = None
for val in [1, 2, 3, 4, 5]:
    root = insert_bst(root, val)

# Verify the skew
node = root
depth = 0
while node:
    depth += 1
    node = node.right
print(f'Height: {depth}')  # 5 = O(n), not O(log n)

Menemukan Nilai Minimum dan Maksimum

Dalam BST, nilai minimum selalu berada pada simpul paling kiri (terus bergerak ke kiri hingga mencapai simpul kosong), sedangkan nilai maksimum berada pada simpul paling kanan. Operasi O(h) ini sering digunakan sebagai subrutin dalam penghapusan BST (untuk menemukan penerus dalam-urutan) dan kueri rentang. Menguasai fungsi pembantu ini akan menghemat waktu dalam wawancara.

def find_min(root):
    while root.left:
        root = root.left
    return root

def find_max(root):
    while root.right:
        root = root.right
    return root

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
root.right.right = TreeNode(9)

print(find_min(root).val)  # 1
print(find_max(root).val)  # 9

Penerus dan Pendahulu Dalam Urutan

Penerus dalam-urutan suatu simpul adalah simpul dengan nilai terkecil yang lebih besar daripada nilai simpul tersebut. Jika simpul memiliki subpohon kanan, penerusnya adalah find_min(node.right). Jika tidak memiliki subpohon kanan, penerusnya adalah leluhur terendah yang subpohon kirinya memuat simpul tersebut. Memahami hal ini sangat penting untuk penghapusan BST dan masalah pengiterasi BST.

def inorder_successor(root, p):
    successor = None
    while root:
        if p.val < root.val:
            successor = root  # possible successor
            root = root.left
        else:
            root = root.right
    return successor

def inorder_predecessor(root, p):
    predecessor = None
    while root:
        if p.val > root.val:
            predecessor = root  # possible predecessor
            root = root.right
        else:
            root = root.left
    return predecessor

root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(6)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
p = root.left  # node with val=2
print(inorder_successor(root, p).val)   # 3
print(inorder_predecessor(root, p).val) # 1

Analisis Kompleksitas Pencarian BST

Kinerja BST sepenuhnya bergantung pada tinggi pohon. Untuk BST seimbang dengan n simpul, tingginya adalah O(log n), sehingga pencarian, penyisipan, dan penghapusan memiliki kompleksitas O(log n). Untuk BST miring, tingginya adalah O(n), sehingga semua operasi memiliki kompleksitas O(n). Python tidak memiliki BST seimbang bawaan (berbeda dari TreeMap milik Java), jadi Anda harus menerapkan AVL atau pohon merah-hitam sendiri, menggunakan sortedcontainers.SortedList, atau mengandalkan tumpukan untuk kasus penggunaan antrean prioritas.

# Python's BST alternatives:
# 1. heapq - min/max heap, O(log n) push/pop
# 2. sortedcontainers.SortedList (third-party, often allowed)
# 3. Manual AVL or Red-Black (rarely required in interviews)

# When interviews say 'use a BST':
# - LeetCode: implement TreeNode-based solution
# - Real interview: mention sortedcontainers or Java TreeMap equivalent
# - O(log n) operations matter when you need ordered access

# For pure insert/lookup without ordering: use dict (O(1) average)
print('Use heap for priority, dict for lookup, BST for ordered range')

Penyisipan ke BST: Kasus Khusus

Selalu pastikan penyisipan Anda menangani: pohon kosong (kembalikan simpul baru sebagai akar), nilai duplikat (tentukan apakah akan mengabaikannya, menyisipkannya ke kiri, atau menyisipkannya ke kanan — dan tetap konsisten), serta nilai yang sangat besar atau sangat kecil. Dalam wawancara, nyatakan asumsi Anda tentang duplikat sebelum menulis kode. Konvensi yang paling umum dalam masalah LeetCode adalah semua nilai berbeda, kecuali dinyatakan sebaliknya.

def insert_bst_no_duplicates(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert_bst_no_duplicates(root.left, val)
    elif val > root.val:
        root.right = insert_bst_no_duplicates(root.right, val)
    # else: val == root.val -> duplicate, skip
    return root

# Test all edge cases:
root = None
root = insert_bst_no_duplicates(root, 5)  # empty tree
root = insert_bst_no_duplicates(root, 5)  # duplicate
root = insert_bst_no_duplicates(root, 3)
root = insert_bst_no_duplicates(root, 7)
print(root.val, root.left.val, root.right.val)  # 5 3 7

BST dari Larik Terurut

Membangun BST seimbang berdasarkan tinggi dari larik terurut (LeetCode #108) menggunakan metode bagi-dan-taklukkan: elemen tengah menjadi akar, separuh kiri menjadi subpohon kiri, dan separuh kanan menjadi subpohon kanan. Cara ini menjamin pohon seimbang dengan tinggi O(log n). Kompleksitas waktunya adalah O(n) karena setiap elemen diproses satu kali.

def sorted_array_to_bst(nums):
    if not nums:
        return None
    mid = len(nums) // 2
    root = TreeNode(nums[mid])
    root.left = sorted_array_to_bst(nums[:mid])
    root.right = sorted_array_to_bst(nums[mid+1:])
    return root

nums = [-10, -3, 0, 5, 9]
root = sorted_array_to_bst(nums)
print(root.val)        # 0 (middle element)
print(root.left.val)   # -3
print(root.right.val)  # 9

Pemeriksaan Singkat

Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.

Ringkasan Pelajaran

Dalam pelajaran ini, Anda mempelajari: properti BST (subpohon kiri lebih kecil secara ketat, subpohon kanan lebih besar secara ketat), pencarian dan penyisipan secara rekursif maupun iteratif dalam waktu O(h), serta pohon miring kasus terburuk yang tingginya sama dengan n. Selanjutnya kita membahas penghapusan BST dan tiga kasusnya.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Penyisipan dan Pencarian BST” gratis?

Ya — teks lengkap “Penyisipan dan Pencarian BST” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Coding Interview Prep, upgrade ke CoddyKit PRO. Kursus Coding Interview Prep mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Penyisipan dan Pencarian BST”?

Implementasikan penyisipan dan pencarian secara rekursif serta iteratif, telusuri jalur dalam pohon untuk berbagai kunci, dan analisis kompleksitas kasus terburuk pada pohon yang tidak seimbang. Kamu berlatih Coding Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Coding Interview Prep?

Tidak diperlukan pengalaman sebelumnya. Coding Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.

Berapa lama pelajaran “Penyisipan dan Pencarian BST” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Coding Interview Prep ini?

Ya. Setiap pelajaran Coding Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Penyisipan dan Pencarian BST
  2. Penghapusan BST: Tiga Kasus
  3. Memvalidasi BST dan Sifat In-Order
  4. Elemen ke-K Terkecil, Jumlah Rentang, dan BST menjadi Array Terurut
← Kembali ke Coding Interview Prep