के-वे मर्ज एल्गोरिदम

कंप्यूटर विज्ञान में, के-वे एल्गोरिदम मर्ज करें या मल्टीवे मर्ज एक विशिष्ट प्रकार के मर्ज एल्गोरिदम हैं जो के क्रमबद्ध सूचियों को लेने और उन्हें एक एकल क्रमबद्ध सूची में विलय करने में विशेषज्ञ हैं। ये मर्ज एल्गोरिदम आम तौर पर मर्ज एल्गोरिदम को संदर्भित करते हैं जो दो से अधिक क्रमबद्ध सूचियों को लेते हैं। दो-तरफा मर्ज को बाइनरी मर्ज भी कहा जाता है। के-वे मर्ज बाहरी सॉर्टिंग एल्गोरिदम भी है।

दोतरफा विलय
मर्ज़ सॉर्ट में इसकी महत्वपूर्ण भूमिका के कारण 2-तरफ़ा मर्ज, या बाइनरी मर्ज का बड़े पैमाने पर अध्ययन किया गया है। इसका एक उदाहरण क्लासिक मर्ज है जो मर्ज सॉर्ट उदाहरणों में अक्सर दिखाई देता है। क्लासिक मर्ज प्रत्येक चरण में सबसे कम कुंजी के साथ डेटा आइटम को आउटपुट करता है; कुछ क्रमबद्ध सूचियों को देखते हुए, यह एक क्रमबद्ध सूची तैयार करता है जिसमें किसी भी इनपुट सूची में सभी तत्व शामिल होते हैं, और यह इनपुट सूचियों की लंबाई के योग के अनुपात में समय पर ऐसा करता है।

बढ़ते क्रम में क्रमबद्ध दो सरणियों को A[1..p] और B[1..q] द्वारा निरूपित करें। इसके अलावा, आउटपुट ऐरे को C[1..n] से निरूपित करें। कैनोनिकल 2-वे मर्ज एल्गोरिदम सूचकांक i, j, और k को क्रमशः A, B, और C में संग्रहीत करता है। प्रारंभ में, ये सूचकांक पहले तत्व को संदर्भित करते हैं, यानी 1 हैं। यदि A[i] < B[j], तो एल्गोरिथ्म A[i] को C[k] में कॉपी करता है और i और k को बढ़ाता है। अन्यथा, एल्गोरिदम B[j] को C[k] में कॉपी करता है और j और k को बढ़ाता है। एक विशेष मामला उत्पन्न होता है यदि i या j में से कोई भी A या B के अंत तक पहुँच गया हो। इस मामले में एल्गोरिदम बी या ए के शेष तत्वों को सी में कॉपी करता है और समाप्त करता है।

के-वे मर्ज
के-वे मर्ज समस्या में समान तत्वों के साथ एकल क्रमबद्ध सरणी बनाने के लिए k क्रमबद्ध सरणियों को मर्ज करना शामिल है। तत्वों की कुल संख्या को n से निरूपित करें। n आउटपुट ऐरे के आकार और k इनपुट ऐरे के आकार के योग के बराबर है। सरलता के लिए, हम मानते हैं कि कोई भी इनपुट ऐरे खाली नहीं है। एक परिणाम के रूप में $$k \le n$$, जो रिपोर्ट किए गए चलने के समय को सरल बनाता है। में समस्या का समाधान किया जा सकता है $$\mathcal{O}(n \cdot \log(k))$$ के साथ समय चल रहा है $$\mathcal{O}(n)$$ अंतरिक्ष। इस रनिंग टाइम को प्राप्त करने वाले कई एल्गोरिदम मौजूद हैं।

पुनरावृत्तीय 2-तरफा विलय
समस्या को 2-तरफा मर्ज का उपयोग करके दो k सरणियों को पुनरावृत्त रूप से मर्ज करके हल किया जा सकता है जब तक कि केवल एक ही ऐरे न रह जाए। यदि सरणियों को मनमाने क्रम में मर्ज किया जाता है, तो परिणामी रनिंग समय केवल O(kn) होता है। यह उप-इष्टतम है.

पहले को दूसरे के साथ, तीसरे को चौथे के साथ, इत्यादि को पुनरावृत्त रूप से विलय करके चलने के समय में सुधार किया जा सकता है। चूँकि प्रत्येक पुनरावृत्ति में सरणियों की संख्या आधी हो जाती है, केवल Θ(लॉग k) पुनरावृत्तियाँ होती हैं। प्रत्येक पुनरावृत्ति में प्रत्येक तत्व को ठीक एक बार स्थानांतरित किया जाता है। इसलिए प्रति पुनरावृत्ति चलने का समय Θ(n) में है क्योंकि n तत्वों की संख्या है। इसलिए कुल चलने का समय Θ(n log k) में है।

