একত্রীকরণের সাজানোর অ্যালগরিদম ব্যবহার করে কীভাবে স্থান স্থানে রাখবেন?


244

আমি জানি প্রশ্নটি খুব নির্দিষ্ট নয়।

আমি চাই কেবল একজনই আমাকে বলতে চান যে কীভাবে একটি সাধারণ মার্জ সাজ্টকে ইন-প্লেস মার্জ সাজ্টে রূপান্তর করতে হয় (বা ধ্রুবক অতিরিক্ত স্পেসের ওভারহেডের সাথে একটি মার্জ সাজান)।

আমি (নেটটিতে) যা কিছু খুঁজে পেতে পারি তা হ'ল পৃষ্ঠাগুলি "এটি খুব জটিল" বা "এই পাঠ্যের আওতার বাইরে" বলে দিচ্ছে।

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

এমনকি যদি এটি খুব জটিল হয় তবে একত্রিত করার পদ্ধতিটিকে কীভাবে স্থানে তৈরি করা যায় তার মূল ধারণাটি কী?


নিস প্রশ্ন আমি জিজ্ঞাসা করলাম যে নিজেকে যখন থেকে গতকাল এক প্রশ্নের মাধ্যমে পড়া: stackoverflow.com/questions/2566459/...
ক্রিস Lercher

এখানে বর্ণিত একটি মোটামুটি সহজ পদ্ধতি রয়েছে: xinok.wordpress.com/2014/08/17/…
ব্র্যাঙ্কো দিমিত্রিজেভিচ

উত্তর:


140

নুথ এটিকে একটি অনুশীলন হিসাবে রেখে গিয়েছিল (খণ্ড 3, 5.2.5)। স্থান মধ্যে একীভূত প্রকারের আছে। সেগুলি অবশ্যই সাবধানতার সাথে প্রয়োগ করা উচিত।

প্রথমত, নিখুঁত ইন-প্লেস মার্জ যেমন এখানে বর্ণিত সঠিক সমাধান নয়। এটি ও (এন 2 ) এর কর্মক্ষমতা হ্রাস করে ।

ধারণাটি হ'ল অ্যারেটির কিছু অংশ বাছাই করার সময় বাকী অংশটি মার্জ করার জন্য হিসাবে ব্যবহার করা হবে।

উদাহরণস্বরূপ নীচের মার্জ ফাংশন মত।

void wmerge(Key* xs, int i, int m, int j, int n, int w) {
    while (i < m && j < n)
        swap(xs, w++, xs[i] < xs[j] ? i++ : j++);
    while (i < m)
        swap(xs, w++, i++);
    while (j < n)
        swap(xs, w++, j++);
}  

এটা তোলে অ্যারে লাগে xs, দুই সাজানো উপ-অ্যারে রেঞ্জ হিসাবে প্রতিনিধিত্ব করা হয় [i, m)এবং [j, n)যথাক্রমে। কর্মক্ষেত্র থেকে শুরু হয় w। বেশিরভাগ পাঠ্যপুস্তকগুলিতে প্রদত্ত স্ট্যান্ডার্ড মার্জ অ্যালগরিদমের সাথে তুলনা করুন, এটি একটিকে সাজানো সাব-অ্যারে এবং কাজের ক্ষেত্রের মধ্যে সামগ্রীর আদান প্রদান করে। ফলস্বরূপ, পূর্ববর্তী কার্যক্ষেত্রে একীভূত বাছাই করা উপাদান থাকে, যখন কার্যক্ষেত্রে সঞ্চিত পূর্ববর্তী উপাদানগুলি দুটি উপ-অ্যারেতে স্থানান্তরিত হয়।

তবে, দুটি বাধা রয়েছে যা অবশ্যই সন্তুষ্ট থাকতে হবে:

  1. কাজের ক্ষেত্রটি অ্যারের সীমানার মধ্যে হওয়া উচিত। অন্য কথায়, কোনও আউট-অফ-বাউন্ড ত্রুটি না ঘটায় উপাদানগুলি আদান-প্রদানের পক্ষে এটি যথেষ্ট বড় হওয়া উচিত।
  2. দু'টি সাজানো অ্যারেগুলির সাথে কাজের ক্ষেত্রটি ওভারল্যাপ করা যায়; তবে এটি অবশ্যই নিশ্চিত করতে হবে যে নিমজ্জিত উপাদানগুলির কোনওটিই ওভাররাইট করা হয়নি।

এই সংশ্লেষিত অ্যালগরিদম সংজ্ঞায়িত করা, এটির সমাধানের কল্পনা করা সহজ, যা অ্যারের অর্ধেক বাছাই করতে পারে; পরবর্তী প্রশ্নটি হ'ল, নীচের চিত্রের মতো কর্মক্ষেত্রে সঞ্চিত বাকিবদ্ধ অংশের কীভাবে মোকাবেলা করতে হবে:

... unsorted 1/2 array ... | ... sorted 1/2 array ...

