الفصل التاسع

Medians and Order Statistic

مقدمة 
في الفصل ده هنتعرض لمشكلة متشابهة مع مشكلة ال sorting الى حد كبير, المشكلة دي هي مشكلة ال Selection , وبنعرف مشكلة ال selection باستخدام ال Order statistic , في الاول يعني ايه Order statistic? او السؤال بشكل أصح يعني ايه ith order statistic لمجموعة عناصر , ببساطة كدة ال ith order statistic لمجموعة عناصر(غير مرتبة) عددها n هو العنصر اللي فيه عدد عناصر i-1 فقط قيمتهم أقل منه في مجموعة العناصر دي, أو تقدر تقول بعد ترتيب مجموعة العناصر دي هو العنصر اللي ترتيبه i فيهم. يعني كمثال لمجموعة العناصر x:
x = {10, 23, 1, 65, 14, 95, 230}
5th order statistic = 65
لان بعد ترتيب المجموعة x هتبقى:
x` = {1, 10, 14, 23, 65, 95, 230}
العنصر 65 ترتيبه الخامس او فيه 4 عناصر فقط قيمتهم أقل منه في المجموعة , وبالتالي هو ال 5th order statistic.

معنى كدة ان ال 1st order statistic هو اللي بنسميه ال Minimum أو العنصر صاحب أقل قيمة في المجموعة , وأن ال nth order statistic هو اللي بنسميه ال Maximum أو العنصر صاحب أكبر قيمة في المجموعة , فيه حاجة تالتة بنسميها ال Median (الوسيط) وهو العنصر اللي بيقسم مجموعة العناصر ل 3 مجموعات أول مجموعة فيها كل العناصر اللي قيمتها أقل من قيمة ال Median وتاني مجموعة هي المجموعة اللي فيها ال Median فقط وتالت مجموعة فيها كل العناصر اللي قيمتها أكبر من ال Median , يعني كمثال المجموعة x :
x = {10, 23, 1, 65, 14, 95, 230}
Median(x) = 23
لان ال 23 قسم المجموعة ل 3 مجموعات :
x = {1, 10, 14} + {23} + {65, 95, 230}
ال median لمجموعة عدد عناصرها n هو قيمة واحدة لو n عدد فردي وقيمتين بنسميها upper median و lower median لو n زوجي, في حالة الفردي الupper median = lower median
ال median ممكن يتعرف ب ال order statistic كالتالي :
lower median i = ⌊(n + 1) / 2⌋
upper median i = ⌈(n + 1) / 2⌉
المثال اللي فات x كان فيها 7 عناصر يعني n فردي وبالتالي ال lower = upper وهو ال 4th order statistic لان
(n + 1) / 2⌋ = ⌈(n + 1) / 2⌉ = 7 + 1 / 2 = 8 / 2 = 4
لو شفنا مثال لمجموعة عدد عناصرها زوجي:
y = {50, 6, 25, 13, 652, 12, 32, 10} n = 8
y` = {6, 10, 12, 13, 25, 32, 50, 652}

lower median i = ⌊(n + 1) / 2⌋ = ⌊8 + 1 / 2⌋ = ⌊9 / 2⌋ = 4
upper median i = ⌈(n + 1) / 2⌉ = ⌈8 + 1 / 2⌉ = ⌈9 / 2⌉ = 5

lower median = 4th order statistic = 13
upper median = 5th order statistic = 25

ال Minimum وال Maximum وال Median هي measures (قياسات) بتساعدنا نوصف البيانات , يعني مثلا لو عندك بيانات عبارة عن مرتبات موظفين , ممكن أعلى مرتب أو أقل مرتب أو الوسيط للمرتبات يمثل وصف مفيد.

كدة ممكن نعرف مشكلة الـ selection كالتالي:
الدخل : مجموعة عناصر غير مرتبة عدد عناصره n , ورقم i حيث i قيمته بين الـ 1 وال n
الخرج : عنصر من مجموعة العناصر فيه عدد i - 1 من العناصر فقط في المجموعة أقل منه (ith order statistic)

