• الإعلانات

    • فيصل الحربي

      تسجيل عضوية جديدة في المنتدى   01/31/2016

      السلام عليكم ورحمة الله وبركاته  عزيزي العضو الجديد :  حاليا رسالة الإيميل لتأكيد صحة إيميلكم تذهب للبريد العشوائي ( جاري حل المشكلة )  فإذا لم تجد رسالة التحقق من إيميلكم في صندوق الوارد لديكم إتجه للبريد العشوائي ( JUNK)  وقم بتفعيل إشتراككم من هناك   

البحث في المنتدى

Showing results for tags 'Tutorial'.

  • البحث بالتاقات

    اكتب الكلمات المفتاحيه بينها علامه الفاصله
  • البحث بكاتب الموضوع

تم إيجاد 11 نتيجة

  1. JavaFX

      بسم الله الحمد لله علي عودة منتدانا الحبيب الذي لايعوض غيابه أي شئ :)  اقدم لكم اليوم رابط لدورة رائعة وسريعة لتقنية JavaFX البديلة ل Swing لانشاء الواجهات الدروس بالفيديو ومقسمة بطريقة جيدة جدا   https://www.youtube.com/playlist?list=PL6gx4Cwl9DGBzfXLWLSYVy8EbTdpGbUIG   بالتوفيق واي استفسار انا في الخدمة   تحياتي
  2. السلام عليكم ورحمة الله وبركاته   لتكن لدينا القائمة التالية : 1 2 7 9 5 3 4 نقول أن 2 هي الحد العلوي للـ 1 , والـ7 هو الحد العلوي للـ 5 , ببساطة لو قمنا بترتيب القائمة فإن الحد العلوي لقيمة ما هو القيمة التي تليها في القائمة ( من أجل قائمة لا تحوي عناصر متكررة )   يعيد لنا التابع std::upper_bound الموجود في المكتبة  algorithm مؤشراً أو iterator للحد العلوي لقيمة ما داخل قائمة مرتّبة, (أي : مؤشراً لأصغر قيمة ممكنة أكبر تماماً من قيمة الوسيط )   لو : بفرض أننا نبحث عن الحد العلوي للقيمة x : لو كانت القيمة x أكبر من أكبر قيمة في القائمة فإن التابع سيعيد مؤشراً إلى ما بعد نهاية القائمة وعندها لا يجوز محاولة الوصول إلى محتوى ما يشير إليه المؤشر لأن ذلك سينتج undefined behavior لو كانت القيمة x  أصغر من أصغر قيمة في القائمة فسيعيد التابع مؤشراً إلى أصغر عنصر في القائمة (حالة طبيعية ) لو كانت القيمة x غير موجودة في القائمة إلا أنها ليست إحدى الحالتين السابقتين فإن التابع يعيد مؤشراً إلى أصغر قيمة موجودة أكبر من x لو كانت القيمة x موجودة فإن التابع يعيد مؤشراً إلى القيمة التي بعدها , مما يعني أنه في حال كانت القيمة x موجودة في نهاية القائمة فسيعيد التابع مؤشراً إلى ما بعد نهاية القائمة   لتلخيص جميع الحالات السابقة في عبارة واحدة نقول أن التابع upper_bound يعيد مؤشراً أو iterator إلى أول عنصر في المجال المعطى يحقق كونه أكبر من القيمة المراد البحث عنها , وإن لم يجد يعيد مؤشراً إلى ما بعد نهاية المجال .   أما أخوه الشقيق التابع std::lower_bound فعلى عكس ما يوحي به الاسم ! إنه لا يعيد مؤشراً لأكبر قيمة أصغر من قيمة معينة . يعيد التابع lower_bound مؤشراً أو iterator لأول عنصر في المجال المعطى ليس أصغر من القيمة المراد البحث عنها ,وإن لم يجد يعيد مؤشراً إلى ما بعد نهاية المجال .   تحذيرات : يجب أن تكون القائمة مرتبة وفقاً لنفس نوع المقارنة الذي سيستخدمه التابع للعثور على الحد العلوي أو السفلي .التابع upper_bound يعيد مؤشراً لعنصر أكبر تماماً من القيمة المحددة بينما يعيد lower_bound يعيد مؤشراً لعنصر أكبر أو يساوي القيمة المحددة (إن وجدت )لنبدأ بالتابع std::upper_bound : تعريف التابع : كما اعتدنا في توابع STL التي تقوم بالمقارنة فإن للتابع upper_bound تعريفان على شكل قوالب , الأول يستخدم عملية المقارنة > لمقارنة العناصر والعثور على الحد العلوي , والثاني يستخدم تابع يمرر كوسيط للمقارنة : الشكل الأول (الافتراضي) : template <class ForwardIterator, class T> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val);يعيد التابع  ForwardIterator يشير إلى الحد العلوي ويأخذ ثلاثة وسطاء : الوسيط الأول هو  ForwardIterator يشير للعنصر الأول في القائمة المراد البحث بداخلها . الوسيط الثاني هو  ForwardIterator يشير للعنصر الذي يلي العنصر الأخير في القائمة المراد البحث بداخلها . الوسيط الثالث هو العنصر المراد على العثور على الحد العلوي له . أي أن أول وسيطين يحددان المجال المراد البحث فيه من first إلى ما قبل last . الشكل الثاني للتابع (المخصص ) : template <class ForwardIterator, class T, class Compare> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);يضاف له وسيط رابع هو تابع مقارنة (يمكن أن يكون تابعاً عادياً يعيد قيمة bool أو functor كما في greater<int>()l أو تعبير lambda .. يمكنك مراجعة الموضوع التالي للمزيد عن طرق تعريف الوسيط compare )   إن جسم التابع مكافئ للجسم التالي : template <class ForwardIterator, class T> ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val){ ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = std::distance(first,last); while (count>0) { it = first; step=count/2; std::advance (it,step); if (!(val<*it)) // or: if (!comp(val,*it)), for version (2) { first=++it; count-=step+1; } else count=step; } return first;}لاحظ وجود عملية بحث ثنائي داخل القائمة .   هذا مثال على استخدام التابعين من المرجع: // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorint main () {  int myints[] = {10,20,30,30,20,10,10,20};  std::vector<int> v(myints,myints+8);           // 10 20 30 30 20 10 10 20  std::sort (v.begin(), v.end());                // 10 10 10 20 20 20 30 30  std::vector<int>::iterator low,up;  low=std::lower_bound (v.begin(), v.end(), 20); //          ^  up= std::upper_bound (v.begin(), v.end(), 20); //                   ^  std::cout << "lower_bound of 20 " << *low << '\n';  std::cout << "upper_bound of 20 " << *up  << '\n';  return 0;}إذا كانت القائمة لا تسمح بالوصول العشوائي non-random-access فإن التابع سيستغرق زمناً (O(N للوصول إلى الحد العلوي أو السفلي , أما إن كانت تدعم الوصول العشوائي فسيتم إجراء مقارنة log2(N)+1 مقارنة .   لننتقل إلى التابع lower_bound : تعريف التابع : مثل سابقه بشكلين , والوسطاء لها نفس الدلالات الشكل الافتراضي : template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val);الشكل المخصص : template <class ForwardIterator, class T, class Compare> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp);كما ذكرنا سابقاً فهو يعيد مؤشراً لأول عنصر في المجال من first إلى ما قبل last يحقق كونه ليس أصغر من val (لو كانت val أكبر من جميع العناصر سيعيد last )   يمكن أن يكون شكل جسم التابع مكافئ لما يلي : template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val){ ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = distance(first,last); while (count>0) { it = first; step=count/2; advance (it,step); if (*it<val) { // or: if (comp(*it,val)), for version (2) first=++it; count-=step+1; } else count=step; } return first;}تحذير : لا يجوز استخدام عملية الـ* للوصول إلى محتوى المؤشر أو الـ iterator إلا إذا كان لا يساوي last (أي يجب التأكد من صلاحية المؤشر أولاً ) والآن لننتقل إلى الجزء الماتع , توظيف التابعين :   1- استخدام lower_bound للبحث الثائي , بل وأفضل : عندما نحتاج البحث عن عنصر ما , فإن البحث الثنائي من أسرع خوارزميات البحث بزمن (log2(N ولكن للأسف , يعيد التابع std::binary_search يعيد فقط true أو false للدلالة على وجود أو عدم وجود القيمة المراد البحث عنها , فكيف يمكننا الوصول للقيمة ؟ أو رقمها في الفهرس ؟ أو القيمة التي قبلها ؟ كل هذا من وظيفة التابع lower_bound تذكرة : يعيد lower_bound مؤشراً لأول عنصر أكبر أو يساوي العنصر الذي نبحث عنه (إن وجد) مثال : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorint main (){    int myints[] = {4,2,3,5,7,8,9,1};    std::vector<int> v(myints,myints+8);    std::sort (v.begin(), v.end());    for(auto x:v)        std::cout<<x<<" ";    std::cout<<std::endl;    for(int y=0; y<10; y++)    {        int index=lower_bound (v.begin(), v.end(), y) - v.begin();        if(v[index]==y)            std::cout<<y<<" is exist with index : "<<index<<std::endl;        else            std::cout<<"we can't find "<<y<<" but the first bigger is "<<v[index]<<std::endl;    }    return 0;}للتأكيد على أن التابع يستخدم البحث الثنائي , لنقم بما يلي : 1- تعريف تابع مقارنة خاص , يحوي بداخله تابع لطباعة العددين الذين يتم مقارنتهما 2- استدعاء الشكل المخصص للتابع وتمرير تابع المقارنة له . 3- تمرير مصفوفة من 32 عنصرأ والبحث عن العنصر الأخير (الحالة الأسوأ) ويجب ان ينفذ التابع فقط 5 مقارنات .   راقب وافهم عمل الكود التالي : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vectorbool comp(const int&a,const int&b){    std::cout<<a<<" "<<b<<std::endl;    return a<b;}int main (){    std::vector<int> v(32);    for(int i=0;i<32;i++)        v[i]=i;    lower_bound (v.begin(), v.end(),31,comp);    return 0;} بالمناسبة :إذا كان العنصر المراد البحث عنه متكرراً عدة مرات في القائمة فإن خوارزمية البحث الثنائي المعتادة لا تفرّق بين العثور على أول وجود له أو آخر وجود له , المهم أن تعثر عليه كيفما كان ولكن lower_bound تضمن لك العثور على أول ظهور له مما يزيد من فائدتها .   2- استخدام الفرق بين نتيجتي  lower_bound وupper_bound  لمعرفة عدد مرات تكرار العنصر :   إن lower_bound تعيد مؤشر لأول ظهور لعنصر ما (إن وجد ) أما upper_bound فتعيد مؤشر لما بعد آخر ظهور لعنصر ما (إن وجد) أما إن كان غير موجود فسيعيدان نفس  المؤشر لأول عنصر أكبر من العنصر المراد . إذا عند طرح قيمة المؤشر الخاص بـ upper_bound من مؤشر lower_bound سيعطينا شيئاً ما :) انظر للقائمة التالية : 6 5 5 5 4 2 1 ببدء الترقيم من الصفر , فإن lower_bound ستعيد 3 و upper_bound ستعيد 6 ( للتسهيل سنعتبر أنها تعيد الـ index إلا أنها تعيد مؤشر وعلينا طرحه من first للحصول على الـ index ) لاحظ أن ناتج upper_bound - ناتج lower_bound = عدد مرات التكرار = 3 // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vector#include <cstdlib>      // rand,srand#include <ctime>        // timeint main (){    std::vector<int> v;    srand(time(0));    for(int i=0;i<10;i++)        {            int repeat=rand()%10;            for(int j=0;j<repeat;j++)                v.push_back(i);        }        int s=5;//search for 5    std::cout<< upper_bound (v.begin(), v.end(),s) - lower_bound (v.begin(), v.end(),s) << std::endl;    for(auto x:v)        std::cout<<x<<" ";    return 0;}3-هل العنصر موجود ؟   هذه الفقرة فقط لتأكيد فهمك للموضوع , وعليك الإجابة الآن : هل التابع التالي يصلح للاستخدام كـ binary_search في vector ؟ bool binary_search_2(std::vector<int>x,int y){    sort(x.begin(),x.end());    if( upper_bound(x.begin(),x.end(),y) == lower_bound(x.begin(),x.end(),y) )        return false;    return true;}جرب الكود التالي : // lower_bound/upper_bound example#include <iostream>     // std::cout#include <algorithm>    // std::lower_bound, std::upper_bound, std::sort#include <vector>       // std::vector#include <cstdlib>      // rand,srand#include <ctime>        // timebool binary_search_2(std::vector<int>&x,int y){    sort(x.begin(),x.end());    if( upper_bound(x.begin(),x.end(),y) == lower_bound(x.begin(),x.end(),y) )        return false;    return true;}int main (){    std::vector<int> v;    srand(time(0));    for(int i=0;i<100;i++)        v.push_back(rand()%100);    if(binary_search_2(v,23))        std::cout << "By Mostafa 0x36a2"<<std::endl;    else        std::cout << "ArabTeam2000"<<std::endl;    for(int i=0;i<100;i++){        if(i and i%10==0)            std::cout<<std::endl;        std::cout<<v[i]<<" ";    }    return 0;}أخيراً تجدر الإشارة إلى أن التابع lower_bound مفيد جداً في تنفيذ خوارزمية longest increasing sub-sequence حيث يجعل زمن التنفيذ (O(n2المعتاد للخوارزمية أفضل بكثير (O(n log2n   وتجدر الإشارة أيضاً إلى وجود نسخ من التابع تختص بالتعامل مع std::set التي تمثل كشجرة بحث ثنائية تسمح بتنفيذ lower_bound بشكل فعال .   المرجع : cplusplus : lower_bound upper_bound مصادر : stackoverflow فهم القيمة المعادة من التابعين ماذا يحدث عند عدم وجود العنصر lower_bound == upper_bound     خاتمة : أخي الكريم , المقال الذي بين يديك تحت رخصة (اكتب بالقدر الذي تستطيعه , سيتابع أحدهم من بعدك !) لذلك واجبك بعد قراءة المقال الزيادة عليه أو على سواه , بالسؤال عن ما لم تفهمه , او بتطبيق مفيد أو رابط متعلق به , أو بالتنبيه للأخطاء فيه أو تحسينها , كما يحق لك نشره إن وجدت فيه الفائدة , يمكنك جمعه مع مقالات أخرى لنشر كتاب مجاني . ساهم برفع المستوى العلمي العربي , وتجنب الردود الخالية من الفائدة لمن سيأتي من بعدك .     والله ولي التوفيق
  3. السلام عليكم ورحمة الله وبركاته   مدخل : إذا بدأنا الحديث عن "إعادة استخدام الكود" فسنبدأ بذكر التوابع , فعندما تكتب جسم التابع ثم تستدعيه مرات ومرات داخل الكود , فأنت توفر إعادة كتابة هذا التابع في كل مرة استدعيته فيها ( باستثناء التوابع العودية التي تقوم بأكثر من ذلك) ثم أخذت الأمور تكبر , وصار لدينا العديد من التوابع وصرنا نحتاج نسخ ولصق أجسام التوابع الخاصة بنا أينما ذهبنا .. لذلك قررنا وضع كل تلك التوابع في ملف واحد , وأسميناه header file وعوضاً عن نسخ محتوى الملف يدوياً جاءت include# لتقوم بعملية النسخ واللصق فقط , ونحن نخبرها بموضع واسم الملف الذي نريد لصق محتواه . ولكن ماذا عن أجسام التوابع ! آلاف التوابع وآلاف الأجسام , وكلها تحتاج للترجمة من قبل الـ compiler كل مرة ! عندها جاءت مكتبات الربط لحل المشكلة .. وأصبحنا ننسخ فقط الـ function prototype فقط ليعرف المترجم أن هناك تابعاً بهذا الاسم وهذه الوسطاء parameters وله القيمة المعادة من النوع الفلاني returned type . ولكن أين أجسام التوابع ؟ كثيراً ما حاولنا رؤية محتوى أحد التوابع المثيرة للاهتمام , ماذا بداخل التابع sin وماذا بداخل التابع rand ! أحياناً يكون متاحاً لنا الوصول إلى أجسام التوابع , وأحياناً أخرى تكون الأجسام مخفية داخل المكتبات الساكنة التي سنتحدث عنها اليوم .   هذا المقال موجّه لمن تجاوز مرحلة انشاء التوابع ويرغب بالتعرف على كيفية حزم التوابع ضمن مكتبات مشابهة لمكتبات اللغة بحيث تظهر الـ prototypes فقط للتوابع ولا تظهر أجسامها.   الفهرس :   0- مقدمة 1- ما هي المكتبات الساكنة static library ؟ 2- لماذا نحتاج إلى مكتبة ساكنة ؟ 3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks ربط المكتبة مع مشروع بلغة C ربط المكتبة مع مشروع بلغة ++C  0-المفدمة : لدينا الكود البسيط التالي : int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;}أين ستضع الكود السابق في حال أردت استخدام التوابع السابقة بشكل متكرر ؟ قد تقوم بنسخها معك أينما ذهبت , وقد تقوم بوضعها في ملف header خاص بك وقوم بعمل include له , ولكن ماذا لو كان لديك المئات من التوابع , هل تدري أنك في كل مرة تقوم بعمل compile يتم إعادة ترجمة الكود كاملاً , وربط كل تلك التوابع مع استدعاءاتها في عمليات طويلة , يمكنك أن تتخيل ان عملية ترجمة ملفات بهذا الحجم ستسغرق الكثير من الوقت , فما بالك عندما تصل إلى آلاف التوابع , ستكون عملية الترجمة لكودك البسيط الذي لم يتجاوز الأسطر .. كابوساً من الانتظار .   1- ما هي المكتبات الساكنة static library ؟ هي ملفات تحوي أجسام توابع تمت ترجمتها مسبقاً ومتغيرات تم حجزها مسبقاً, يتم نسخ محتويات المكتبة إلى الملف التنفيذي مباشرة عند بناء مشروع مرتبط linked بها بعد عمل الـ linking اللازمة لربط استدعاءات التوابع بأجسامها كما يمكن أن تنسخ إلى مساحة ذاكرة ساكنة خاصة بها محددة في وقت الترجمة .   2- لماذا نحتاج إلى مكتبة ساكنة ؟ كما ذكرنا في المقدمة , فإن انشاء مكتبة ساكنة يخفف الحمل عن المترجم compiler في وقت الترجمة , فالمكتبة مترجمة مسبقاً وتنتظر الربط linking كما أنها تقيد في تجزئة ملفات الكود وتنظيم بنية المشروع , ويمكننا أن نضيف إلى فوائدها : إغلاق مصدر البرنامج , أي جعله closed source وذلك لأن عدم وجود أجسام للتوابع ضمن ملفات المشروع يجعل هذا الجزء مغلق المصدر , مما يتيح بعض الخصوصية وحقوق النشر للمبرمج والشركة.   3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks يمكن إنشاء مكتبات الربط بأي مترجم , وتتيح أي بيئة القيام بذلك بسهولة , باستخدام code::blocks سنقوم بإنشاء مكتبة ربط ساكنة ثم نربطها بمشروع يستخدمها , من القائمة file اختر new ثم project واختر نوع المشروع Static Library لدينا أجسام التوابع التالية : int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return (long long)i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;} انسخ الكود السابق واستبدل المحتوى السابق للمشروع (الذي تنشئه البيئة افتراضياً) به . والآن قم بعمل Build ويفترض أن الكود خالٍ من الأخطاء ( لا تقم بعمل run لأن هذا ليس مشروعاً كاملاً ولا يحوي main ) ربط المكتبة مع مشروع بلغة C والآن لنقم بإنشاء مشروع جديد عادي من نوع console project واختر لغة C لكتابة المشروع للتبسيط , سنقوم بلصق تصاريخ التوابع قبل الـmain مباشرة : سيكون لدينا الكود التالي في المشروع : #include <stdio.h>#include <stdlib.h>int Add(int,int);long long Mul(int, int);int Sub(int, int);int Div(int, int);int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;}والآن إلى عملية الـ linking , من Settings>> Compiler اختر Linker settings ثم قم بالضغط على Add واختر مسار المكتبة الذي أنشأناها قبل قليل ثم O.K -- O.K والآن يمكنك عمل Build ثم run للمشروع وتكون قد أنشأت أول مكتبة ربط ساكنة لك   ربط المكتبة مع مشروع بلغة ++Cتختلف توابع الـ C عن توابع ++C بمسألة تسمى name mangling وهي عملية يقوم بها المترجم فيغيّر أسماء التوابع قبل مرحلة الـ linking ليتمكن من عمل  overloading للتوابع أو إذا كانت بداخل classes , المهمّ أن توابع ++C لا تبقى بنفس الاسم الذي نكتبه عند التعريف , وكل مترجم له mangling خاص به , ولكن في C لا يوجد overloading ولا تغليف للتوابع , فالتابع يبقى بنفس اسمه بالنسبة للمترجم أثناء الربط , لذلك عندما نقوم بعمل مكبتة ربط ساكنة ونريد ربطها مع كود بلغة ++C فعلينا اخبار المترجم أن هذه التوابع مكتوبة ومترجمة بلغة C وذلك عن طريق الكلمة المجوزة التي لا نستخدمها كل يوم , extern ويصبح كود الـ ++C كما يلي : #include <cstdio>#include <cstdlib>extern "C"{    int Add(int,int);    long long Mul(int, int);    int Sub(int, int);    int Div(int, int);}int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;} والآن يمكنك الانطلاق لعمل مكاتبك الساكنة الخاصة بك , وتنظيم مشاريعك بطريقة أكثر تقدماً .   والله ولي التوفيق
  4. السلام عليكم ورحمة الله وبركاته كثيراً ما نحتاج البحث عن أكبر عنصر أو أصغر عنصر في قائمة/مصفوفة/سلسلة/أو أي شيء يمكننا التأشير إليه (أي كل ما يملك ForwardIterator ) فالبحث عن اكبر عنصر هو عملية أساسية في Selection sort كما في Pancacke sort عدا عن كونه عملية أساسية مستقلة للكثير من الحسابات الهامة كإيجاد أفضل الطلاب في قائمة أو العثور على أقصر الطرق ضمن قائمة طرق متاحة مثلاً .. ورغم أنها عملية سهلة التكويد (كتابة الكود) بشكل كبير , إلا ان وجود حلقة البحث داخل الكود غالباً يسبب المزيد من الصعوبة في فهم الكود , كما أنه لا داع لتوضيح أهمية استخدام الأدوات الجاهزة في تسريع عملية التطوير  . لنبدأ إذا في التعرف على استخدام التابع max_element من مكتبة algorithm : تم تعريف التابع كـfunction template بنسختين   أولاً - النسخة الافتراضية للتابع : template <class ForwardIterator> ForwardIterator max_element (ForwardIterator first, ForwardIterator last);يعيد التابع مؤشراً للعنصر الأكبر في القائمة التي أول مؤشر لها هو first و مؤشر العنصر بعد الأخير  هو last وأعني بالمؤشر هنا : Iterator إن كنا في container خاص في STL أو عنوان حقيقي إن كنا داخل مصفوفة . هذا التابع الافتراضي يستخدم العملية >operator لمقارنة العناصر , والعنصر الذي لم يعثر على أي عنصر آخر أكبر منه , هو العنصر الأكبر علينا إعادة تعريف العملية >operator إذا أردنا العثور على أكبر عنصر في مجموعة من نوع جديد ( راجع هذا الموضوع للتدرب على إعادة تعريف هذا المعامل )   لنبدأ بالبحث في المصفوفات : الوسيط الأول لهذا التابع هو مؤشر بداية المجال للمصفوفة , علينا إرسال عنوان العنصر المراد البدء بالبحث منه الوسيط الثاني هو مؤشر العنصر بعد الأخير   مثال : لدينا المصفوفة التالية : int A[10]={8,5,7,1,2,4,9,3,4,7};للبحث عن أكبر عنصر في المصفوفة نكتب : max_element(&A[0],&A[10]);الاستدعاء السابق يعيد (((عنوان))) أكبر عنصر ماذا لو أردنا البحث عن أكبر عنصر في المجال من 1 إلى 3 max_element(&A[1],&A[4]);(لا تنس أن الوسيط الثاني هو عنوان العنصر بعد الأخير) يمكننا التعامل مع العناوين مباشرة مثلاً , للعثور على أكبر عنصر في المجال 0 إلى 4 max_element(A,A+5);والشكل السابق أسهل للكتابة من max_element(&A[0],&A[5]);ومفضل عليه دوماً , لأن كتابة [10]A& تعني أننا نصل إلى عنوان عنصر خارج المصفوفة وهذا ليس آمناً . إذا سنعتمد عند استخدامنا للمؤشرات في المصفوفات على ( اسم المصفوفة + الانزياح عن المبدأ ) (ملاحظة : تم استخدام المقارنة المعتادة هنا بين الأعداد لمعرفة العنصر الأكبر )   لنتابع إلى البحث في الحاويات : لدينا الـvector التالي : vector<int> A={8,5,7,1,2,4,9,3,4,7};لإيجاد أكبر عنصر في مجاله كله max_element(A.begin(),A.end());أو يمكننا البدء من begin إلى begin+offset كما يلي : max_element(A.begin(),A.begin()+10);مثلاً إذا أردنا البحث عن أكبر عنصر في المجال من 3 إلى 7 : max_element(A.begin()+3,A.begin()+8);لنقم بإعادة تعريف العملية >operator بالنسبة للنوع الجديد koko المعرف كما يلي struct koko{        int a;        koko(int x):a(x){        }};وسنعيد تعريف المعامل >operator  كما يلي : bool operator<(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}إذا كنت قوي الملاحظة فستعرف أن عملية > الآن تتصرف كما لو كانت عملية < , وهذا يعني أن max_element ستعيد الآن العنصر الأصغر : مثلاً الاستدعاء التالي : max_element(A.begin()+3,A.begin()+8)سيعيد iterator يشير إلى العناصر الأصغر وهو 1 . ماذا تتوقع أن يعيد الاستدعاء التالي : min_element(A.begin()+3,A.begin()+8)أظن أن الفكرة أصبحت واضحةً , فالـ max_element سيعيد العنصر الذي يرجع false عند مقارنته مع جميع العناصر الباقية (أي أنه ليس أصغر من أحد حسب تعريف العملية أصغر ) لنتجه الآن إلى الشكل الآخر للتابع , الشكل المفصل : ثانياً- النسخة المفصلة للتابع : إذا رأينا اننا بحاجة إلى أعادة تعريف العملية > لاستخدام هذا التابع , فربما يكون أكثر وضوحاً ان نستخدم الشكل المفصل للتابع : template <class ForwardIterator, class Compare> ForwardIterator max_element (ForwardIterator first, ForwardIterator last, Compare comp);الوسيط الآخير , هو تابع compare له نفس شكل العملية >operator ويعيد قيمة bool تكون true عندما يكون الوسيط الأول أصغر من الثاني , ولكن لننظر إلى الأمر بشكل مختلف , عندما نبحث عن max_element فالعنصر الذي نعرّفه كـ max هو العنصر الذي يعيد false عندما يتم استدعاء التابع compare ووضعه كوسيط أول مهما كان الوسيط الثاني , وكذلك العنصر الـ min هو العنصر الذي يعيد التابع compare قيمة true إذا كان هو الوسيط الأول مهما يكن الوسيط الثاني (طبعاً في كلا الحالتين نستثني أن يكون الوسيط الثاني هو نفس الوسيط الأول ) لنرجع إلى مثال koko بدلاً من إعادى تعريف العملية > كما يلي : bool operator<(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}سنكتب التابع compare كما يلي : bool compare(const koko&first,const koko&second){    if(first.a<=second.a)        return false;    else        return true;}وسيصبح الاستدعاء كما يلي : max_element(A.begin()+3,A.begin()+8,compare)لاحظ أننا نمرر اسم التابع فقط . يمكننا الآن التخلي عن البنية التغليفية koko (حيث وضعناها فقط لأن إعادة تعريف العملية > بالنسبة لـ int أمر ممنوع) وذلك بفضل التابع compare انظر إلى الكود التالي : #include <iostream>#include <algorithm>#include <vector>using namespace std;bool compare(const int&first,const int&second){    if(first<=second)        return false;    else        return true;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    cout<<(*max_element(A.begin()+3,A.begin()+8,compare));    return 0;}مارأيك لو نبحث عن أكبر عدد زوجي ضمن القائمة ؟ كل ما علينا هو تعديل كود التابع compare bool compare(const int&first,const int&second){    if(second%2==0 and first<second)        {            return true;        }    else        return false;}العبارة الفاصلة والتي يجب أن تكون خلاصة هذا المقال هي : يعيد التابع max_element العنصر الذي لا يوجد عنصر أكبر منه , وهذا يعني أن أي مقارنة يكون هو الـ second كوسيط فيها يجب أن تعيد true وأي مقارنة يكون هو الـ first فيها يجب أن تعيد false وذلك واضح من كون عملية المقارنة هي first<second وطالما أنك تحقق هذه العلاقة يمكنك القيام بأي اختبار تريده . ما رأيك بأكبر عدد أولي في القائمة !! واثق من أن الكود التالي سينال إعجابك ! #include <iostream>#include <algorithm>#include <vector>#include <cstdlib>#include <ctime>using namespace std;bool is_prime(const int &x){    for(int i=2;i*i<=x;i++)        if(x%i==0)            return false;    return true;}bool compare(const int&first,const int&second){    if(first<second)        {            if(is_prime(second))                return true;            else                return false;        }    else if(second<first)        {            if(!is_prime(first) and is_prime(second))                return true;            return false;        }    else        return false;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    srand(time(0));    for(int i=0;i<100;i++)        A.push_back(rand());    cout<<*max_element(A.begin(),A.end(),compare);    return 0;}ما رأيك بجعله يعيد أقرب عنصر للمتوسّط !! #include <iostream>#include <algorithm>#include <vector>#include <cmath>#include <cstdlib>#include <ctime>using namespace std;int average;bool compare(const int&first,const int&second){    if(abs(first-average)<abs(second-average))        return false;    return true;}int main(){    vector<int> A={8,5,7,1,2,4,9,3,4,7};    srand(time(0));    for(int i=0;i<100;i++)        A.push_back(rand());    average=0;    for(int x:A)        average+=x;    average/=A.size();    cout<<"average = "<<average<<endl;    cout<<*max_element(A.begin(),A.end(),compare);    return 0;}الـ max هو الذي يعيد false كلما كان هو الوسيط الأول ويعيد true كلما كان هو الوسيط الثاني (في تابع المقارنة)   تجدر الإشارة إلى أن جسم التابع هو مشابه لما يلي : template <class ForwardIterator> ForwardIterator max_element ( ForwardIterator first, ForwardIterator last ){ if (first==last) return last; ForwardIterator largest = first; while (++first!=last) if (*largest<*first) // or: if (comp(*largest,*first)) for version (2) largest=first; return largest;}-أخيراً من الأمور التي يجب معرفتها أن بعض البنى لا توفر Forward Iterator مثل stack و queue .. وهذه لا يمكن البحث بداخلها عن أكبر عنصر باستخدام هذا التابع .   المراجع : cpp-reference أسئلة وأمثلة : مثال مباشر وواضح stackoverflow   والله ولي التوفيق
  5. السلام عليكم ورحمة الله وبركاته اعتدنا أثناء الترتيب على البحث عن الخوارزمية ذات عدد المقارنات الأقل less comparisons , او على الخوارزمية ذات عدد الاستبدالات الأقل less swaps بين العناصر , ولكن ماذا لو كان لدينا كومة من الفطائر المكدسة فوق بعضها البعض وذات أقطار مختلفة .. ونريد ترتيبها . إن سبب تعدد خوارزميات الترتيب هو اختلاف الخوارزمية المثالية لبنية المعطيات التي لدينا , وهذا مبدأ هام جداً في دراسة الخوارزميات , فقد تكون عملية الاستبدال swap مكلفة في بنية ما , بينما تكون (O(1 في بنية أخرى , لذلك علينا العثور على خوارزمية تشمل العمليات الأقل كلفة حسب البنية المعطاة لنرجع إلى فطائرنا .. إن عملية استبدال فطيرتين مكلفة ! فهي تسبب اتساخ اليد بالـ"sauce" الموجود عليها , كما ان استخدام الملاعق لاستبدال الفطيرتين ... لك أن تتخيل ذلك , رفع ما فوق الفطيرة السفلى ثم رفع ما فوق الفطيرة العليا ثم التبديل ثم انزال الكدسات المرفوعة ... عملية مكلفة بكل ما تعني الكلمة ولكن ماذا عن عملية القلب flip  ؟ يمكننا وضع ملعقة بداخل الكدسة ثم قلب كل ما فوق هذه الكدسة , الشكل التالي يوضح كدسة فطائر قبل وبعد القلب واضح ان العملية بسيطة جداً , وغير مكلفة , ولذلك تم عمل خوارزمية الترتيب Flip Sort او ما يسمى Pancake Sort التي تعتمد على هذه الـ operator غير المكلفة , الـ FLIP operator في هذه الخورازمية يمكننا فقط القيام بعملية الـ flip هذه , ولترتيب القائمة التي لدينا علينا اتباع الخطوات التالية :   إذا كان لدينا n عنصر , فعلينا تكرار ما يلي n  مرة ولنضع عدادا i يبدأ من 1 : 1- العثور على العنصر الأكبر خلال المجال من i إلى n 2- وضع الملعقة على موضع العنصر الأكبر وقلب الكدسة التي فوقه . 3- وضع الملعقة في الموضع i وقلب الكدسة التي فوقه 4- زيادة العداد i والتوقف إذا كان i==n   للتوضيح : عملية قلب الكدسة هي عملية flip للعناصر من موضع القلب إلى القمة (أي إلى n ) هذا المقطع يوضح هذه الخوارزمية   الخوارزمية السابقة , يمكن تحسينها حيث لا نحتاج لعمليتي القلب إن كان العنصر في مكانه , كما لا نحتاج عملية القلب الأولى إن كان العناصر أصلاً في القمة (أي في الموضع n ) وبذلك يمكننا تحسينها إلى :   إذا كان لدينا n عنصر , فعلينا تكرار ما يلي n  مرة ولنضع عدادا i يبدأ من 1 : 1- العثور على العنصر الأكبر خلال المجال من i إلى n 2-    2.1- إذا كان العنصر الأكبر في الموضع i نتركه كما هو    2.2- إذا كان العنصر الأكبر في الموضع n نقوم بوضع الملعقة في الموضع i ونقلب الكدسة رأساً على عقب    2.3- إذا لم يكن العنصر الأكبر هو العنصر i  ولا  العنصر n  فعلينا وضع المعقة في موضع العنصر الأكبر وليكن j وقلب الكدسة التي فوقها عندها سيصبح في الموضع n ثم ننفذ 2.2 3-نزيد قيمة i (عند هذه النقطة يكون كل العناصر من الأسفل وحتى i مرتبة ) ونتوقف إذا كان i==n   إذا اعتبرنا عملية الـ flip هي العملية الوحيدة فإن أكبر عدد من الـ flip تحتاجه الكدسة حتى يتم ترتيبها هو 2*n (مرتان لكل موضع ) ولا ننسى أننا بحاجة إلى العثور على العنصر الأكبر في الكدسة , مما يعني (O(n للبحث كل مرة , وبذلك يكون التعقيد الزمني للخوارزمية لو كانت عملية القلب (O(1 هي (O(n2 ولكن عملية القلب حوسبياً هي عملية (O(n وبالتالي تعقيد الخوارزمية حسابياً هو (O(n3 إذا هي فعالة في الحياة العملية أكثر منها في الحاسوب .   كانت هذه لمحة موجزة و سريعة عن هذه الخوارزمية , أرجو أن تكون مفيدة والله ولي التوفيق     المصادر : Wikipedia GeeksForGeeks
  6. تعرف على التابع std::sort

    السلام عليكم ورحمة الله ويركاته   هدف هذا المقال هو التعرف على تابع الترتيب الجاهز في مكتبة STL التي توفرها ++C , والذي يتم تطوير الـimplimentation بداخله نسخةً بعد نسخة , فقد بدأت بالترتيب السريع quick sort مع أول ظهور لها (إذ كانت تماثل تابع qsort في cstdlib ) أما الآن فهي تعتمد خوارزميات ترتيب أفضل , وأكثر ثباتاً ( ليست عشوائية , وتحقق(n*log (n في الحالة الأسوأ ) , آخر نسخة أعرفها تستخدم intro sort كمرحلة أولى ثم insertion sort كمرحلة ثانية .   فهرس المقالة : 1-  تعريف التابع sort 2- وسطاء التابع 2.5- عملية المقارنة 3- Member < Operator 4- Global < Operator 5- تمرير الوسيط الثالث كمؤشر إلى تابع 6- تمرير الوسيط الثالث كــ function object 7- تمرير الوسيط الثالث كعبارة lambda   التابع sort : ما يهمنا هنا هو استخدام هذا التابع , والمعرّف كقالب template بالشكلين التاليين : template <class RandomAccessIterator>void sort ( RandomAccessIterator first, RandomAccessIterator last );template <class RandomAccessIterator, class Compare>void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );  التعريف الأول يستخدم االعملية <  لمقارنة العناصر , أما الثاني فيستخدم تابع خاص للمقارنة .   وسطاء التابع : الوسيط الأول: مؤشر وصول عشوائي لأول عنصر في القائمة المراد ترتيبها , مثلاً لو أردنا ترتيب مصفوفة فهو عنوان أول عنصر , أما لو أردنا ترتيب vector فهو الـ iterator الذي تعيده الدالة ()begin الوسيط الثاني: مؤشر وصول عشوائي للعنصر بعد الأخير القائمة المراد ترتيبها .مثلاً لو أردنا ترتيب مصفوفة فهو عنوان أول عنصر + عدد العناصر , أما لو أردنا ترتيب vector فهو الـ iterator الذي تعيده الدالة ()end الوسيط الثالث : هو مؤشر إلى تابع , أو functor سيتم شرحه بالتفصيل لاحقاً في هذا المقال . مثال على ترتيب مصفوفة أعداد صحيحة : #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9,7,5, 4,1,8,  2,3,4,  5};    sort(a,a+10);    for(int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}مثال على ترتيب vector : #include <iostream>#include <algorithm>#include <vector>using namespace std;int main(){    vector<int>a={9,7,5, 4,1,8,  2,3,4,  5};    sort(a.begin(),a.end());    for(int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  عملية المقارنة : أثناء القيام بعملية الترتيب , تتم مقارنة العناصر . في لغة C يوجد التابع qsort الذي يحتاج وسيطاً هو تابع مقارنة , يعيد 1 في حال كان الوسيط الأول أكبر من الثاني , و -1 في حال أصغر , و 0 في حال التساوي . أما في ++C , فالتابع sort  يقوم باختبار بولياني bool يعيد true أو false   Member < Operator : ففي النسخة الأولى من التابع (ذات الوسيطين ) يقوم تلقائياً باختبار(if(a<b أي أنه يستخدم العملية (أصغر > )  , فلو كنت تريد ترتيب قائمة من نوع جديد , يجب أن يحوي هذا النوع بداخله على تعريف للعملية > . مثال : لدينا نوع جديد اسمه book وأردنا تعريف عملية المقارنة > بحسب تاريخ الكتاب , ثم اسم مؤلفه , #include <iostream>#include <algorithm>#include <string>#include <vector>using namespace std;struct book{    int date;// 2000bc --> 2014 ac    string author;    book(int d,string a):date(d),author(a){    }    bool operator<(const book second){        if(date<second.date)            return true;        else if(date==second.date){            if(author<=second.author)                return true;            else                return false;        }else            return false;    }    void print(){        cout<<"author "<<author<<" date:"<<date<<endl;    }};int main(){    vector<book>a;    a.push_back(book(1999,"mohammad"));    a.push_back(book(2014,"mostafa"));    a.push_back(book(2010,"ahmad"));    a.push_back(book(1988,"mohammad"));    sort(a.begin(),a.end());    for(unsigned int i=0;i<a.size();i++){        a[i].print();    }    return 0;}/*( ملاحظة : الكود لا يعمل على Code::blocks لسبب لا أعرفه , تمت تجربته بنجاح على VS2008 )*/هنا استعملنا العملية كـ member function , وكملاحظة سريعة : يمكننا استخدام أي من التعاريف التالية للوسيط :     bool operator<(const book second);    bool operator<(const book &second);    bool operator<(book second);    bool operator<(book &second);ولكن تختلف بغعاليتها , أما من ناحية الصلاحية فهي صالحة .   Global < Operator: كما يمكننا تعريف عملية > بدون وضعها داخل فئة معينة , أي تعريقها كــ  Global Operator كما يلي : #include <iostream>#include <algorithm>#include <string>#include <vector>using namespace std;struct book{    int date;// 2000bc --> 2014 ac    string author;    book(int d,string a):date(d),author(a){    }    void print(){        cout<<"author "<<author<<" date:"<<date<<endl;    }};bool operator<(const book&first,const book&second){        if(first.date<second.date)            return true;        else if(first.date==second.date){            if(first.author<=second.author)                return true;            else                return false;        }else            return false;    }int main(){    vector<book>a;    a.push_back(book(1999,"mohammad"));    a.push_back(book(2014,"mostafa"));    a.push_back(book(2010,"ahmad"));    a.push_back(book(1988,"mohammad"));    sort(a.begin(),a.end());    for(unsigned int i=0;i<a.size();i++){        a[i].print();    }    return 0;}   إن مسألة تعريف عملية الأصغر, مسألة مثيرة للاهتمام , فلا يمكنك ترتيب قائمة إن لم تكن تستطيع تحديد أي العناصر تريدها أن تكون في بداية القائمة وأيها في نهاية القائمة . وعلى هذا المبدأ , يتعمد (التعريف الثاني للتابع ) على الوسيط الثالث compare وهو تابع يأخذ وسيطين (من نوع العناصر في القائمة) ويعيد قيمة بوليانية boolean تكون true إن كان الأول أصغر من الثاني وfalse إن كان أكبر أو يساوي . وبذلك يمكننا خداع الدالة بحيث تتعامل مع العملية > ونكون فعلياً نتعامل معها على أنها < لكي نعكس الترتيب (تصاعدي أو تنازلي ) ولكن للأسف , لا يمكننا إعادة تعريف عملية > للأنواع الأساسية , مثل int . فالكود التالي يعتبر خاطئاً bool operator<(const int&a,const int&b){    /*some operations*/}لذلك سنلجأ إلى كتابة تابع compare يقوم بالمهمة , وهو تماماً كفكرة عملية الـ > , يعيد قيمة بوليانية boolean ويأخذ وسيطين هما القيمتان المراد مقارنتهما .   تمرير الوسيط الثالث كمؤشر إلى تابع : لفهم عمل التابع يجب فهم كيفية التعامل مع القيمة المعادة منه : عندما يعيد هذا التابع true فإنه يضمن لك أن يكون الوسيط الأول قبل الوسيط الثاني ( لننس فكرة الأصغر والأكبر ) , فلو كنت تريد أن يكون العنصر الأصغر في البداية والأكبر في النهاية (ترتيب تصاعدي ) عليك إعادة true في حال كان الوسيط الأول أصغر من الثاني , أما إن كنت تريد الترتيب التنازلي فعليك إعادة true  إن كان الوسيط الأول أكبر من الوسيط الثاني , وبذلك سيضمن لك التابع أن الوسيط الأول سيستقر قبل الثاني في المصفوفة . لمعرفة هل العددان متساويان يتم استدعاء التابع مرّتين بحيث تكون الثانية هي نقس الأولى ولكن بعكس ترتيب الوسطاء ,لذلك على التابع أن يحقق هذه العمليات المنطقية , فلا يجوز أن يعيد true مهما كانت الوسطاء مثلاً .. المثال التالي يوضح كيفية تمرير (مؤشر إلى تابع) أو ببساطة (تابع) كوسيط ثالث للدالة sort #include <iostream>#include <algorithm>using namespace std;bool compare(const int&a,const int&b){    if(a<b)        return true;    else return false;}int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,compare);    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}الكود السابق يقوم بالترتيب التصاعدي العادي , أما التالي فهو (بتغيير محتوى تابع المقارنة ) يقوم بالترتيب التنازلي (سأضع الدالة compare  فقط ) bool compare(const int&a,const int&b){    if(b<a)        return true;    else return false;}لاحظوا أننا لو كتبنا الدالة compare كما يلي : bool compare(const int&a,const int&b){    return true;}سيتم وضع المصفوفة بشكل عشوائي لأن عملية الترتيب لن تتم بأي شكل منطقي .   تمرير الوسيط الثالث كــ function object : يمكن تمرير الوسيط كـ functor أي كـ struct تم تعريف العملية () بداخله , وهذه الطريقة مفيدة في تسريع الكود , حيث يمكنها استغلال خاصية الـ inlining في الكود #include <iostream>#include <algorithm>using namespace std;struct test{    bool operator()(const int&a,const int&b){        if(a>b)            return true;        else return false;    }};int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,test());    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  أحد هذه الfunctor الجاهزة هو greater نستخدمه للترتيب التنازلي كـ functor جاهز : #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,greater<int>());    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  تمرير الوسيط الثالث كعبارة lambda  (خاص بـ C++11 وما بعد ) : بالعودة إلى مؤشر التابع , من الأمور الممتعة في C++11 تعابير lambda , التي تسمح بتعريق التابع في وقت استخدامه ,وأحياناً يكون استخدامه مفيداً جداً في توضيح الكود ( بحيث نضع طريقة المقارنة في نفس مكان استدعاء الترتيب ) #include <iostream>#include <algorithm>using namespace std;int main(){    int a[]={9, 7,6,4,   8,2,5, 4,3,1};    sort(a,a+10,[](const int&a,const int&b){if(a>b)return true;else return false;});    for(unsigned int i=0;i<10;i++){        cout<<a[i]<<" ";    }    return 0;}  هنا نصل إلى نهاية المقالة , أرجو أن أكون قد نقلت معظم الطرق التي تستخدم بها المقارنة في هذه الدالة , وأتمنى انه قد أصبح بإمكانك البدء باستخدام التابع std::sort دون أن تجد صعوبة في تحديد الطريقة التي تريد بها ترتيب العناصر .     المصادر : STL Sort Comparison Function cpp-reference كيف تكتب تابع compare مثال على ترتيب vector يحوي vector     والله ولي التوفيق
  7. [ltr] Visual Basic 6.0 lesson - Temperature convector ScrollBar control is a very handy tool for Visual Basic programmers. It is used in many tricks like (sizing, scrolling texts .... etc) Visual Basic ScrollBar example Temperature Convector Desktop application source code project is a good example for Visual Basic beginners to start studying ScrollBars and how handy they are for a programmer as a tool on the form. Scrollbars in Visual Basic 6.0 is free to use, easy to place on a form (Horizontally or Vertically) according to your need in the design-time (IDE), in our example we will place one Scrollbar on the form and some labels, TextBoxes and CommandButtons as in the photo below . Temperature Convector VB6 Source Code What is Celsius and Fahrenheit ? - Celsius is a scale and unit of measurement for temperature. It is named after the Swedish astronomer Anders Celsius (1701–1744), who developed a similar temperature scale. The degree Celsius (°C) can refer to a specific temperature on the Celsius scale as well as a unit to indicate a temperature interval, a difference between two temperatures or an uncertainty. The unit was known until 1948 as "centigrade" from the Latin centum translated as 100 and gradus translated as "steps". - Fahrenheit is a temperature scale based on one proposed in 1724 by, and named after, the physicist Daniel Gabriel Fahrenheit (1686–1736).[1] Within this scale, the freezing of water into ice is defined at 32 degrees, while the boiling point of water is defined to be 212 degrees - on Fahrenheit's original scale the freezing point of brine was zero degrees.   Option Explicit' C = (F-32)*5/9Dim TempC As IntegerDim TempF As IntegerPrivate Sub CmdExit_Click ()EndEnd SubPrivate Sub Command1_Click()VsbTemp.Value = 98.6TxtExp.Caption = "Here is Where Body Temp. at 37C Equals F.Temp."End SubPrivate Sub Command1_LostFocus()TxtExp.Caption = ""End SubPrivate Sub Command2_Click()VsbTemp.Value = -40TxtExp.Caption = "Here is Where F.Temp Equals The C.Temp At -40 Point"End SubPrivate Sub Command2_LostFocus()TxtExp.Caption = ""End SubPrivate Sub Command3_Click()VsbTemp.Value = 32TxtExp.Caption = "Scale Resets"End SubPrivate Sub Command4_Click()TxtExp.Caption = "http://evry1falls.freevar.com/vb6/"End SubPrivate Sub Command4_LostFocus()TxtExp.Caption = ""End SubPrivate Sub VsbTemp_Change()'Read F and convert to C.TempF = VsbTemp.ValueLblTempF.Caption = Str(TempF)TempC = CInt(TempF - 32) * 5 / 9LblTempS.Caption = Str(TempC)End SubPrivate Sub VsbTemp_Scroll()'Read F and Convert To C.TempF = VsbTemp.ValueLblTempF.Caption = Str(TempF)TempC = CInt(TempF - 32) * 5 / 9LblTempS.Caption = Str(TempC)End SubSource : Here
  8. السلام عليكم : مشكلة .. ما قدرت اختار عنوان مناسب .. وهذه عقدتي :wacko: المهم . عندك برنامج وانت تحب انك تضيف ايقونه له جنب الساعة .. ويسمونها .. أيقونة صينيةِ النظام -- system tray icon اولا تنشئ هذا التركيب :   NOTIFYICONDATA  system_icon;تركيب عادي .. تقوم بملئه بالمعلومات التي يحتاجها النظام عشان يربط برنامجك بشريط المهام الن سنملأه بالمعلومات : اولا system_icon.cbSize=sizeof(NOTIFYICONDATA);حجم التركيب كما هو حال باقي التراكيب في الويندوز .   system_icon.hIcon = LoadIcon(NULL,IDI_INFORMATION);الايقونة التي تريدها ان تظهر .. نحن اخترنا احد ايقونات النظام ..   system_icon.hWnd = hWnd;مقبض نافذتنا .   system_icon.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;مهم جدا . هنا تعطي الخصائص العامة لهذا التركيب وهي ثلاث ونحن جمعنا بينها كلها . NIF_ICON يعني هل تريد له ايقونة او لا . NIF_TIP هل تريد اظهار شريط المعلومات الاصفر TOOL TIP عند توقف الماوس على الايقونة ... NIF_MESSAGE هل تريد استقبال رسائل من ايقونتنا .. اذا اخترت هذه الخاصية ستتمكن من استقبال الرسائل الواردة اليها .. في الغالب جميع ما سبق تحتاجه ..   system_icon.uCallbackMessage = WM_TRAYMESSAGE;هنا .. نعين الرسالة التي ستعالج الرسائل القادمة الى نافذتنا ..   system_icon.uID = ICONIDENT;ID الخاص بالايقونة .. حيث يعتبر همزة الوصل بيننا وتلك الايقونة .. وهو عبارة عن رقم انت تحدده ... مثلا #define ICONIDENT  102 strcpy(system_icon.szTip,"arab team ");الان وضعنا tool tip .. او شريط المعلومات الاصفر الذي سيظهر .. واعتقد مايحتاج شرح . خلاص الان عبأنا التركيب بالمعلومات الكافية .. سنجعله في ايقونة النظام   Shell_NotifyIcon(NIM_ADD,& system_icon);هذه الدالة تمكننا من اظهار برنامجنا في ايقونة النظام . .. البارمتر الاول نوع العملية .. NIM_ADD اضافة NIM_DELETE حذف NIM_MODIFY تعديل بالنسبة للاضافة تعلمناها .. الحذف امره واضح .. التعديل ايضا سهل .. مثلا تغير النص الذي سيظهر في الشريط الاصفر . تغير الايقونة وهكذا .. وذلك بان تعيد كتابة اجزاء من التركيب السابق ثم تعيد تعيينه مثلا ستغير الكلام .. فقط   strcpy (system_icon.szTip,"al slam alaikum");ونعدله   Shell_NotifyIcon(MODIFY,& system_icon);اذا انتهيت من البرنامج .. و اردت ان تحذف الايقونة   Shell_NotifyIcon(NIM_DELETE,& system_icon);اذا اردت ان تستقبل الرسائل ببساطة : case WM_TRAYMESSAGE:  switch(wParam)  {  case ICONIDENT:switch(lParam)   {case WM_LBUTTONUP:    MessageBox(hWnd,"You clicked the LEFT   button!","SysTray Icon Example",MB_OK);}اذا الرسالة TRAYMESSAGE __ wParam الخاص بها هو ID الخاص بالايقونة .. وهو الان ICONIDENT الذي حددناه قبل قليل .. اما lParam الخاص بالرسالة TRAYMESSAGE فهو يحدد نوع الرسالة نقرة ماوس الخ .. نحن قلنا اذا كانت نقرة ماوس .. اظهر مسج .. تلميحه ! نشاهد في كثير من البرامج .. عند النقر على الزر الايمن فوق ايقونة ما....ستظهر قائمة . كيف يتم ذلك .. الامر بسيط لكن ان شاء الله انك تعرف كيف تتنشئ قائمة وتتعامل معها . وسأفترض ذلك .   POINT pxy; case WM_RBUTTONUP: GetCursorPos(&pxy); TrackPopupMenu(hmenu,TPM_LEFTALIGN|TPM_TOPALIGN,(pxy.x)+1,pxy.y,0,hWnd,NULL);خزنا موقع الفأرة عند النقر .. في التركيب POINT واللي اكيد انك تعرفه .. يحتوي على X و Y متغيرين يعني .. وحركنا القائمة الى موقع المشيرة وهو موقع ايقونتا .. طبعا الرسالة WM_RBUTTONUP هي lParam للرسالة WM_TRAYMESSAGE .. الان برنامجك متصل بالمحيط الخارجي : ) الموضوع هذا لقيته في ملف وورد كاتبه من شهور :D ,, ما راجعته ... لكن إن شاء الله انه مافيه اخطاء .. والملف المرفق سأضيفه لاحقا بمشيئة الله ,
  9. Multithread

    بسم الله الرحمن الرحيم بصراحة لا اعلم افضل طريقة للشرح في منتدى به الاف من الاعضاء اكتب الكود و اعلق ام ماذا ... ليتكم تساعدوني بالاسئلة - داخل اطار البرنامج - الـMutlithread امر مهم جدا احيانا يكون الكمبيوتر مشغول بالقراءة من الكيبورد او التعامل مع الشاشة او كارت الشبكات فبدلا من تنفيذ البرنامج بطريقة تسلسلية من الممكن ان تصممه بالعمل كعدة اجزاء thread يعني خيط !!! المهم البرنامج يكون بعدة انفاس او ارواح من الممكن ان تنفذ بدون تسلسلية البرنامج ليس مثالي و كتب بعرض تعليمي و من الممكن اجراء الكثير من التعديلات!!! همي الاول السهولة و البساطة اليكم الكود و ندير حلقة نقاشية تعليمية حوله ما رأيكم دام فضلكم - يا ترى الشاى على مين   // dos2.cpp : A good example of MultiThread Program with emphasis of pointer.////#include "stdafx.h"//#include <stdlib.h>#include <stdio.h>#include <process.h>#define ddum(a,b) a+bint addem(int);int factoria(int);int AddThree(int list[]);int DataAdd(int *list);int StrPrint(char *str);int side=4;int main(int argc, char* argv[]){// int arr[2];arr[1]=4;arr[2]=5;// float *ptr_y,yy[2]={3.0,9.2};int id1,id2,id3,id4,id5;int list[]={3,5,19},kll[]={8,1,2,3,4,5,6,7};int (*ptr)(char *str);char str[] = "*** Pointing to a function.";ptr = StrPrint;printf(" --** Hello World! **--\n");id1=_beginthread((void (*)(void *))addem, 0, (void *)4);id2=_beginthread((void (*)(void *))factoria, 0, (void *)4);id3=_beginthread((void (*)(void *))AddThree, 0, (void *) list);id4=_beginthread((void (*)(void *))DataAdd, 0, (void *) kll);id5=_beginthread((void (*)(void *))ptr, 0, (void *) str);addem(20);(*ptr)(str);if ((*ptr)(str)) printf("Done!\n");/* printf("Sum of %d and %d is %d",arr[1],arr[2],ddum(arr[1],arr[2]));printf("\npid1 = %d, pid2 = %d, pid3 = %d\n\n",id1,id2,id3);ptr_y = &yy[0];printf("ptr_y: address=0x%p, content=0x%p\n", &ptr_y, ptr_y);printf("*ptr_y +7 => %5.2f.......*(ptr_y + 1) => %5.2f\n", *ptr_y +7,*(ptr_y+1));printf("%f ..... %f\n\n",yy[0],yy[1]);AddThree(list);DataAdd(kll);*/ return 0;}int addem(int count){int i, sum;sum = 0;for (i=0; i<=count; ++i) {printf("I The value of I is %d\n", i);fflush(stdout);sum += i;}printf("I *** The sum is %d\n", sum);fflush(stdout);return 0;}int factoria(int don){int j, mul;mul=1;for(j=1;j<=don;j++) {printf("II The value of II is %d\n", j);fflush(stdout);mul *= j;}printf("II *** The mul is %d\n", mul);fflush(stdout);return 0;}int AddThree(int list[]){int i;int result =0;for (i=0; i<3; i++){printf("III The Value of III is %d\n",i);result += list[i];}printf("III *** The sum of the three integers is: %d\n", result);return 0;}int DataAdd(int *listt){int i;int sum =0,max=listt[0];// printf("max is %d\n",max);for (i=1; i<max; i++){printf("IVV The Value of IVV is %d\n",i);sum += listt[i];}printf("IVV *** The Sum is %d\n",sum);return 0;}int StrPrint(char *str){printf("%s\n", str);return 1;} الـOutput و بالطبع يختلف من جهاز بل على نفس الجهاز يختلف من ظرف لاخر C'est la Multithread   --** Hello World! **--I The value of I is 0I The value of I is 0II The value of II is 1III The Value of III is 0IVV The Value of IVV is 1*** Pointing to a function.IVV The Value of IVV is 2IVV The Value of IVV is 3IVV The Value of IVV is 4IVV The Value of IVV is 5IVV The Value of IVV is 6IVV The Value of IVV is 7IVV *** The Sum is 28III The Value of III is 1I The value of I is 1I The value of I is 2I The value of I is 3I The value of I is 4I The value of I is 5I The value of I is 6I The value of I is 7I The value of I is 8I The value of I is 1II The value of II is 2III The Value of III is 2III *** The sum of the three integers is: 27II The value of II is 3II The value of II is 4II *** The mul is 24I The value of I is 2I The value of I is 3I The value of I is 4I *** The sum is 10I The value of I is 9I The value of I is 10I The value of I is 11I The value of I is 12I The value of I is 13I The value of I is 14I The value of I is 15I The value of I is 16I The value of I is 17I The value of I is 18I The value of I is 19I The value of I is 20I *** The sum is 210*** Pointing to a function.*** Pointing to a function.Done! و الان اتركه لكم ثم نرجع له لما يشاء المناقشة
  10. مكتبة DevIL . http://openil.sourceforge.net/ تمهيد ... الجزء الاول : هذه دروس .. سأضعها ... عن هذه المكتبة .,,,, لنثبت للجميع ان السي ,,,, ليست مجرد شاشة سوداء او ارجوانية .. بعد ان ذقت الامرين في تعلم هذه المكتبة ... بالرغم من انها سهلة الا انه لاتوجد دروس متكاملة عنها ... الا درس واحد خاص بـ GL هذه المكتبة تمكننا من تحميل عشرات الانساق من الصور .. الانساق التي تستطيع المكتبة فتحها : .bmp, .cut, .dds, .doom, .gif, .ico, .jpg, .lbm, .mdl, .mng, .pal, .pbm, .pcd, .pcx, .pgm, .pic, .png, .ppm, .psd, .psp, .raw, .sgi, .tga and .tif اما الانساق التي تستطيع المكتبة حفظها : .bmp, .dds, .h, .jpg, .pal, .pbm, .pcx, .pgm,.png, .ppm, .raw, .sgi, .tga and .tif. ولو قارنت هذه المكتبة .. بـ برنامج ACDSee لعرفت قيمتها .. بل الفوتوشوب .. لايستطيع فتح وحفظ كل هذه الانساق . بالرغم من انه ينفرد ببعض الانساق ... اضافة لذلك توفر هذه المكتبة .. عدة دوال تمكنك من اضافة تأثيرات للصورة . وهذه المكتبة تتكامل مع Opengl Directx WIN API Allegro كانت هذه المكتبة موجهة في الاساس الى opengl لكن بعد ذلك صارت عامة وتحول اسمها من openil الى DevIL هذه احد الروايات التي قرأتها : ) والمكتبة تعمل على الويندوز ولينوكس .... وايضا على عدة مترجمات و لغات Djgpp, MSVC++, Linux gcc, Delphi, Visual Basic, Power Basic and Dev-C++. راجع http://openil.sourceforge.net/features.php لتحميل اي نوع : ILuint ImageId;ilGenImages(1, &ImageId);ilBindImage(ImageId);ilLoadImage("monkey.tga");فقط ....... اذا كنت لاتريد استخدام مكتبات تسهل عليك تحميل الصور فعليك ان تقرأ ملفات الصور بطريقتك وهذا يعني عشرات الاسطر ... :) اولا حمل هذه الحزمة : http://prdownloads.sourceforge.net/openil/...l-SDK-1.6.7.zip قم بفك الملف المضغوط .. ستجد ثلاث ملفات DLL هي DevIL.dll ILU.dll ILUT.dll انسخها الى مجلد system32 .. يعني في الغالب تجده هنا c:\WINDOWS\system32 ثم انسخ المكتبات التالية من المجلد LIB DevIL ILU ILUT والصقها في مجلد المكتبات الخاص بمترجمك .. وهذا يختلف من مترجم لاخر .. لو كنت تستخدم visual c اذهب لمجلد المترجم .. واتبع : C:\Program Files\Microsoft Visual Studio\VC98\Lib الان الصق الملفات اللي نسختها الى ذلك المجلد . طبعا على حسب موقع المترجم عندك .. الان بقي الملفات الرأسية / افتح المجلد اللي حملت قبل قليل ... وبالتحديد مجلد Devil-SDK-1.6.7\include\IL انسخ هذه الملفات il.h ilu.h ilut.h config.h il_wrap.h ilu_region.h devil_internal_exports.h واذهب الى مجلد الملفات الرأسية الخاص بمترجمك .. اذا كنت على الفيجوال سي / C:\Program Files\Microsoft Visual Studio\VC98\Include طبع على حسب موقع المترجم . الان انشأ ملف جديد داخل المجلد include وسمه IL ... الصق الملفات اللي نسختها قبل قليل .. في المجلد IL الان انتهى التثبيت .. بقي شيء واحد وهو ربط المكتبات بمترجمك .. اذا كنت تستخدم الفيجوال سي قبل ان تستدعي الملفات الرأسية اكتب : #   pragma comment (lib, "DevIL.lib")    #   pragma comment (lib, "ILU.lib")        #   pragma comment (lib, "ILUT.lib")       الملفات الرأسية اللي تستدعيها هي /   #include <IL/il.h>#include <IL/ilu.h>#include <IL/ilut.h>الان انتهى كل شيء :: الدرس القادم سنتعلم كيف نستورد صورة . اذهب لهذا الرابط وحمل الوثائق اذا احببت الاطلاع على الدوال + بعض التعليمات ..وملفات المساعدة . http://openil.sourceforge.net/docs/index.php اما السورس كود ... فلايهمنا كثير .. لكن اذا اردت : - http://umn.dl.sourceforge.net/sourceforge/...DevIL-1.6.7.zip
  11. السلام عليكم اليوم كنت أقرا عن الـ D Language http://www.digitalmars.com/d و بالصدفة وجدت معلومة فريدة اجدها لأول مرة: معالجات البنتيوم فيها امر لمعرفة الوقت! الأمر عبارة عن سطر اسمبلي واحد يخزن القيمة في الرجستر eax تلقائيا, و هذا الأمر (حسب ما فهمت) يعطيك عدد دقات ال.. كيف يقولوها .. processor cycles اظن دقات ساعة المعالج, يعني ادق شي مكن تحصل عليه. هذا الأمر هو rdtsc و لتسهيل استخدامه نستطيع بكل بساطة كتابة فنكشن صغير هكذا: inline unsigned int tick(){    __asm    {        rdtsc;    }    //no need for a return statement,    //time is already stored in eax, which is what return does}و عند ترجمة هذا الكود فستصبح مجرد سطر واحد في الأسمبلي, يعني عند استدعاء هذا الفنكشن فكل ما سيحصل هو تنفيذ الأمر rdtsc, فهو inline يعني لا يوجد حتى استدعاء لأي فنكشن, اللهم الا اذا كان الكومبايلر معد عالـ debug, في الفجول سي بلص بلص مثلا, اذا كنت تعمل في الـdebug configuration فسيكون هناك استدعاء لفنكشن حتى مع وجود كلمة inline, اما لو كنت في الـ release configuration, فسيتم تحويل الفنكشن الى inline حتى لو تكن هناك كلمة inline. طبعا انا ضعيف في الأسمبلي, فلا أعرف إذا ما كان هذا السطر مثلا سينفذ كأمر واحد ام كعدة اوامر .. ولا اعرف شي عن طبيعة عمل بنتيوم ولا غيره من هذا الكلام. تستطيع استخدام التوقيت لحساب الفرق بين زمنين هكذا:      unsigned int cpu = tick();    //do something here ..    //basically what you want to time    cpu = tick() - cpu;    cout << "CPU time: " << cpu << endl;اعتقد لا توجد طريقة اسرع او ادق من هذه لحساب الوقت المتغرق لتنفيذ كمية معينة من الكود, فهي اولا تعطيك الوقت نسبة الى المعالج, و ثانيا الكود اللذي يحضر الوقت ليس سوى سطر واحد في الأسمبلي, يعني لا يوجد احتمال ان الكود اللذي ياخذ الوقت هو نفسه يستغرق وقتا اضافيا. الحكاية شفتها اليوم بالصدفة و استفاديت منها, و بصراحة لم اسمع بها ابدا من قبل مع اني بحثت طويلا عن أساليب لاسترجاع قيمة دقيقة لوقت, الا انني لم اجد ابدا اي اشارة لهذا الأمر في البنتيوم. المشكلة الوحيدة هي ان هذا الأمر خاص بالبنتيوم, و قد لا يعمل على اي معالج آخر. ان شاء الله تستفيدون منه.