রান-টাইম জটিলতার (বিগ-ও) লিনকিউ পদ্ধতির কী গ্যারান্টি রয়েছে?


120

আমি সম্প্রতি লিনকিউ ব্যবহার করা বেশ খানিকটা শুরু করেছি এবং লিনকিউ পদ্ধতির কোনওটির জন্য রান-টাইম জটিলতার কোনও উল্লেখ আমি সত্যিই দেখিনি। স্পষ্টতই, এখানে খেলতে অনেকগুলি কারণ রয়েছে, তাই আসুন সমতল IEnumerableলিনকু-টু-অবজেক্টস সরবরাহকারীর কাছে সীমাবদ্ধ রাখি । এর পরে, ধরে নেওয়া যাক যে Funcনির্বাচক / মিউটর / ইত্যাদি হিসাবে পাস করা যে কোনও একটি সস্তা ও (1) অপারেশন।

এটি সুস্পষ্ট বলে মনে হয় সব একক পাস অপারেশন (যে Select, Where, Count, Take/Skip,Any/All , ইত্যাদি) হে (ঢ) যেহেতু তারা শুধুমাত্র একবার ক্রম হেঁটে যাওয়ার প্রয়োজন হবে; যদিও এটি অলসতার সাপেক্ষে।

আরও জটিল ক্রিয়াকলাপগুলির জন্য বিষয়গুলি মার্কিয়ার; সেট মত অপারেটার ( Union, Distinct, Except, ইত্যাদি) কাজ ব্যবহার GetHashCodeডিফল্টরূপে (আমি যতদূর জানি), তাই এটি তারা একটি হ্যাশ টেবিল ব্যবহার করছেন অভ্যন্তরীণভাবে, উপার্জন এই ক্রিয়াকলাপগুলি হে (ঢ) পাশাপাশি সাধারণভাবে অনুমান করা যুক্তিসঙ্গত বলে মনে হয়। যে সংস্করণগুলি ব্যবহার করে সেগুলি সম্পর্কে কী IEqualityComparer?

OrderByএকটি সাজানোর প্রয়োজন হবে, তাই সম্ভবত আমরা ও (এন লগ এন) এ খুঁজছি। যদি এটি ইতিমধ্যে বাছাই করা হয়? আমি যদি বলি OrderBy().ThenBy()এবং উভয়কে একই কী সরবরাহ করি তবে কীভাবে ?

আমি GroupBy(এবং Join) বাছাই বা হ্যাশিং ব্যবহার করে দেখতে পেতাম । ইহা কোনটা?

Containsএ এর উপর ও (এন) হবে List, তবে ও (1) এ HashSet- লিনকিউ কি অন্তর্নিহিত ধারকটি পরীক্ষা করে এটি জিনিসগুলিকে দ্রুততর করতে পারে কিনা তা পরীক্ষা করে?

এবং আসল প্রশ্ন - এখনও অবধি, আমি এটিকে বিশ্বাসের সাথে নিয়েছি যে অপারেশনগুলি পারফরম্যান্স হয়। তবে, আমি কি এটি ব্যাঙ্ক করতে পারি? উদাহরণস্বরূপ, এসটিএল পাত্রে প্রতিটি অপারেশনের জটিলতা স্পষ্টভাবে উল্লেখ করুন specify .NET লাইব্রেরি স্পেসিফিকেশনে লিনকিউ পারফরম্যান্সে কি একই রকম গ্যারান্টি আছে?

আরও প্রশ্ন (মন্তব্যের জবাবে):
ওভারহেড সম্পর্কে সত্যিই চিন্তাভাবনা করা হয়নি, তবে আমি সাধারণ লিনক-টু-অবজেক্টগুলির পক্ষে খুব বেশি হবে বলে আশা করি না। কোডিংহরর পোস্টটি লিনক-টু-এসকিউএল সম্পর্কে কথা বলছে, যেখানে আমি কোয়েরিটি বিশ্লেষণ করতে এবং এসকিউএল তৈরি করা ব্যয় যুক্ত করতে পারে তা বুঝতে পারি - অবজেক্ট সরবরাহকারীর জন্যও কি একই রকম ব্যয় আছে? যদি তা হয় তবে আপনি কি ঘোষণামূলক বা কার্যকরী বাক্য গঠন ব্যবহার করছেন তা ভিন্ন?


যদিও আমি সত্যই আপনার প্রশ্নের উত্তর দিতে পারি না আমি মন্তব্য করতে চাই যে সাধারণভাবে কার্যকারিতার বৃহত অংশটি মূল কার্যকারিতার তুলনায় "ওভারহেড" হবে। এটি অবশ্যই ক্ষেত্রে নয় যখন আপনার খুব বড় ডেটাসেট (> 10 কে আইটেম) থাকে তাই আপনি আগ্রহী im
হেনরি