একটি স্বজ্ঞাত ধারণাটি হ'ল কাজের ক্ষেত্রের আরও অর্ধেক পুনরুত্থিত করা, সুতরাং কেবলমাত্র 1/4 টি উপাদান এখনও সাজানো হয়নি।

... unsorted 1/4 array ... | sorted 1/4 array B | sorted 1/2 array A ...

এই পর্যায়ে মূল বিষয়টি হ'ল আমাদের অবশ্যই বাছাই করা 1/4 উপাদান বি বাছাই করা 1/2 উপাদানগুলির সাথে শিগগির বা তার পরে একত্রীকরণ করতে হবে।

কর্মক্ষেত্রটি কি বাকী আছে, যা কেবল 1/4 উপাদান ধারণ করে, এ এবং বি মিশে যাওয়ার পক্ষে যথেষ্ট বড়? দুর্ভাগ্যক্রমে, এটা না।

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

প্রকৃতপক্ষে, কাজের ক্ষেত্রের দ্বিতীয়ার্ধকে বাছাইয়ের পরিবর্তে আমরা প্রথমার্ধটি বাছাই করতে পারি এবং দু'টি সাজানো অ্যারের মধ্যে কাজের ক্ষেত্রটি এইভাবে রাখতে পারি:

... sorted 1/4 array B | unsorted work area | ... sorted 1/2 array A ...