हम दो सबसे छोटी सरणियों को पुनरावृत्त रूप से मर्ज करके, इस एल्गोरिदम में और सुधार कर सकते हैं। यह स्पष्ट है कि यह चलने के समय को कम करता है और इसलिए पिछले पैराग्राफ में वर्णित रणनीति से बदतर नहीं हो सकता है। इसलिए चलने का समय O(n log k) में है। सौभाग्य से, सीमावर्ती मामलों में चलने का समय बेहतर हो सकता है। उदाहरण के लिए पतित मामले पर विचार करें, जहां एक सरणी को छोड़कर सभी में केवल एक तत्व होता है। पिछले पैराग्राफ में बताई गई रणनीति के लिए Θ(n log k) रनिंग टाइम की आवश्यकता होती है, जबकि बेहतर रणनीति के लिए केवल Θ(n + k log k) रनिंग टाइम की आवश्यकता होती है।

डायरेक्ट के-वे मर्ज
इस मामले में, हम एक साथ k-रन को एक साथ मर्ज कर देंगे।

एक सीधा कार्यान्वयन न्यूनतम निर्धारित करने के लिए सभी k सरणियों को स्कैन करेगा। इस सीधे कार्यान्वयन के परिणामस्वरूप Θ(kn) का रनिंग टाइम प्राप्त होता है। ध्यान दें कि इसका उल्लेख केवल चर्चा के लिए एक संभावना के रूप में किया गया है। हालाँकि यह काम करेगा, लेकिन यह कुशल नहीं है।

हम सबसे छोटे तत्व की तेजी से गणना करके इसमें सुधार कर सकते हैं। हीप (डेटा संरचना), टूर्नामेंट ट्री, या बिखरा हुआ पेड़  का उपयोग करके, सबसे छोटा तत्व O(लॉग k) समय में निर्धारित किया जा सकता है। इसलिए परिणामी चलने का समय O(n log k) में है।

ढेर का उपयोग आमतौर पर अधिक किया जाता है, हालांकि टूर्नामेंट ट्री व्यवहार में तेज़ होता है। एक ढेर प्रत्येक चरण में लगभग 2*लॉग(k) तुलनाओं का उपयोग करता है क्योंकि यह पेड़ को जड़ से नीचे तक संभालता है और प्रत्येक नोड के दोनों बच्चों की तुलना करने की आवश्यकता होती है। इस बीच, एक टूर्नामेंट ट्री को केवल लॉग (के) तुलना की आवश्यकता होती है क्योंकि यह पेड़ के नीचे से शुरू होता है और जड़ तक काम करता है, प्रत्येक परत में केवल एक ही तुलना करता है। इसलिए टूर्नामेंट ट्री को पसंदीदा कार्यान्वयन होना चाहिए।

ढेर
विचार यह है कि k सूचियों का न्यूनतम-ढेर बनाए रखा जाए, प्रत्येक को उनके सबसे छोटे वर्तमान तत्व द्वारा कुंजीबद्ध किया जाए। एक सरल एल्गोरिदम ढेर से नोड्स के साथ एक आउटपुट बफर बनाता है। नोड्स का एक न्यूनतम-ढेर बनाकर प्रारंभ करें, जहां प्रत्येक नोड में सूची का एक प्रमुख तत्व और सूची का शेष (या पूंछ) होता है। चूँकि सूचियाँ प्रारंभ में क्रमबद्ध होती हैं, शीर्ष प्रत्येक सूची का सबसे छोटा तत्व होता है; हीप प्रॉपर्टी गारंटी देती है कि रूट में सभी सूचियों में न्यूनतम तत्व शामिल हैं। हीप से रूट नोड निकालें, हेड एलिमेंट को आउटपुट बफर में जोड़ें, टेल से एक नया नोड बनाएं और इसे हीप में डालें। तब तक दोहराएं जब तक कि ढेर में केवल एक नोड न रह जाए, उस बिंदु पर बस उस शेष सूची (हेड और टेल) को आउटपुट बफर में जोड़ दें।

