কোনও লিঙ্কযুক্ত তালিকে বাছাই করার জন্য দ্রুততম অ্যালগরিদম কী?


97

আমি আগ্রহী যদি ও (এন লগ এন) লিঙ্কযুক্ত লিস্টটি করতে পারে তবে তা করতে পারে।


32
কেবলমাত্র আপনি জানেন যে, ও (nlogn) তুলনা ভিত্তিক প্রকারের জন্য আবদ্ধ। ও (এন) পারফরম্যান্স (যেমন গণনা বাছাই) দিতে পারে তার চেয়ে তুলনামূলক ভিত্তিক বিভিন্ন প্রকার রয়েছে তবে তাদের ডেটাতে অতিরিক্ত বাধা দরকার।
এমএকে

4
সেই দিনগুলিতে যখন প্রশ্নগুলি "এই কোডটি কেন কাজ করে না ?????" এসও গ্রহণযোগ্য ছিল।
অভিজিৎ সরকার

উত্তর:


102

আপনি চলমান সময়ে ও (এন লগ এন) এর চেয়ে ভাল আর কিছু করতে পারবেন না এমন প্রত্যাশা করা যুক্তিসঙ্গত ।

যাইহোক, আকর্ষণীয় অংশটি হ'ল আপনি এটিকে স্থানে বাছাই করতে পারেন কিনা তা তদন্ত করা , স্টেবল , এর সবচেয়ে খারাপ পরিস্থিতি এবং এগুলি

পুট্টি খ্যাতির সাইমন তাতাম ব্যাখ্যা করেছেন যে কীভাবে সংযুক্তিযুক্ত তালিকার সাথে কোনও লিঙ্কযুক্ত তালিকাটি বাছাই করা যায় । তিনি নিম্নলিখিত মন্তব্যে সমাপ্ত:

যে কোনও স্ব-সম্মানজনক সাজানোর অ্যালগরিদমের মতো, এতে চলমান সময় হে (এন লগ এন) রয়েছে। কারণ এটি মার্জেসোর্ট, সবচেয়ে খারাপ চলমান সময় এখনও ও (এন লগ এন); কোনও প্যাথলজিকাল কেস নেই।

সহায়ক স্টোরেজ প্রয়োজনীয়তা ছোট এবং ধ্রুবক (যেমন বাছাই রুটিনের মধ্যে কয়েকটি ভেরিয়েবল)। অ্যারে থেকে লিঙ্কযুক্ত তালিকার অন্তর্নিহিত পৃথক আচরণের জন্য ধন্যবাদ, এই Mergesort বাস্তবায়ন সাধারণত অ্যালগরিদমের সাথে যুক্ত ও (এন) সহায়ক স্টোরেজ ব্যয়কে এড়িয়ে চলে।

সিতে একটি উদাহরণ বাস্তবায়নও রয়েছে যা একক এবং দ্বিগুণ লিঙ্কযুক্ত তালিকার জন্য কাজ করে।

যেমন @ জর্জেন ফোগ নীচে উল্লেখ করেছেন, বিগ-ও স্বরলিপি কিছু ধ্রুবক কারণগুলি লুকিয়ে থাকতে পারে যা একটি অ্যালগরিদমকে স্মৃতিশক্তির কারণে কম সংখ্যক আইটেম ইত্যাদির কারণে আরও ভাল সম্পাদন করতে পারে etc.


4
এটি একক সংযুক্ত তালিকার জন্য নয়। তার সি কোডটি * পূর্ব এবং পরবর্তী * ব্যবহার করছে।
এল

4
@ এলইটি আসলে দুজনেরই জন্য । তোমার জন্য স্বাক্ষর দেখতে পান, তাহলে listsort, আপনি প্যারামিটার ব্যবহার করে সুইচ করতে পারেন দেখতে পাবেন int is_double
সিএসএল