এই সেটআপটি কার্যকরভাবে উপ-অ্যারের সাথে কাজের ক্ষেত্রটি ওভারল্যাপের ব্যবস্থা করে This এই ধারণাটি [জিরকি কাটাজাইনেন, টমি পাসানেন, জুকা তিউহোলায় প্রস্তাবিত। `Ract কার্যত স্থানের একত্রীকরণ ''। নর্ডিক জার্নাল অফ কম্পিউটিং, 1996]।

সুতরাং কেবলমাত্র অবশিষ্টটি হ'ল উপরের পদক্ষেপটি পুনরাবৃত্তি করা, যা কাজের ক্ষেত্রটি 1/2, 1/4, 1/8 থেকে হ্রাস করে ... যখন কর্মক্ষেত্র যথেষ্ট পরিমাণে ছোট হয়ে যায় (উদাহরণস্বরূপ, কেবলমাত্র দুটি উপাদান বাকী রয়েছে), আমরা পারি এই অ্যালগরিদম শেষ করতে একটি তুচ্ছ সন্নিবেশ সাজানোর স্যুইচ করুন।

এই কাগজের উপর ভিত্তি করে এএনএসআই সি তে বাস্তবায়ন এখানে।

void imsort(Key* xs, int l, int u);

void swap(Key* xs, int i, int j) {
    Key tmp = xs[i]; xs[i] = xs[j]; xs[j] = tmp;
}

/* 
 * sort xs[l, u), and put result to working area w. 
 * constraint, len(w) == u - l
 */
void wsort(Key* xs, int l, int u, int w) {
    int m;
    if (u - l > 1) {
        m = l + (u - l) / 2;
        imsort(xs, l, m);
        imsort(xs, m, u);
        wmerge(xs, l, m, m, u, w);
    }
    else
        while (l < u)
            swap(xs, l++, w++);
}

void imsort(Key* xs, int l, int u) {
    int m, n, w;
    if (u - l > 1) {
        m = l + (u - l) / 2;
        w = l + u - m;
        wsort(xs, l, m, w); /* the last half contains sorted elements */
        while (w - l > 2) {
            n = w;
            w = l + (n - l + 1) / 2;
            wsort(xs, w, n, l);  /* the first half of the previous working area contains sorted elements */
            wmerge(xs, l, l + n - w, n, u, w);
        }
        for (n = w; n > l; --n) /*switch to insertion sort*/
            for (m = n; m < u && xs[m] < xs[m-1]; ++m)
                swap(xs, m, m - 1);
    }
}

যেখানে ডুবন্ত আগে সংজ্ঞায়িত করা হয়।

সম্পূর্ণ উত্স কোডটি এখানে পাওয়া যাবে এবং বিস্তারিত ব্যাখ্যা এখানে পাওয়া যাবে

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


6
Knuth left this as an exercise (Vol 3, 5.2.5).প্রাক্তন বোঝায়। 13. [40] [এই বিভাগের সমাপ্তিতে ] প্রস্তাবিত অভ্যন্তরীণ বাছাই পদ্ধতিটি কার্যকর করুন, উত্পাদন করে যা কেবলমাত্র ও ( স্কয়ার্ট (এন)) অতিরিক্ত মেমরি অবস্থানের ওমে (এন) ইউনিটগুলিতে র্যান্ডম ডেটা সাজায় ? ( 40 ইঙ্গিত বেশ কঠিন বা লম্বা সমস্যা যা সম্ভবত শ্রেণীকক্ষ পরিস্থিতিতে একটি শব্দ প্রকল্প হিসেবে উপযুক্ত। )
বৃদ্ধলোক

4
আমি মনে করি যে পেঙ্গুইন.ইউ সাইটে উল্লিখিত ইন-প্লেস অ্যালগরিদমের সময় জটিলতা হ'ল লগ এন * এন ^ 2) we ঠিক তাই না?
fun

1
এই অ্যালগরিদম এখনও স্থিতিশীল এবং এন লগ এন সময় আছে?
পল স্টেলিয়ান

1
@ পলস্টেলিয়ান - এটি স্থিতিশীল নয়। বাছাই করা অঞ্চলের উপাদানগুলিতে ক্রমবর্ধমান ক্রম অনুসারে কর্মক্ষম অঞ্চলের উপাদানগুলিকে পুনরায় সাজানো হয়। এর অর্থ সমান মানগুলির সাথে কাজ করার অঞ্চল উপাদানগুলি পুনরায় সাজানো হবে যাতে তারা আর তাদের মূল ক্রমে থাকে না।
rcgldr

1
@ পলস্টেলিয়ান - উইকির ব্লক সংযুক্তি বাছাইয়ের জন্য একটি নিবন্ধ রয়েছে , যা আপনি মন্তব্য করেছিলেন হিসাবে স্থিতিশীল। যদি সর্বনিম্ন 2 · স্কয়ার্ট (এন) অনন্য মান থাকে তবে এটি সবচেয়ে ভাল কাজ করে, যা তাদেরকে অ্যারের কাজের ক্ষেত্রগুলি সরবরাহ করতে এবং স্থিতিশীল থাকার জন্য পুনরায় আদেশ করার মঞ্জুরি দেয়।
rcgldr

59

এর "বড় ফলাফল" সহ, এই কাগজটি ইন-প্লেস একত্রিত করার ধরণের (পিডিএফ) বেশ কয়েকটি রূপ বর্ণনা করে:

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.22.5514&rep=rep1&type=pdf

কম চালগুলির সাথে ইন-প্লেস বাছাই করা

জিরকি কাটাজাইনেন, টমি এ প্যাসেনেন

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

আমি মনে করি এটিও প্রাসঙ্গিক। আমার এর প্রিন্টআউটটি পড়ে আছে, আমার কাছে সহকর্মীর হাতে পৌঁছেছে, তবে আমি এটি পড়ে নি। এটি বুনিয়াদি তত্ত্বকে আবৃত করে বলে মনে হচ্ছে, তবে বিষয়টির সাথে আমি কতটা বিস্তৃতভাবে বিচার করতে পারি তা সম্পর্কে আমি তেমন পরিচিত নই:

http://comjnl.oxfordjournals.org/cgi/content/abstract/38/8/681

অনুকূল স্থিতিশীল মার্জ

আন্তোনিওস সিমভোনিস

এই কাগজটি দেখায় যে স্থিরভাবে ও (এম + এন) কার্যনির্বাহী, ও (ম্লগ (এন / এম + 1)) এর সাথে যথাক্রমে দুটি মাপের এন এবং বি, এম B n দুটি সিকোয়েন্সিকে কীভাবে একত্রীকরণ করা যায় এবং কেবল একটি ধ্রুবক ব্যবহার করা যায় অতিরিক্ত স্থান পরিমাণ। এই ফলাফলটি সমস্ত পরিচিত নিম্ন সীমার সাথে মেলে ...


12

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

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

মনে রাখবেন যে এটি অন্তর্ভুক্ত নয় এমন ক্লাসিক সংযুক্তি সাজানোর চেয়েও ধীর।


9
কুইকোর্ট স্থিতিশীল নয়। এটি সত্যই প্রচুর উত্পাদন কোডের জন্য গুরুত্বপূর্ণ।
ডোনাল ফেলো

7
quicksort স্থিতিশীল হতে, এবং iirc সাজানোর একত্রীকরণ অগত্যা জায়গায় যদি স্থিতিশীল নয় পারবেন
জে।

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

4
কুইকোর্টের একটি ও (এন ^ 2) বিশেষ নকশা করা ইনপুটগুলির জন্য সবচেয়ে খারাপ পরিস্থিতিও রয়েছে
হাবোবেেন

4
@ ডোনালফেলোস: জে কে ঠিক ঠিক; কুইকসোর্ট অতিরিক্ত স্থান ব্যয় ছাড়াই স্থিতিশীল হতে প্রয়োগ করা যেতে পারে। উইকিপিডিয়া পরীক্ষা করুন।
মরিচা

10

সমালোচনামূলক পদক্ষেপটি নিজেই স্থানটিতে মার্জ হয়ে যাচ্ছে getting এই উত্সগুলি তৈরি করা ততটা কঠিন নয়, আপনি চেষ্টা করার পরে আপনি কিছু হারিয়ে ফেলেন।

সংযুক্তির এক ধাপের দিকে তাকানো:

[... তালিকা অনুসারে বাছাই করা ... | এক্স ... তালিকা- ... | y ... তালিকা- বি ...]

আমরা জানি যে সাজানো ক্রম অন্য সব কিছুর চেয়ে কম হয়, যে এক্স মধ্যে অন্য সব কিছুর চেয়ে কম হয় একটি , এবং যে Y মধ্যে অন্য সব কিছুর চেয়ে কম হয় বি । যে ক্ষেত্রে x y এর চেয়ে কম বা সমান , আপনি আপনার পয়েন্টারটিকে A এর শুরুতে সরিয়ে নিয়ে যান। কেস যেখানে সালে Y চেয়ে কম হয় এক্স , আপনি অদলবদল পেয়েছেন Y সমগ্র অতীত একজন থেকে সাজানো । এই শেষ পদক্ষেপটি এটিকে ব্যয়বহুল করে তোলে (অধঃপতনজনিত ক্ষেত্রে বাদে)।

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


5
আপনার স্থানটিতে একত্রিত হওয়ার ক্ষেত্রে ও (এম এন) সবচেয়ে খারাপ ক্ষেত্রে জটিলতা রয়েছে, যেখানে মিটার আকার হ'ল এবং এন হ'ল বি আকার। এটি এ ক্ষেত্রে ঘটে যখন এ-এর প্রথম আইটেমটি বি এর শেষ আইটেমের চেয়ে বড় হয় জটিলতাটি ও (কে লগ (কে) + এম + এন) এ উন্নত করা যেতে পারে , যেখানে কে = মিনিট (মি, এন) যুক্ত করে এ এবং বি এর মধ্যে স্তূপ হ'ল এ থেকে আই থেকে আইটেমগুলি থাকা উচিত, যা বিতে থাকা অবশিষ্ট আইটেমের চেয়ে বড়, তবে এ-এর অবশিষ্ট আইটেমের চেয়ে ছোট তবে যদি এ প্রথমে নিঃশেষ হয়ে যায়, তবে গাদাটি অবশ্যই বি এর শেষ প্রান্তে চলে যেতে হবে must অন্যথায় গাদাটি অবশ্যই এ এর ​​শুরুতে সরিয়ে নেওয়া উচিত Then
ভালয়ালা

2
@ ওয়ালিয়াল নোট করুন যে একটি গাদা ব্যবহার করার সময়, সাজানো আর স্থিতিশীল থাকে না। এছাড়াও, আপনি যদি একটি হিপ ব্যবহার করেন তবে আপনি মার্জ সাজ্টের পরিবর্তে হিপ সাজানোর সাথে যেতে পারেন।
মার্টিনকুনেভ

8

শুধু রেফারেন্সের জন্য, এখানে সুন্দর একটি স্থিতিশীল ইন-জায়গা একত্রীকরণ সাজানোর বাস্তবায়ন । জটিল, তবে খুব খারাপ নয়।

আমি উভয় একটি বাস্তবায়নের শেষ পর্যন্ত স্থিতিশীল ইন-জায়গা একত্রীকরণ সাজানোর এবং একটি স্থিতিশীল ইন-জায়গা quicksort জাভা। দয়া করে নোট করুন ও (এন (লগ এন) ^ 2)


4

সি-তে বাফারলেস সংযুক্তির উদাহরণ

#define SWAP(type, a, b) \
    do { type t=(a);(a)=(b);(b)=t; } while (0)

static void reverse_(int* a, int* b)
{
    for ( --b; a < b; a++, b-- )
       SWAP(int, *a, *b);
}
static int* rotate_(int* a, int* b, int* c)
/* swap the sequence [a,b) with [b,c). */
{
    if (a != b && b != c)
     {
       reverse_(a, b);
       reverse_(b, c);
       reverse_(a, c);
     }
    return a + (c - b);
}

static int* lower_bound_(int* a, int* b, const int key)
/* find first element not less than @p key in sorted sequence or end of
 * sequence (@p b) if not found. */
{
    int i;
    for ( i = b-a; i != 0; i /= 2 )
     {
       int* mid = a + i/2;
       if (*mid < key)
          a = mid + 1, i--;
     }
    return a;
}
static int* upper_bound_(int* a, int* b, const int key)
/* find first element greater than @p key in sorted sequence or end of
 * sequence (@p b) if not found. */
{
    int i;
    for ( i = b-a; i != 0; i /= 2 )
     {
       int* mid = a + i/2;
       if (*mid <= key)
          a = mid + 1, i--;
     }
    return a;
}

static void ip_merge_(int* a, int* b, int* c)
/* inplace merge. */
{
    int n1 = b - a;
    int n2 = c - b;

    if (n1 == 0 || n2 == 0)
       return;
    if (n1 == 1 && n2 == 1)
     {
       if (*b < *a)
          SWAP(int, *a, *b);
     }
    else
     {
       int* p, * q;

       if (n1 <= n2)
          p = upper_bound_(a, b, *(q = b+n2/2));
       else
          q = lower_bound_(b, c, *(p = a+n1/2));
       b = rotate_(p, b, q);

       ip_merge_(a, p, b);
       ip_merge_(b, q, c);
     }
}

void mergesort(int* v, int n)
{
    if (n > 1)
     {
       int h = n/2;
       mergesort(v, h); mergesort(v+h, n-h);
       ip_merge_(v, v+h, v+n);
     }
}

অভিযোজিত সংযুক্তির উদাহরণ (অনুকূলিত) optim

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

#include <stdlib.h>
#include <string.h>

static int* copy_(const int* a, const int* b, int* out)
{
    int count = b - a;
    if (a != out)
       memcpy(out, a, count*sizeof(int));
    return out + count;
}
static int* copy_backward_(const int* a, const int* b, int* out)
{
    int count = b - a;
    if (b != out)
       memmove(out - count, a, count*sizeof(int));
    return out - count;
}

static int* merge_(const int* a1, const int* b1, const int* a2,
  const int* b2, int* out)
{
    while ( a1 != b1 && a2 != b2 )
       *out++ = (*a1 <= *a2) ? *a1++ : *a2++;
    return copy_(a2, b2, copy_(a1, b1, out));
}
static int* merge_backward_(const int* a1, const int* b1,
  const int* a2, const int* b2, int* out)
{
    while ( a1 != b1 && a2 != b2 )
       *--out = (*(b1-1) > *(b2-1)) ? *--b1 : *--b2;
    return copy_backward_(a1, b1, copy_backward_(a2, b2, out));
}

static unsigned int gcd_(unsigned int m, unsigned int n)
{
    while ( n != 0 )
     {
       unsigned int t = m % n;
       m = n;
       n = t;
     }
    return m;
}
static void rotate_inner_(const int length, const int stride,
  int* first, int* last)
{
    int* p, * next = first, x = *first;
    while ( 1 )
     {
       p = next;
       if ((next += stride) >= last)
          next -= length;
       if (next == first)
          break;
       *p = *next;
     }
    *p = x;
}
static int* rotate_(int* a, int* b, int* c)
/* swap the sequence [a,b) with [b,c). */
{
    if (a != b && b != c)
     {
       int n1 = c - a;
       int n2 = b - a;

       int* i = a;
       int* j = a + gcd_(n1, n2);

       for ( ; i != j; i++ )
          rotate_inner_(n1, n2, i, c);
     }
    return a + (c - b);
}

static void ip_merge_small_(int* a, int* b, int* c)
/* inplace merge.
 * @note faster for small sequences. */
{
    while ( a != b && b != c )
       if (*a <= *b)
          a++;
       else
        {
          int* p = b+1;
          while ( p != c && *p < *a )
             p++;
          rotate_(a, b, p);
          b = p;
        }
}
static void ip_merge_(int* a, int* b, int* c, int* t, const int ts)
/* inplace merge.
 * @note works with or without additional memory. */
{
    int n1 = b - a;
    int n2 = c - b;

    if (n1 <= n2 && n1 <= ts)
     {
       merge_(t, copy_(a, b, t), b, c, a);
     }
    else if (n2 <= ts)
     {
       merge_backward_(a, b, t, copy_(b, c, t), c);
     }
    /* merge without buffer. */
    else if (n1 + n2 < 48)
     {
       ip_merge_small_(a, b, c);
     }
    else
     {
       int* p, * q;

       if (n1 <= n2)
          p = upper_bound_(a, b, *(q = b+n2/2));
       else
          q = lower_bound_(b, c, *(p = a+n1/2));
       b = rotate_(p, b, q);

       ip_merge_(a, p, b, t, ts);
       ip_merge_(b, q, c, t, ts);
     }
}
static void ip_merge_chunk_(const int cs, int* a, int* b, int* t,
  const int ts)
{
    int* p = a + cs*2;
    for ( ; p <= b; a = p, p += cs*2 )
       ip_merge_(a, a+cs, p, t, ts);
    if (a+cs < b)
       ip_merge_(a, a+cs, b, t, ts);
}

static void smallsort_(int* a, int* b)
/* insertion sort.
 * @note any stable sort with low setup cost will do. */
{
    int* p, * q;
    for ( p = a+1; p < b; p++ )
     {
       int x = *p;
       for ( q = p; a < q && x < *(q-1); q-- )
          *q = *(q-1);
       *q = x;
     }
}
static void smallsort_chunk_(const int cs, int* a, int* b)
{
    int* p = a + cs;
    for ( ; p <= b; a = p, p += cs )
       smallsort_(a, p);
    smallsort_(a, b);
}

static void mergesort_lower_(int* v, int n, int* t, const int ts)
{
    int cs = 16;
    smallsort_chunk_(cs, v, v+n);
    for ( ; cs < n; cs *= 2 )
       ip_merge_chunk_(cs, v, v+n, t, ts);
}

static void* get_buffer_(int size, int* final)
{
    void* p = NULL;
    while ( size != 0 && (p = malloc(size)) == NULL )
       size /= 2;
    *final = size;
    return p;
}
void mergesort(int* v, int n)
{
    /* @note buffer size may be in the range [0,(n+1)/2]. */
    int request = (n+1)/2 * sizeof(int);
    int actual;
    int* t = (int*) get_buffer_(request, &actual);

    /* @note allocation failure okay. */
    int tsize = actual / sizeof(int);
    mergesort_lower_(v, n, t, tsize);
    free(t);
}

2
তুমি কি এটা লিখেছ? এটি অন্যান্য উত্তরে প্রকাশিত অসুবিধাগুলি কীভাবে কাটিয়ে উঠবে? তার চলমান সময় কি?
থমাস আহলে

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

দু'টি সাজানো তালিকার একত্রীকরণের জন্য কেন আপনার পুনরাবৃত্তি বা অতিরিক্ত বাফারের প্রয়োজন? আমি মনে করি দুটি পয়েন্টারকে সামনে রেখে এবং ডানদিকের চেয়ে বড় হলে অদলবদল করে এটি করা যেতে পারে।
জ্যাক 15

3

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

ব্যবহারিক দৃষ্টিকোণ থেকে প্রমাণ পাওয়া যায় যে স্থানে খাঁটি বাস্তবায়ন বাস্তব বিশ্বের পরিস্থিতিগুলিতে আরও ভাল সম্পাদন করছে না। উদাহরণস্বরূপ, সি ++ স্ট্যান্ডার্ডটি স্ট্যান্ড :: ইনপ্লেস_মার্জকে সংজ্ঞায়িত করে , যা নাম হিসাবে অন্তর্ভূক্ত একত্রিতকরণ ক্রিয়াকলাপকে বোঝায়।

ধরে নেওয়া যে সি ++ লাইব্রেরিগুলি সাধারণত খুব ভালভাবে অনুকূলিত হয় এটি কীভাবে প্রয়োগ করা হয় তা দেখতে আকর্ষণীয়:

1) libstdc ++ (জিসিসি কোড বেসের অংশ): স্টাড :: ইনপ্লেস_মেজার

বাস্তবায়নটি ___প্লেজ_মার্জে প্রতিনিধি , যা একটি অস্থায়ী বাফার বরাদ্দ করার চেষ্টা করে সমস্যাটি ডজ করে:

typedef _Temporary_buffer<_BidirectionalIterator, _ValueType> _TmpBuf;
_TmpBuf __buf(__first, __len1 + __len2);

if (__buf.begin() == 0)
  std::__merge_without_buffer
    (__first, __middle, __last, __len1, __len2, __comp);
else
  std::__merge_adaptive
   (__first, __middle, __last, __len1, __len2, __buf.begin(),
     _DistanceType(__buf.size()), __comp);

অন্যথায়, এটি একটি বাস্তবায়নের পিছনে পড়ে ( __ विसাহী_বিহীন_বফার ), যার অতিরিক্ত মেমরির প্রয়োজন নেই, তবে ও (এন) সময়ে আর চলবে না।

2) libc ++ (ক্ল্যাং কোড বেসের অংশ): স্টাড :: ইনপ্লেস_মেজার

অনুরূপ দেখাচ্ছে। এটি একটি ফাংশনে প্রতিনিধিত্ব করে , যা বাফার বরাদ্দ করার চেষ্টা করে । এটি পর্যাপ্ত উপাদান পেয়েছিল কিনা তার উপর নির্ভর করে এটি বাস্তবায়নটি বেছে নেবে। ধ্রুবক-মেমরি ফ্যালব্যাক ফাংশনকে __ বাফার্ড_ইনপ্লেস নিমজ্জন বলে

এমনকি ফ্যালব্যাকটি এখনও ও (এন) সময়, তবে মূল বিষয়টি হ'ল অস্থায়ী মেমরি পাওয়া গেলে তারা প্রয়োগটি ব্যবহার করে না।


নোট করুন যে সি ++ স্ট্যান্ডার্ড স্পষ্টভাবে বাস্তবায়নগুলি ও (এন) থেকে ও (এন লগ এন) এ প্রয়োজনীয় জটিলতা হ্রাস করে এই পদ্ধতিটি বেছে নেওয়ার স্বাধীনতা দেয়:

জটিলতা: যথাযথভাবে N-1 তুলনা করলে অতিরিক্ত অতিরিক্ত মেমরি পাওয়া যায়। স্মৃতি অপর্যাপ্ত হলে ও (এন লগ এন) তুলনা করুন।

অবশ্যই, এটিকে প্রমাণ হিসাবে গ্রহণ করা যায় না যে স্থির স্থান স্থানে স্থানে ও (এন) সময়ে একত্রিত হওয়া কখনও ব্যবহার করা উচিত নয়। অন্যদিকে, এটি দ্রুততর হলে, অনুকূলিত সি ++ গ্রন্থাগারগুলি সম্ভবত এই ধরণের বাস্তবায়নে স্যুইচ করবে।


2

এটি আমার সি সংস্করণ:

void mergesort(int *a, int len) {
  int temp, listsize, xsize;

  for (listsize = 1; listsize <= len; listsize*=2) {
    for (int i = 0, j = listsize; (j+listsize) <= len; i += (listsize*2), j += (listsize*2)) {
      merge(& a[i], listsize, listsize);
    }
  }

  listsize /= 2;

  xsize = len % listsize;
  if (xsize > 1)
    mergesort(& a[len-xsize], xsize);

  merge(a, listsize, xsize);
}

void merge(int *a, int sizei, int sizej) {
  int temp;
  int ii = 0;
  int ji = sizei;
  int flength = sizei+sizej;

  for (int f = 0; f < (flength-1); f++) {
    if (sizei == 0 || sizej == 0)
      break;

    if (a[ii] < a[ji]) {
      ii++;
      sizei--;
    }
    else {
      temp = a[ji];

      for (int z = (ji-1); z >= ii; z--)
        a[z+1] = a[z];  
      ii++;

      a[f] = temp;

      ji++;
      sizej--;
    }
  }
}

নোট করুন যে এই বাস্তবায়নটি সবচেয়ে খারাপ ক্ষেত্রে (বিপরীত অ্যারে) Θ (n ^ 2 লগ এন) সময় নেয়।
মার্টিনকুনেভ

1

ক্রোনরোডের মূল কৌশলটি ব্যবহার করে তবে আরও সহজ বাস্তবায়নের সাথে ইন-প্লেস মার্জ সাজ্টের তুলনামূলকভাবে সহজ বাস্তবায়ন রয়েছে। চিত্রটির উদাহরণ যা এই কৌশলটি চিত্রিত করে তা এখানে পাওয়া যাবে: http://www.logiccoder.com/TheSortProblem/BestMergeInfo.htm

এই লিঙ্কের সাথে যুক্ত একই লেখকের আরও তাত্ত্বিক বিশ্লেষণের লিঙ্কগুলি রয়েছে।


এই লিঙ্কটির ফলাফল 403
শার্লোট টান

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

-6

আমি কেবল নীচের পদক্ষেপগুলি ব্যবহার করে সন্নিবেশ সাজানোর অ্যালগরিদম ব্যবহার করে জেভিএতে মার্জ সাজানোর জন্য স্থানটি মার্জ অ্যালগরিদমকে চেষ্টা করেছি ।
1) দুটি বাছাই করা অ্যারে পাওয়া যায়।
2) প্রতিটি অ্যারের প্রথম মানগুলির তুলনা করুন; এবং সর্বনিম্ন মানটিকে প্রথম অ্যারেতে রাখুন।
3) সারণি সারণি (বাম থেকে ডানে অনুপ্রবেশ) ব্যবহার করে দ্বিতীয় অ্যারেতে বৃহত্তর মানটি রাখুন।
4) তারপরে আবার প্রথম অ্যারের দ্বিতীয় মান এবং দ্বিতীয় অ্যারের প্রথম মানের তুলনা করুন এবং একই কাজ করুন। তবে অদলবদল হওয়ার সাথে সাথে অন্যান্য আইটেমগুলির সাথে তুলনা করার বিষয়ে কিছু সূত্র রয়েছে তবে কেবল অদলবদল প্রয়োজন।

আমি এখানে কিছু অপ্টিমাইজেশন করেছি; সন্নিবেশ সাজানোর তুলনায় কম তুলনা রাখা।
এই সমাধানগুলির সাথে আমি খুঁজে পেয়েছি শুধুমাত্র ত্রুটি এটির জন্য দ্বিতীয় অ্যারে অ্যারের উপাদানগুলির বৃহত্তর অদলবদল প্রয়োজন।

যেমন)

প্রথম___আরয়ে: 3, 7, 8, 9

দ্বিতীয় অ্যারে: 1, 2, 4, 5

তারপরে 7, 8, 9 নিজেকে সর্বশেষে রাখার জন্য তার প্রতিটি উপাদানকে একের পর এক অদলবদল করে (একের পর এক বাম দিকে সরান) দ্বিতীয় অ্যারে করে তোলে।

সুতরাং ধারণা এখানে আইটেম অদলবদল দুটি আইটেমের তুলনায় তুলনামূলকভাবে নগণ্য।

https://github.com/skanagavelu/algorithams/blob/master/src/sorting/MergeSort.java

package sorting;

import java.util.Arrays;

public class MergeSort {
    public static void main(String[] args) {
    int[] array = { 5, 6, 10, 3, 9, 2, 12, 1, 8, 7 };
    mergeSort(array, 0, array.length -1);
    System.out.println(Arrays.toString(array));

    int[] array1 = {4, 7, 2};
    System.out.println(Arrays.toString(array1));
    mergeSort(array1, 0, array1.length -1);
    System.out.println(Arrays.toString(array1));
    System.out.println("\n\n");

    int[] array2 = {4, 7, 9};
    System.out.println(Arrays.toString(array2));
    mergeSort(array2, 0, array2.length -1);
    System.out.println(Arrays.toString(array2));
    System.out.println("\n\n");

    int[] array3 = {4, 7, 5};
    System.out.println(Arrays.toString(array3));
    mergeSort(array3, 0, array3.length -1);
    System.out.println(Arrays.toString(array3));
    System.out.println("\n\n");

    int[] array4 = {7, 4, 2};
    System.out.println(Arrays.toString(array4));
    mergeSort(array4, 0, array4.length -1);
    System.out.println(Arrays.toString(array4));
    System.out.println("\n\n");

    int[] array5 = {7, 4, 9};
    System.out.println(Arrays.toString(array5));
    mergeSort(array5, 0, array5.length -1);
    System.out.println(Arrays.toString(array5));
    System.out.println("\n\n");

    int[] array6 = {7, 4, 5};
    System.out.println(Arrays.toString(array6));
    mergeSort(array6, 0, array6.length -1);
    System.out.println(Arrays.toString(array6));
    System.out.println("\n\n");

    //Handling array of size two
    int[] array7 = {7, 4};
    System.out.println(Arrays.toString(array7));
    mergeSort(array7, 0, array7.length -1);
    System.out.println(Arrays.toString(array7));
    System.out.println("\n\n");

    int input1[] = {1};
    int input2[] = {4,2};
    int input3[] = {6,2,9};
    int input4[] = {6,-1,10,4,11,14,19,12,18};
    System.out.println(Arrays.toString(input1));
    mergeSort(input1, 0, input1.length-1);
    System.out.println(Arrays.toString(input1));
    System.out.println("\n\n");

    System.out.println(Arrays.toString(input2));
    mergeSort(input2, 0, input2.length-1);
    System.out.println(Arrays.toString(input2));
    System.out.println("\n\n");

    System.out.println(Arrays.toString(input3));
    mergeSort(input3, 0, input3.length-1);
    System.out.println(Arrays.toString(input3));
    System.out.println("\n\n");

    System.out.println(Arrays.toString(input4));
    mergeSort(input4, 0, input4.length-1);
    System.out.println(Arrays.toString(input4));
    System.out.println("\n\n");
}

private static void mergeSort(int[] array, int p, int r) {
    //Both below mid finding is fine.
    int mid = (r - p)/2 + p;
    int mid1 = (r + p)/2;
    if(mid != mid1) {
        System.out.println(" Mid is mismatching:" + mid + "/" + mid1+ "  for p:"+p+"  r:"+r);
    }

    if(p < r) {
        mergeSort(array, p, mid);
        mergeSort(array, mid+1, r);
//      merge(array, p, mid, r);
        inPlaceMerge(array, p, mid, r);
        }
    }

//Regular merge
private static void merge(int[] array, int p, int mid, int r) {
    int lengthOfLeftArray = mid - p + 1; // This is important to add +1.
    int lengthOfRightArray = r - mid;

    int[] left = new int[lengthOfLeftArray];
    int[] right = new int[lengthOfRightArray];

    for(int i = p, j = 0; i <= mid; ){
        left[j++] = array[i++];
    }

    for(int i = mid + 1, j = 0; i <= r; ){
        right[j++] = array[i++];
    }

    int i = 0, j = 0;
    for(; i < left.length && j < right.length; ) {
        if(left[i] < right[j]){
            array[p++] = left[i++];
        } else {
            array[p++] = right[j++];
        }
    }
    while(j < right.length){
        array[p++] = right[j++];
    } 
    while(i < left.length){
        array[p++] = left[i++];
    }
}

//InPlaceMerge no extra array
private static void inPlaceMerge(int[] array, int p, int mid, int r) {
    int secondArrayStart = mid+1;
    int prevPlaced = mid+1;
    int q = mid+1;
    while(p < mid+1 && q <= r){
        boolean swapped = false;
        if(array[p] > array[q]) {
            swap(array, p, q);
            swapped = true;
        }   
        if(q != secondArrayStart && array[p] > array[secondArrayStart]) {
            swap(array, p, secondArrayStart);
            swapped = true;
        }
        //Check swapped value is in right place of second sorted array
        if(swapped && secondArrayStart+1 <= r && array[secondArrayStart+1] < array[secondArrayStart]) {
            prevPlaced = placeInOrder(array, secondArrayStart, prevPlaced);
        }
        p++;
        if(q < r) {     //q+1 <= r) {
            q++;
        }
    }
}

private static int placeInOrder(int[] array, int secondArrayStart, int prevPlaced) {
    int i = secondArrayStart;
    for(; i < array.length; i++) {
        //Simply swap till the prevPlaced position
        if(secondArrayStart < prevPlaced) {
            swap(array, secondArrayStart, secondArrayStart+1);
            secondArrayStart++;
            continue;
        }
        if(array[i] < array[secondArrayStart]) {
            swap(array, i, secondArrayStart);
            secondArrayStart++;
        } else if(i != secondArrayStart && array[i] > array[secondArrayStart]){
            break;
        }
    }
    return secondArrayStart;
}

private static void swap(int[] array, int m, int n){
    int temp = array[m];
    array[m] = array[n];
    array[n] = temp;
}
}

3
এটি উভয়ই (এন ^ 2) এবং অত্যধিক অপঠনযোগ্য (মাঝে মাঝে সিনট্যাক্স ত্রুটি এবং বেমানান / খারাপ শৈলীর কারণে)
গ্লাবা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.