লিফো বনাম ফিফো
লিফো মানে লাস্ট ইন, ফার্স্ট আউট। হিসাবে, স্ট্যাকের মধ্যে রাখা সর্বশেষ আইটেমটি স্ট্যাকের বাইরে নেওয়া প্রথম আইটেম।
আপনি আপনার থালা খাবার উপমা ( প্রথম সংশোধনীতে ) দিয়ে যা বর্ণনা করেছেন তা হ'ল একটি সারি বা ফিফো, ফার্স্ট ইন, ফার্স্ট আউট।
উভয়ের মধ্যে প্রধান পার্থক্য হ'ল লিফো / স্ট্যাক একই প্রান্ত থেকে পুশ (সন্নিবেশ) এবং পপস (অপসারণ), এবং একটি ফিফো / সারি বিপরীত প্রান্ত থেকে তাই করে।
// Both:
Push(a)
-> [a]
Push(b)
-> [a, b]
Push(c)
-> [a, b, c]
// Stack // Queue
Pop() Pop()
-> [a, b] -> [b, c]
স্ট্যাক পয়েন্টার
স্ট্যাকের আড়ালে কী ঘটছে তা একবার দেখে নিই under এখানে কিছু স্মৃতি রয়েছে, প্রতিটি বাক্সের একটি ঠিকানা:
...[ ][ ][ ][ ]... char* sp;
^- Stack Pointer (SP)
এবং বর্তমানে খালি স্ট্যাকের নীচে একটি স্ট্যাক পয়েন্টার নির্দেশ করছে (স্ট্যাকটি বড় হয় বা নীচে নেমে আসে তা এখানে বিশেষভাবে প্রাসঙ্গিক নয় তাই আমরা এটিকে অগ্রাহ্য করব, তবে অবশ্যই বাস্তব বিশ্বে এটি নির্ধারণ করে যে কোন অপারেশন যুক্ত হয়েছে , এবং যা এসপি থেকে বিয়োগ করে)।
সুতরাং আসুন a, b, and c
আবার ধাক্কা । বামদিকে গ্রাফিকস, মাঝখানে "উচ্চ স্তরের" অপারেশন, ডানদিকে সি-ইশ সিউডো কোড:
...[a][ ][ ][ ]... Push('a') *sp = 'a';
^- SP
...[a][ ][ ][ ]... ++sp;
^- SP
...[a][b][ ][ ]... Push('b') *sp = 'b';
^- SP
...[a][b][ ][ ]... ++sp;
^- SP
...[a][b][c][ ]... Push('c') *sp = 'c';
^- SP
...[a][b][c][ ]... ++sp;
^- SP
আপনি দেখতে পাচ্ছেন, প্রতিবার আমরা push
, এটি স্ট্যাক পয়েন্টারটি বর্তমানে নির্দেশ করছে এমন স্থানে যুক্তি সন্নিবেশ করিয়ে দেয় এবং স্ট্যাক পয়েন্টারটিকে পরবর্তী অবস্থানে নির্দেশ করতে সামঞ্জস্য করে।
এখন পপ করা যাক:
...[a][b][c][ ]... Pop() --sp;
^- SP
...[a][b][c][ ]... return *sp; // returns 'c'
^- SP
...[a][b][c][ ]... Pop() --sp;
^- SP
...[a][b][c][ ]... return *sp; // returns 'b'
^- SP
Pop
এর বিপরীত push
, এটি স্ট্যাক পয়েন্টারটিকে পূর্ববর্তী স্থানে নির্দেশ করতে সামঞ্জস্য করে এবং সেখানে উপস্থিত আইটেমটি সরিয়ে দেয় (সাধারণত যাকে ডাকে তাকে ফিরিয়ে দিতে pop
)।
আপনি সম্ভবত এটি লক্ষ্য করেছেন b
এবং c
এখনও স্মৃতিতে রয়েছেন। আমি কেবল আপনাকে নিশ্চিত করতে চাই যে সেগুলি টাইপস নয়। আমরা শীঘ্রই এটি ফিরে যাব।
স্ট্যাক পয়েন্টার ছাড়াই জীবন
আসুন দেখুন আমাদের স্ট্যাক পয়েন্টার না থাকলে কী হয়। আবার ঠেলাঠেলি দিয়ে শুরু:
...[ ][ ][ ][ ]...
...[ ][ ][ ][ ]... Push(a) ? = 'a';
এর, হুম ... আমাদের যদি স্ট্যাক পয়েন্টার না থাকে তবে আমরা যে ঠিকানার দিকে ইঙ্গিত করে তাতে কিছু স্থানান্তরিত করতে পারি না। হতে পারে আমরা একটি পয়েন্টার ব্যবহার করতে পারি যা শীর্ষের পরিবর্তে বেসকে নির্দেশ করে।
...[ ][ ][ ][ ]... char* bp; // "base pointer"
^- bp bp = malloc(...);
...[a][ ][ ][ ]... Push(a) *bp = 'a';
^- bp
// No stack pointer, so no need to update it.
...[b][ ][ ][ ]... Push(b) *bp = 'b';
^- bp
আহ ওহ. যেহেতু আমরা স্ট্যাকের বেসের স্থির মানটি পরিবর্তন করতে পারি না, আমরা কেবল একই স্থানে a
চাপ b
দিয়ে ওভাররোট করি ।
ঠিক আছে, আমরা কতবার ঠেলেছি তার খোঁজ কেন রাখি না। এবং আমাদের পপ করার সময়গুলিও আমাদের লক্ষ্য রাখতে হবে।
...[ ][ ][ ][ ]... char* bp; // "base pointer"
^- bp bp = malloc(...);
int count = 0;
...[a][ ][ ][ ]... Push(a) bp[count] = 'a';
^- bp
...[a][ ][ ][ ]... ++count;
^- bp
...[a][b][ ][ ]... Push(a) bp[count] = 'b';
^- bp
...[a][b][ ][ ]... ++count;
^- bp
...[a][b][ ][ ]... Pop() --count;
^- bp
...[a][b][ ][ ]... return bp[count]; //returns b
^- bp
ভাল এটি কাজ করে, তবে এটি আসলে আগের মতো বেশ সমান, ব্যয় করার *pointer
চেয়ে কম pointer[offset]
(অতিরিক্ত গাণিতিক নয়) ব্যতীত এটি উল্লেখ না করা। এটাই আমার ক্ষতি বলে মনে হচ্ছে।
আবার চেষ্টা করা যাক. অ্যারে-ভিত্তিক সংকলনের (সংগ্রহের মধ্যে কতগুলি আইটেম রয়েছে তা ট্র্যাকিং) সন্ধানের জন্য পাস্কাল স্ট্রিং স্টাইলটি ব্যবহার না করে, আসুন সি স্ট্রিং স্টাইলটি চেষ্টা করুন (শুরু থেকে শেষ পর্যন্ত স্ক্যান করুন):
...[ ][ ][ ][ ]... char* bp; // "base pointer"
^- bp bp = malloc(...);
...[ ][ ][ ][ ]... Push(a) char* top = bp;
^- bp, top
while(*top != 0) { ++top; }
...[ ][ ][ ][a]... *top = 'a';
^- bp ^- top
...[ ][ ][ ][ ]... Pop() char* top = bp;
^- bp, top
while(*top != 0) { ++top; }
...[ ][ ][ ][a]... --top;
^- bp ^- top return *top; // returns '('
আপনি এখানে ইতিমধ্যে সমস্যাটি অনুমান করতে পারেন। অবিশ্রুত মেমরি 0 থাকার নিশ্চয়তা নেই, সুতরাং যখন আমরা শীর্ষে স্থানটি অনুসন্ধান করি তখন আমরা a
অব্যবহৃত মেমরির একগুচ্ছ উপরের দিকে ঝাঁপিয়ে পড়ি যার মধ্যে এলোমেলো আবর্জনা রয়েছে। একইভাবে, যখন আমরা শীর্ষে স্ক্যান করি, আমরা শেষ অবধি a
কেবল ধাক্কা ছাড়াই শেষ না হওয়া অবধি আমরা শেষ অবধি অন্য কোনও মেমরির অবস্থানটি সন্ধান না করি যা সবেমাত্র ঘটে থাকে 0
, এবং পিছনে সরে যায় এবং এর আগে এলোমেলো আবর্জনা ফিরিয়ে দেয়।
এটি ঠিক করার পক্ষে যথেষ্ট সহজ, আমাদের কেবলমাত্র অপারেশন যুক্ত করতে হবে Push
এবং Pop
নিশ্চিত করতে হবে যে স্ট্যাকের শীর্ষটি সর্বদা একটি হিসাবে চিহ্নিত হওয়ার জন্য আপডেট করা হয় 0
, এবং আমাদের এই ধরনের একটি টার্মিনেটর দিয়ে স্ট্যাকটি আরম্ভ করতে হবে। অবশ্যই এর অর্থ হ'ল আমাদের 0
স্ট্যাকের প্রকৃত মান হিসাবে আমরা (বা আমরা যে কোনও মান টার্মিনেটর হিসাবে বেছে নিই) রাখতে পারি না।
তার উপরে, আমরা ও (1) অপারেশনগুলি ও (এন) অপারেশনে পরিবর্তন করেছি changed
টি এল; ডিআর
স্ট্যাক পয়েন্টার স্ট্যাকের শীর্ষের উপর নজর রাখে, যেখানে সমস্ত ক্রিয়া ঘটে। এটিকে পরিত্রাণের বিভিন্ন উপায় রয়েছে ( bp[count]
এবং top
মূলত স্ট্যাক পয়েন্টার এখনও রয়েছে), তবে তারা উভয়ই কেবল স্ট্যাক পয়েন্টার না রেখে আরও জটিল এবং ধীর হয়ে যায়। এবং স্ট্যাকের শীর্ষটি কোথায় তা না জানা মানে আপনি স্ট্যাকটি ব্যবহার করতে পারবেন না।
দ্রষ্টব্য: x86 এ রানটাইম স্ট্যাকের "নীচে" দিকে ইঙ্গিত করা স্ট্যাক পয়েন্টারটি পুরো রানটাইম স্ট্যাকটি উল্টে থাকার সাথে সম্পর্কিত একটি ভুল ধারণা হতে পারে। অন্য কথায়, স্ট্যাকের ভিত্তি একটি উচ্চ মেমরির ঠিকানায় স্থাপন করা হয় এবং স্ট্যাকের ডগাটি নীচের স্মৃতি ঠিকানাগুলিতে বৃদ্ধি পায় grows স্ট্যাক পয়েন্টার আছে স্ট্যাকের যেখানে সব কর্ম ঘটে, ঠিক যে ডগা স্ট্যাক বেস কম মেমরি অ্যাড্রেস এ ডগা বিন্দু।