2
পুনরায়: "আপনি যদি ঘোষণামূলক বা কার্যকরী বাক্য গঠন ব্যবহার করেন তবে এটি কি আলাদা?" - সংকলক ঘোষণামূলক বাক্য গঠনটি কার্যকরী সিনট্যাক্সে অনুবাদ করে যাতে তারা একই হয়।
জন রাশ

"এসটিএল পাত্রে প্রতিটি অপারেশনের জটিলতা স্পষ্টভাবে উল্লেখ করা হয়"। নেট পাত্রে প্রতিটি অপারেশনের জটিলতাও স্পষ্টভাবে উল্লেখ করে। লিনক এক্সটেনশানগুলি এসটিএল অ্যালগরিদমের অনুরূপ, এসটিএল পাত্রে নয়। ঠিক যখন আপনি কোনও এসটিএল ধারকটিতে একটি এসটিএল অ্যালগরিদম প্রয়োগ করেন, ফলস্বরূপ জটিলতার যথাযথ বিশ্লেষণ করতে আপনাকে লিনক এক্সটেনশনের জটিলতার সাথে .NET ধারক ক্রিয়াকলাপের জটিলতা একত্রিত করতে হবে। এটিতে টেমপ্লেট বিশেষীকরণের জন্য অ্যাকাউন্টিং অন্তর্ভুক্ত রয়েছে, যেমন অ্যারোনআটের উত্তরের উল্লেখ রয়েছে।
টিম্বো

একটি অন্তর্নিহিত প্রশ্ন হ'ল মাইক্রোসফ্ট কেন এই বিষয়ে আরও চিন্তিত নন যে কোনও আইলিস্ট <টি> অপ্টিমাইজেশন সীমিত উপযোগী হবে, এই বিবেচনায় রেখে যে কোনও বিকাশকারী যদি তার কোডটি সম্পাদন করার জন্য তার উপর নির্ভরশীল হয় তবে তাকে অননুমোদিত আচরণের উপর নির্ভর করতে হবে।
এডওয়ার্ড ব্রে

ফলাফল সেট তালিকায় AsParallel (); আপনাকে ~ O (1) <O (n)
লেটেন্সি

উত্তর:


121

এখানে খুব কম গ্যারান্টি রয়েছে তবে কয়েকটি অপ্টিমাইজেশন রয়েছে:

  • যেমন এক্সটেনশন পদ্ধতি সূচীবদ্ধ এক্সেস ব্যবহার করেন, ElementAt, Skip, Lastবা LastOrDefaultহোক বা না হোক অন্তর্নিহিত টাইপ কার্যকরী দেখতে চেক করবে IList<T>, যাতে আপনি হে (1) অ্যাক্সেস পরিবর্তে পেতে হে (ঢ) করুন।

  • Countএকটি জন্য পদ্ধতি চেক ICollectionবাস্তবায়ন, তাই হে (1) পরিবর্তে যে এই অপারেশন হে (ঢ)।

  • Distinct, GroupBy Join এবং আমিও বিশ্বাস করি যে সেট-অগ্রিগেশন পদ্ধতিগুলি ( Union, Intersectএবং Except) হ্যাশিং ব্যবহার করে, সুতরাং সেগুলি ও (এনও) এর পরিবর্তে ও (এন) এর কাছাকাছি হওয়া উচিত।

  • Contains একটি জন্য চেক ICollectionবাস্তবায়নের , সুতরাং এটি ও (1) হতে পারে যদি অন্তর্নিহিত সংগ্রহটি ও (1) হয়, যেমন ক HashSet<T>, তবে এটি প্রকৃত ডেটা কাঠামোর উপর নির্ভর করে এবং এটির নিশ্চয়তা নেই। হ্যাশ Containsপদ্ধতিটিকে ওভাররাইড করে দেয় , এজন্য তারা ও (1)।

  • OrderBy পদ্ধতিগুলি একটি স্থিতিশীল কুইকোর্ট ব্যবহার করে, তাই এগুলি ও (এন লগ এন) গড় কেস।

আমি মনে করি এটি অন্তর্নির্মিত এক্সটেনশন পদ্ধতিগুলির মধ্যে না থাকলে সবচেয়ে বেশি জুড়ে। কার্য সম্পাদনের গ্যারান্টি খুব কম রয়েছে; লিনক নিজেই দক্ষ ডেটা স্ট্রাকচারের সুবিধা নেওয়ার চেষ্টা করবে তবে সম্ভাব্য অক্ষম কোডটি লেখার জন্য এটি কোনও বিনামূল্যে পাস নয়।


IEqualityComparerওভারলোড সম্পর্কে কীভাবে ?
tzaman