4
@ এলএ: এখানে সি কোডের একটি পাইথন সংস্করণ রয়েছে যা listsortকেবলমাত্র একা-সংযুক্ত তালিকাগুলি সমর্থন করে
jfs

ও (না) তাত্ত্বিকভাবে রৈখিক, এবং বালতি সাজানোর মাধ্যমে অর্জন করা যায়। একটি যুক্তিসঙ্গত কে (বিট / আকার বাছাই করা বস্তুর আকার) ধরে নেওয়া, এটি কিছুটা দ্রুত হতে পারে
অ্যাডাম

74

বেশ কয়েকটি কারণের উপর নির্ভর করে তালিকাটি কোনও অ্যারেতে অনুলিপি করা এবং তারপরে একটি কুইকোর্ট ব্যবহার করা আসলে দ্রুততর হতে পারে ।

এটি দ্রুত হওয়ার কারণটি হ'ল লিঙ্কযুক্ত তালিকার চেয়ে অ্যারেতে আরও ভাল ক্যাশে পারফরম্যান্স রয়েছে। তালিকার নোডগুলি মেমরিতে বিচ্ছুরিত হলে আপনি পুরো জায়গা জুড়ে ক্যাশে মিস করতে পারেন। তারপরে আবার অ্যারে বড় হলে আপনি যেভাবেই ক্যাশে মিস করবেন।

মার্জর্ট সমান্তরালগুলি আরও ভাল, সুতরাং যদি এটি আপনি চান তবে এটি আরও ভাল পছন্দ হতে পারে। আপনি যদি সরাসরি লিঙ্কযুক্ত তালিকায় এটি সম্পাদন করেন তবে এটি আরও দ্রুত।

যেহেতু উভয় অ্যালগরিদমগুলি ও (এন * লগ এন) এ চালিত হয়, তাই একটি জ্ঞাত সিদ্ধান্ত নেওয়া উভয়কেই মেশিনে চালনা করতে চাইলে তাদের প্রোফাইল করা জড়িত।

--- সম্পাদনা

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

এগুলি ফলাফল:

এন = 1000:

মার্জ সাজানোর সাথে খণ্ডিত তালিকা: 0.000000 সেকেন্ড

কিউসোর্ট সহ অ্যারে: 0.000000 সেকেন্ড

মার্জ সাজানোর সাথে প্যাক করা তালিকা: 0.000000 সেকেন্ড

এন = 100000:

মার্জ সাজানোর সাথে খণ্ডিত তালিকা: 0.039000 সেকেন্ড

কিউসোর্ট সহ অ্যারে: 0.025000 সেকেন্ড

মার্জ সাজানোর সাথে প্যাক করা তালিকা: 0.009000 সেকেন্ড

এন = 1000000:

মার্জ সাজানোর সাথে খণ্ডিত তালিকা: 1.162000 সেকেন্ড

কিউসোর্ট সহ অ্যারে: 0.420000 সেকেন্ড

মার্জ সাজানোর সাথে প্যাক তালিকা: 0.112000 সেকেন্ড

এন = 100000000:

মার্জ সাজানোর সাথে ফ্রেগমেন্টযুক্ত তালিকা: 364.797000 সেকেন্ড

কিউসোর্ট সহ অ্যারে: 61.166000 সেকেন্ড

মার্জ সাজানোর সাথে প্যাক তালিকা: 16.525000 সেকেন্ড

উপসংহার:

কমপক্ষে আমার মেশিনে, ক্যাশে পারফরম্যান্সের উন্নতি করার জন্য একটি অ্যারে অনুলিপি করা ভাল since এটি লক্ষ্য করা উচিত যে আমার মেশিনটিতে একটি 2.8GHz ফেনম II রয়েছে তবে কেবল 0.6GHz র‌্যাম, তাই ক্যাশেটি খুব গুরুত্বপূর্ণ important


