ما هي الخوارزمية؟
عصر الخوارزميات
ثمَّة هالة من الغموض تطوِّق كل ذلك، الأمر الذي ربما يداعب خُيلاء أنصار الخوارزميات. إن وصف «مبرمج» أو «عالم كمبيوتر» يصف المرء بأنه شخصية جديرة بالاحترام، وإن كان وصفًا تقنيًّا نوعًا ما. إلى أي مدًى تفضِّل أن تكون فردًا في جماعةٍ توشك أن تغيِّر كل شيء تقريبًا في حياتنا؟
لا شكَّ أن ثمَّة مغزًى من وصف الخوارزميات بأنها أقرب إلى إله. ففي أغلب الأحيان تكون في منأًى عن المساءلة مثل الآلهة؛ فالأشياء تحدث ليس بسبب قدرة البشر، ولكن لأن مَن قرَّر حدوثها خوارزمية، والخوارزمية فوق مستوى المساءلة. والمجالات التي يمكن أن تتفوَّق فيها الأجهزة التي تعمل بالخوارزميات على الأداء البشري في تزايد؛ لدرجة أن نطاق تفوُّق البشر يبدو في تناقصٍ يومًا بعد يوم، ويعتقد البعض أن اليوم الذي سنرى فيه قدرة أجهزة الكمبيوتر على التفوق على البشر في مجالات المعرفة كافة بات قريبًا.
لكن ثمَّة جانبًا أيضًا لا تتشابه فيه الخوارزميات مع الآلهة على الرغم من أننا لا نراه في كثير من الأحيان. فالخوارزميات لا تظهر نتائجها بالبوح الصريح. نحن نعلم تمامَ العلم القواعدَ التي تتبعها ونوعية الخطوات التي تتخذها. ومهما كانت روعة النتائج، يمكن إرجاعها دومًا إلى بعض العمليات البسيطة. وقد يتفاجأ المستجدون حديثو العهد بالخوارزميات من مدى سهولة تلك العمليات. وهذا لا يقلل من شأن الخوارزميات؛ فمعرفة الطريقة التي يسير بها شيءٌ ما يمكن أن تزيل جزءًا من غموضه. وفي الوقت نفسه، يتيح لنا فهمُ طريقة عمل شيء تقديرَ روعة تصميمه حتى لو لم يَعُد غامضًا.
يقوم هذا الكتاب على فرضية أن الخوارزميات ليست غامضة في الواقع. إنها أدوات تتيح لنا حُسن إنجاز أشياء معينة؛ إنها أنواع محدَّدة من الأدوات الهدفُ منها أن تتيح لنا حلَّ المسائل. وهي بهذا المعنى تعتبر أدواتٍ معرفية؛ ولكنها بذاتها ليست الأدوات المعرفية الوحيدة. فالأعداد والعمليات الحسابية أيضًا من الأدوات المعرفية. وقد استغرق الأمر آلاف السنين حتى طوَّر الإنسان نظامًا للأعداد يسهُل على الأطفال تعلُّمه في المدارس بحيث يمكنهم إجراء العمليات الحسابية التي كان ليستحيل إجراؤها من دون ذلك النظام. لقد صارت إجادة مبادئ علم الحساب من المسلَّمات الآن، ولكن قبل بضعة أجيال، لم يكن يعرفه سوى قلة قليلة من البشر.
بالمثل، ينبغي ألَّا تكون الخوارزميات امتيازًا لقلةٍ قليلة من الصفوة؛ فنظرًا لكونها أدواتٍ معرفية، فإن بإمكان البشر بشتَّى أطيافهم فهْمَها، وليس فقط محترفو الكمبيوتر. إضافة إلى ذلك، «ينبغي» أن يفهم مزيدٌ من الناس الخوارزميات؛ لأن ذلك سيتيح لنا وضعها في منظورها الصحيح؛ أي معرفة ما تقوم به الخوارزميات، وكيف تقوم به، وما الذي يمكن أن نتوقَّعه منها فعليًّا.
إن ما نرمي إليه في هذا الكتاب هو اكتساب معرفةٍ أساسية بالخوارزميات بحيث يمكننا أن نشارك بجزء هادف في الأحاديث عن عصر الخوارزميات. هذا العصر ليس مفروضًا علينا، بل هو من صنْع أيدينا، وقائم على أدواتٍ نحن مَن اخترعناها. ودراسة هذه الأدوات هي موضوع هذا الكتاب. الخوارزميات أدوات رائعة، ومعرفة لمحة عن طريقة تركيبها وعملها يمكن أن يساعدنا في تعزيز طريقة تفكيرنا.
سنبدأ بدحض فكرةٍ مزعجة، وهي أن الخوارزميات تتعلَّق بأجهزة الكمبيوتر. وهذا منطقي — كما سنرى — كقول إن الأعداد مرتبطة بالآلات الحاسبة.
طريقة لإنجاز المهام
أحجية من أحاجي الورقة والقلم، وموسيقى، ومجموعة متنوعة من الأعداد، ومسرِّعات نيوترونات في فيزياء الجسيمات؛ سنرى أن العامل المشترك بين هذه الأشياء جميعًا هو الخوارزمية نفسها، المطبَّقة في تلك المجالات على اختلافها، ولكنها قائمة على المبادئ الأساسية نفسها. كيف يمكن هذا؟
قد يميل المرء إلى الاعتقاد بأن الخوارزميات شيء نقوم به بواسطة أجهزة الكمبيوتر، ولكن هذا الاعتقاد خاطئ. ويُعزى خطؤه إلى أن الخوارزميات كانت موجودة قبل اختراع أجهزة الكمبيوتر بزمن طويل.
نلاحظ في النمط الذي ظهر لنا أنه يتبقى عمودان جهة اليمين. نأخذ العمودين المتبقيين اللذين يشتمل كل واحد منهما على علامة • واحدة، ونضعهما تحت أول عمودين بحيث يشكِّلان صفًّا ثالثًا:
نلاحظ الآن أنه قد تبقى ثلاثة أعمدة. نأخذ العمودين جهة اليمين ونضعهما تحت العمودين جهة اليسار:
الآن، لا يتبقى سوى عمود واحد، ومِن ثَم نتوقَّف هنا. نضع الأعمدة في سلسلة تبدأ من اليسار إلى اليمين كما يلي:
هذا إيقاع الجرس في كولومبيا ومشهور في كوبا وغرب أفريقيا، وإيقاع طبول في كينيا، ويُستخدم في مقدونيا أيضًا. وإذا قلبناه بحيث يبدأ بالبادئة الثالثة أو الرابعة أو الخامسة، تبرز لنا إيقاعاتٌ أخرى شهيرة حول العالم.
هل نخرج بتلك النتيجة مرة واحدة؟ يمكننا أن نحاول إنشاء إيقاع مكوَّن من ١٢ جزءًا من سبعة أصوات بادئة وخمسة أصوات صامتة؛ وهو نوع من عكس الأصوات البادئة الخمسة والأصوات الصامتة السبعة التي أوضحناها من قبل. إذا اتبعنا الإجراء نفسه بحذافيره، فسنخرج بالنتيجة التالية:
وهذا إيقاع أيضًا. ويُستخدم في إيقاع إمبيري المشهور في إقليم أشانتي بغانا، وإذا بدأنا الإيقاع بالبادئة الأخيرة، نراه مستخدَمًا بين جماعة اليوروبا في نيجيريا وكذلك في أفريقيا الوسطى وسيراليون.
لئلا تعتقد أننا نسينا بعض الأماكن الجغرافية، إذا بدأنا بخمسة أصوات بادئة و١١ صوتًا صامتًا، نحصل على النمط التالي:
هذا إيقاع بوسا نوفا مقلوبٌ. يبدأ إيقاع بوسا نوفا الأصلي بالصوت البادئ الثالث؛ ومِن ثَم فالنمط المطابق المثالي له هو:
وإذا بدأنا بثلاثة أصوات بادئة وأربعة أصوات صامتة، فسنحصل على النمط التالي:
هذا الإيقاع مشهور في الوزن الإيقاعي سبعة/أربعة، وليس في الموسيقى التقليدية فقط. وهو النمط الإيقاعي لأغنية بينك فلويد «ماني»، من بين نغمات أخرى:
هذا المثال يبيِّن لنا أن نضع سبعة أصوات بادئة في البداية، منشئين بذلك سبعة أعمدة من الأصوات البادئة، يتبعها الأصوات غير المشددة الخمسة المتبقية من عملية القسمة:
نعيد القسمة مرة أخرى، ولكن هذه المرة نقسم المقسوم عليه في عملية القسمة السابقة وهو العدد ٧، على الباقي في القسمة السابقة نفسها وهو العدد ٥. ويكون ناتج القسمة ١ مرة أخرى، بينما يكون الباقي ٢:
وهذا يعني أن علينا أن نأخذ الأعمدة الخمسة جهة اليمين ونضعها تحت الأعمدة الخمسة جهة اليسار، ونترك الباقي وهما ٢:
نكرِّر الخطوة نفسها: نقسم المقسوم عليه في مسألة القسمة السابقة وهو العدد ٥، على الباقي في القسمة السابقة نفسها وهو العدد ٢. فيكون ناتج القسمة ٢ والباقي ١:
تلك العملية تخبرنا بأن نأخذ «ضعف» العمودين جهة اليمين ونضعهما تحت العمودين جهة اليسار، ونترك الباقي ١:
لاحظ أن كلمة «ضعف» تعني أن هذا يعادل ما كنَّا سنفعله في خطوتين لو اتبعنا طريقة الحل السابقة من دون استخدام عملية القسمة. ومِن ثَم سننتقل من النمط:
إلى النمط التالي أولًا:
ثم إلى النمط:
وإذا جمعنا الأعمدة في سلسلة، فسنحصل على إيقاع إمبيري:
الخوارزمية الأولى
-
(١)
نقسم على سيكون لدينا ناتج القسمة والباقي. إذا عبَّرنا عن ناتج القسمة بالحرف وعن الباقي بالحرف ، فستصبح المسألة بالشكل التالي: . هذه قسمة أعداد صحيحة كما نعرفها. نأخذ ونضربها في عدد الأعمدة جهة اليمين ثم ننقلها تحت الأعمدة جهة اليسار، ونترك باقي الأعمدة جهة اليمين.
-
(٢)
إذا كان الباقي يساوي صفرًا أو واحدًا، نتوقَّف هنا. أما لو كان غير ذلك، فنعود إلى الخطوة ١، ولكن في هذه المرة ستحل قيمة مكان قيمة ، وستحل قيمة مكان قيمة . أو بعبارة أخرى، سنعود إلى الخطوة ١، ونجعل تساوي ، ونجعل تساوي .
إذا أمعنا النظر في الجدول، يمكننا التأكُّد من أن كل صفٍّ يتطابق مع خطوة من خطوات تكوين الصف ونقله، ولكن لدينا تعريف أدق للطريقة التي استخدمناها. في الحقيقة، إن لدينا سلسلة خطوات يمكن إجراؤها بالورقة والقلم، وبذلك تكون هذه أول خوارزمية معنا! إن لدينا خوارزمية لإنشاء أنماط تتطابق مع العديد من الإيقاعات الموسيقية، والحق أنها كثيرة إلى حدٍّ مذهل. فباستخدام أعداد مختلفة من الأصوات البادئة والأصوات الصامتة، يمكننا الحصول على نحو ٤٠ نمطًا إيقاعيًّا توجد في مختلف الإيقاعات الموسيقية حول العالم. وهنا ينبغي أن نتوقَّف قليلًا: إنها خوارزمية بسيطة (تتكوَّن من خطوتين فقط تتكرَّران)، ومع ذلك يمكن أن تفرز العديد من النتائج المذهلة.
- (١) لإيجاد العامل المشترك الأكبر للعددين و، نقسم العدد على العدد . سيعطينا ذلك ناتج قسمة وباقيًا. إذا عبَّرنا عن ناتج القسمة بالحرف وعن الباقي بالحرف ، فستصبح المسألة بالشكل التالي: .
- (٢) إذا كان الباقي يساوي صفرًا، فسنتوقف هنا، وسيصبح العامل المشترك الأكبر للعدد والعدد هو . أما لو كان غير ذلك، فسنعود إلى الخطوة ١، ولكن في هذه المرة ستحل قيمة مكان قيمة وستحل قيمة مكان قيمة . أو بعبارة أخرى، سنعود إلى الخطوة ١، ونجعل تساوي ونجعل تساوي .
تلك هي الخطوات التي اتبعناها بالضبط من قبل. الفرق الوحيد هو أننا عند إيجاد الإيقاعات، نتوقَّف عندما يصبح الباقي ٠ أو ١ في الخطوة الثانية، بينما تتوقَّف خوارزمية إقليدس عندما يكون الباقي صفرًا. إن الأمر سيان في الواقع؛ فإذا كان الباقي يساوي ١، فعند تكرار الخطوة ١ مرة أخرى سيكون الباقي صفرًا؛ لأن أيَّ عدد صحيح يقبل القسمة على ١. لنجرِّب العددين ٩ و٥: ٩ = ١ × ٥ + ٤، ومِن ثَم ننتقل إلى ٥ = ١ × ٤ + ١، ثم إلى ٤ = ١ × ٤ + ٠، وبذلك يكون العامل المشترك الأكبر بين العددين ٩ و٥ هو ١.
- (١)
توضع الخطوات في «تسلسل».
- (٢)
قد تبيِّن الخطوات «اختيارًا» يحدِّد الخطوات التي ينبغي اتباعها. في الخطوة ٢، نجد اختبارًا لمعرفة إذا ما كان الباقي يساوي صفرًا أم لا. ومِن ثَم يصبح لدينا بديلان بناءً على الناتج: إما التوقُّف أو العودة إلى الخطوة ١.
- (٣)
يمكن وضع الخطوات في «حلقة» أو «تكرار» حيث يتكرَّر تنفيذها. في الخطوة ٢، إذا لم يكن الباقي يساوي صفرًا، نعود إلى الخطوة ١.
نطلق على تلك الطرق الثلاث لدمج الخطوات اسم «بنيات التحكُّم»؛ لأنها تملي الإجراء الذي سيُتخذ عند تطبيق الخوارزمية. وجميع الخوارزميات تُبنَى بتلك الطريقة. إنها تتكوَّن من خطوات لإجراء العمليات الحسابية ومعالجة البيانات؛ إذ تُجمع هذه الخطوات معًا وتُصمَّم باستخدام بنيات التحكم الثلاث المذكورة. وكلما زاد تعقيد الخوارزمية، زادت خطواتها وربما زاد تعقيد تصميمها كذلك. لكن بنيات التحكم الثلاث كافية لوصف الطريقة التي ينبغي بها دمج خطوات الخوارزمية معًا.
تعمل خطوات الخوارزمية — من بين أشياء أخرى — بناءً على المدخلات التي نوفِّرها. والمدخلات هي البيانات التي تعالجها الخوارزمية. وإذا اعتمدنا طريقة عرض تتمحور حول البيانات، فسنستخدم خوارزمية لتحويل بعض البيانات — التي تصف مسألةً ما — إلى شكلٍ يتطابق مع حل المسألة.
لقد وجدنا خوارزمية وراء الإيقاعات الموسيقية عبارة عن تطبيق لعملية قسمة، ولكن في الواقع لا داعي إلى الذهاب إلى بعيد؛ فالقسمة في حد ذاتها عبارة عن خوارزمية. حتى إن لم تسمع عن خوارزمية إقليدس، فأنت تعرف كيفية قسمة عددين كبيرين؛ كلنا قضينا بعض الوقت خلال سنوات التعلُّم الأولى في إجراء مسائل ضرب وقسمة مطوَّلة. وقضى معلمونا ساعاتٍ يحفرون طريقةَ حل تلك المسائل في عقولنا: إنها مجموعة خطوات نضع فيها الأعداد في الخانات في المواضع الصحيحة ونجري العمليات الحسابية بها، وتلك هي الخوارزميات. ولكن الخوارزميات ليست مرتبطة بالأعداد فحسب كما رأينا منذ لحظات. فقد اكتشفنا أنها مرتبطة بطريقة إعداد إيقاع موسيقي. ومع ذلك فلا يوجد شيء محيِّر بشأنها. فالإيقاع هو طريقة لتوزيع النبرات في فترة زمنية معينة، وينطبق المبدأ نفسه عند تعبئة الرقائق والجبن.
الخوارزميات وأجهزة الكمبيوتر والرياضيات
قلنا إن الخوارزميات ليست مرتبطة بأجهزة الكمبيوتر، على الرغم من أن الغالبية يربطون بينهما في وقتنا الحالي. صحيح أن الخوارزميات تُظهر إمكانياتها عندما تقترن بأجهزة الكمبيوتر، ولكن الكمبيوتر ما هو في الواقع إلا آلة تملك تلك السمة الخاصة التي تمكننا من إعطائه أوامرَ لإنجاز مهامَّ بعينها. ونحن نعطي تلك الأوامر عن طريق «البرمجة»، وعادةً ما نقوم ببرمجته من أجل تنفيذ الخوارزميات.
هذا التوضيح يقودنا إلى البرمجة نفسها. البرمجة هي نظامٌ لتحويل أهدافنا إلى رموزٍ يستطيع جهاز الكمبيوتر فهْمها. نطلق على تلك الرموز «لغة البرمجة»؛ لأنها في بعض الأحيان تشبه ما نكتبه بلغة بشرية، ولكن لغات البرمجة مسألة بسيطة للغاية مقارنةً بثراء اللغات البشرية وتعقيدها. في الوقت الحاضر، لا يفهم جهاز الكمبيوتر أيَّ شيء بالطبع. قد تتغيَّر الأمور في المستقبل إذا استطعنا أن ننتج آلاتٍ ذكية بحق، ولكن في الوقت الحاضر عندما نقول إن الكمبيوتر يفهم الرموز، فهذا يعني في الحقيقة أن الرموز تتحوَّل إلى سلسلةٍ من التعليمات لمعالجة التيار في الدوائر الإلكترونية (يمكن أيضًا استخدام التيار الخفيف بدلًا من التيار الكهربي، وإن كانت الفكرة واحدة).
البرمجة هي نظامٌ لتحويل أهدافنا إلى رموزٍ يستطيع جهاز الكمبيوتر فهْمها. نطلق على تلك الرموز «لغة البرمجة».
إذا كانت الخوارزمية مجموعة خطوات يمكننا تنفيذها بأنفسنا، فالبرمجة هي النشاط الذي ندوِّن به الخطوات بالرموز التي يفهمها الكمبيوتر. وعندئذٍ يكون الكمبيوتر هو من سيقوم بتنفيذ تلك الخطوات. فأجهزة الكمبيوتر أسرع بكثير من البشر؛ ولذا يمكن أن تنفِّذ الخطوات في وقتٍ أقل. والعامل الأساسي في الحوسبة هو «السرعة». أما من الناحية النوعية، فلا يمكن لجهاز الكمبيوتر أن يفعل أكثر مما يفعله البشر، ولكنه يقوم به على نحوٍ أسرع، بل أسرع كثيرًا. فالخوارزمية تكتسب قوة على الكمبيوتر نظرًا لإمكانية تنفيذها عليه في جزء صغير من الوقت الذي يستغرقه الإنسان كي ينفذ الخطوات نفسها، «لكن في النهاية تظل الخطوات واحدة».
إذا كانت الخوارزمية مجموعة خطوات يمكننا تنفيذها بأنفسنا، فالبرمجة هي النشاط الذي ندوِّن به الخطوات بالرموز التي يفهمها الكمبيوتر.
توفِّر لنا لغة البرمجة طريقةً لوصف خطوات تنفيذ الخوارزميات لجهاز الكمبيوتر. كذلك توفِّر وسيلةً لبناء تلك الخوارزميات باستخدام ثلاث بنيات تحكُّم أساسية وهي: التسلسل والاختيار والتكرار. فنحن نكتب الخطوات ونصف طريقة تصميمها باستخدام المفردات والعبارات التي توفِّرها لغة البرمجة التي نستخدمها.
توجد ميزة إضافية لاستخدام أجهزة الكمبيوتر غير السرعة؛ إن كنت تتذكَّر كيف تعلمتَ طرق حل مسائل الضرب والقسمة المطولة، فستجد أن الأمر ربما استغرق تدريبًا لفترة طويلة، وربما لم يكن مسليًا. وكما أشرنا سلفًا، تُحفر هذه الدروس داخل عقولنا في عمرٍ مبكِّر، وحفر الأشياء في العقل ليس بالأمر السار. أما أجهزة الكمبيوتر فلا تعاني السَّأم؛ ومِن ثَم يكون من الأسباب الأخرى لترك مهمة تنفيذ الخوارزميات لها أن تزيح عنا الملل وتترك لنا وقتًا للقيام بمهامَّ أكثر إثارة ومتعة.
على الرغم من أن الخوارزميات عادة ما تنفَّذ على جهاز كمبيوتر، بعد كتابتها بإحدى لغات البرمجة، فإنها في الأساس مكتوبة للبشر؛ الذين ينبغي أن يفهموا آلية عملها ومتى يمكن استخدامها. وهذا يقودنا إلى شيء أساسي يغفل عنه حتى علماء الكمبيوتر المتمرسون والمبرمجون المحنَّكون. هذا الشيء هو أن الطريقة الوحيدة لفهم الخوارزمية بحق هو تنفيذها يدويًّا. لا بد أن نتمكَّن من تنفيذ الخوارزمية بالطريقة نفسها التي ينفِّذ بها جهاز الكمبيوتر البرنامج الذي يطبِّقها. وفي الوقت الحاضر، نحظى بمجموعة مذهلة من ملفات الوسائط بين أيدينا يمكن أن تساعدنا في التعلم، مثل تطبيقات المحاكاة والرسوم المتحركة ومقاطع الفيديو الرائعة التي يمكن الوصول إليها بضغطة زر واحدة. كل هذا رائع، ولكن عندما يستعصي عليك أمرٌ، احتفظ بالورقة والقلم بجانبك. ينطبق الأمر نفسه على هذا الكتاب. هل فهمت حقًّا طريقةَ إنشاء الإيقاعات؟ هل جرَّبت إنشاء إيقاع؟ هل يمكنك إيجاد العامل المشترك الأكبر بين العددين ٢٥٢ و٢٤؟
- (١)
يجب أن تنتهي الخطوات بعد عدد محدَّد من الخطوات. فلا يمكن لخوارزمية أن تستمر إلى ما لا نهاية. (يمكن لبرنامجٍ أن يعمل بلا انقطاعٍ ما دام جهاز الكمبيوتر الذي يعمل عليه قيد التشغيل. وفي تلك الحالة لا يكون البرنامج تنفيذًا لخوارزمية، بل فقط مجرد عملية حاسوبية.)
- (٢)
يجب أن تكون الخطوات دقيقة بحيث يمكن تنفيذها دون ارتباك أو حيرة.
- (٣)
قد تعمل الخوارزمية على بعض المدخلات؛ كخوارزمية إقليدس التي تعمل على عددين صحيحين.
- (٤)
للخوارزمية بعض النتائج؛ وهذا مجمل الهدف منها: أن تنتج شيئًا يهدف إلى الوصول إلى نتيجة. والنتيجة في خوارزمية إقليدس هي العامل المشترك الأكبر.
- (٥)
يجب أن تكون الخوارزمية فعَّالة. يجب أن يتمكَّن الإنسان من تنفيذ كل خطوة في قدرٍ معقول من الوقت باستخدام الورقة والقلم.
تضمن هذه الخصائص الوصول إلى نتيجةٍ من الخوارزمية. فوجود الخوارزميات يُعزى إلى قيامها بشيء مفيد. توجد خوارزميات عبثية وقد يخترع علماء الكمبيوتر خوارزميات لا فائدة منها، إما على سبيل المزاح أو بالخطأ، ولكننا في الحقيقة مهتمون بالخوارزميات التي تحمل بعض الفائدة لنا. عند العمل بالخوارزميات، لا يكفي أن تبيِّن قدرتها على إنجاز مهمةٍ ما. نريد أن تكون الخوارزمية ذات فائدة عملية، ولذا يجب أن تؤدي إلى نتيجة جيدة.
هنا يكمن فارق جوهري بين الخوارزميات والرياضيات. معظم علماء الكمبيوتر الأوائل كانوا علماء في الرياضيات، وعلم الكمبيوتر يستخدم كمًّا هائلًا من الرياضيات، ولكنه ليس منهجًا رياضيًّا. فعالِم الرياضيات يريد إثبات «نتيجةٍ ما»؛ أما عالِم الكمبيوتر فيريد لتلك النتيجة «أن تؤتي ثمارها».
الخاصية الأولى للخوارزميات هي ضرورة التقيُّد بعددٍ محدَّد من الخطوات. تلك الخاصية ليست دقيقة للغاية. فنحن لا نريد مجرد التقيُّد بعدد محدَّد من الخطوات. بل نريد عددًا قليلًا من الخطوات يكفي لتنفيذها عمليًّا، بحيث تنتهي الخوارزمية في غضون فترة زمنية معقولة. وهذا يعني أن مجرد التوصُّل إلى خوارزمية غير كافٍ؛ بل يجب أن تكون فعَّالة من المنظور العملي. لنضرب مثالًا كي نوضِّح الفرق بين معرفة الشيء ومعرفة طريقة عمل الشيء بكفاءة. تخيَّل أن لدينا شبكة كالتالية:
نريد إيجاد أقصر مسار من الركن العلوي جهة اليسار إلى الركن السفلي جهة اليمين من دون المرور على مكان واحد مرتين. طول كل مسار يساوي عدد الخطوط التي تربط بين النقاط على الشبكة. توجد هنا طريقة واحدة للقيام بذلك وهي: إيجاد جميع تلك المسارات، وقياس طول كل مسار، واختيار أقصرها، أو اختيار أيٍّ من المسارات الأقصر طولًا حال وجود أكثر من واحد. إجمالي عدد المسارات يساوي ١٢، كما نرى فيما يلي:
توجد ستة مسارات بطول ٤، ومِن ثَم يمكننا اختيار أي مسار منها.
إن طريقة عدِّ جميع المسارات واختيار المسار الأقصر منها صحيحةٌ بلا شك، وستعطينا المسار الأقصر دائمًا — أو أيًّا من المسارات الأقصر إذا كان هناك عدد من المسارات المتساوية القصر — ولكن تلك الطريقة ليست عملية بالتأكيد. كما أنها ليست مفيدة على الإطلاق؛ إذ توجد خوارزميات ستوجِد أقصر مسار دون الاضطرار إلى عدِّ كل المسارات المحتملة، ومِن ثَم توفِّر قدرًا كبيرًا من الوقت، وتتيح لنا التعامل مع الشبكات مهما كان حجمها. ففي الشبكة التي تتكوَّن من ٢٦ × ٢٦ نقطة، يصل عدد الخطوات اللازمة للحصول على الإجابة إلى مئات تقريبًا؛ سنرى ذلك في الفصل التالي.
إن السؤال عن ماهية الخوارزمية العملية وبأي معنًى تكون الخوارزمية عملية أكثرَ من غيرها هو من صميم أي تطبيق للخوارزميات. وسنرى على مدى ما تبقى من الكتاب أنه كثيرًا ما توجد خوارزميات مختلفة لحل مسألة واحدة، ونحن مَن نختار الخوارزمية الأنسب للتطبيق في كل موقف بعينه. فمثل جميع الأدوات، بعض الخوارزميات تكون أنسب لحالاتٍ معينة من غيرها. ولكن على خلاف العديد من الأدوات الأخرى، نمتلك طريقة محدَّدة لتقييم مزايا الخوارزميات.
قياس الخوارزميات
عندما نبحث في خوارزمية لحل مسألة ما، نرغب في معرفة الكيفية التي ستقوم بإجراء المسألة من خلالها. ودائمًا ما تكون السرعة عاملًا مهمًّا في هذا الشأن. فنحن نستخدم الخوارزميات على الكمبيوتر لإنجاز المهام أسرع من الإنسان.
مع تحسُّن العناصر المكوِّنة لجهاز الكمبيوتر، عادةً ما لا نكتفي بمعرفة طريقة عمل البرنامج الذي ينفِّذ خوارزمية ما على كمبيوتر معيَّن. فقد يكون جهاز الكمبيوتر الخاص بنا أسرع أو أبطأ من الكمبيوتر الذي قيست عليه الخوارزمية، وبعد مرور بضع سنوات، لن يكون لقياسات الخوارزميات على الأجهزة القديمة أي أهمية سوى الأهمية التاريخية. نحن بحاجة إلى معرفة مدى جودة أداء الخوارزمية بعيدًا عن مكوِّنات الكمبيوتر.
لكن ينبغي أن ينعكس حجم المسألة التي نحاول حلها في طريقة قياس أداء الخوارزمية. فنحن في الحقيقة لا يهمنا الوقت المستغرق في ترتيب ١٠ عناصر؛ فبإمكاننا أن نفعل ذلك بأيدينا على أي حال. بل يهمنا الوقت المستغرق في ترتيب مليون عنصر أو أكثر. نحن نريد مقياسًا لتوقعنا لأداء الخوارزمية في المسائل غير التافهة.
وفي سبيل ذلك، نحتاج إلى طريقةٍ لتحديد حجم المسائل التي تُغذَّى بها الخوارزمية. ويتفاوت بُعد الأهمية بين مختلف المسائل. فإذا أردنا فرز عدد من العناصر على الكمبيوتر، فالبعد المهم هو عدد العناصر التي نريد فرزها (وليس حجم العناصر أو تكوينها مثلًا). وإذا أردنا ضرب عددين، فالبعد المهم هو عدد الأرقام في العددين (هذا البُعد يهم الإنسان أيضًا؛ لأن السبب في «طول» عملية الضرب المطولة راجع إلى اعتمادها على عدد الأرقام في كل عدد من العددين). عندما ندرس مسألة ونُرشِّح خوارزمية لحلها، فإننا نفعل ذلك دومًا واضعين في الاعتبار حجم المسألة.
يرتبط الوقت الذي تحتاج إليه الخوارزمية بما تتسم به من «تعقيد حسابي». والتعقيد الحسابي للخوارزمية هو مقدار الموارد اللازمة كي تعمل. يوجد نوعان أساسيان من الموارد هنا هما: الوقت، أي المدة التي تستغرقها الخوارزمية، والمساحة، أي السعة اللازمة لها في ذاكرة التخزين الخاصة بالكمبيوتر.
سنركِّز في الوقت الحالي على الوقت. نظرًا لتنوُّع أجهزة الكمبيوتر تبعًا لتنوُّع مواصفات الأداء فيها؛ فالحديث عن الوقت الذي تستغرقه الخوارزمية لكي تعمل على جهاز كمبيوترٍ معيَّن قد يعطينا مؤشرًا لما يفترض أن نتوقَّعه عند تشغيلها على أجهزة كمبيوتر أخرى، ولكننا نريد شيئًا أعمَّ. تعتمد سرعة الكمبيوتر على الوقت الذي يستغرقه في إجراء عمليات أساسية. ولتجنُّب مثل تلك التفاصيل، سنختار الحديث عن «عدد العمليات» اللازمة لتشغيل خوارزمية ما، وليس عن الوقت الفعلي الذي تستغرقه الخوارزمية على كمبيوتر معيَّن لإجراء تلك العمليات.
بعد التوضيح، يُرجى العلم أننا سنسيء استعمال المصطلحات قليلًا ونعامل لفظة «العمليات» ولفظة «الوقت» باعتبارهما مترادفتين. على الرغم من ضرورة التزام الدقة عند القول إن الخوارزمية تتطلب «العدد س من العمليات»، سنقول أيضًا إن الخوارزمية تستغرق «المدة س من الوقت» للإشارة إلى أنها تعمل في المدة اللازمة لتنفيذ العدد س من العمليات على أي كمبيوتر تعمل عليه الخوارزمية فعليًّا. وعلى الرغم من تفاوت الوقت الفعلي المطلوب باختلاف مكوِّنات الكمبيوتر، فإن هذا لا يهم عندما نريد المقارنة بين خوارزميتين تعملان في «الوقت س» و«الوقت ص» على جهاز الكمبيوتر «نفسه» بغض النظر عن مواصفاته.
نعود الآن إلى حجم المسألة المدخلة إلى الخوارزمية. بما أننا مهتمون بالمسائل غير التافهة، فلن نأبه بما يحدث مع المسائل الصغيرة الحجم. بل سنهتم بما يحدث في المسألة بمجرد الوصول إلى حجم معيَّن. لن نحدد حجم تلك المسائل بالضبط، ولكننا سنفترض دومًا أنها كبيرة.
-
إذا كنت تريد البحث عن شيء في سلسلة عناصر — يوجد عدد من العناصر — وسلسلة العناصر ليست مرتَّبة بأي صورة، فإن التعقيد يساوي . وهذا يعني، بالنسبة إلى العدد من العناصر، أن الوقت اللازم لإيجاد عنصر معيَّن في تلك السلسلة لن يزيد على مضاعف ضرب عدد العناصر.
-
إذا كنت تريد ضرب عددين مكوَّنين من من الأرقام باستخدام عملية ضرب مطولة، فإن التعقيد يساوي . وهذا يعني أن الوقت اللازم لإنجاز عملية الضرب لن يزيد على مضاعف مربع حجم العددين.
ستساعدنا تلك الأمثلة في تقدير المزايا النسبية لخوارزمياتٍ معينة سنتناولها فيما تبقَّى من هذا الكتاب. وعلى الرغم من إمكانية وجود خوارزميات — من الناحية النظرية — تنطوي على أي نوع من التعقيد، فإن الخوارزميات التي نتعامل معها عادةً ما تندرج تحت عدد قليل من المجموعات المختلفة.
فئات التعقيد
تُعتبر اللوغاريتمات في بعض الأحيان الحد الفاصل بين الرياضيات للجميع والرياضيات للمبتدئين؛ حتى الاسم تحوطه هالةٌ من عدم الفهم. إذا بدت اللوغاريتمات غامضة بعض الشيء، فعليك أن تتذكَّر أن لوغاريتم العدد هو معكوس رفع العدد إلى قوة أسية. فكما في رفع العدد إلى قوة أسية تكرار لعملية الضرب، فإن في تناول لوغاريتم ما تكرارًا لعملية القسمة.
1000000 | 1000 | 100 | 10 | 1 | |
19.93 | 9.97 | 6.64 | 3.32 | 0 | |
1.9 × 107 | 9965.78 | 664.39 | 33.22 | 0 | |
1012 | 1000000 | 10000 | 100 | 1 | |
1018 | 109 | 1000000 | 1000 | 1 | |
1 | |||||
10105.5 | 10301 | 1.3 × 1030 | 1024 | 2 | |
10106.7 | 4 × 102567 | 9.33 × 10157 | 3628800 | 1 |