递归到循环的转换

使用栈模拟递归解决等差数列与汉诺塔问题
这篇博客探讨了如何使用栈来模拟递归算法,分别解决了判断一个数组是否为等差数列以及汉诺塔问题。对于等差数列,通过将问题分解为子问题并利用栈存储中间结果来实现;对于汉诺塔问题,同样利用栈来保存中间状态,避免了递归调用。这种方法有助于理解递归过程,并能提高算法效率。

判断数组 a 是不是一个等差数列

使用栈模拟递归解法

struct Param : public Object
{
    Param(int begin = -1, int end = -1, int d = -1)
    {
        this->begin = begin;
        this->end = end;
        this->d = d;
        this->ret = false;
    }

    int begin;
    int end;
    int d;
    bool ret;
};

bool IsArithProg(int a[], int begin, int end, int& d)
{
    LinkStack<Param> st;
    Param obj(begin, end);
    Param ans;  // ans 为模拟递归后得到的结果

    st.push(obj);

    while(st.size() > 0)
    {
        Param curr = st.top();

        if(curr.begin == curr.end)  // 递归出口,数列只有一个元素时
        {
            ans.begin = curr.begin;
            ans.end = curr.end;
            ans.ret = true;
            st.pop();
        }
        else if((curr.end - curr.begin) == 1)  // 递归出口,数列只有两个元素时
        {
            ans.begin = curr.begin;
            ans.end = curr.end;
            ans.d = a[curr.end] - a[curr.begin];
            ans.ret = true;
            st.pop();
        }
        else
        {
            if((curr.begin == (ans.begin - 1)) && (curr.end == ans.end))  // 子问题解决,带着子问题的答案解决当前问题
            {
                if(ans.ret && ((a[curr.begin + 1] - a[curr.begin]) == ans.d))  // 子数组为等差数列并且子数组的第一个元素减去当前元素的值等于子数组的公差
                {
                    ans.begin = curr.begin;
                    st.pop();
                }
                else  // 不满足等差数列,直接退出循环
                {
                    ans.ret = false;
                    break;
                }
            }
            else
            {
                st.push(Param(curr.begin + 1, curr.end));  // 问题分解,将子问题入栈
            }
        }
    }

    return (ans.ret ? (d = ans.d, true) : false);
}

bool IsArithProg(int a[], int len, int& d)
{
    return IsArithProg(a, 0, len - 1, d);
}

将原问题分解成两个子问题

struct Param : public Object
{
    Param(int begin = -1, int end = -1, int d = -1)
    {
        this->begin = begin;
        this->end = end;
        this->d = d;
        this->ret = false;
    }

    int begin;
    int end;
    int d;
    bool ret;
};

bool IsArithProg(int a[], int begin, int end, int& d)
{
    LinkStack<Param> st;
    LinkStack<Param> answer;
    Param obj(begin, end);  // 目标问题

    st.push(obj);

    while(st.size() > 0)
    {
        Param ans;
        Param curr = st.top();  // 当前问题

        if(curr.begin == curr.end)  // 递归出口,数列只有一个元素时
        {
            ans.begin = curr.begin;
            ans.end = curr.end;
            ans.ret = true;
            st.pop();  // 当前问题解决
            answer.push(ans);  // 答案入栈
        }
        else if((curr.end - curr.begin) == 1)  // 递归出口,数列只有两个元素时
        {
            ans.begin = curr.begin;
            ans.end = curr.end;
            ans.d = a[curr.end] - a[curr.begin];
            ans.ret = true;
            st.pop();  // 当前问题解决
            answer.push(ans);  // 答案入栈
        }
        else
        {
            Param ans0;
            Param ans1;

            if(answer.size() > 0)  // 栈顶找答案
            {
                ans0 = answer.top();
                answer.pop();
            }

            if(answer.size() > 0)  // 栈顶找答案
            {
                ans1 = answer.top();
                answer.pop();
            }

            if((curr.begin == ans0.begin) && (curr.end == ans1.end))  // 找到的答案能否解决当前问题
            {
                /* [ans0.begin, ans1.end] 组成的数列构成等差数列, 则将新的答案入栈 */
                if(ans0.ret && ans1.ret && (ans0.d == ans1.d))
                {
                    ans.begin = curr.begin;
                    ans.end = curr.end;
                    ans.d = ans0.d;
                    ans.ret = ans0.ret;
                    st.pop();
                    answer.push(ans);
                }
                else
                {
                    ans.ret = false;
                    answer.push(ans);
                    break;
                }
            }
            else  // 将当前问题分解成子问题
            {
                int mid = (curr.begin + curr.end) / 2;
                Param np0(curr.begin, mid);
                Param np1(mid, curr.end);

                /* 找到的答案不能解决当前问题,将答案重新入栈 */
                if(ans1.begin != -1)
                {
                    answer.push(ans1);
                }

                /* 找到的答案不能解决当前问题,将答案重新入栈 */
                if(ans0.begin != -1)
                {
                    answer.push(ans0);
                }

                /* 将子问题入栈 */
                st.push(np0);
                st.push(np1);
            }
        }
    }

    return (answer.top().ret ? (d = answer.top().d, true) : false);
}