Minimum and Maximum 
في السكشن ده عايزين نشوف ازاي ممكن نجيب الـ Minimum أو الـ Maximum لمجموعة عناصر عدد عناصرها n , لو عايزين نجيب ال Minimum بسهولة ممكن افترض مبدأيا ان اول قيمة هي ال minimum واخزنها واعدي على باقي عناصر المجموعة اقارن كل عنصر مع ال minimum لو العنصر ده اقل من ال minimum اخزنه هو وفي الاخر ارجع ال minimum اللي وصلتله.
لو هنجيب ال maximum التغيير اللي هنعمله بس هو بدل علامة اصغر من في سطر 3 هستخدم اكبر من واغير اسم المتغير ل max علشان المعنى. طبعا واضح ان ال running time بتاع ال algorithm ده عبارة O(n) , وعدد ال comparisons اللي بنعملها هي n - 1.
Simultaneous minimum and maximum 
لو عاوز أجيب ال minimum وال maximum في نفس ال algorithm ممكن أعمل متغيرين min و max والاتنين اساويهم بأول عنصر وأعدي على باقي العناصر , كل عنصر أقارنه بال min وال max وأعدل , وفي الاخر ارجع ال min وال max في array او structure او whatever حسب لغة البرمجة اللي بتستخدمها. هنا برده ال running time عبارة عن O(n) وعدد ال comparisons بيساوي 2n - 2 . هل فيه طريقة أفضل؟

ممكن بدل مبقارن عنصر عنصر أقارن عنصرين عنصرين , بمعنى انا معايا قيمة لل min وقيمة لل max ممكن اعدي على العناصر Pairs عنصرين عنصرين , في كل مرة اقران العنصرين دول واحدد مين الاكبر فيهم واقرانه مع الـ max والاصغر منهم اقارنه مع الـ min وبالتالي انا عملت 3 comparisons بس لكل عنصرين وفي الـ algorithm الاول العادي كنت بعمل 4 comparisons لكل عنصرين وبالتالي في الحالة التانية عدد الـ comparisons الكلي هيكون:
  • في حالة ان n عدد زوجي هقارن اول عنصرين ببعض واحدد مين فيهم الـ max ومين الـ min وبعدبن اعدي على باقي العناصر , كل عنصرين هعمل عليهم 3 comparisons , وبالتالي مجموع عدد الـ comparisons هيساوي:
1 + 3 * (n/2 - 1) = 3 * n/2 - 2
  • في حالة ان n عدد فردي هنساوي الـ min وال max باول عنصر واعدي على باقي العناصر , كل عنصرين هعمل عليهم 3 comparisons , وبالتالي مجموع عدد الـ comparisons هيساوي: 
3 * ⌊n/2⌋ 

وده
imlementation بلغة الـ c لل 4 algorithms اللي شفناهم لغاية دلوقتي:

Selection in expected linear time 
طبعا مشكلة الـ selection ممكن تتحل بسهولة باستخدام ما يسمى بال naive algorithm (وكلمة naive معناها ساذج) من خلال انك ترتب مجموعة العناصر في الاول باستخدام أي sorting algorithm وبعدين ترجع العنصر الـ index بتاعه i لانه بعد الترتيب الـ ith order statistic بيكون موجود في الـ index i (ده في حالة الـ 1-based index) , الـ running time بتاع الـ naive algorithm هو الـ running time بتاع الـ sorting algorithm , وبما ان أقل running time ل sorting algorithm بيشتغل بدون أي assumptions على الـ input هو الـ O(nlgn) زي الـ quick_sort وال merge_sort وال heap_sort فهو ده الـ running time بتاع الـ naive algorithm.

بس هل احنا محتاجين نرتب مجموعة العناصر كلها علشان نجيب الـ ith order statistic؟ في الحقيقة لأ مش محتاجين ودلوقتي هنشوف algorithm بيشتغل في average(expected) case running time عبارة عن O(n) أو linear ولكن في worst case running time عبارة عن O(n2) ولكن علشان هو randomized فنقدر نقول ان مفيش input محدد يقدر يخلي الـ algorithm في الـ worst case , وبالتاالي احتمالية انه يشتغل في الـ worst case ضعيفة جدا جدا. الـ algorithm اسمه Randomized_Select وهو مبني على الـ Randomized_Quicksort (الفصل السابع), لو نفتكر في الـ randomized_quicksort كنا بنعتمد على الـ Randomized_Partition subroutine , نفس الـ procedure هنستخدمه في الـ Randomized_Select ولكن بعد منعمل partition هنشوف الـ index بتاع الـ pivot ومن خلاله هنعمل recursion مع جزء واحد بس(الـ pivot بيقسم المجموعة لجزئين) الجزء اللي فيه العنصر اللي احنا عايزينه , يعني كمثال لو احنا عايزين الـ 33th order statistic وعملنا randomized_partition رجعلنا الـ pivot الـ index بتاعه 50 فانا مش محتاج اعمل اي حاجة على العناصر اللي في الجزء اللي فوق الـ pivot , انا متأكد ان العنصر اللي انا عايزه موجود في الجزء اللي تحت الـ pivot.


  • الـ algorithm بياخد دخل عبارة عن : A وهي الـ array اللي فيها العناصر, p الـ index اللي بيحدد بداية الجزء بتاع الـ call الحالي, r الـ index اللي بيحدد نهاية الجزء بتاع الـ call الحالي, i هو اللي بيحدد الـ ith order statistic اللي انا عايزه في مجموعة العناصركاملة.
  • سطر 1 بي check لو الـ p = r يعني الـجزء الحالي فيه عنصر 1 اذا (سطر 2) رجعه هو اللي انا بدور عليه.
  • سطر 3 اعمل partition وخز index الـ pivot في q.
  • سطر 4 احسب عدد عناصر المجموعة اللي اقل من الـ  pivot زائد 1 وخزنها في k.
  • سطر 5 قارن الـ i بال k لو بيساوو بعض يبقى (سطر 6) رجع العنصر اللي بيشاور عليه الـ pivot (لان معنى ان i بتساوي الـ  k ان الـ pivot فيه عدد i - 1 عناصر اقل منه وبالتالي هو اللي انا عايزه).
  • سطر 7 لو i اصغر من الـ k يبقى (سطر 8) recursively نادي على نفس الـ algorith بس مع الجزء اللي اقل من الـ pivot و i مش هيتغير.
  • سطر 9 لو i اكبر من الـ k يبقى recursively نادي على نفس الـ algorithm مع الجزؤ اللي اكبر من الـ pivot بس غير الـ i لان بالنسبة للجزء الاكبر من الـ pivot الـ order بتاع i  اتغير , بمعنى انك لو بتدور على 35th order statistic وال pivot بتاعك طلع 25 فترتيب الـ 35th في الجزء الاكبر من الـ pivot (فوق الـ 25) هو الـ 11th.
وده implementation لل Randomized_Select بلغة الـ C:


عايزين نعمل analysis لل algorithm بشكل informal بدون maths , الـ running time بتاع الـ algorithm بيعتمد على الـ partitioning , لو الـ partitioning بيتم بشكل stable مثلا 1 : 9 وكل مرة الـ i بيقع في الجزء الكبير هنعبر عن الـ running time بال recurrence ده:
T(n) = T(9/10 n) + O(n)

طبعا باستخدام الـ master theorem الحالة التالتة الحل هيكون O(n) , حتى لو الـ partitioning عبارة عن 1:99 هيبقى بنفس الناتج أول أي constant partitioning زي مشفنا في الـ Quicksort. أما الـ worst case بتحصل في حالة ان دايما الـ partition بينتج جزء فاضي وجزء فيه n - 1 عنصر في الحالة دي بس هنكون في الـ worst case ودي حالة احتمالها ضعيف جدا جدا جدا.

Selection in worst-case linear time 

دلوقتي هنشوف Selection algorithm بيشتغل في الـ worst-case في O(n) , هو مجرد تعديل على الـ Randomized_Select , المشكلة في الـ randomized_select اللي مخلياه بيشتغل في O(n) في الـ expected case مش الـ worst case هو اننا مش قادرين نضمن ان الـ partitioning stable , الفكرة هنا ان انا هنختار مسبقا الـ pivot اللي يخلي الـ partitioning يكون stable ونبعته ك argument لل partition procedure وهو يعمل partition استخدام الـ pivot ده فيكون stable , الـفكرة هنا ان احنا نجيب الـ pivot ده في linear time علشان الناتج يكون linear.
كل اللي غيرناه هو سطر 3 و 4 , احنا بنحسب في الاول الـ median وبعدينه نبعته لل partition procedure علشان يعمل partition عليه وبالتالي نضمن انه stable.
  • محتاجين طريقة نجيب بيها الـ median تكون linear time؟ ممكن نقسم الـ array لمجموعات كل مجموعة فيها بحد أقصى 5 عناصر وبعدبن نرتب كل مجموعة باستخدام الـ insertion sort (لانه سريع مع دخل قليل) ونجيب الـ median بعد ترتيبها بسهولة, بعد كدة ن call نفس الـ algorithm وال recurrence الناتج هيكون linear.
  • ازاي نعمل partition باستخدام الـ median? انت هيجيلك الـ median ت iterate في الاول على الـ array لغاية متوصله بعدين تعمله swap مع اخر عنصر في الـ array وت call الـ partition procedure العادي اللي شفناه في الفصل السابع(دي طريقة ممكن تشوف طريقة أحسن).

 
وده Implementation لل Quick_select algorithm بلغة الـ C:
 
 
 


 


 
 

تعليقات

المشاركات الشائعة من هذه المدونة

الفصل الرابع

الفصل السادس

الفصل الثاني عشر