অ্যামোর্টাইজড অ্যানালাইসিস (Amortized Analysis)
ধরুন একটি জিমের সদস্যপদের কথা চিন্তা করুন। বেশিরভাগ মাসেই আপনি শুধু ৩০ ডলার দেন এবং জিমে যান। কিন্তু বছরে একবার সেখানে ৩০০ ডলারের বার্ষিক ফি বা ইকুইপমেন্ট ফি দিতে হয়। আপনি যদি সেই ফি ১২ মাসের সবার মধ্যে ভাগ করে দেন, তাহলে গড়ে মাসে মাত্র ২৫ ডলার করে বেশি দিতে হয়। অর্থাৎ, একবারের বড় পেমেন্ট প্রথম দেখাতে কষ্টকর মনে হলেও — সেটি ভাগ করে দিলে বেশ সাশ্রয়ী হয়।
অ্যামোর্টাইজড অ্যানালাইসিস (Amortized Analysis) ঠিক একইভাবে কাজ করে। "একটি একক অপারেশনে কতটা সর্বোচ্চ সময় লাগতে পারে?" এই প্রশ্নটি জিজ্ঞাসা করার পরিবর্তে, এটি জিজ্ঞাসা করে "দীর্ঘক্ষণ ধরে চলা অনেকগুলো অপারেশনে প্রতিটি অপারেশনের জন্য গড়ে কত খরচ হয়?" কিছু অপারেশন বেশ ব্যয়বহুল বা দামি হতে পারে, তবে যদি সেগুলো যথেষ্ট বিরল (rare) হয়, তবে দীর্ঘমেয়াদে গড় (average) খরচ খুব কমই থাকে।
ক্লাসিক উদাহরণ: ডাইনামিক অ্যারে পুশ (Dynamic Array Push)
একটি ডাইনামিক অ্যারে (Python-এর list, Java-এর ArrayList) ছোট আকার থেকে শুরু হয় এবং যখন এটি ভরে যায় তখন এর ধারণক্ষমতা (capacity) বা সাইজ দ্বিগুণ করে। বেশিরভাগ push কলগুলো হলো O(1) — অর্থাৎ শুধুমাত্র পরবর্তী ফাঁকা জায়গায় রাইট (write) করা। কিন্তু যখন অ্যারেটি সম্পূর্ণ ভরে যায়, তখন এটি অবশ্যই পূর্বের চেয়ে দ্বিগুণ বড় একটি নতুন অ্যারে তৈরি করে এবং সব ডেটা সেখানে কপি করে। এই রিসাইজ (resize) করতে সময় লাগে O(n)।
একবারের ব্যয়বহুল রিসাইজ দেখে আপনার মনে হতে পারে যে পুশ করাটা বেশ ধীরগতির। কিন্তু পুরো চিত্রটা একটু কল্পনা করুন: যদি অ্যারেটি সবেমাত্র n/2 সাইজ থেকে দ্বিগুণ হয়ে n হয়ে থাকে, আপনি n/2 সংখ্যক উপাদান কপি করেছেন। পুনরায় রিসাইজ করার আগে, আপনাকে আরও n/2 সংখ্যক সস্তা বা কম খরচের পুশ করতে হবে। তাই প্রতিটি উপাদান নিজস্ব ভবিষ্যৎ কপির জন্য একপ্রকার আগাম মূল্য বা "পেমেন্ট" পরিশোধ করে রাখে। সমস্ত পুশগুলোর মধ্যে ছড়িয়ে দিলে, প্রতিটি পুশের জন্য গড়ে অ্যামোর্টাইজড খরচ বা সময় O(1) হয়ে দাঁড়ায়।
এটি প্রমাণের তিনটি পদ্ধতি (The Three Methods for Proving It)
অ্যাগ্রিগেট পদ্ধতি (Aggregate method): n সংখ্যক অপারেশনের জন্য মোট কাজের পরিমাণ গণনা করুন, তারপর সেটিকে n দিয়ে ভাগ করুন। ডাবলিং বা দ্বিগুণ করার মাধ্যমে n বার পুশ করার জন্য: রিসাইজগুলোতে 1 + 2 + 4 + … + n/2 সংখ্যক উপাদান, অর্থাৎ মোট O(n) সংখ্যক উপাদান কপি করা হয়। সুতরাং n সংখ্যক পুশের জন্য মোট খরচ O(n) → তাই প্রতিটির জন্য খরচ O(1)।
অ্যাকাউন্টিং পদ্ধতি (Accounting method): প্রতিটি পুশকে 3 ইউনিটের একটি "ক্রেডিট" দিন: 1 ইউনিট ইনসার্ট করার জন্য, এবং 2 ইউনিট জমা রাখার জন্য। যখন একটি রিসাইজ ঘটে, তখন প্রতিটি উপাদানের জন্য ওই জমা রাখা 2 ক্রেডিট দিয়ে সেই উপাদানটিকে এবং নতুন অ্যারের অতিরিক্ত একটি জায়গাকেও কপি করার খরচ মেটানো হয়। ক্রেডিট কখনোই নেগেটিভ হয় না, যা এর সত্যতাকে জোরালোভাবে প্রমাণ করে।
পটেনশিয়াল পদ্ধতি (Potential method): একটি পটেনশিয়াল বা সম্ভাবনা Φ (সঞ্চিত শক্তির মতো) সংজ্ঞায়িত করুন যা অ্যারে ভরার সাথে সাথে বেড়ে যায় এবং রিসাইজ হওয়ার সময় কমে যায়। অ্যামোর্টাইজড খরচ = আসল খরচ + ΔΦ। ডাইনামিক অ্যারের জন্য একটি ভালো Φ হতে পারে 2·(size) − capacity। এই পদ্ধতিটি জটিল ডেটা কাঠামোর বেলায়ও দারুণভাবে কাজ করে যেখানে শুধুমাত্র সাধারণ কল্পনা করাটা যথেষ্ট নয়।