WEEK 1 • خوارزميات البحث

Binary Search

البحث الثنائي

One of the most efficient search algorithms. Find any element in a sorted array in O(log n) time!

الفكرة الأساسية

Understanding the Core Concept

🔍 إيه هو البحث الثنائي (Binary Search)؟

📖 تشبيه القاموس

تخيل إنك عايز تدور على كلمة في القاموس. هل هتبدأ من أول صفحة وتقلب صفحة صفحة؟ طبعاً لأ! ده هيكون بطيء جداً.

بدل كده، هتفتح القاموس من النص، تبص على الكلمة اللي قدامك:

  • • لو الكلمة اللي بتدور عليها قبلها ← تدور في النص الأول
  • • لو الكلمة اللي بتدور عليها بعدها ← تدور في النص التاني
  • • لو الكلمة هي نفسها ← مبروك! لقيتها! 🎉

⚡ ليه ده أسرع؟

لأنك في كل خطوة بتشيل نص العناصر من البحث!

مثال: لو عندك 1,000,000 عنصر:

  • • البحث العادي (Linear): ممكن يحتاج 1,000,000 خطوة! 😱
  • • البحث الثنائي (Binary): بيحتاج ~20 خطوة بس! 🚀

⚠️ شرط مهم جداً!

البحث الثنائي بيشتغل بس على المصفوفات المُرتبة (Sorted)!

لو المصفوفة مش مترتبة، لازم ترتبها الأول أو تستخدم Linear Search.

📝 الخطوات بالتفصيل

1

حدد نطاق البحث

حط مؤشر low على أول عنصر (index 0).
وحط مؤشر high على آخر عنصر (index = length - 1).

دول بيحددوا "النطاق" اللي بتدور فيه.

2

احسب منتصف النطاق

mid = (low + high) / 2
ده الـ index بتاع العنصر اللي في النص.

بنستخدم Math.floor() عشان ناخد رقم صحيح.

3

قارن العنصر الوسط بالهدف

لو arr[mid] == targetلقيناه! 🎉
لو arr[mid] > target ← الهدف في النص الشمال، حدث high = mid - 1
لو arr[mid] < target ← الهدف في النص اليمين، حدث low = mid + 1

4

كرر لحد ما تلاقي أو النطاق يخلص

استمر في تكرار الخطوات 2 و 3 طالما low <= high.
لو low > high ← العنصر مش موجود في المصفوفة.

مثال خطوة بخطوة

Step-by-Step Walkthrough

مثال: البحث عن الرقم 23 في المصفوفة

[ 2, 5, 8, 12, 16, 23, 38, 56, 72, 91 ]
1

الخطوة الأولى

low=02
5
8
12
mid=416
23
38
56
72
high=991

low = 0 (أول عنصر)

high = 9 (آخر عنصر)

mid = (0 + 9) / 2 = 4

العنصر في النص: 16

16 < 23 ← الهدف في النص اليمين!
نحدث: low = mid + 1 = 5

2

الخطوة الثانية

2
5
8
12
16
low=523
38
mid=756
72
high=991

low = 5

high = 9

mid = (5 + 9) / 2 = 7

العنصر في النص: 56

56 > 23 ← الهدف في النص الشمال!
نحدث: high = mid - 1 = 6

لاحظ: شيلنا 5 عناصر من البحث! (العناصر الباهتة)

3

الخطوة الثالثة - لقيناه! 🎉

2
5
8
12
16
low=523
high=638
56
72
91

low = 5

high = 6

mid = (5 + 6) / 2 = 5

العنصر في النص: 23

23 == 23 ← لقيناه!
الـ index بتاعه: 5

✅ لقينا العنصر في 3 خطوات بس من أصل 10 عناصر!

تحليل التعقيد

Complexity Analysis

Time Complexity

O(log n)

ليه log n؟

لأننا في كل خطوة بنقسم المصفوفة على 2.
كام مرة نقدر نقسم n على 2 لحد ما نوصل لـ 1؟
الإجابة: log₂(n) مرة!

أمثلة عملية:

n = 16 log₂(16) = 4 خطوات
n = 1,000 ~10 خطوات
n = 1,000,000 ~20 خطوة بس!
n = 1 مليار ~30 خطوة فقط!

Space Complexity

O(1)

ليه O(1)؟

لأننا بنستخدم متغيرات ثابتة بس:

  • low - مؤشر البداية
  • high - مؤشر النهاية
  • mid - مؤشر النصف

مش محتاجين ذاكرة إضافية تتناسب مع حجم المصفوفة.

⚠️ ملاحظة

لو استخدمت الـ Recursive version بدل الـ Iterative، الـ Space Complexity هتبقى O(log n) بسبب الـ call stack.

INTERACTIVE

Try It Yourself!

جربها بنفسك!

Enter a number and click "Search" or "Step" to begin.

Logs will appear here.

Implementation

الكود مع شرح كل سطر

binarySearch.js
1function binarySearch(arr, target) {
2  let low = 0;
3  let high = arr.length - 1;
4
5  while (low <= high) {
6    let mid = Math.floor((low + high) / 2);
7    let guess = arr[mid];
8
9    if (guess === target) {
10      return mid;
11    }
12    if (guess > target) {
13      high = mid - 1;
14    } else {
15      low = mid + 1;
16    }
17  }
18
19  return -1;
20}

شرح كل سطر 📖

سطر 1: تعريف الـ function - بتاخد المصفوفة والقيمة اللي بندور عليها
سطر 2-3: تحديد نطاق البحث - من أول عنصر (0) لآخر عنصر (length - 1)
سطر 5: نستمر طالما النطاق صالح (low أصغر من أو يساوي high)
سطر 6-7: نحسب النص ونجيب القيمة اللي فيه
سطر 9-11: لقيناه! نرجع الـ index بتاعه
سطر 12-13: لو القيمة أكبر من الهدف ← ندور في النص الشمال (نقلل high)
سطر 14-15: لو القيمة أصغر من الهدف ← ندور في النص اليمين (نزود low)
سطر 19: لو خرجنا من الـ loop يعني العنصر مش موجود - نرجع -1