bool IsArithProg(int a[], int len, int& d)
{
    return IsArithProg(a, 0, len - 1, d);
}

汉诺塔问题

递归解法

void hanoi_rec(int n, char a, char b, char c)
{
    if(n > 0)
    {
        hanoi_rec(n - 1, a, c, b);  // 将 n-1 个木块借助C柱由A柱移动到B柱
        cout << a << " -> " << c << endl;  // 将最底层的唯一木块直接移动到C柱
        hanoi_rec(n - 1, b, a, c);  // 将 n-1 个木块借助A柱由B柱移动到C柱
    }
}

 

非递归解法

struct Param : public Object
{
    Param(int n = -1, int a = 0, int b = 0, int c = 0)
    {
        this->n = n;
        this->a = a;
        this->b = b;
        this->c = c;
    }

    int n;
    char a;
    char b;
    char c;
};

void hanoi_non(int n, char a, char b, char c)
{
    if(n > 0)
    {
        LinkStack<Param> st;
        LinkStack<Param> answer;
        Param obj(n, a, b, c);  // 目标问题

        st.push(obj);

        while(st.size() > 0)
        {
            Param curr = st.top();  // 当前问题

            if(curr.n == 0)
            {
                cout << curr.a << " -> " << curr.c << endl;
                st.pop();
            }
            else if(curr.n == 1)  // 出口
            {
                cout << curr.a << " -> " << curr.c << endl;  // 直接将A柱最底层唯一的木块移动到C柱
                st.pop();  // 最小问题解决
                answer.push(curr);  // 将答案入栈
            }
            else
            {
                Param ans0;
                Param ans1;

                /* 尝试取答案 */
                if(answer.size() > 0)
                {
                    ans1 = answer.top();
                    answer.pop();
                }

                /* 尝试取答案 */
                if(answer.size() > 0)
                {
                    ans0 = answer.top();
                    answer.pop();
                }

                if((curr.n == (ans0.n + 1)) && (curr.a == ans0.a) && (curr.b == ans0.c) && (curr.c == ans0.b) &&
                        (curr.n == (ans1.n + 1)) &&(curr.a == ans1.b) && (curr.b == ans1.a) && (curr.c == ans1.c))  // 答案与当前的问题相匹配,尝试解决当前问题
                {
                    st.pop();  // 当前问题解决
                    answer.push(curr);  // 将答案入栈
                }
                else  // 需要继续分解问题
                {
                    /* 答案不能解决当前问题,重新将答案入栈 */
                    if(ans0.n != -1)
                    {
                        answer.push(ans0);
                    }

                    /* 答案不能解决当前问题,重新将答案入栈 */
                    if(ans1.n != -1)
                    {
                        answer.push(ans1);
                    }

                    /* 问题分解 */
                    st.push(Param(curr.n - 1, curr.b, curr.a, curr.c));
                    st.push(Param(0, curr.a, curr.b, curr.c));
                    st.push(Param(curr.n - 1, curr.a, curr.c, curr.b));
                }
            }
        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值