पॉइंटर्स का उपयोग करना, एक इन-प्लेस हीप एल्गोरिदम इनपुट सरणियों में पॉइंटर्स का एक न्यूनतम-ढेर आवंटित करता है। प्रारंभ में ये पॉइंटर्स इनपुट ऐरे के सबसे छोटे तत्वों की ओर इशारा करते हैं। सूचकों को उस मान के आधार पर क्रमबद्ध किया जाता है जिस पर वे इंगित करते हैं। O(k) प्रीप्रोसेसिंग चरण में मानक हीपिफ़ाई प्रक्रिया का उपयोग करके ढेर बनाया जाता है। बाद में, एल्गोरिदम पुनरावृत्त रूप से उस तत्व को स्थानांतरित करता है जिसे रूट पॉइंटर इंगित करता है, इस पॉइंटर को बढ़ाता है और रूट तत्व पर मानक कमी कुंजी प्रक्रिया निष्पादित करता है। वृद्धि कुंजी प्रक्रिया का चलने का समय O(लॉग k) से घिरा है। चूँकि n तत्व हैं, कुल चलने का समय O(n log k) है।

ध्यान दें कि कुंजी को बदलने और पुनरावृत्त रूप से कमी-कुंजी या सिफ्ट-डाउन करने का संचालन कई प्राथमिकता कतार पुस्तकालयों जैसे सी ++ एसटीएल और जावा द्वारा समर्थित नहीं है। एक्स्ट्रेक्ट-मिन और इंसर्ट फ़ंक्शन करना कम कुशल है।

टूर्नामेंट ट्री
टूर्नामेंट ट्री खेल प्रतियोगिताओं की तरह, एक एलिमिनेशन टूर्नामेंट पर आधारित है। प्रत्येक गेम में, दो इनपुट तत्व प्रतिस्पर्धा करते हैं। विजेता को अगले दौर में पदोन्नत किया जाता है। इसलिए, हमें खेलों का एक द्विआधारी वृक्ष मिलता है। सूची को आरोही क्रम में क्रमबद्ध किया गया है, इसलिए गेम का विजेता दोनों तत्वों में से छोटा होता है।

के-वे विलय के लिए, केवल प्रत्येक गेम के हारने वाले को स्टोर करना अधिक कुशल है (छवि देखें)। इसलिए डेटा संरचना को लूज़र ट्री कहा जाता है। पेड़ बनाते समय या किसी तत्व को उसकी सूची में से अगले तत्व से प्रतिस्थापित करते समय, हम अभी भी गेम के विजेता को शीर्ष पर बढ़ावा देते हैं। पेड़ एक खेल मैच की तरह भरा हुआ है लेकिन नोड्स केवल हारने वाले को ही संग्रहीत करते हैं। आमतौर पर, रूट के ऊपर एक अतिरिक्त नोड जोड़ा जाता है जो समग्र विजेता का प्रतिनिधित्व करता है। प्रत्येक पत्ता किसी एक इनपुट ऐरे में एक पॉइंटर संग्रहीत करता है। प्रत्येक आंतरिक नोड एक मान और एक सूचकांक संग्रहीत करता है। आंतरिक नोड का सूचकांक इंगित करता है कि मान किस इनपुट सरणी से आता है। मान में संबंधित इनपुट सरणी के पहले तत्व की एक प्रति शामिल है।

एल्गोरिथ्म पुनरावृत्त रूप से न्यूनतम तत्व को परिणाम में जोड़ता है और फिर तत्व को संबंधित इनपुट सूची से हटा देता है। यह अद्यतन पत्ती से रूट (प्रतिस्थापन चयन) तक पथ पर नोड्स को अद्यतन करता है। हटाया गया तत्व समग्र विजेता है। इसलिए, इसने इनपुट ऐरे से रूट तक के पथ पर प्रत्येक गेम जीता है। इनपुट ऐरे से एक नया तत्व चुनते समय, तत्व को रूट के पथ पर पिछले हारे हुए तत्वों के खिलाफ प्रतिस्पर्धा करने की आवश्यकता होती है। हारे हुए पेड़ का उपयोग करते समय, गेम को दोबारा खेलने के लिए भागीदार पहले से ही नोड्स में संग्रहीत होता है। दोबारा खेले गए प्रत्येक गेम के हारने वाले को नोड में लिखा जाता है और विजेता को पुनरावृत्त रूप से शीर्ष पर पदोन्नत किया जाता है। जब रूट पर पहुंच जाता है, तो नया समग्र विजेता मिल जाता है और विलय के अगले दौर में इसका उपयोग किया जा सकता है।

