سؤال

عند التكرار على عناصر المتجه، يفضل استخدام التكرارات بدلاً من الفهرس (انظر لماذا نستخدم التكرارات بدلاً من مؤشرات المصفوفة؟).

std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   // do work
}

ومع ذلك، قد يكون من الضروري استخدام الفهرس الموجود في نص الحلقة.أي مما يلي سيكون الأفضل في هذه الحالة، مع الأخذ في الاعتبار الأداء والمرونة/قابلية التوسعة؟

  1. العودة إلى الحلقة المفهرسة
    std::vector vec;
    size_t i;
    for ( i = 0; i < vec.size(); ++i )
    {
       // use i
    }
    
  2. حساب الإزاحة
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = it - vec.begin(); 
       // use i
    }
    
  3. استخدم الأمراض المنقولة جنسيا :: المسافة
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = std::distance( vec.begin(), it );
       // use i
    }
    
هل كانت مفيدة؟

المحلول

إذا كنت تخطط لاستخدام ناقل حصريًا، فقد ترغب في الرجوع مرة أخرى إلى الحلقة المفهرسة، لأنها تنقل نيتك بشكل أكثر وضوحًا من حلقة التكرار.ومع ذلك، إذا كان تطور برنامجك في المستقبل قد يؤدي إلى تغيير الحاوية، فيجب عليك الالتزام بالمكررات واستخدام std::distance، والتي تضمن العمل مع جميع التكرارات القياسية.

نصائح أخرى

يعد استخدام std::distance أكثر عمومية لأنه يعمل مع جميع التكرارات، وليس فقط مكررات الوصول العشوائي.وينبغي أن يكون بنفس السرعة - vec.begin() في حالة تكرارات الوصول العشوائي.

إنه - vec.begin() هو في الأساس مؤشر حسابي.

std::distance(vec.begin(), it) سوف أعطيك الفهرس it يشير إلى، على افتراض أنه يشير إلى vec.

كارل

العودة إلى الحلقة المفهرسة.

في الأساس، في 90% من الحالات، تكون المكررات متفوقة، وهذه واحدة من تلك الـ 10%.باستخدام المكرر، فإنك تجعل التعليمات البرمجية أكثر تعقيدًا وبالتالي يصعب فهمها، في حين أن السبب الكامل لاستخدام المكرر في المقام الأول هو تبسيط التعليمات البرمجية الخاصة بك.

ينقصك حل واحد:احتفظ بفهرس في حالة احتياجك إليه، لكن لا تستخدمه كشرط حلقة.يعمل على القوائم أيضًا، والتكاليف (لكل حلقة) هي O(n) وتسجيل إضافي.

سأميل دائمًا إلى الاستمرار مع التكرارات لأسباب التطوير المستقبلية.

في المثال أعلاه، إذا قررت تبديل std::vector بـ std::set (ربما كنت بحاجة إلى مجموعة فريدة من العناصر)، فإن استخدام التكرارات و distance() سيستمر في العمل.

أنا متأكد تمامًا من أنه سيتم تحسين أي مشكلات في الأداء إلى درجة أنها لا تذكر.

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

يمكن أن تكون التكرارات المتجهة أسرع قليلًا من الفهرس من الناحية النظرية، نظرًا لأنها تستخدم حساب المؤشر للتكرار عبر القائمة.ومع ذلك، عادةً ما أجد أن سهولة القراءة تستحق أدنى فرق في وقت التشغيل.

أستخدم التكرارات لأنواع الحاويات الأخرى، وأحيانًا عندما لا تحتاج إلى متغير الحلقة.لكن إذا كنت بحاجة إلى متغير الحلقة، فلن تفعل أي شيء سوى زيادة صعوبة كتابة الحلقة.(لا أستطيع الانتظار حتى يتم تشغيل c++0x تلقائيًا..)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top