4
ভাল মন্তব্য, তবে আপনার তালিকা থেকে কোনও অ্যারেতে অনুলিপি করার জন্য অবিচ্ছিন্ন ব্যয় (আপনার তালিকাটি অতিক্রম করতে হবে) এবং কুইকোর্টের জন্য সবচেয়ে খারাপ সময় হিসাবে বিবেচনা করা উচিত।
সিএসএল

4
ও (এন * লগ এন) তাত্ত্বিকভাবে ও (এন * লগ এন + এন) এর মতো, যা অনুলিপিটির ব্যয় সহ অন্তর্ভুক্ত থাকবে। যে কোনও পর্যাপ্ত পরিমাণে বড় এন এর জন্য, অনুলিপিটির ব্যয়টি আসলেই গুরুত্বপূর্ণ নয়; একটি তালিকা একবারে ট্র্যাভারিংয়ের সময় হওয়া উচিত এন টাইম।
ডিন জে

4
@ ডিএনজে: তাত্ত্বিকভাবে, হ্যাঁ, তবে মনে রাখবেন যে আসল পোস্টারটি এমন ঘটনাটি প্রকাশ করছে যেখানে মাইক্রো-অপটিমাইজেশন গুরুত্বপূর্ণ। এবং সেক্ষেত্রে একটি লিঙ্ক-তালিকাকে অ্যারে রূপান্তরিত করতে ব্যয় করা সময় বিবেচনা করতে হবে। মন্তব্যগুলি অন্তর্দৃষ্টিপূর্ণ, তবে আমি বাস্তবে পারফরম্যান্স লাভের পক্ষে এটি পুরোপুরি নিশ্চিত নই। এটি সম্ভবত খুব ছোট এন এর জন্য কাজ করবে।
সিএসএল

4
@ সিএসএল: প্রকৃতপক্ষে, আমি বৃহত এন এর জন্য স্থানীয় অঞ্চলের সুবিধাগুলি প্রত্যাশা করব বলে ধরে নিচ্ছি যে ক্যাশে মিস করা প্রভাবশালী পারফরম্যান্স প্রভাব, তারপরে অনুলিপি-অনুলিপি-অনুলিপি কপির জন্য প্রায় 2 * এন ক্যাশে মিস করেছে, এছাড়াও কিউসোর্টের জন্য মিসের সংখ্যা, যা এন লগ (এন) এর একটি ছোট ভগ্নাংশ হবে (যেহেতু কিউসোর্টে সর্বাধিক অ্যাক্সেসগুলি সম্প্রতি অ্যাক্সেস করা উপাদানের নিকটবর্তী কোনও উপাদানের সাথে থাকে)। সংযুক্তি বাছাইয়ের জন্য মিসের সংখ্যা এন লগ (এন) এর একটি বৃহত ভগ্নাংশ , যেহেতু তুলনার একটি উচ্চ অনুপাত ক্যাশে মিসের কারণ। সুতরাং বৃহত্তর এন এর জন্য, এই শব্দটি আধিপত্য বিস্তার করে এবং সংহতকরণকে ধীর করে দেয়।
স্টিভ জেসোপ

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

10

এটি এই বিষয় একটি দুর্দান্ত ছোট কাগজ। তাঁর অভিজ্ঞতামূলক উপসংহারটি হল ট্রাইসোর্ট সেরা, তার পরে কুইকোর্ট এবং মার্জেসোর্ট। পলি বাছাই, বুদ্বুদ সাজান, নির্বাচন বাছাই খুব খারাপভাবে সঞ্চালন।

চিং-কুয়াং শেনির লিঙ্কযুক্ত তালিকা অনুসারে বাছাইয়ের একটি সমন্বিত অধ্যয়ন

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.9981


8

তুলনার ধরণ (যেমন উপাদানগুলির তুলনার উপর ভিত্তি করে) সম্ভবত এর চেয়ে দ্রুততর হতে পারে না n log n । অন্তর্নিহিত ডেটা স্ট্রাকচার কী তা বিবেচ্য নয়। উইকিপিডিয়া দেখুন ।