@ তাজমান: তাদের কী হবে? আপনি যদি সত্যই অদক্ষ রীতিনীতিটি ব্যবহার IEqualityComparerনা করেন, অ্যাসিপটোটিক জটিলতায় এটি প্রভাবিত করার কারণ আমি বলতে পারব না।
অ্যারোনআট

1
হ্যাঁ সঠিক. আমি EqualityComparerপ্রয়োগগুলি GetHashCodeপাশাপাশি উপলব্ধি করতে পারি নি Equals; তবে অবশ্যই এটি সঠিক ধারণা তৈরি করে makes
tzaman

2
@ আইমেজেন: লুপটি ও (এন * এম) সাথে যোগ দেয় যা সম্পর্কহীন সেটের জন্য ও (N²) কে সাধারণীকরণ করে। লিনক হ্যাশ যোগ দেয় যা ও (এন + এম), যা ও (এন) কে সাধারণীকরণ করে। এটি একটি অর্ধেক শালীন হ্যাশ ফাংশনটি ধরে নিয়েছে, তবে। নেট এ জড়ান hard
অ্যারোনআট

1
হয় Orderby().ThenBy()এখনও N logNবা এটা (N logN) ^2বা কিছু যে মত?
এমকাজেম আখগারি

10

আমি দীর্ঘদিন ধরে জানি যে .Count()ফিরে আসে.Count গণনাটি যদি একটি হয় তবেIList

কিন্তু আমি সবসময় সেট অপারেশনের রান-টাইম জটিলতা সম্পর্কে একটু ক্লান্ত ছিল: .Intersect(), .Except(),.Union()

.Intersect()(মন্তব্য খনি) এর জন্য বি দ্রবীভূত বিসিএল (.NET 4.0 / 4.5) বাস্তবায়ন এখানে রয়েছে :

private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
  Set<TSource> set = new Set<TSource>(comparer);
  foreach (TSource source in second)                    // O(M)
    set.Add(source);                                    // O(1)

  foreach (TSource source in first)                     // O(N)
  {
    if (set.Remove(source))                             // O(1)
      yield return source;
  }
}

উপসংহার:

  • কর্মক্ষমতা হ'ল (এম + এন)
  • সংগ্রহগুলি ইতিমধ্যে সেট হয়ে গেলে বাস্তবায়নের সুবিধা নেয় না । (এটি অগত্যা সহজবোধ্য নাও হতে পারে, কারণ ব্যবহারকারীরও মেলানো দরকার))IEqualityComparer<T>

সম্পূর্ণতার জন্য, এখানে জন্য বাস্তবায়নের হয় .Union()এবং .Except()

স্পোলার সতর্কতা: তাদেরও ও (এন + এম) জটিলতা রয়েছে।

private static IEnumerable<TSource> UnionIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
  Set<TSource> set = new Set<TSource>(comparer);
  foreach (TSource source in first)
  {
    if (set.Add(source))
      yield return source;
  }
  foreach (TSource source in second)
  {
    if (set.Add(source))
      yield return source;
  }
}


private static IEnumerable<TSource> ExceptIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
{
  Set<TSource> set = new Set<TSource>(comparer);
  foreach (TSource source in second)
    set.Add(source);
  foreach (TSource source in first)
  {
    if (set.Add(source))
      yield return source;
  }
}

8

আপনি যে বিষয়টি সত্যই ব্যাঙ্ক করতে পারেন তা হ'ল গণ্য পদ্ধতিগুলি সাধারণ ক্ষেত্রে ভাল লেখা থাকে এবং নিষ্পাপ আলগোরিদিম ব্যবহার করবে না। সম্ভবত তৃতীয় পক্ষের স্টাফ রয়েছে (ব্লগ ইত্যাদি) যা বাস্তবে ব্যবহৃত অ্যালগরিদমগুলি বর্ণনা করে তবে এসটিএল অ্যালগরিদমগুলি এই অর্থে অফিসিয়াল বা গ্যারান্টিযুক্ত নয়।

উদাহরণস্বরূপ, এখানে সিস্টেমের জন্য প্রতিবিম্বিত উত্স কোড (আইএলএসপি এর সৌজন্যে) রয়েছে Enumerable.Count:

// System.Linq.Enumerable
public static int Count<TSource>(this IEnumerable<TSource> source)
{
    checked
    {
        if (source == null)
        {
            throw Error.ArgumentNull("source");
        }
        ICollection<TSource> collection = source as ICollection<TSource>;
        if (collection != null)
        {
            return collection.Count;
        }
        ICollection collection2 = source as ICollection;
        if (collection2 != null)
        {
            return collection2.Count;
        }
        int num = 0;
        using (IEnumerator<TSource> enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                num++;
            }
        }
        return num;
    }
}