इस अनुभाग में टूर्नामेंट ट्री और हारने वाले ट्री की छवियां समान डेटा का उपयोग करती हैं और हारने वाले ट्री के काम करने के तरीके को समझने के लिए उनकी तुलना की जा सकती है।

एल्गोरिथम
एक टूर्नामेंट ट्री को इनपुट सूचियों में सेंटिनल्स जोड़कर (यानी अनंत के मूल्य के साथ प्रत्येक सूची के अंत में एक सदस्य जोड़कर) और संख्या तक शून्य सूचियां (केवल एक सेंटिनल शामिल करके) जोड़कर एक संतुलित बाइनरी ट्री के रूप में दर्शाया जा सकता है। सूचियाँ दो की शक्ति है। संतुलित वृक्ष को एक ही सारणी में संग्रहित किया जा सकता है। वर्तमान सूचकांक को दो से विभाजित करके मूल तत्व तक पहुंचा जा सकता है।

जब पत्तों में से एक को अद्यतन किया जाता है, तो पत्ते से जड़ तक सभी खेल दोबारा खेले जाते हैं। निम्नलिखित छद्मकोड में, एक सरणी के बजाय एक ऑब्जेक्ट ओरिएंटेड ट्री का उपयोग किया जाता है क्योंकि इसे समझना आसान है। इसके अतिरिक्त, विलय की जाने वाली सूचियों की संख्या दो की घात मानी जाती है।

फ़ंक्शन मर्ज(L1, ..., Ln) बिल्डट्री (L1, ..., Ln के प्रमुख) जबकि पेड़ में तत्व होते हैं विजेता := वृक्ष.विजेता आउटपुट विजेता.मान नया:=विजेता.index.next रीप्लेगेम्स(विजेता, नया) // प्रतिस्थापन चयन

फ़ंक्शन रीप्लेगेम्स (नोड, नया) हारने वाला, विजेता := प्लेगेम(नोड, नया) नोड.मूल्य := हारा हुआ.मूल्य नोड.इंडेक्स := लूजर.इंडेक्स यदि नोड != रूट रीप्लेगेम्स(नोड.पैरेंट, विजेता)

फ़ंक्शन बिल्डट्री (तत्व) अगली परत := नई सारणी जबकि तत्व खाली नहीं हैं el1 := element.take el2 := element.take हारने वाला, विजेता := प्लेगेम(el1, el2) पैरेंट:= नया नोड(el1, el2, लूज़र) अगली परत.जोड़ें(मूल) यदि नेक्स्टलेयर.आकार == 1 रिटर्न नेक्स्टलेयर // केवल रूट अन्य रिटर्न बिल्डट्री (नेक्स्टलेयर)

चलने का समय
शुरुआत में, पेड़ पहली बार Θ(k) समय में बनाया गया है। विलय के प्रत्येक चरण में, केवल नए तत्व से रूट तक के पथ पर गेम को फिर से चलाने की आवश्यकता होती है। प्रत्येक परत में, केवल एक तुलना की आवश्यकता है। चूँकि पेड़ संतुलित है, इनपुट सरणियों में से एक से रूट तक के पथ में केवल Θ(लॉग k) तत्व होते हैं। कुल मिलाकर, ऐसे n तत्व हैं जिन्हें स्थानांतरित करने की आवश्यकता है। परिणामस्वरूप कुल चलने का समय Θ(n log k) में है।

उदाहरण
निम्नलिखित अनुभाग में प्रतिस्थापन चयन चरण के लिए एक विस्तृत उदाहरण और एकाधिक प्रतिस्थापन चयन वाले पूर्ण मर्ज के लिए एक उदाहरण शामिल है।

प्रतिस्थापन चयन
खेल नीचे से ऊपर तक दोबारा खेले जाते हैं। पेड़ की प्रत्येक परत में, नोड का वर्तमान में संग्रहीत तत्व और नीचे की परत से प्रदान किया गया तत्व प्रतिस्पर्धा करते हैं। विजेता को तब तक शीर्ष पर पदोन्नत किया जाता है जब तक हमें नया समग्र विजेता नहीं मिल जाता। हारने वाला पेड़ के नोड में संग्रहीत होता है।



मर्ज
मर्ज को निष्पादित करने के लिए, समग्र सबसे छोटे तत्व को बार-बार अगले इनपुट तत्व के साथ प्रतिस्थापित किया जाता है। उसके बाद, शीर्ष तक के खेल दोबारा खेले जाते हैं।