তালিকায় প্রচুর পরিমাণে অভিন্ন উপাদান (যেমন গণনা বাছাই করা), বা তালিকার উপাদানগুলির কিছু প্রত্যাশিত বিতরণ থাকার সুবিধা গ্রহণ করা অন্যান্য ধরণের ক্রম দ্রুততর হয়, যদিও আমি বিশেষত ভালভাবে কাজ করে এমন কোনওটির কথা ভাবতে পারি না though একটি লিঙ্কযুক্ত তালিকায়।


5

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

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

এছাড়াও, যদি আপনার কাছে একটি নিখুঁত হ্যাশযুক্ত বস্তু থাকতে পারে (বা কমপক্ষে একটি হ্যাশ যা সমস্ত মানকে আলাদাভাবে মানচিত্র করে) তবে আপনি তাদের হ্যাশ ফাংশনগুলিতে একটি গণনা বা রেডিক্স সাজানোর চেষ্টা করতে পারেন।


3

একটি Radix বাছাই বিশেষত একটি লিঙ্কযুক্ত তালিকার জন্য উপযুক্ত, যেহেতু একটি অঙ্কের প্রতিটি সম্ভাব্য মানের সাথে মিল রেখে প্রধান পয়েন্টারগুলির একটি টেবিল তৈরি করা সহজ।


4
আপনি কি দয়া করে এই বিষয়টিতে আরও ব্যাখ্যা করতে পারেন বা লিঙ্কযুক্ত তালিকায় রেডিক্স সাজানোর জন্য কোনও সংস্থান লিঙ্ক দিতে পারেন।
লাভটোকোড

2

মার্জ সাজানোর জন্য O (1) অ্যাক্সেসের প্রয়োজন হয় না এবং এটি O (n ln n)। সাধারণ ডেটা বাছাইয়ের জন্য কোনও অ্যালগরিদম ও (N ln n) এর চেয়ে ভাল নয়।

বিশেষ তথ্য অ্যালগরিদম যেমন র‌্যাডিক্স সাজ্ট (ডেটার আকার সীমাবদ্ধ করা) বা হিস্টোগ্রাম সাজানোর (পৃথক ডেটা গণনা করা) কোনও সংযুক্ত তালিকে কম বৃদ্ধি ফাংশন সহ বাছাই করতে পারে যতক্ষণ না আপনি অ (অ) অস্থায়ী স্টোরেজ হিসাবে অ্যাক্সেসের সাথে আলাদা কাঠামো ব্যবহার করেন as ।

আর একটি বিশেষ শ্রেণীর ডেটা হ'ল প্রায় উপাদান অনুসারে সাজানো তালিকার তুলনা বাছাই। এটি (না) অপারেশনে বাছাই করা যেতে পারে।

অ্যারে এবং পিছনে তালিকাটি অনুলিপি করা হবে ও (এন), সুতরাং কোনও স্থান বাছাই করা অ্যালগরিদম ব্যবহার করা যেতে পারে যদি স্থান কোনও সমস্যা না হয়।

উদাহরণস্বরূপ, যুক্ত লিঙ্কযুক্ত তালিকা দেওয়া uint_8, এই কোডটি হিস্টোগ্রাম বাছাই করে ও (এন) সময়ে এটি সাজান:

#include <stdio.h>
#include <stdint.h>
#include <malloc.h>

typedef struct _list list_t;
struct _list {
    uint8_t value;
    list_t  *next;
};


list_t* sort_list ( list_t* list )
{
    list_t* heads[257] = {0};
    list_t* tails[257] = {0};

    // O(N) loop
    for ( list_t* it = list; it != 0; it = it -> next ) {
        list_t* next = it -> next;

        if ( heads[ it -> value ] == 0 ) {
            heads[ it -> value ] = it;
        } else {
            tails[ it -> value ] -> next = it;
        }

        tails[ it -> value ] = it;
    }

    list_t* result = 0;

    // constant time loop
    for ( size_t i = 255; i-- > 0; ) {
        if ( tails[i] ) {
            tails[i] -> next = result;
            result = heads[i];
        }
    }

    return result;
}

