260 lines
9.7 KiB
Markdown
260 lines
9.7 KiB
Markdown
|
---
|
||
|
title: Binary Search
|
||
|
localeTitle: بحث ثنائي
|
||
|
---
|
||
|
## بحث ثنائي
|
||
|
|
||
|
يقوم البحث الثنائي بتحديد موقع عنصر في مصفوفة تم فرزها عن طريق قسمة الفاصل الزمني للبحث مراراً إلى النصف.
|
||
|
|
||
|
كيف تبحث عن اسم في دليل الهاتف؟
|
||
|
|
||
|
إحدى الطرق هي البدء من الصفحة الأولى وإلقاء نظرة على كل اسم في دليل الهاتف حتى نجد ما نبحث عنه. ولكن هذا سيكون وسيلة شاقة للغاية وغير فعالة للبحث.
|
||
|
|
||
|
نظرًا لأننا نعلم أنه يتم ترتيب الأسماء في دليل الهاتف أبجديًا ، فقد نتمكن من العمل على طول الخطوات التالية:
|
||
|
|
||
|
1. افتح الصفحة الوسطى من دليل الهاتف
|
||
|
2. إذا كان لديه الاسم الذي نبحث عنه ، فقد انتهينا!
|
||
|
3. وبخلاف ذلك ، يمكنك التخلص من نصف دليل الهاتف الذي لا يحتوي على الاسم
|
||
|
4. كرر ذلك حتى تجد الاسم أو لم تعد هناك صفحات أخرى في دليل الهاتف
|
||
|
|
||
|
تعقيد الوقت: بينما نتخلص من جزء واحد من حالة البحث أثناء كل خطوة من خطوات البحث الثنائي ، ونقوم بعملية البحث في النصف الآخر ، فإن ذلك يؤدي إلى تعقيد زمن الحالة الأسوأ لـ _O_ ( _log 2 N_ ).
|
||
|
|
||
|
تعقيد الفضاء: يستغرق البحث الثنائي مسافة ثابتة أو _O_ ( _1_ ) مما يعني أننا لا نفعل أي تعريف متغير ذي صلة بحجم متغير.
|
||
|
|
||
|
للبحث عن مجموعات صغيرة ، فإن البحث الخطي يكون أفضل ولكن في الحالات الأكبر ، يكون استخدام البحث الثنائي أكثر فاعلية.
|
||
|
|
||
|
بالتفصيل ، كم مرة يمكنك قسمة N على 2 حتى يكون لديك 1؟ هذا هو القول الأساسي ، قم بإجراء بحث ثنائي (نصف العناصر) حتى تجده. في صيغة هذا سيكون هذا:
|
||
|
|
||
|
`1 = N / 2x
|
||
|
`
|
||
|
|
||
|
اضرب 2x:
|
||
|
|
||
|
`2x = N
|
||
|
`
|
||
|
|
||
|
الآن القيام log2:
|
||
|
|
||
|
`log2(2x) = log2 N
|
||
|
x * log2(2) = log2 N
|
||
|
x * 1 = log2 N
|
||
|
`
|
||
|
|
||
|
هذا يعني أنه يمكنك تقسيم سجل N مرة حتى يتم تقسيم كل شيء. مما يعني أنه يجب عليك تقسيم السجل N ("القيام بعملية البحث الثنائي") حتى تعثر على العنصر الخاص بك.
|
||
|
|
||
|
_O_ ( _log 2 N_ ) يكون هكذا لأنه في كل خطوة نصف العناصر الموجودة في مجموعة البيانات تختفي والتي يتم تبريرها بواسطة قاعدة الدالة اللوغاريتمية.
|
||
|
|
||
|
هذه هي خوارزمية البحث الثنائي. إنه أنيق وفعال ولكن لكي يعمل بشكل صحيح ، يجب **فرز** الصفيف.
|
||
|
|
||
|
* * *
|
||
|
|
||
|
ابحث عن 5 في مجموعة معينة من الأرقام باستخدام البحث الثنائي.
|
||
|
|
||
|
![بحث ثنائي 1](https://i.imgur.com/QAuugOL.jpg)
|
||
|
|
||
|
ضع علامات منخفضة وعالية ومتوسطة في الصفيف.
|
||
|
|
||
|
![البحث الثنائي 2](https://i.imgur.com/1710fEx.jpg)
|
||
|
|
||
|
قارن العنصر الذي تبحث عنه مع العنصر الأوسط.
|
||
|
|
||
|
![بحث ثنائي 3](https://i.imgur.com/jr4icze.jpg)
|
||
|
|
||
|
تخلص من النصف الأيسر وابحث في النصف الأيمن.
|
||
|
|
||
|
![بحث ثنائي 4](https://i.imgur.com/W57lGsk.jpg)
|
||
|
|
||
|
مرة أخرى مقارنة مع العنصر الأوسط.
|
||
|
|
||
|
![بحث ثنائي 5](https://i.imgur.com/5Twm8NE.jpg)
|
||
|
|
||
|
الآن ، انتقل إلى النصف الأيسر.
|
||
|
|
||
|
![البحث الثنائي 6](https://i.imgur.com/01xetay.jpg)
|
||
|
|
||
|
العنصر الأوسط هو العنصر الذي كنا نبحث عنه!
|
||
|
|
||
|
تأخذ خوارزمية البحث الثنائي مقاربة divide و Conquer حيث يتم تقسيم الصفيف باستمرار حتى يتم العثور على العنصر أو حتى لا يكون هناك عناصر أخرى متبقية للفحص. وبالتالي ، يمكن تعريف هذه الخوارزمية بشكل متكرر لتوليد حل أنيق.
|
||
|
|
||
|
تكون الحالتان الأساسيتان للتكرار:
|
||
|
|
||
|
* لا مزيد من العناصر المتبقية في الصفيف
|
||
|
* تم العثور على العنصر
|
||
|
|
||
|
قوة البحث الثنائي في نظم البيانات (أشجار B +): أشجار البحث الثنائي هي قوية جدا بسبب أوقات البحث O (log n) ، ثانيًا إلى هيكل بيانات hashmap الذي يستخدم مفتاح hasing للبحث عن البيانات في O (1). من المهم أن تفهم كيف يأتي وقت تشغيل السجل n من ارتفاع شجرة البحث الثنائية. إذا تم تقسيم كل عقدة إلى عقدتين ، (ثنائي) ، فإن عمق الشجرة هو log n (base 2) .. من أجل تحسين هذه السرعة في نظام البيانات ، نستخدم أشجار B + لأن لها عامل تفرع أكبر ، و وبالتالي مزيد من الارتفاع. آمل أن تساعد هذه المقالة القصيرة في توسيع نطاق تفكيرك حول كيفية استخدام البحث الثنائي في الأنظمة العملية.
|
||
|
|
||
|
يظهر رمز البحث الثنائي العودي أدناه:
|
||
|
|
||
|
### تطبيق جافا سكريبت
|
||
|
|
||
|
`function binarySearch(arr, item, low, high) {
|
||
|
if (low > high) { // No more elements in the array.
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// Find the middle of the array.
|
||
|
var mid = Math.ceil((low + high) / 2);
|
||
|
|
||
|
if (arr[mid] === item) { // Found the item!
|
||
|
return mid;
|
||
|
}
|
||
|
|
||
|
if (item < arr[mid]) { // Item is in the half from low to mid-1.
|
||
|
return binarySearch(arr, item, low, mid-1);
|
||
|
}
|
||
|
|
||
|
else { // Item is in the half from mid+1 to high.
|
||
|
return binarySearch(arr, item, mid+1, high);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var numbers = [1,2,3,4,5,6,7];
|
||
|
print(binarySearch(numbers, 5, 0, numbers.length-1));
|
||
|
`
|
||
|
|
||
|
في ما يلي تطبيق آخر في جافا سكريبت:
|
||
|
|
||
|
`function binary_search(a, v) {
|
||
|
function search(low, high) {
|
||
|
if (low === high) {
|
||
|
return a[low] === v;
|
||
|
} else {
|
||
|
var mid = math_floor((low + high) / 2);
|
||
|
return (v === a[mid])
|
||
|
||
|
||
|
(v < a[mid])
|
||
|
? search(low, mid - 1)
|
||
|
: search(mid + 1, high);
|
||
|
}
|
||
|
}
|
||
|
return search(0, array_length(a) - 1);
|
||
|
}
|
||
|
`
|
||
|
|
||
|
### تطبيق روبي
|
||
|
|
||
|
`def binary_search(target, array)
|
||
|
sorted_array = array.sort
|
||
|
low = 0
|
||
|
high = (sorted_array.length) - 1
|
||
|
|
||
|
while high >= low
|
||
|
middle = (low + high) / 2
|
||
|
|
||
|
if target > sorted_array[middle]
|
||
|
low = middle + 1
|
||
|
elsif target < sorted_array[middle]
|
||
|
high = middle - 1
|
||
|
else
|
||
|
return middle
|
||
|
end
|
||
|
end
|
||
|
return nil
|
||
|
end
|
||
|
`
|
||
|
|
||
|
### مثال في C
|
||
|
|
||
|
`int binarySearch(int a[], int l, int r, int x) {
|
||
|
if (r >= l){
|
||
|
int mid = l + (r - l)/2;
|
||
|
if (a[mid] == x)
|
||
|
return mid;
|
||
|
if (arr[mid] > x)
|
||
|
return binarySearch(arr, l, mid-1, x);
|
||
|
return binarySearch(arr, mid+1, r, x);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
`
|
||
|
|
||
|
### تنفيذ C / C ++
|
||
|
|
||
|
`int binary_search(int arr[], int l, int r, int target)
|
||
|
{
|
||
|
if (r >= l)
|
||
|
{
|
||
|
int mid = l + (r - l)/2;
|
||
|
if (arr[mid] == target)
|
||
|
return mid;
|
||
|
if (arr[mid] > target)
|
||
|
return binary_search(arr, l, mid-1, target);
|
||
|
return binary_search(arr, mid+1, r, target);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
`
|
||
|
|
||
|
### تنفيذ بايثون
|
||
|
|
||
|
`def binary_search(arr, l, r, target):
|
||
|
if r >= l:
|
||
|
mid = l + (r - l)/2
|
||
|
if arr[mid] == target:
|
||
|
return mid
|
||
|
elif arr[mid] > target:
|
||
|
return binary_search(arr, l, mid-1, target)
|
||
|
else:
|
||
|
return binary_search(arr, mid+1, r, target)
|
||
|
else:
|
||
|
return -1
|
||
|
`
|
||
|
|
||
|
### مثال في C ++
|
||
|
|
||
|
`// Binary Search using iteration
|
||
|
int binary_search(int arr[], int beg, int end, int num)
|
||
|
{
|
||
|
while(beg <= end){
|
||
|
int mid = (beg + end) / 2;
|
||
|
if(arr[mid] == num)
|
||
|
return mid;
|
||
|
else if(arr[mid] < num)
|
||
|
beg = mid + 1;
|
||
|
else
|
||
|
end = mid - 1;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
`
|
||
|
|
||
|
`// Binary Search using recursion
|
||
|
int binary_search(int arr[], int beg, int end, int num)
|
||
|
{
|
||
|
if(beg <= end){
|
||
|
int mid = (beg + end) / 2;
|
||
|
if(arr[mid] == num)
|
||
|
return mid;
|
||
|
else if(arr[mid] < num)
|
||
|
return binary_search(arr, mid + 1, end, num);
|
||
|
else
|
||
|
return binary_search(arr, beg, mid - 1, num);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
`
|
||
|
|
||
|
### مثال في C ++
|
||
|
|
||
|
نهج متكرر!
|
||
|
|
||
|
\`\` \`C ++ - نهج تكراري int binarySearch (int arr \[\]، int start، int int، int x) { إذا (انتهى> = البدء) { int mid = start + (end-start) / 2؛ إذا (arr \[mid\] == x)
|
||
|
عودة منتصف ؛
|
||
|
|
||
|
` if (arr[mid] > x)
|
||
|
return binarySearch(arr, start, mid-1, x);
|
||
|
|
||
|
return binarySearch(arr, mid+1, end, x);
|
||
|
`
|
||
|
|
||
|
} العودة -1 ؛ }
|
||
|
|
||
|
`Iterative approach!
|
||
|
`
|
||
|
|
||
|
C ++ - نهج تكراري int binarySearch (int arr \[\]، int start، int int، int x) { بينما (تبدأ <= النهاية) { int mid = start + (end-start) / 2؛ إذا (arr \[mid\] == x) عودة منتصف ؛ إذا (arr \[mid\] <x) start = mid + 1؛ آخر end = mid - 1؛ } العودة -1 ؛ } \`\` \`
|
||
|
|
||
|
### معلومات اكثر
|
||
|
|
||
|
* [بحث ثنائي (فيديو يوتيوب)](https://youtu.be/P3YID7liBug)
|
||
|
* [البحث الثنائي - CS50](https://www.youtube.com/watch?v=5xlIPT1FRcA)
|