একটি স্ট্যাক, দুটি সারি


59

পটভূমি

বেশ কয়েক বছর আগে, যখন আমি একজন স্নাতক ছিলাম, তখন আমাদের অনুশীলন বিশ্লেষণের একটি হোমওয়ার্ক দেওয়া হয়েছিল। আমি একটি সমস্যার সমাধান করতে অক্ষম ছিলাম। আমি এর মধ্যে জিজ্ঞাসা করেছিলেন comp.theory , কিন্তু কোন সন্তোষজনক ফলাফলের এসেছেন। আমি মনে করি কোর্স টিএ এমন কিছু বিষয়ে জোর দিয়েছিল যা সে প্রমাণ করতে পারেনি, এবং বলেছিল যে সে প্রমাণটি ভুলে গেছে, এবং ... [আপনি কী জানেন]।

আজ, আমি সমস্যাটি মনে করলাম। আমি এখনও জানতে আগ্রহী ছিলাম, সুতরাং এটি এখানে ...

প্রশ্নটি

দুটি সারি ব্যবহার করে কোনও স্ট্যাক বাস্তবায়ন করা সম্ভব , যাতে পুশ এবং পিওপি উভয় ক্রিয়াকলাপটি এমোরিটাইজড সময়ে চালিত হয় O (1) ? যদি হ্যাঁ, আপনি আমাকে বলতে পারেন কিভাবে?

দ্রষ্টব্য: আমরা দুটি স্ট্যাকের সাথে একটি সারি কার্যকর করতে চাইলে (যথাযথ ক্রিয়াকলাপ এনকিউইউডিকিউইউ ) যদি পরিস্থিতিটি বেশ সহজ হয় । পার্থক্য পর্যবেক্ষণ করুন।

PS: উপরের সমস্যাটি নিজেই হোমওয়ার্ক নয়। বাড়ির কাজটি কোনও নিম্ন সীমানার প্রয়োজন হয় না; কেবল একটি বাস্তবায়ন এবং চলমান সময় বিশ্লেষণ।


2
আমার ধারণা, আপনি কেবল দুটি সারি (ও (1) বা ও (লগ এন) ব্যতীত সীমিত পরিমাণের জায়গা ব্যবহার করতে পারেন। আমার কাছে অসম্ভব মনে হচ্ছে, কারণ দীর্ঘ ইনপুট স্ট্রিমের ক্রমকে বিপরীত করার কোনও উপায় আমাদের কাছে নেই। তবে অবশ্যই এটির কোনও প্রমাণ নেই যদি না একে কঠোর দাবি হিসাবে তৈরি করা যায়…।
Tsuyoshi Ito

@ শুয়োশি: সীমিত স্থান অনুমান সম্পর্কে আপনি ঠিক বলেছেন। এবং হ্যাঁ, আমি সেই (
অনড়) টিএকে বলেছিলাম

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

@ সাদেকদৌস্টি আমার মতে, যদি আপনি একটি সারিটির লিঙ্কযুক্ত তালিকা প্রয়োগ এবং কিছু পয়েন্টার সর্বদা "স্ট্যাক" এর শীর্ষে দেখানোর জন্য ব্যবহার করেন
চার্লস অ্যাডিস

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

উত্তর:


45

আমার কাছে সত্যিকারের উত্তর নেই, তবে সমস্যাটি খোলার জন্য এখানে কিছু প্রমাণ রয়েছে:

  • এটি মিং লি, লুক লংপ্রে এবং পল এমবি ভিটেনি, "কাতারের শক্তি", স্ট্রাকচারস 1986-তে উল্লেখ করা হয়নি, যা অন্যান্য বিভিন্ন ঘনিষ্ঠভাবে সম্পর্কিত অনুকরণগুলি বিবেচনা করে

  • থিওর, "মার্টিন হাহনে" "বেশ কয়েকটি কাতারের শক্তিতে" এটি উল্লেখ নেই। বন্দীরা। সী। 1993, একটি ফলো অন কাগজ।

  • এটি হোলার পিটারসন, "স্ট্যাকস বনাম ডেকস", কোকন 2001-তে উল্লেখ নেই।

  • বার্টন রোজেনবার্গ, "দুটি সারি ব্যবহার করে প্রসঙ্গ-মুক্ত ভাষার স্বীকৃতি" Proc। লেট। 1998, দুটি সারি ব্যবহার করে যে কোনও সিএফএলকে স্বীকৃতি দেওয়ার জন্য একটি ও (এন লগ এন) দ্বি-কাতারি অ্যালগোরিদম দেয়। তবে একটি ননডেটেরিমেন্টিক পুশডাউন অটোমেটন লিনিয়ার সময়ে সিএফএলগুলি সনাক্ত করতে পারে। সুতরাং যদি অপারেশন অনুযায়ী ও (লগ এন) এর চেয়ে দুটি কাতারের সাথে স্ট্যাকের সিমুলেশন থাকে তবে রোজেনবার্গ এবং তার রেফারিকে এটি সম্পর্কে জানা উচিত ছিল।


4
চমৎকার রেফারেন্সের জন্য +1। কিছু প্রযুক্তি রয়েছে, যদিও: প্রথমগুলির মতো কিছু কাগজপত্র দুটি সারি ব্যবহার করে একটি স্ট্যাক সিমুলেট করার সমস্যাটিকে বিবেচনা করে না (আমি বিমূর্ত থেকে যতটা বলতে পারি)। অন্যরা আমলকীকরণ ব্যয় নয়, সবচেয়ে খারাপ ক্ষেত্রে বিশ্লেষণ বিবেচনা করে।
এমএস দৌস্তি

13

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

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

আমি দুটি অ্যালগরিদম উপস্থাপন করছি, প্রথমটি হ'ল একটি সাধারণ অ্যালগরিদম পপের জন্য একটি চলমান সময় এবং দ্বিতীয়টি পপের জন্য ও চলমান সময় সহ। আমি প্রথমটির বর্ণনাটি মূলত তার সরলতার কারণে করি যাতে দ্বিতীয়টি বোঝা সহজ হয়।( )O(n)O(n)

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

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

প্রথম অ্যালগরিদম

আমাদের দুটি সারি রয়েছে: সারিতে এবং সারি । হবে আমাদের 'পুশ কিউ', এবং ইতিমধ্যে 'স্ট্যাক ক্রম' এ থাকা সারি হবে।s e c o n d f i r s t s e c o n dfirstsecondfirstsecond

  • পুশ করা সহজভাবে প্যারামিটারটি সারিবদ্ধ করেই করা হয় ।first
  • পপিং নিম্নলিখিত হিসাবে সম্পন্ন করা হয়। যদি খালি থাকে, আমরা কেবল প্রাপ্য করে ফলাফলটি ফিরিয়ে দেব । অন্যথায়, আমরা বিপরীত , থেকে সমস্ত সংযোজন এবং এবং অদলবদল । তারপরে আমরা স্থানটি প্রেরণ করি এবং শিরোনামের ফলাফলটি ফিরিয়ে দেব।গুলি এন আমি r গুলি টি গুলি এন আমি r গুলি টন আমি r গুলি টি গুলি এন গুলি এন firstsecondfirstsecondfirstfirstsecondsecond

প্রথম অ্যালগরিদমের জন্য সি # কোড

আপনি এটি আগে কখনও সি # না দেখলেও এটি বেশ পঠনযোগ্য হতে পারে। জেনেরিক কী তা যদি আপনি না জানেন তবে কেবল স্ট্রিংয়ের জন্য স্ট্রিংয়ের জন্য আপনার মনে 'স্ট্রিং' দিয়ে 'টি' এর সমস্ত উদাহরণ প্রতিস্থাপন করুন।

public class Stack<T> {
    private Queue<T> first = new Queue<T>();
    private Queue<T> second = new Queue<T>();
    public void Push(T value) {
        first.Enqueue(value);
    }
    public T Pop() {
        if (first.Count == 0) {
            if (second.Count > 0)
                return second.Dequeue();
            else
                throw new InvalidOperationException("Empty stack.");
        } else {
            int nrOfItemsInFirst = first.Count;
            T[] reverser = new T[nrOfItemsInFirst];

            // Reverse first
            for (int i = 0; i < nrOfItemsInFirst; i++)
                reverser[i] = first.Dequeue();    
            for (int i = nrOfItemsInFirst - 1; i >= 0; i--)
                first.Enqueue(reverser[i]);

            // Append second to first
            while (second.Count > 0)
                first.Enqueue(second.Dequeue());

            // Swap first and second
            Queue<T> temp = first; first = second; second = temp;

            return second.Dequeue();
        }
    }
}

বিশ্লেষণ

অবশ্যই পুশ সময়ে কাজ করে works পপ এবং অভ্যন্তরে সমস্ত কিছু স্পর্শ করতে পারে ধীরে ধীরে কয়েকবার, তাই আমাদের সবচেয়ে খারাপ অবস্থায় রয়েছে। অ্যালগরিদম এই আচরণটি প্রদর্শন করে (উদাহরণস্বরূপ) যদি কেউ উপাদানগুলিকে স্ট্যাকের দিকে ঠেলে দেয় এবং তারপরে বারবার একটি সাইন পুশ এবং ক্রমাগত একক পপ অপারেশন করে।O(1)firstsecondO(n)n

দ্বিতীয় অ্যালগরিদম

আমাদের দুটি সারি রয়েছে: সারিতে এবং সারি । হবে আমাদের 'পুশ কিউ', এবং ইতিমধ্যে 'স্ট্যাক ক্রম' এ থাকা সারি হবে।firstsecondfirstsecond

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

  • পুশিংটি এখনও প্যারামিটারটি সহজভাবে তৈরি করেই করা হয় ।first
  • পপিং নিম্নলিখিত হিসাবে সম্পন্ন করা হয়। যদি খালি থাকে, আমরা কেবল প্রাপ্য করে ফলাফলটি ফিরিয়ে দেব । অন্যথায়, আমরা সামগ্রীর পুনর্গঠন করি যাতে তারা স্ট্যাক ক্রমে থাকে। যদি আমরা কেবল প্রাপ্য এবং ফলাফলটি ফিরিয়ে দিই । অন্যথায়, আমরা দিকে সংযোজন , এবং অদলবদল , শিরোনাম এবং ফলাফল ফিরে।firstsecondfirst|first|<|second|firstsecondfirstfirstsecondsecond

প্রথম অ্যালগরিদমের জন্য সি # কোড

আপনি এটি আগে কখনও সি # না দেখলেও এটি বেশ পঠনযোগ্য হতে পারে। জেনেরিক কী তা যদি আপনি না জানেন তবে কেবল স্ট্রিংয়ের জন্য স্ট্রিংয়ের জন্য আপনার মনে 'স্ট্রিং' দিয়ে 'টি' এর সমস্ত উদাহরণ প্রতিস্থাপন করুন।

public class Stack<T> {
    private Queue<T> first = new Queue<T>();
    private Queue<T> second = new Queue<T>();
    int unsortedPart = 0;
    public void Push(T value) {
        unsortedPart++;
        first.Enqueue(value);
    }
    public T Pop() {
        if (first.Count == 0) {
            if (second.Count > 0)
                return second.Dequeue();
            else
                throw new InvalidOperationException("Empty stack.");
        } else {
            int nrOfItemsInFirst = first.Count;
            T[] reverser = new T[nrOfItemsInFirst];

            for (int i = nrOfItemsInFirst - unsortedPart - 1; i >= 0; i--)
                reverser[i] = first.Dequeue();

            for (int i = nrOfItemsInFirst - unsortedPart; i < nrOfItemsInFirst; i++)
                reverser[i] = first.Dequeue();

            for (int i = nrOfItemsInFirst - 1; i >= 0; i--)
                first.Enqueue(reverser[i]);

            unsortedPart = 0;
            if (first.Count * first.Count < second.Count)
                return first.Dequeue();
            else {
                while (second.Count > 0)
                    first.Enqueue(second.Dequeue());

                Queue<T> temp = first; first = second; second = temp;

                return second.Dequeue();
            }
        }
    }
}

বিশ্লেষণ

অবশ্যই পুশ সময়ে কাজ করে worksO(1)

পপ মোড়িত সময়ে কাজ করে। দুটি ক্ষেত্রে আছে: যদি , তারপরে আমরা স্ট্যাক অর্ডারে স্থানান্তরিত করব । যদি , তারপরে অবশ্যই আমাদের কমপক্ষে ush পুশের জন্য কল করা উচিত। অতএব, আমরা কেবল প্রতি কেস পুশ এবং পপকে এই আঘাত করতে পারি । এই ক্ষেত্রে আসল চলমান সময় হ'ল , সুতরাং অনুপাতের সময়টি হ'ল rac ।O(n)|first|<|second|firstO(|first|)=O(n)|first||second|nnO(n)O(nn)=O(n)

চূড়ান্ত নোট

পপকে সমস্ত কাজ করার পরিবর্তে প্রতি কলটিতে পুনর্গঠিত করে পপ- ক্রিয়াকলাপ তৈরি করে অতিরিক্ত ভেরিয়েবলটি নির্মূল করা সম্ভব ।O(n)first


আমি প্রথম অনুচ্ছেদগুলি সম্পাদনা করেছি যাতে আমার উত্তর প্রশ্নের প্রকৃত উত্তর হিসাবে সূচিত হয়।
অ্যালেক্স টেন ব্রিংক

6
আপনি বিপরীতের জন্য একটি অ্যারে (বিপরীতমুখী) ব্যবহার করছেন! আমি মনে করি না যে আপনাকে এটি করার অনুমতি দেওয়া হয়েছে।
কাভেহ

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

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

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

12

আমার পূর্ববর্তী উত্তরের উপর কিছু মন্তব্য অনুসরণ করার পরে, এটি আমার কাছে পরিষ্কার হয়ে গেছে যে আমি কম বা কম প্রতারণা করছি: আমার পপ পদ্ধতিটি কার্যকর করার সময় আমি দ্বিতীয় অ্যালগরিদমে অতিরিক্ত স্থান ( অতিরিক্ত স্থান ব্যবহার করেছি।O(n)

নিম্নলিখিত অ্যালগরিদম পুশ এবং পপ কার্যকর করার সময় পদ্ধতি এবং কেবল অতিরিক্ত স্থানের মধ্যে কোনও অতিরিক্ত স্থান ব্যবহার করে না । পুশের একটি চলমান সময়কে ধীরে ধীরে চালিত করা হয় এবং পপের একটি সবচেয়ে খারাপ পরিস্থিতি (এবং amorised) চলমান সময়।O(1)O(n)O(1)

মডারেটরদের কাছে নোট: আমি এটিকে পৃথক উত্তর দেওয়ার সিদ্ধান্তটি সঠিক কিনা, তা আমি পুরোপুরি নিশ্চিত নই। আমি ভেবেছিলাম আমার মূল উত্তরটি মুছে ফেলা উচিত নয় কারণ এটি এখনও প্রশ্নের সাথে কিছুটা প্রাসঙ্গিক হতে পারে।

অ্যালগরিদম

আমাদের দুটি সারি রয়েছে: সারিতে এবং সারি । হবে আমাদের 'ক্যাশে', এবং হবে আমাদের প্রধান 'স্টোরেজ'। উভয় সারি সর্বদা 'স্ট্যাক ক্রমে' থাকবে। স্ট্যাকের শীর্ষে থাকা উপাদানগুলি এবং স্ট্যাকের নীচে থাকা উপাদানগুলি থাকবে। আকার সর্বদা বর্গমূল হতে হবে ।firstsecondfirstsecondfirstsecondfirstsecond

  • কশুর শুরুতে প্যারামিটারটি 'সন্নিবেশ' করার মাধ্যমে পুশ করা হয়: আমরা প্যারামিটারটি তৈরি করি এবং তারপরে অন্যান্য সমস্ত উপাদানগুলি চিহ্নিত করে পুনরায় সজ্জিত করি । এইভাবে, প্যারামিটারটি প্রথম শুরুতে ।firstfirstfirst
  • তাহলে বর্গমূল চেয়ে বড় হয়ে , আমরা সমস্ত উপাদান সারিবদ্ধ সম্মুখের একের পর এক এবং তারপর অদলবদল এবং । এইভাবে, উপাদানগুলি (স্ট্যাকের শীর্ষে) মাথায় শেষ হয় ।firstsecondsecondfirstfirstsecondfirstsecond
  • পপ শনাক্ত করে এবং ফলাফলটি খালি না হলে ফিরে আসার মাধ্যমে করা হয়, এবং অন্যথায় এবং ফলাফলটি ফেরত দিয়ে।firstfirstsecond

প্রথম অ্যালগরিদমের জন্য সি # কোড

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

public class Stack<T> {
    private Queue<T> first = new Queue<T>();
    private Queue<T> second = new Queue<T>();
    public void Push(T value) {
        // I'll explain what's happening in these comments. Assume we pushed
        // integers onto the stack in increasing order: ie, we pushed 1 first,
        // then 2, then 3 and so on.

        // Suppose our queues look like this:
        // first: in 5 6 out
        // second: in 1 2 3 4 out
        // Note they are both in stack order and first contains the top of
        // the stack.

        // Suppose value == 7:
        first.Enqueue(value);
        // first: in 7 5 6 out
        // second: in 1 2 3 4 out

        // We restore the stack order in first:
        for (int i = 0; i < first.Count - 1; i++)
            first.Enqueue(first.Dequeue());
        // first.Enqueue(first.Dequeue()); is executed twice for this example, the 
        // following happens:
        // first: in 6 7 5 out
        // second: in 1 2 3 4 out
        // first: in 5 6 7 out
        // second: in 1 2 3 4 out

        // first exeeded its capacity, so we merge first and second.
        if (first.Count * first.Count > second.Count) {
            while (second.Count > 0)
                first.Enqueue(second.Dequeue());
            // first: in 4 5 6 7 out
            // second: in 1 2 3 out
            // first: in 3 4 5 6 7 out
            // second: in 1 2 out
            // first: in 2 3 4 5 6 7 out
            // second: in 1 out
            // first: in 1 2 3 4 5 6 7 out
            // second: in out

            Queue<T> temp = first; first = second; second = temp;
            // first: in out
            // second: in 1 2 3 4 5 6 7 out
        }
    }
    public T Pop() {
        if (first.Count == 0) {
            if (second.Count > 0)
                return second.Dequeue();
            else
                throw new InvalidOperationException("Empty stack.");
        } else
            return first.Dequeue();
    }
}

বিশ্লেষণ

স্পষ্টতই পপ সবচেয়ে খারাপ ক্ষেত্রে সময়ে কাজ করে ।O(1)

পুশ মোড়িত সময়ে কাজ করে। দুটি ক্ষেত্রে আছে: যদি তারপরে পুশ সময় নেয়। যদি তারপরে পুশ সময় নেয় তবে এই ক্রিয়াকলাপের পরে খালি থাকবে। একে চালনা করবে সময় আগে আমরা এই ক্ষেত্রে আবার পেতে, তাই amortized সময় সময়।O(n)|first|<|second|O(n)|first||second|O(n)firstO(n)O(nn)=O(n)


কোনও উত্তর মুছে ফেলার বিষয়ে, দয়া করে একবার দেখুন মেটা.সিস্টেওরি.স্ট্যাককেেক্সচেঞ্জ / কিউ / 386/873
এমএস দৌস্তি

আমি লাইন বুঝতে পারি না first.Enqueue(first.Dequeue())। আপনি কিছু ভুল টাইপ করেছেন?
এমএস দৌস্তি

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

আমার জন্য অ্যালগরিদম সম্পাদনার আগে আরও পঠনযোগ্য এবং বুঝতে সহজ ছিল।
কাভেহ

9

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

সবচেয়ে খারাপ পরিস্থিতি অনুসারে পুশ অপারেশন থাকে, তার পরে পুশ অপারেশন এবং পিওপি অপারেশন হয়, তারপরে আবার পুশ অপারেশন এবং পিওপি অপারেশন ইত্যাদি থাকে That হল:NNNNN

PUSHN(PUSHNPOPN)N

প্রাথমিক পুশ অপারেশনের পরে পরিস্থিতিটি বিবেচনা করুন । অ্যালগরিদম কীভাবে কাজ করে তা বিবেচনা না করেই কমপক্ষে একটি সারিতে অন্তত এন্ট্রি থাকতে হবে।NN/2

এখন (প্রথম সেট) পুশ এবং পিওপি অপারেশনগুলির সাথে ডিল করার কাজটি বিবেচনা করুন । যে কোনও অ্যালগরিদমিক কৌশল যে কোনও দুটি ক্ষেত্রেই পড়তে হবে:N

প্রথম ক্ষেত্রে, অ্যালগরিদম উভয় সারি ব্যবহার করবে। এই সারিগুলির বৃহত্তর এতে কমপক্ষে টি প্রবেশ রয়েছে, সুতরাং শেষ পর্যন্ত আমাদের একক উপাদানকে পুনরুদ্ধার করতে আমাদের কমপক্ষে সারি ক্রিয়াকলাপের জন্য ব্যয় করতে হবে এবং পরবর্তীকালে এই বৃহত্তর সারিটি থেকে ডিকুইউ করা দরকার।N/2N/2

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

উভয় ক্ষেত্রেই, স্ট্যাক ক্রিয়াকলাপ পরিচালনা করতে আমাদের কমপক্ষে সময় (সারি ক্রিয়াকলাপ) প্রয়োজন । যেহেতু আমরা এই প্রক্রিয়াটি বার পুনরাবৃত্তি করতে পারি, তাই মোট স্ট্যাক অপারেশনগুলি প্রক্রিয়া করার জন্য আমাদের সময় দরকার , অপারেশন অনুযায়ী lower প্রান্তিক সময় দেওয়া ।N/22NNNN/23NΩ(N)


জ্যাক এটি সম্পাদনা করেছে যাতে আমার মতো এটির মতো রাউন্ডের সংখ্যা (প্রথম বন্ধনীতে প্রকাশক) পরিবর্তে is হয় । এর কারণ এটি ছিল যে আমি আপনাকে পুরো ক্রমটির উপরে নিরস্ত্রীকরণ করতে পারি না তা দেখানোর আগে যা ছিল তা ছিল "ওভারকিল", এবং আপনি এটি কেবল পুনরাবৃত্তিগুলি থেকে দেখতে পারেন । ধন্যবাদ, জ্যাক! NN
শন হারকার

এই দুটি মামলার মিশ্রণ কী হবে? উদাহরণস্বরূপ, আমরা এন্ট্রিগুলি বিকল্পভাবে (কমপক্ষে এন্ট্রি সহ একটি) এবং (অন্যান্য সারি) এর মধ্যে চাপ ? আমি অনুমান করি যে এই প্যাটার্নটির জন্য আরও বেশি খরচ হয় তবে এটি সম্পর্কে কীভাবে তর্ক করা যায়? এবং দ্বিতীয় ক্ষেত্রে, আমি মনে করি স্ট্যাক ক্রিয়াকলাপের প্রত্যেকটির জন্য গড় (amorised) ব্যয় কমপক্ষে। nQ1N/2Q22nn4:1+2++n+n2n
হেনগ্সিন

স্পষ্টতই পিটারের উত্তরটি এই নিম্ন সীমাটির সাথে বিরোধিতা করে?
জো

@ জো আমি মনে করি না যে পিটারের উত্তরটি এই নীচের সীমানার সাথে বিরোধিতা করে যেহেতু প্রথম এন ধাক্কা এই ক্রমটিতে কখনই পপ হয় না। যে কোনও পরিবর্তিত পদ্ধতির জন্য কমপক্ষে ও (এন) সময় লাগবে, সুতরাং এটি প্রতিটি `` পর্যায় '' গ্রহণ করা উচিত ( ক্রিয়াকলাপ) আমরা এখনও amortized আছে ফেজ জন্য। বিশেষত এ জাতীয় একটি অ্যালগরিদম আমার বিশ্লেষণে "প্রথম ক্ষেত্রে" এর অধীনে আসে। PUSHNPOPNO(N)
শন হার্কার

@ চেঞ্জিন আপনার মন্তব্য আমাকে অনুধাবন করেছে যে আমি আমার যুক্তিটি যেমনটি প্রকাশ করতে চেয়েছিলাম তেমন স্পষ্টভাবে প্রকাশ করি নি। আমি এটি সম্পাদনা করেছি তাই এখন আপনার প্রস্তাবিত প্যাটার্নটি প্রথম মামলার আওতায় আনা উচিত clear যুক্তিটি হ'ল আমরা যদি একটির ক্ষেত্রেও একটি একক উপাদানকে বৃহত্তর কাতারে সন্ধান করি তবে শেষ পর্যন্ত এটি পুনরুদ্ধারের জন্য আমাদের অপারেশন প্রয়োজন require O(N)
শন হার্কার

6

আপনি একটি পেতে পারেন (amortized) মন্দার যদি অনেক পরে স্প্যানিশ ভাষায় এবং কোন গুলি, যখন আপনি একটি দেখতে আপনি দুই সারি ব্যবহার নিখুঁত shuffles একটা ক্রম সঞ্চালন। এটি ডায়াকনিস, গ্রাহাম এবং ক্যান্টর ১৯৮৩ সালে "দ্য ম্যাথমেটিক্স অফ পারফেক্ট শফুলস" দ্বারা প্রমাণিত হয়েছিল যে নিখুঁত শ্যাফেলস দ্বারা "ডেক" কে যে কোনও ক্রমে পুনরায় অর্ডার করতে পারে। সুতরাং, আপনি "ইনপুট সারি" হিসাবে একটি সারি এবং "আউটপুট সারি" হিসাবে দুটি সারি বজায় রাখতে পারেন (দুটি স্ট্যাকের ক্ষেত্রে অনুরূপ) এবং তারপরে যখন কোনও অনুরোধ করা হয় এবং আউটপুট সারি খালি থাকে, আপনি নিখুঁত ক্রম সম্পাদন করেন ইনপুট সারিটি বিপরীত করতে এবং আউটপুট সারিতে এটি সঞ্চয় করতে শাফলগুলি।O(lgn)pushpoppopO(lgn)pop

কেবলমাত্র অবশিষ্ট প্রশ্নটি হ'ল নিখুঁত শ্যাফেলগুলির নির্দিষ্ট প্যাটার্নটি চেয়ে বেশি মেমরির প্রয়োজন না হওয়ার জন্য যথেষ্ট নিয়মিত whetherO(1)

আমি যতদূর জানি এটি একটি নতুন ধারণা ...



আহা! আমার কোনও আপডেট হওয়া বা সম্পর্কিত প্রশ্নের সন্ধান করা উচিত ছিল। আপনার পূর্ববর্তী উত্তরে যে কাগজপত্রগুলি আপনি লিঙ্ক করেছেন সেগুলি কে স্ট্যাক এবং কে + 1 স্ট্যাকের মধ্যে একটি সম্পর্ক পোষ্ট করেছে। এই কৌশলটি কি কে এবং কে + 1 স্ট্যাকের মধ্যে কে সারিগুলির শক্তি রাখে? যদি তাই হয়, এটি একটি ঝরঝরে সিডেনোট of যেভাবেই হোক, আমাকে আপনার উত্তরের সাথে সংযুক্ত করার জন্য ধন্যবাদ তাই আমি অন্য জায়গার জন্য এটি লেখার জন্য খুব বেশি সময় নষ্ট করি না।
পিটার বুথ

1

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


0

আমি ক্রমাগত ধীরে ধীরে স্ট্যাক প্রয়োগ করার জন্য সারিগুলি পেতে পারি না। যাইহোক, আমি সবচেয়ে খারাপ ক্ষেত্রে রৈখিক সময়ে স্ট্যাক প্রয়োগ করতে দুটি সারি পাওয়ার উপায় সম্পর্কে ভাবতে পারি।

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

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

এই সমস্ত কাজ করে কারণ প্রতিটি সময় একটি পুশ অপারেশন করা হয়, নতুন উপাদানটি একটি খালি কাতারের মাথায় রাখা হয় এবং পুরো কাতাকে এর লেজ প্রান্তে যুক্ত করা হয়, কার্যকরভাবে উপাদানগুলিকে বিপরীত করে।

আপনি যদি নিয়মিত ধ্রুবক সময় ক্রিয়াকলাপ পেতে চান তবে আপনাকে সম্ভবত আরও চালাক কিছু করতে হবে।


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

দেখে মনে হচ্ছে! যাইহোক, দেখে মনে হচ্ছে এইভাবে একটি স্ট্যাক সিমুলেশন করার জন্য একাধিক ক্লাসিকাল কাতারের প্রয়োজন।
রস স্নাইডার

0

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

ফ্রন্ট লোডিং অনুমতি না দিয়ে, এখানে অন্য সমাধান:

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

পুশ অপারেশন তুচ্ছ, এটি নিছক নিয়ে গঠিত:

*primary.enqueue(value);

পিওপি অপারেশন কিছুটা বেশি জড়িত; এটির জন্য প্রাথমিক সারির শেষ আইটেমটি ব্যতীত অন্য সকলকেই স্পুলিং করা প্রয়োজন, পয়েন্টারগুলিকে অদলবদল করা, এবং শেষের বাকি আইটেমটি মূল সারি থেকে ফিরে আসা:

while(*primary.size() > 1)
{
    *secondary.enqueue(*primary.dequeue());
}

swap(primary, secondary);
return(*secondary.dequeue());

কোনও সীমানা পরীক্ষা করা হয় না, এবং এটি ও (1) নয়।

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


এখানে দুটি সারি এবং একটি পয়েন্টার, যথাক্রমে Q1, Q2, এবং قطار_p ব্যবহার করে আরও একটি সমাধান দেওয়া হয়েছে:

প্রারম্ভিককরণের পরে, Q1 এবং Q2 খালি এবং কিউ_ পয়েন্ট Q1 তে পয়েন্ট করুন।

আবার, পুশ অপারেশনটি তুচ্ছ, তবে অন্য কাতারে কুই_পি দেখানোর আরও একটি ধাপ প্রয়োজন:

*queue_p.enqueue(value);
queue_p = (queue_p == &Q1) ? &Q2 : &Q1;

পিওপি অপারেশন অপারেশন আগের মত, তবে এখন এন / 2 আইটেম রয়েছে যেগুলি সারিতে ঘোরানো দরকার:

queue_p = (queue_p == &Q1) ? &Q2 : &Q1;
for(i=0, i<(*queue_p.size()-1, i++)
{
    *queue_p.enqueue(*queue_p.dequeue());
}
return(*queue_p.dequeue());

পুশ অপারেশনটি এখনও ও (1), কিন্তু এখন পিওপি অপারেশনটি ও (এন / 2)।

ব্যক্তিগতভাবে, এই সমস্যার জন্য, আমি একটি একক, ডাবল-এন্ডেড সারি (ডীক) বাস্তবায়ন এবং যখন আমরা চাই তখন এটিকে স্ট্যাক বলার ধারণাটি পছন্দ করি।


আপনার দ্বিতীয় অ্যালগরিদম অ্যালেক্সের আরও জড়িত একটি বোঝার জন্য সহায়ক is
হেনগ্সিন

0

সারিগুলির সাথে একটি স্ট্যাকের সর্বোত্তম সিমুলেশনটিতে অপারেশন প্রতি সময় লাগে - নির্বিশেষে: সময়টি সবচেয়ে খারাপ-অনুভূতিযুক্ত, - আমরা একটি স্তুপ বা সারি সহ কোনও স্থির সংখ্যক স্ট্যাকের সিমুলেট করি sim মোট, - হ'ল ক্রিয়াকলাপ বা আইটেমের সর্বাধিক মোট একযোগে সংখ্যা, - পুশ (তবে পপ নয়) বা না।kΘ(n1/k)

k
n
O(1)

এক দিকে (অর্থাত্ উপরের আবদ্ধ), ম সারির আকার size এবং নিম্ন-সংখ্যাযুক্ত সারিতে একসাথে সাম্প্রতিকতম স্ট্যাক প্রতি আইটেম (যদি কোনও স্ট্যাকের কম উপাদান থাকে তবে আইটেমগুলি কেবল স্থানান্তরিত হয় এবং অনুলিপি করা হয় না)। আমরা সারিগুলি মধ্যে আইটেমগুলি সরালে, বাল্ক মধ্যে প্যাচসমূহ এমনটি করা হলেও তা যেমন অর্জন করা এই বাধ্যতা বজায় রাখা আইটেম প্রতি সময় সারিতে সরানো এবং সারিতে । প্রতিটি আইটেম তার স্ট্যাকের পরিচয় এবং স্ট্যাকের মধ্যে এর উচ্চতা দ্বারা টীকায়িত হয়; যদি আমরা ধাক্কাটিকে (বা আমাদের কাছে যদি কেবল একটি স্ট্যাক থাকে এবং এমোরিটাইজড পপ সময়কে অনুমতি দেয়) তবে এটির প্রয়োজন নেই।iΘ(ni/k)Θ(ni/k)O(1)i+1O(n1/k)i1Θ(n1/k)

অন্যান্য দিক (অর্থাত লোয়ার বাউন্ড), আমরা কিছু জন্য পর্যন্ত আইটেম যোগ করার রাখতে পারবেন না , ম সাম্প্রতিকতম আইটেম আইটেম প্রতিটি কিউ শেষে থেকে দূরে এটা ধারণকারী, এবং তারপর আমরা এটি অনুরোধ এবং পুনরাবৃত্তি। মনে করুন যে এটি যথেষ্ট না ঘটে। তারপরে, একটি নতুন আইটেমটি সাধারণত মাপের একটি সারিতে যুক্ত করা উচিত । এই সারির আকারটি ধরে রাখতে আইটেমগুলিকে ফ্রিকোয়েন্সি দিয়ে অন্য একটি কাতারে স্থানান্তরিত করতে হবে , যার আকার সাধারণত হওয়া উচিত, সরানোর পরে দ্রুত পর্যাপ্ত আইটেম পুনরুদ্ধার করার অনুমতি দিতে । এই যুক্তিটি পুনরাবৃত্তি করে, আমরা প্রয়োজন হিসাবে মোট মাপের (এবং বর্ধমান) সহ সারি পাই ।এম Ω ( এম এন 1 / কে ) ( এন 1 / কে ) Ω ( এন 1 / কে ) ( এন 2 / কে ) কে ( এন )mmΩ(mn1/k)o(n1/k)Ω(n1/k)o(n2/k)ko(n)

এছাড়াও, যদি কোনও স্ট্যাক একবারে সমস্ত খালি করা আবশ্যক (আমরা আবার আইটেমগুলি যুক্ত করা শুরু করার আগে), আমি প্রত্যাশা করি সর্বোত্তম amorised পারফরম্যান্স হ'ল (দুটি বা আরও বেশি সারি ব্যবহার করে একটি স্ট্যাক); এই পারফরম্যান্সটি (মূলত) মার্জ সাজানোর সাহায্যে অর্জন করা যায়।Θ(logn)


-3

একটি স্ট্যাক দুটি ক্যু ব্যবহার করে দ্বিতীয় সারিটি অ্যাবেফার হিসাবে ব্যবহার করে প্রয়োগ করা যেতে পারে। আইটেমগুলি স্ট্যাকের দিকে ঠেলাঠেলি করে এগুলি সারির শেষের দিকে যুক্ত করা হয়। প্রতিবার যখন কোনও আইটেমটি পপ করা হয়, প্রথম সারির এন - 1 উপাদানগুলি দ্বিতীয়টিতে স্থানান্তর করতে হবে, যখন বাকী আইটেমটি ফিরে আসে। পাবলিক ক্লাস কুইউস্ট্যাক টিএস ইসট্যাক-প্রাইভেট আইকিউ কিউ 1 = নতুন কুইউ () প্রয়োগ করে; বেসরকারী আইকিউ কিউ 2 = নতুন ক্যু (); সর্বজনীন শূন্যতা পুশ (E ই) {q1.enqueue (ই) // ও (1)} সর্বজনীন ই পপ (ই ই) {যখন (1 <q1.size ()) // O (n) {q2.enqueue ( q1.dequeue ()); } sw apQueues (); রিটার্ন q2.dequeue (); ; পি রিভেট অকার্যকর অদলবদল () {আইকিউউ কিউ = কিউ 2; কিউ 2 = কিউ 1; q1 = প্রশ্ন; }}


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