list_t* make_list ( char* string )
{
    list_t head;

    for ( list_t* it = &head; *string; it = it -> next, ++string ) {
        it -> next = malloc ( sizeof ( list_t ) );
        it -> next -> value = ( uint8_t ) * string;
        it -> next -> next = 0;
    }

    return head.next;
}

void free_list ( list_t* list )
{
    for ( list_t* it = list; it != 0; ) {
        list_t* next = it -> next;
        free ( it );
        it = next;
    }
}

void print_list ( list_t* list )
{
    printf ( "[ " );

    if ( list ) {
        printf ( "%c", list -> value );

        for ( list_t* it = list -> next; it != 0; it = it -> next )
            printf ( ", %c", it -> value );
    }

    printf ( " ]\n" );
}


int main ( int nargs, char** args )
{
    list_t* list = make_list ( nargs > 1 ? args[1] : "wibble" );


    print_list ( list );

    list_t* sorted = sort_list ( list );


    print_list ( sorted );

    free_list ( list );
}

4
এটি প্রমাণিত হয়েছে যে কোনও তুলনা-ভিত্তিক সাজানো অ্যালগরিদম নেই যা এন লগ এন এর চেয়ে দ্রুত।
আর্টেলিয়াস

9
না, এটি প্রমাণিত হয়েছে যে সাধারণ ডেটাতে তুলনা-ভিত্তিক সাজানো অ্যালগরিদমগুলি লগ এন এর চেয়ে দ্রুত হয় না
পিট কির্খাম

না, O(n lg n)তুলনায়-ভিত্তিক (উদাঃ, রেডিক্স সাজান) এর চেয়ে দ্রুততর কোনও ধরণের অ্যালগোরিদম । সংজ্ঞা অনুসারে, তুলনা বাছাই এমন কোনও ডোমেনের ক্ষেত্রে প্রযোজ্য যাতে মোট অর্ডার রয়েছে (যেমন, তুলনা করা যায়)।
বিডনলান

4
"বিডনলান" "সাধারণ তথ্য" এর বিন্দুটি হ'ল এমন অ্যালগরিদম রয়েছে যা এলোমেলো ইনপুটের পরিবর্তে সীমাবদ্ধ ইনপুটটির জন্য দ্রুত। সীমাবদ্ধ ক্ষেত্রে, আপনি একটি তুচ্ছ ও (1) অ্যালগরিদম লিখতে পারেন যা ইনপুট ডেটা বাছাই করা সীমাবদ্ধ হিসাবে প্রদত্ত একটি তালিকা সাজায়
পিট কির্খাম

এবং এটি তুলনা-ভিত্তিক সাজানো হবে না। "সাধারণ ডেটাতে" এই সংশোধকটি রিডানড্যান্ট, যেহেতু তুলনার ধরণগুলি ইতিমধ্যে সাধারণ ডেটা হ্যান্ডেল করে (এবং বিগ-ও স্বীকৃতি তুলনা সংখ্যার জন্য)।
স্টিভ জেসোপ

1

আপনার প্রশ্নের সরাসরি উত্তর নয়, তবে আপনি যদি এড়িয়ে যান তালিকাটি ব্যবহার করেন তবে এটি ইতিমধ্যে বাছাই করা হয়েছে এবং ও (লগ এন) অনুসন্ধানের সময় রয়েছে।


4
প্রত্যাশিত O(lg N) অনুসন্ধানের সময় - তবে গ্যারান্টিযুক্ত নয়, কারণ স্কিপ তালিকাগুলি এলোমেলোভাবে নির্ভর করে। আপনি যদি অবিশ্বস্ত ইনপুট পেয়ে থাকেন তবে নিশ্চিত হয়ে নিন যে ইনপুট সরবরাহকারী আপনার আরএনজি সম্পর্কে ভবিষ্যদ্বাণী করতে পারে না, বা তারা আপনাকে এমন ডেটা প্রেরণ করতে পারে যা তার সবচেয়ে খারাপ ক্ষেত্রে পারফরম্যান্সকে ট্রিগার করে
বিডনলান

