যখন কিছু (অপেক্ষাকৃত) বেসিক (প্রথম বর্ষের কলেজ স্তর সিএস শিক্ষার্থী ভাবেন) এর উদাহরণগুলি যখন কেউ কেবল একটি লুপের পরিবর্তে পুনরাবৃত্তি ব্যবহার করবে?
যখন কিছু (অপেক্ষাকৃত) বেসিক (প্রথম বর্ষের কলেজ স্তর সিএস শিক্ষার্থী ভাবেন) এর উদাহরণগুলি যখন কেউ কেবল একটি লুপের পরিবর্তে পুনরাবৃত্তি ব্যবহার করবে?
উত্তর:
আমি প্রায় দুই বছর ধরে আন্ডারগ্রাজুয়েটদের C ++ শিখিয়েছি এবং পুনরুক্তি আবৃত করেছি। আমার অভিজ্ঞতা থেকে আপনার প্রশ্ন এবং অনুভূতি খুব সাধারণ are চূড়ান্তভাবে, কিছু শিক্ষার্থী পুনরাবৃত্তিটিকে বুঝতে অসুবিধা হিসাবে দেখেন অন্যরা এটি বেশ কিছু কিছুর জন্য ব্যবহার করতে চান।
আমার মনে হয় ডেভ এটির পরিমাণটি ভালভাবে লিখেছেন: এটি যেখানে উপযুক্ত তা ব্যবহার করুন। অর্থাৎ প্রাকৃতিক বোধ করলে এটি ব্যবহার করুন। আপনি যখন কোনও সমস্যার মুখোমুখি হন যেখানে এটি দুর্দান্তভাবে ফিট করে, আপনি সম্ভবত এটি সনাক্ত করতে পারবেন: মনে হবে আপনি এমনকি পুনরাবৃত্তি সমাধানের সাথে আসতে পারেন না। এছাড়াও, স্পষ্টতা প্রোগ্রামিংয়ের একটি গুরুত্বপূর্ণ দিক। অন্যান্য ব্যক্তিদের (এবং আপনিও!) আপনার উত্পন্ন কোডটি পড়তে এবং বুঝতে সক্ষম হওয়া উচিত। আমি মনে করি এটি পুনরুক্তার চেয়ে পুনরুক্তিযুক্ত লুপগুলি প্রথম দর্শনে বোঝা সহজ say
আপনি সাধারণভাবে প্রোগ্রামিং বা কম্পিউটার বিজ্ঞানকে কতটা ভাল জানেন তা আমি জানি না তবে আমি দৃ strongly়ভাবে অনুভব করি যে ভার্চুয়াল ফাংশন, উত্তরাধিকার সম্পর্কে বা এখানে কোনও উন্নত ধারণা সম্পর্কে কথা বলার কোনও মানে হয় না। আমি প্রায়শই ফিবোনাচি নম্বরগুলি গণনার ক্লাসিক উদাহরণ দিয়ে শুরু করেছি। এটি এখানে সুন্দরভাবে ফিট করে, যেহেতু ফিবোনাচি সংখ্যাগুলি পুনরাবৃত্তভাবে সংজ্ঞায়িত হয় । এটি বোঝা সহজ এবং ভাষার কোনও অভিনব বৈশিষ্ট্যের প্রয়োজন নেই । শিক্ষার্থীরা পুনরাবৃত্তি সম্পর্কে কিছু প্রাথমিক ধারণা অর্জন করার পরে, আমরা এর আগে তৈরি কিছু সাধারণ ফাংশনগুলিতে আরেকবার নজর রেখেছি। এখানে একটি উদাহরণ:
স্ট্রিংয়ে কি একটি অক্ষর ?
আমরা এটির আগে এটি করেছি: স্ট্রিংটি পুনরাবৃত্তি করুন এবং দেখুন কোনও সূচীতে রয়েছে কিনা ।
bool find(const std::string& s, char x)
{
for(int i = 0; i < s.size(); ++i)
{
if(s[i] == x)
return true;
}
return false;
}
প্রশ্নটি তখন, আমরা কি এটি পুনরাবৃত্তি করতে পারি? অবশ্যই আমরা পারি, এখানে একটি উপায়:
bool find(const std::string& s, int idx, char x)
{
if(idx == s.size())
return false;
return s[idx] == x || find(s, ++idx);
}
পরবর্তী প্রাকৃতিক প্রশ্নটি তখন কি আমাদের এটি করা উচিত? সম্ভবত না. কেন? এটি বোঝা শক্ত এবং এটির সাথে আসা আরও কঠিন। অতএব এটিও ত্রুটি হওয়ার প্রবণতা বেশি।
কিছু সমস্যার সমাধান পুনরাবৃত্তি ব্যবহার করে স্বাভাবিকভাবেই প্রকাশ করা হয়।
উদাহরণস্বরূপ, ধরে নিন যে আপনার কাছে দুটি ধরণের নোড সহ একটি গাছের ডেটা কাঠামো রয়েছে: পাতা, যা একটি পূর্ণসংখ্যার মান সঞ্চয় করে; এবং শাখাগুলি, যার ক্ষেত্রগুলিতে একটি বাম এবং ডান উপশক্তি রয়েছে। ধরে নিন যে পাতা অর্ডার করা হয়েছে, যাতে সর্বনিম্ন মান বামতম পাতায় থাকে।
মনে করুন কাজটি গাছের মানগুলি যথাযথভাবে মুদ্রণ করা। এটি করার জন্য একটি পুনরাবৃত্ত অ্যালগরিদম যথেষ্ট স্বাভাবিক:
class Node { abstract void traverse(); }
class Leaf extends Node {
int val;
void traverse() { print(val); }
}
class Branch extends Node {
Node left, right;
void traverse() { left.traverse(); right.traverse(); }
}
পুনরাবৃত্তি ব্যতীত সমতুল্য কোড লেখা অনেক বেশি কঠিন হবে। চেষ্টা করে দেখুন!
আরও সাধারণভাবে, পুনরাবৃত্তি গাছগুলির মতো পুনরাবৃত্তির উপাত্ত কাঠামোর উপর অ্যালগোরিদমগুলির জন্য বা প্রাক-সমস্যার মধ্যে প্রাকৃতিকভাবে ভেঙে যেতে পারে এমন সমস্যার জন্য ভাল কাজ করে। উদাহরণস্বরূপ, অ্যালগরিদমগুলি ভাগ করুন এবং জয় করুন ।
যদি আপনি সত্যিই এর সবচেয়ে প্রাকৃতিক পরিবেশে পুনরাবৃত্তি দেখতে চান, তবে আপনার হাস্কেলের মতো ক্রিয়ামূলক প্রোগ্রামিং ভাষার দিকে নজর দেওয়া উচিত। এই জাতীয় ভাষায়, কোনও লুপিং কনস্ট্রাক্ট নেই, তাই পুনরাবৃত্তি (বা উচ্চতর ক্রমের ক্রিয়াকলাপগুলি ব্যবহার করে সমস্ত কিছু প্রকাশ করা হয়, তবে এটি অন্য গল্প, এটি সম্পর্কেও জানার মতো মূল্য)।
ফাংশনাল প্রোগ্রামিং ভাষাগুলি অনুকূলিত পুচ্ছ পুনরাবৃত্তি করে Note এর অর্থ হ'ল তারা স্ট্যাক ফ্রেম রাখে না যতক্ষণ না তাদের প্রয়োজন হয় --- মূলত, পুনরাবৃত্তি একটি লুপে রূপান্তর করা যায়। ব্যবহারিক দৃষ্টিকোণ থেকে, আপনি একটি প্রাকৃতিক ফ্যাশনে কোড লিখতে পারেন, তবে পুনরাবৃত্ত কোডের কর্মক্ষমতা পান get রেকর্ডের জন্য, দেখে মনে হচ্ছে যে সি ++ সংকলকগুলি লেজ কলগুলিও অনুকূলিত করে , তাই সি ++ এ পুনরাবৃত্তি ব্যবহার করার জন্য কোনও অতিরিক্ত ওভারহেড নেই।
যিনি ব্যবহারিকভাবে পুনরাবৃত্তি করে থাকেন তার কাছ থেকে আমি চেষ্টা করব এবং এই বিষয়ে কিছু আলোকপাত করব।
প্রথমে যখন পুনরাবৃত্তির সাথে পরিচয় করিয়ে দেওয়া হবে আপনি শিখবেন যে এটি একটি ফাংশন যা নিজেকে কল করে এবং মূলত গাছের ট্র্যাভারসাল এর মতো অ্যালগরিদম দিয়ে প্রদর্শিত হয়। পরে আপনি দেখতে পাবেন এটি এলআইএসপি এবং এফ # এর মতো ভাষার জন্য ফাংশনাল প্রোগ্রামিংয়ে প্রচুর ব্যবহৃত হয় । F # দিয়ে আমি লিখি, আমি যা লিখি তার বেশিরভাগটি পুনরাবৃত্ত এবং প্যাটার্ন মেলানো।
আপনি যদি এফ # এর মতো ক্রিয়ামূলক প্রোগ্রামিং সম্পর্কে আরও শিখেন তবে আপনি এফ # তালিকা শিখবেন যেগুলি এককভাবে সংযুক্ত তালিকাগুলি হিসাবে প্রয়োগ করা হয় যার অর্থ কেবলমাত্র তালিকার শীর্ষস্থানীয় অ্যাক্সেস করা অপারেশনগুলি হ'ল (1), এবং উপাদান অ্যাক্সেস ও (এন)। একবার আপনি এটি শিখলে আপনি তালিকা হিসাবে ডেটা অতিক্রম করতে, বিপরীত ক্রমে নতুন তালিকা তৈরি করা এবং তারপরে ফাংশন থেকে ফিরে আসার আগে তালিকার বিপরীতে যা খুব কার্যকর।
এখন আপনি যদি এই সম্পর্কে ভাবতে শুরু করেন আপনি শীঘ্রই বুঝতে পারবেন যে পুনরাবৃত্ত ফাংশনগুলি প্রতিবার কোনও ফাংশন কল করার সময় একটি স্ট্যাক ফ্রেমটিকে ধাক্কা দেয় এবং স্ট্যাকের ওভারফ্লো হতে পারে। তবে, যদি আপনি আপনার পুনরাবৃত্ত ফাংশনটি তৈরি করেন যাতে এটি একটি লেজ কল করতে পারে এবং সংকলক লেজ কলটির জন্য কোডটি অনুকূলিত করার ক্ষমতা সমর্থন করে। যেমন। নেট ওপকোডস। টেলকল ক্ষেত্র আপনি স্ট্যাকের ওভারফ্লো করতে পারবেন না। এই মুহুর্তে আপনি কোনও পুনরাবৃত্তি ফাংশন হিসাবে কোনও লুপিং এবং ম্যাচ হিসাবে কোনও সিদ্ধান্ত লিখতে শুরু করেন; দিন if
এবং while
এখন ইতিহাস।
আপনি যখন PROLOG- র মতো ভাষাগুলিতে ব্যাকট্র্যাকিং ব্যবহার করে এআই তে চলে যান, তারপরে সবকিছু পুনরাবৃত্ত হয়। যদিও এটি আবশ্যক কোডের থেকে একদম আলাদাভাবে চিন্তা করা দরকার, যদি PROLOG সমস্যার সঠিক উপায় হয় তবে এটি আপনাকে প্রচুর কোডের লাইন লেখার বোঝা থেকে মুক্তি দেয় এবং নাটকীয়ভাবে ত্রুটির সংখ্যা হ্রাস করতে পারে। দেখুন: আমজি গ্রাহক ইওটেক
পুনরাবৃত্তি কখন ব্যবহার করবেন তা আপনার প্রশ্নে ফিরে যেতে; আমি প্রোগ্রামিংয়ের দিকে নজর রাখার একটি উপায় হ'ল এক প্রান্তে হার্ডওয়্যার এবং অন্য প্রান্তে বিমূর্ত ধারণাগুলি। হার্ডওয়্যার কাছাকাছি সমস্যাটি আমি অনুজ্ঞাসূচক ভাষায় মনে if
এবং while
, আরো বিমূর্ত সমস্যা, আরো আমি recursion উচ্চ পর্যায়ের সঙ্গে ভাষায় মনে করি। তবে, আপনি যদি নিম্ন স্তরের সিস্টেম কোড এবং এ জাতীয় লেখা শুরু করেন এবং আপনি এটির বৈধতা যাচাই করতে চান তবে আপনি তখন উপপাদ্য প্রবাদগুলির মতো সমাধানগুলি সন্ধান করতে পারেন যা পুনরাবৃত্তির উপর নির্ভর করে।
আপনি যদি জেন স্ট্রিটের দিকে লক্ষ্য করেন তবে দেখবেন তারা কার্যকরী ভাষা ওসিএএমএল ব্যবহার করে । যদিও আমি তাদের কোডগুলির কোনওটিই দেখি নি, তারা তাদের কোড সম্পর্কে কী উল্লেখ করেছে সেগুলি পাঠ করা থেকে তারা নিরবচ্ছিন্নভাবে পুনরাবৃত্তভাবে চিন্তা করছে।
সম্পাদনা
যেহেতু আপনি ব্যবহারের তালিকার সন্ধান করছেন, তাই আমি কোডে কী সন্ধান করতে হবে তার একটি প্রাথমিক ধারণা এবং প্রাথমিক ব্যবহারগুলির একটি তালিকা যা বেশিরভাগ মৌলিক ধারণা ছাড়াই ক্যাটামোরফিজমের ধারণার ভিত্তিতে তৈরি করব ।
সি ++ এর জন্য: আপনি যদি কোনও কাঠামো বা শ্রেণীর সংজ্ঞা দেন যা একই কাঠামো বা শ্রেণীর পয়েন্টার রয়েছে তবে পয়েন্টারগুলি ব্যবহার করে এমন ট্র্যাভার্সাল পদ্ধতিগুলির জন্য পুনরাবৃত্তি বিবেচনা করা উচিত।
সরল কেসটি এক দিকের লিঙ্কযুক্ত তালিকা। আপনি তালিকাটি মাথা বা লেজ থেকে শুরু করে প্রক্রিয়া করবেন এবং তারপরে পয়েন্টারগুলি ব্যবহার করে তালিকাকে ক্রমাগত অতিক্রম করবেন।
একটি গাছ অন্য ক্ষেত্রে যেখানে পুনরাবৃত্তি প্রায়শই ব্যবহৃত হয়; এত বেশি যে আপনি যদি পুনরাবৃত্তি না করে গাছের আড়াআড়ি দেখতে পান তবে আপনার জিজ্ঞাসা শুরু করা উচিত কেন? এটি ভুল নয়, তবে এমন কিছু যা মন্তব্যগুলিতে লক্ষ্য করা উচিত।
পুনরাবৃত্তির সাধারণ ব্যবহারগুলি হ'ল:
আপনাকে এমন একটি ব্যবহারের ক্ষেত্রে যা অন্যান্য উত্তরের চেয়ে কম তীক্ষ্ণ হয়: পুনরাবৃত্তি একটি সাধারণ উত্স থেকে প্রাপ্ত গাছের মতো (অবজেক্ট ওরিয়েন্টেড) শ্রেণিবদ্ধ কাঠামোর সাথে খুব ভাল মিশ্রিত হয়। একটি সি ++ উদাহরণ:
class Expression {
public:
// The "= 0" means 'I don't implement this, I let my subclasses do that'
virtual int ComputeValue() = 0;
}
class Plus : public Expression {
private:
Expression* left
Expression* right;
public:
virtual int ComputeValue() { return left->ComputeValue() + right->ComputeValue(); }
}
class Times : public Expression {
private:
Expression* left
Expression* right;
public:
virtual int ComputeValue() { return left->ComputeValue() * right->ComputeValue(); }
}
class Negate : public Expression {
private:
Expression* expr;
public:
virtual int ComputeValue() { return -(expr->ComputeValue()); }
}
class Constant : public Expression {
private:
int value;
public:
virtual int ComputeValue() { return value; }
}
উপরের উদাহরণটি পুনরাবৃত্তি ব্যবহার করে: কমপিউটিভালু পুনরাবৃত্তির সাথে প্রয়োগ করা হয়। উদাহরণটিকে কাজ করতে আপনি ভার্চুয়াল ফাংশন এবং উত্তরাধিকার ব্যবহার করেন। প্লাস বর্গের বাম এবং ডান অংশগুলি ঠিক কী তা আপনি জানেন না, তবে আপনি পাত্তা দিচ্ছেন না: এটি এমন একটি জিনিস যা তার নিজস্ব মান গণনা করতে পারে, যা আপনার জানা দরকার।
উপরোক্ত পদ্ধতির গুরুত্বপূর্ণ সুবিধাটি হ'ল প্রতিটি শ্রেণী নিজস্ব গণনাগুলির যত্ন নেয় । আপনি প্রতিটি সম্ভাব্য সুবে এক্সপ্রেশনগুলির বিভিন্ন বাস্তবায়ন সম্পূর্ণ আলাদা করে দেন: একে অপরের কাজ সম্পর্কে তাদের কোনও জ্ঞান নেই। এটি প্রোগ্রাম সম্পর্কে যুক্তি সহজ করে তোলে এবং তাই প্রোগ্রামটি বোঝা, বজায় রাখা এবং প্রসারিত করা সহজ করে তোলে।
আমার প্রথম প্রোগ্রামিং ক্লাসে পুনরাবৃত্তি শেখানোর জন্য ব্যবহৃত প্রথম উদাহরণটি হ'ল বিপরীত ক্রমে পৃথক সংখ্যায় সমস্ত সংখ্যা তালিকাভুক্ত করা একটি ফাংশন।
void listDigits(int x){
if (x <= 0)
return;
print x % 10;
listDigits(x/10);
}
বা এর মতো কিছু (আমি এখানে স্মৃতি থেকে যাচ্ছি এবং পরীক্ষা করছি না)। এছাড়াও, আপনি যখন উচ্চ স্তরের শ্রেণিতে প্রবেশ করেন, আপনি বিশেষত অনুসন্ধান অ্যালগরিদমগুলি, বাছাইকরণ অ্যালগরিদম ইত্যাদিতে প্রচুর পরিমাণে পুনরাবৃত্তি ব্যবহার করবেন
সুতরাং এটি এখন ভাষাতে একটি অকেজো ফাংশন বলে মনে হতে পারে তবে এটি দীর্ঘকালীন সময়ে খুব কার্যকর।