আপনি দেখতে পাচ্ছেন যে, প্রতিটি উপাদানকে সহজভাবে গণনা করার নিষ্পাপ সমাধান এড়াতে কিছু প্রচেষ্টা চলে যায়।


গণনাটি পাওয়ার জন্য পুরো অবজেক্টের মধ্য দিয়ে পুনরাবৃত্তি করা () যদি এটি একটি অনুজ্ঞাপূর্ণ বলে মনে হয় আমার কাছে বেশ নির্বোধ ...
জোনকো

4
@ জোনকো: আমি আপনার বক্তব্য বুঝতে পারি না। আমি আমার উত্তরটি সংশোধন করে দেখানোর চেষ্টা করেছি যে Enumerable.Countযদি কোনও সুস্পষ্ট বিকল্প না থাকে তবে পুনরাবৃত্তি হয় না। আপনি কিভাবে এটি কম নিষ্প্রভ করতে হবে?
মার্সেলো ক্যান্টোস

ঠিক আছে, হ্যাঁ, উত্সটি প্রদত্ত পদ্ধতিগুলি সবচেয়ে কার্যকর উপায়ে প্রয়োগ করা হয়। যাইহোক, সর্বাধিক দক্ষ উপায় হ'ল কখনও কখনও একটি নিষ্পাপ অ্যালগরিদম এবং লিনাক ব্যবহার করার সময় এক সাবধানতা অবলম্বন করা উচিত কারণ এটি কলগুলির আসল জটিলতা লুকায়। আপনি যে জিনিসগুলি চালাচ্ছেন তার অন্তর্নিহিত কাঠামোর সাথে যদি আপনি পরিচিত না হন তবে আপনি সহজেই আপনার প্রয়োজনের জন্য ভুল পদ্ধতি ব্যবহার করতে পারেন।
জোনকো

@ মার্সেলো ক্যান্টোস কেন অ্যারে পরিচালনা করা হয় না? এটা তোলে ElementAtOrDefault পদ্ধতি জন্য একই referencesource.microsoft.com/#System.Core/System/Linq/...
Freshblood

@ ফ্রেশব্লুড তারা (অ্যারে আইকোলিকেশন বাস্তবায়ন করে)) এলিমেটআরআরডিফল্ট সম্পর্কে জানেন না। আমি অনুমান করছি অ্যারেগুলি আইকোলিকেশন <টি> প্রয়োগও করে তবে আমার। নেট আজকাল বেশ মরিচা।
মার্সেলো ক্যান্টোস

3

আমি কেবল প্রতিফলক ছড়িয়ে দিয়েছি এবং যখন Containsডাকা হয় তখন তারা অন্তর্নিহিত ধরণের পরীক্ষা করে ।

public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
{
    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)
    {
        return is2.Contains(value);
    }
    return source.Contains<TSource>(value, null);
}

3

সঠিক উত্তরটি "এটি নির্ভর করে"। এটি অন্তর্নিহিত IEnumerable কি প্রকারের উপর নির্ভর করে। আমি জানি যে কয়েকটি সংগ্রহের জন্য (যেমন সংগ্রহগুলি আইকোলিকেশন বা আইলিস্ট বাস্তবায়ন করে) সেখানে বিশেষ কোডেপথ ব্যবহার করা হয়, তবে প্রকৃত বাস্তবায়ন বিশেষ কিছু করার নিশ্চয়তা দেয় না। উদাহরণস্বরূপ আমি জানি যে এলিমেন্টআট () এর সূচকযোগ্য সংগ্রহের জন্য একটি বিশেষ কেস রয়েছে, একইভাবে কাউন্ট () এর সাথে। তবে সাধারণভাবে আপনার সম্ভবত সবচেয়ে খারাপ পরিস্থিতি হে (এন) এর কর্মক্ষমতা অনুমান করা উচিত।

উত্সাহীনভাবে আমি মনে করি না আপনি যে ধরনের পারফরম্যান্স গ্যারান্টি চান তা সন্ধান করতে চলেছেন, যদিও আপনি যদি কোনও লিনাক অপারেটরের সাথে কোনও নির্দিষ্ট পারফরম্যান্স সমস্যা নিয়ে চলে যান তবে আপনি সর্বদা এটি আপনার নির্দিষ্ট সংগ্রহের জন্য পুনরায় প্রতিস্থাপন করতে পারেন। এছাড়াও অনেকগুলি ব্লগ এবং এক্সটেনসিবিলিটি প্রকল্প রয়েছে যা লিনককে এই ধরণের পারফরম্যান্স গ্যারান্টি যুক্ত করতে অবজেক্টগুলিতে প্রসারিত করে। আরও কার্য সম্পাদনের সুবিধার জন্য অপারেটর সেটটিতে প্রসারিত এবং সংযোজনকারী সূচিযুক্ত লিনকিউ পরীক্ষা করে দেখুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.