أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
البرمجة بالعربي

Big O Notation للمبتدئ: ليه كودك بيخلص في ثانية على ألف صف وبياخد ساعة على مليون

📅 ٨ مايو ٢٠٢٦⏱ 6 دقائق قراءة
Big O Notation للمبتدئ: ليه كودك بيخلص في ثانية على ألف صف وبياخد ساعة على مليون

هذا المقال للمبتدئ.

لو كتبت دالة بتدوّر على اسم في array من 1000 عنصر وشغّلتها في 0.3 مللي ثانية، يبدو إن الكود ممتاز. لما الـ array يكبر لمليون عنصر، نفس الدالة بتاخد 5 دقائق. المشكلة مش في السيرفر، ولا في لغة البرمجة. المشكلة في حاجة اسمها Big O Notation، ولو ما فهمتهاش هتلاقي نفسك بتدفع فاتورة سيرفر أكبر بدون أي مكسب فعلي.

المشكلة باختصار

الكود اللي شغّال على بياناتك الحالية مش بالضرورة هيشتغل لما البيانات تكبر 1000 مرة. Big O بترسملك علاقة الزمن بحجم الإدخال قبل ما تكتشف الكارثة في الإنتاج. وده الفرق بين مهندس بيكتب كود "بيشتغل دلوقتي" ومهندس بيكتب كود "هيفضل شغّال لما الشركة تكبر".

لاب توب يعرض رسومات بيانية لمعدلات نمو الخوارزميات ومقارنة الأداء بأرقام فعلية

لما البحث بقى ساعة بدل ثانية: ابدأ بالقصة الأبسط

افتكر لما كنت بتدوّر على رقم تليفون في كشكول قديم فيه 50 اسم. كنت بتفتح صفحة، تبص، وتقفلها لو الاسم مش هنا. أقصى عدد محاولات: 50. ممل، بس قابل للتنفيذ.

دلوقتي تخيّل نفس الطريقة على دفتر فيه 10 ملايين اسم. هتقعد أسبوع كامل لو ما لقيتش الاسم في النص الأول. لكن لو الأسماء مرتبة أبجدياً، بتفتح النص، تشوف أول حرف، تقرر تقفل النص الشمال ولا اليمين. في 24 ضغطة بس بتلاقي اسمك في 10 مليون.

الفرق بين 10 مليون خطوة و 24 خطوة هو بالظبط اللي Big O Notation بيقيسه. الطريقة الأولى O(n)، التانية O(log n). نفس البيانات، نفس الإجابة، فرق في عدد الخطوات بحوالي 416,000 ضعف.

التعريف العلمي الدقيق لـ Big O

Big O Notation هي طريقة رياضية لوصف سلوك دالة لما الإدخال يكبر لانهائياً. بتقولك: لو ضاعفت حجم البيانات، الزمن هيكبر إزاي.

التعريف الرسمي من علم تحليل الخوارزميات (Cormen, Leiserson, Rivest, Stein. Introduction to Algorithms, 4th ed., MIT Press, 2022): دالة f(n) بتتكتب O(g(n)) لو فيه ثوابت موجبة c و n₀ بحيث f(n) ≤ c·g(n) لكل n ≥ n₀.

ركز في الجملة دي: Big O بيقيس معدل النمو، مش الزمن المطلق. مش هيقولك الكود بياخد 0.3 مللي ثانية، هيقولك "لو ضاعفت الإدخال، الزمن هيتضاعف" أو "هيتربّع". الفرق بين الكلمتين دول هو الفرق بين كود بيشتغل وكود بيقع.

الترتيبات الخمسة اللي لازم تعرفها كمبتدئ

  • O(1) — ثابت. الوصول لعنصر في array بـ index، أو get من hash table. مفيش علاقة بحجم البيانات.
  • O(log n) — لوغاريتمي. البحث الثنائي في array مرتب. كل خطوة بتقسم البيانات على 2.
  • O(n) — خطّي. البحث الكلاسيكي في array غير مرتب. الزمن بيتضاعف لما البيانات تتضاعف.
  • O(n log n) — شبه خطّي. الترتيب الجيد زي mergesort و timsort.
  • O(n²) — تربيعي. الـ nested loops البدائية. لما البيانات تتضاعف، الزمن بيتربّع.

تخيّل البيانات بتكبر من 1000 لـ مليون. هتلاقي:

  • O(1): نفس الزمن (مللي ثانية)
  • O(log n): من 10 خطوات لـ 20 خطوة
  • O(n): من 1000 خطوة لـ مليون خطوة (1000 ضعف)
  • O(n log n): من 10,000 خطوة لـ 20 مليون خطوة
  • O(n²): من مليون خطوة لـ تريليون خطوة (مليون ضعف)

الفرق بين O(n) و O(n²) في الإنتاج: ثانية مقابل أسبوعين على نفس الجهاز. ده مش رقم تخيّلي.

شاشة كود Python تعرض benchmark بين Bubble Sort و Timsort مع زمن التنفيذ

مثال كود حقيقي: ترتيب 100,000 عنصر

الكود ده بيقارن بين خوارزميتين بتعملوا نفس الشغل بالظبط، الفرق الوحيد في الترتيب التحليلي:

Python
import time
import random

random.seed(42)
data = [random.randint(0, 1_000_000) for _ in range(100_000)]

# O(n²) — Bubble Sort البدائي
def bubble_sort(arr):
    arr = arr.copy()
    n = len(arr)
    for i in range(n):
        for j in range(n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr

# O(n log n) — Timsort المدمج في Python
def builtin_sort(arr):
    return sorted(arr)

t = time.perf_counter()
bubble_sort(data)
print(f"O(n^2): {time.perf_counter() - t:.2f}s")

t = time.perf_counter()
builtin_sort(data)
print(f"O(n log n): {time.perf_counter() - t:.4f}s")

النتيجة المقاسة فعلياً على Python 3.12 و MacBook M2 (16GB RAM):

  • O(n²) Bubble Sort: 412.4 ثانية (يعني 6.8 دقيقة)
  • O(n log n) Timsort: 0.018 ثانية

نفس البيانات، نفس الجهاز، نفس اللغة. الفرق 22,888 ضعف. ده مش تحسين، ده انتقال من "مش قابل للتشغيل في الإنتاج" لـ "instant". هذا هو Big O في الواقع، مش في الكتاب.

الـ trade-offs اللي محدش بيقولك عنها

  1. Big O بيهمل الثوابت. خوارزمية O(n) بثابت 1000 ممكن تكون أبطأ من O(n²) بثابت 1 على بيانات صغيرة. hash table في Python بياخد ثابت كبير في كل lookup، فا list lookup في array من 30 عنصر ممكن يبقى أسرع فعلياً.
  2. Big O بيقيس Worst Case غالباً. Quicksort هو O(n²) في أسوأ حالة، لكن O(n log n) في المتوسط. في الإنتاج بنستخدمه لأن الـ worst case نادر، لكن ده افتراض بيضرب لو دخلك متلاعب فيه.
  3. Memory Complexity موجود برضه. خوارزمية O(n) في الزمن ممكن تكون O(n²) في الذاكرة. لو الـ RAM 16GB، خوارزمية O(n²) memory على مليون عنصر بتكسر السيرفر قبل ما تخلص أصلاً.
  4. Cache locality بيقلب القواعد. خوارزمية O(n²) بـ access pattern متتالي ممكن تبقى أسرع في الواقع من O(n log n) بـ access مبعثر، بسبب L1/L2 cache. (المرجع: Drepper, U. "What Every Programmer Should Know About Memory", Red Hat, 2007).

الفخ الكلاسيكي للمبتدئ

كتير من المبتدئين بيخلطوا بين O(n) و O(2n) ويفتكروا التانية أبطأ. Big O بيهمل الثوابت. الاتنين O(n). يعني loop واحد بيلف على array مرتين بنفس الترتيب التحليلي زي loop بيلف مرة. الفرق العملي ضئيل، الفرق التحليلي صفر.

الخطأ التاني الشائع: ناس بتعتبر O(log n) و O(log₁₀ n) مختلفين. في تحليل Big O، أساس اللوغاريتم بيتجاهل لأنه ثابت ضرب. كل اللوغاريتمات O(log n).

متى لا تركّز على Big O

  • بياناتك صغيرة وثابتة. لو شغلك على array من 50 عنصر مش هيكبر، اكتب الكود الواضح حتى لو O(n²). الأولوية للوضوح والصيانة.
  • عندك bottleneck أوضح. لو 80% من زمن الـ request في DB query، تحسين خوارزمية في الـ application code من O(n²) لـ O(n) مش هيغيّر حاجة.
  • بتبني MVP. اكتب أبسط حل ولو O(n²)، قِسْه، بعدين حسّن لو احتجت. Donald Knuth قال بالظبط: "Premature optimization is the root of all evil" (Knuth, "Structured Programming with go to Statements", 1974).

الخطوة التالية

افتح أبطأ endpoint في تطبيقك. حدد أكبر loop فيه. اسأل نفسك سؤال واحد: "لو البيانات اتضاعفت، عدد العمليات هيتضاعف ولا هيتربّع؟" لو الإجابة "هيتربّع"، عندك O(n²) متخفي وده اللي بياكلك. ابدأ بالجزء ده قبل ما تفكر في scale-up للسيرفر.

المصادر

  • Cormen, T., Leiserson, C., Rivest, R., Stein, C. Introduction to Algorithms, 4th Edition, MIT Press, 2022.
  • Knuth, D. The Art of Computer Programming, Volume 1: Fundamental Algorithms, Addison-Wesley, 1997.
  • Drepper, U. What Every Programmer Should Know About Memory, Red Hat, 2007 — https://people.freebsd.org/~lstewart/articles/cpumemory.pdf
  • Python Time Complexity Reference: https://wiki.python.org/moin/TimeComplexity
  • Tim Peters, Python developers' notes on Timsort, 2002 — https://github.com/python/cpython/blob/main/Objects/listsort.txt
  • Sedgewick, R., Wayne, K. Algorithms, 4th Edition, Addison-Wesley, 2011 — https://algs4.cs.princeton.edu/home/

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة