ढेर और प्रत्यावर्तन उन्मूलन लेख कैप्चर ढेर पर ढेर फ्रेम externalizing का विचार है, लेकिन एक प्रदान नहीं करता है सीधा और repeatable परिवर्तित करने के लिए जिस तरह से। नीचे एक है।
पुनरावृत्ति कोड में परिवर्तित करते समय, किसी को यह पता होना चाहिए कि पुनरावर्ती कॉल मनमाने ढंग से गहरे कोड ब्लॉक से हो सकता है। इसका न केवल पैरामीटर, बल्कि तर्क पर लौटने का बिंदु भी है जो निष्पादित होने के लिए रहता है और चर की स्थिति जो बाद की स्थिति में भाग लेते हैं, जो मायने रखते हैं। नीचे कम से कम परिवर्तनों के साथ पुनरावृति कोड में परिवर्तित करने का एक बहुत ही सरल तरीका है।
इस पुनरावर्ती कोड पर विचार करें:
struct tnode
{
tnode(int n) : data(n), left(0), right(0) {}
tnode *left, *right;
int data;
};
void insertnode_recur(tnode *node, int num)
{
if(node->data <= num)
{
if(node->right == NULL)
node->right = new tnode(num);
else
insertnode(node->right, num);
}
else
{
if(node->left == NULL)
node->left = new tnode(num);
else
insertnode(node->left, num);
}
}
Iterative कोड:
// Identify the stack variables that need to be preserved across stack
// invocations, that is, across iterations and wrap them in an object
struct stackitem
{
stackitem(tnode *t, int n) : node(t), num(n), ra(0) {}
tnode *node; int num;
int ra; //to point of return
};
void insertnode_iter(tnode *node, int num)
{
vector<stackitem> v;
//pushing a stackitem is equivalent to making a recursive call.
v.push_back(stackitem(node, num));
while(v.size())
{
// taking a modifiable reference to the stack item makes prepending
// 'si.' to auto variables in recursive logic suffice
// e.g., instead of num, replace with si.num.
stackitem &si = v.back();
switch(si.ra)
{
// this jump simulates resuming execution after return from recursive
// call
case 1: goto ra1;
case 2: goto ra2;
default: break;
}
if(si.node->data <= si.num)
{
if(si.node->right == NULL)
si.node->right = new tnode(si.num);
else
{
// replace a recursive call with below statements
// (a) save return point,
// (b) push stack item with new stackitem,
// (c) continue statement to make loop pick up and start
// processing new stack item,
// (d) a return point label
// (e) optional semi-colon, if resume point is an end
// of a block.
si.ra=1;
v.push_back(stackitem(si.node->right, si.num));
continue;
ra1: ;
}
}
else
{
if(si.node->left == NULL)
si.node->left = new tnode(si.num);
else
{
si.ra=2;
v.push_back(stackitem(si.node->left, si.num));
continue;
ra2: ;
}
}
v.pop_back();
}
}
ध्यान दें कि कोड की संरचना अभी भी कैसे पुनरावर्ती तर्क के लिए सही है और संशोधन न्यूनतम हैं, जिसके परिणामस्वरूप बग की संख्या कम है। तुलना के लिए, मैंने ++ और - के साथ परिवर्तनों को चिह्नित किया है। V.push_back को छोड़कर अधिकांश नए सम्मिलित ब्लॉक, किसी भी परिवर्तित पुनरावृत्ति तर्क के लिए सामान्य हैं
void insertnode_iter(tnode *node, int num)
{
+++++++++++++++++++++++++
vector<stackitem> v;
v.push_back(stackitem(node, num));
while(v.size())
{
stackitem &si = v.back();
switch(si.ra)
{
case 1: goto ra1;
case 2: goto ra2;
default: break;
}
------------------------
if(si.node->data <= si.num)
{
if(si.node->right == NULL)
si.node->right = new tnode(si.num);
else
{
+++++++++++++++++++++++++
si.ra=1;
v.push_back(stackitem(si.node->right, si.num));
continue;
ra1: ;
-------------------------
}
}
else
{
if(si.node->left == NULL)
si.node->left = new tnode(si.num);
else
{
+++++++++++++++++++++++++
si.ra=2;
v.push_back(stackitem(si.node->left, si.num));
continue;
ra2: ;
-------------------------
}
}
+++++++++++++++++++++++++
v.pop_back();
}
-------------------------
}