यह उदाहरण इनपुट के रूप में चार क्रमबद्ध सरणियों का उपयोग करता है।

{2, 7, 16} {5, 10, 20} {3, 6, 21} {4, 8, 9}

एल्गोरिदम की शुरुआत प्रत्येक इनपुट सूची के प्रमुखों से की जाती है। इन तत्वों का उपयोग करके, हारे हुए लोगों का एक द्विआधारी वृक्ष बनाया जाता है। विलय के लिए, निम्नतम सूची तत्व 2 को पेड़ के शीर्ष पर समग्र न्यूनतम तत्व को देखकर निर्धारित किया जाता है। फिर उस मान को हटा दिया जाता है, और उसके पत्ते को 7 से भर दिया जाता है, जो इनपुट सूची में अगला मान है। प्रतिस्थापन चयन के बारे में पिछले अनुभाग की तरह शीर्ष पर जाने वाले खेल दोबारा खेले जाते हैं। हटाया जाने वाला अगला तत्व 3 है। सूची में अगले मान 6 से शुरू करके, गेम को रूट तक दोबारा खेला जाता है। इसे तब तक दोहराया जा रहा है जब तक कि पेड़ का न्यूनतम मान अनंत के बराबर न हो जाए।



चलने के समय की निचली सीमा
कोई यह दिखा सकता है कि O(n f(k)) में चलने वाले समय के साथ कोई तुलना-आधारित k-वे मर्ज एल्गोरिदम मौजूद नहीं है, जहां f एक लघुगणक की तुलना में असम्बद्ध रूप से धीमी गति से बढ़ता है, और n तत्वों की कुल संख्या है। (असंयुक्त श्रेणियों जैसे वांछनीय वितरण वाले डेटा को छोड़कर।) इसका प्रमाण तुलना-आधारित छँटाई से एक सीधा-सीधा कमी है। मान लीजिए कि ऐसा कोई एल्गोरिदम मौजूद है, तो हम निम्न प्रकार से रनिंग टाइम O(n f(n)) के साथ तुलना-आधारित सॉर्टिंग एल्गोरिदम का निर्माण कर सकते हैं: इनपुट ऐरे को आकार 1 के n ऐरे में काटें। इन n सरणियों को k-वे मर्ज एल्गोरिथम के साथ मर्ज करें। परिणामी सरणी को क्रमबद्ध किया गया है और एल्गोरिथ्म में O(n f(n)) में चलने का समय है। यह सुविख्यात परिणाम का विरोधाभास है कि O(n log n) के नीचे सबसे खराब स्थिति में चलने वाले समय के साथ कोई तुलना-आधारित सॉर्टिंग एल्गोरिदम मौजूद नहीं है।

बाहरी छँटाई
के-वे मर्ज का उपयोग बाहरी सॉर्टिंग प्रक्रियाओं में किया जाता है। बाहरी सॉर्टिंग सॉर्टिंग एल्गोरिदम का एक वर्ग है जो भारी मात्रा में डेटा को संभाल सकता है। बाहरी सॉर्टिंग की आवश्यकता तब होती है जब सॉर्ट किया जा रहा डेटा कंप्यूटिंग डिवाइस (आमतौर पर रैम) की मुख्य मेमोरी में फिट नहीं होता है और इसके बजाय उन्हें धीमी बाहरी मेमोरी (आमतौर पर हार्ड ड्राइव) में रहना चाहिए। के-वे मर्ज एल्गोरिदम आमतौर पर बाहरी सॉर्टिंग एल्गोरिदम के दूसरे चरण में होते हैं, ठीक वैसे ही जैसे वे मर्ज सॉर्ट के लिए करते हैं।

मल्टीवे मर्ज मेमोरी के बाहर की फ़ाइलों को बाइनरी मर्ज की तुलना में कम पास में मर्ज करने की अनुमति देता है। यदि 6 रन हैं जिन्हें मर्ज करने की आवश्यकता है तो एक बाइनरी मर्ज को 3 मर्ज पास लेने की आवश्यकता होगी, 6-वे मर्ज के एकल मर्ज पास के विपरीत। मर्ज पास की यह कमी विशेष रूप से बड़ी मात्रा में जानकारी को ध्यान में रखते हुए महत्वपूर्ण है जिसे आम तौर पर पहले स्थान पर क्रमबद्ध किया जाता है, जिससे अधिक गति-अप की अनुमति मिलती है जबकि धीमी भंडारण तक पहुंच की मात्रा भी कम हो जाती है।