กองและการกำจัด recursionจับบทความความคิดของ externalizing กรอบสแต็คในกอง แต่ไม่ได้ให้ตรงไปตรงมาและทำซ้ำวิธีที่จะแปลง ด้านล่างเป็นหนึ่ง
ในขณะที่แปลงเป็นรหัสซ้ำคุณต้องทราบว่าการเรียกซ้ำอาจเกิดขึ้นจากการบล็อกรหัสที่มีความลึกโดยพลการ ไม่ใช่เพียงแค่พารามิเตอร์ แต่ยังรวมถึงจุดที่จะกลับไปสู่ตรรกะที่ยังคงต้องดำเนินการและสถานะของตัวแปรที่เข้าร่วมในเงื่อนไขที่ตามมาซึ่งมีความสำคัญ ด้านล่างเป็นวิธีที่ง่ายมากในการแปลงเป็นรหัสซ้ำโดยมีการเปลี่ยนแปลงน้อยที่สุด
พิจารณารหัสซ้ำนี้:
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);
}
}
รหัสซ้ำ:
// 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();
}
-------------------------
}