1

যেমনটি আমি জানি, সেরা বাছাই করা অ্যালগরিদম হ'ল (এন * লগ এন), যে পাত্রে যাই হোক না কেন - এটি প্রমাণিত হয়েছে যে শব্দের বিস্তৃত অর্থে বাছাই করা (একীকরণ / কুইকসোর্ট ইত্যাদি স্টাইল) কম যেতে পারে না। একটি লিঙ্কযুক্ত তালিকা ব্যবহার করা আপনাকে আরও ভাল সময় দেওয়ার সুযোগ দেয় না।

ও (এন) এ যে একমাত্র অ্যালগরিদম চলে তা হ'ল "হ্যাক" অ্যালগরিদম যা বাছাইয়ের পরিবর্তে গণনা মানগুলিতে নির্ভর করে।


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

দৃrict়ভাবে বলতে গেলে, এটি চলে O(n lg c)। যদি আপনার সমস্ত উপাদানগুলি অনন্য c >= nহয়, এবং তাই এটি এর চেয়ে বেশি সময় নেয় O(n lg n)
বিডনলান

1

এখানে এমন একটি বাস্তবায়ন রয়েছে যা তালিকায় একবারে ট্র্যাভার করে, রান সংগ্রহ করে, তারপরে মার্জগুলিকে একইভাবে মার্জগুলির সময়সূচি দেয়।

জটিলতা হ'ল হে (এন লগ এম) যেখানে এন হল আইটেমের সংখ্যা এবং এম রানের সংখ্যা। সর্বোত্তম কেস হ'ল ও (এন) (যদি ডেটা ইতিমধ্যে সাজানো থাকে) এবং সবচেয়ে খারাপ ক্ষেত্রে O (n লগ এন) প্রত্যাশার মতো।

এটি ও (লগ এম) অস্থায়ী মেমরির প্রয়োজন; বাছাই তালিকাগুলি জায়গায় জায়গায় করা হয়।

(নীচে আপডেট হয়েছে com মন্তব্যকারী একটি ভাল পয়েন্ট তোলে যে আমার এটি এখানে বর্ণনা করা উচিত)

অ্যালগরিদমের सारটি হ'ল:

    while list not empty
        accumulate a run from the start of the list
        merge the run with a stack of merges that simulate mergesort's recursion
    merge all remaining items on the stack

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

এখানে মার্জিং কোডটি আটকানো সবচেয়ে সহজ:

    int i = 0;
    for ( ; i < stack.size(); ++i) {
        if (!stack[i])
            break;
        run = merge(run, stack[i], comp);
        stack[i] = nullptr;
    }
    if (i < stack.size()) {
        stack[i] = run;
    } else {
        stack.push_back(run);
    }

তালিকাটি সাজানোর বিবেচনা করুন (দাগিবেফজহ) (রান উপেক্ষা করে)। স্ট্যাকের রাজ্যগুলি নিম্নরূপে অগ্রসর হয়:

    [ ]
    [ (d) ]
    [ () (a d) ]
    [ (g), (a d) ]
    [ () () (a d g i) ]
    [ (b) () (a d g i) ]
    [ () (b e) (a d g i) ]
    [ (c) (b e) (a d g i ) ]
    [ () () () (a b c d e f g i) ]
    [ (j) () () (a b c d e f g i) ]
    [ () (h j) () (a b c d e f g i) ]

তারপরে, অবশেষে, এই সমস্ত তালিকাটি মার্জ করুন।

নোট করুন যে স্ট্যাকের আইটেমগুলির (রান) সংখ্যা হয় শূন্য বা 2 ^ i এবং স্ট্যাকের আকার 1 + লগ 2 (নরুনস) দ্বারা সীমাবদ্ধ। প্রতিটি উপাদান স্ট্যাক স্তর প্রতি একবার মার্জ করা হয়, সুতরাং ও (এন লগ এম) তুলনা। টিমসোর্টের সাথে এখানে একটি উত্তীর্ণের মিল রয়েছে, যদিও টিমসোর্ট ফিবোনাচি ক্রমের মতো কিছু ব্যবহার করে এটি স্ট্যাক বজায় রাখে যেখানে এটি দুটিয়ের শক্তি ব্যবহার করে।

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

(উম ... দ্বিতীয় আপডেট।)

অথবা কেবল নীচের অংশে একত্রীকরণের উইকিপিডিয়া দেখুন ।


"বিপরীত ইনপুট" দিয়ে রান ক্রিয়েশন দুর্দান্ত পারফরম্যান্স করা একটি দুর্দান্ত স্পর্শ। O(log m)অতিরিক্ত মেমরির প্রয়োজন হবে না - একটি খালি না হওয়া পর্যন্ত কেবল দুটি তালিকায় রান যোগ করুন।
গ্রেইবার্ড

1

আপনি এটি একটি অ্যারে অনুলিপি এবং তারপর এটি বাছাই করতে পারেন।

  • অ্যারে অনুলিপি করা (এন),

  • বাছাই O (nlgn) (আপনি যদি মার্জ সাজানোর মতো দ্রুত অ্যালগরিদম ব্যবহার করেন),

  • লিঙ্কযুক্ত তালিকায় আবার অনুলিপি করা প্রয়োজন (এন) যদি প্রয়োজন হয়,

সুতরাং এটি O (nlgn) হতে চলেছে।

মনে রাখবেন যে আপনি যদি লিঙ্কযুক্ত তালিকার উপাদানগুলির সংখ্যা না জানেন তবে আপনি অ্যারের আকার জানেন না। আপনি জাভাতে কোডিং দিচ্ছেন উদাহরণস্বরূপ আপনি একটি অ্যারেলিস্ট ব্যবহার করতে পারেন।


জুর্গেন ফোগের উত্তরের সাথে এটি কী যুক্ত করে ?
গ্রাইবার্ড


0

প্রশ্নটি লেটকোড # 148 , এবং সমস্ত বড় ভাষায় প্রচুর সমাধান দেওয়া হয়। খনিটি নিম্নরূপ, তবে আমি সময় জটিলতার বিষয়ে ভাবছি। মধ্যম উপাদানটি সন্ধান করার জন্য, আমরা প্রতিবার সম্পূর্ণ তালিকাটি অতিক্রম করি। প্রথমবারের nউপাদানগুলি পুনরাবৃত্তি হয়, দ্বিতীয়বারের 2 * n/2উপাদানগুলি পুনরাবৃত্তি হয়, এবং আরও অনেক কিছু। মনে হয় O(n^2)সময় হয়েছে।

def sort(linked_list: LinkedList[int]) -> LinkedList[int]:
    # Return n // 2 element
    def middle(head: LinkedList[int]) -> LinkedList[int]:
        if not head or not head.next:
            return head
        slow = head
        fast = head.next

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

        return slow

    def merge(head1: LinkedList[int], head2: LinkedList[int]) -> LinkedList[int]:
        p1 = head1
        p2 = head2
        prev = head = None

        while p1 and p2:
            smaller = p1 if p1.val < p2.val else p2
            if not head:
                head = smaller
            if prev:
                prev.next = smaller
            prev = smaller

            if smaller == p1:
                p1 = p1.next
            else:
                p2 = p2.next

        if prev:
            prev.next = p1 or p2
        else:
            head = p1 or p2

        return head

    def merge_sort(head: LinkedList[int]) -> LinkedList[int]:
        if head and head.next:
            mid = middle(head)
            mid_next = mid.next
            # Makes it easier to stop
            mid.next = None

            return merge(merge_sort(head), merge_sort(mid_next))
        else:
            return head

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