递归逆序的使用

在下面这个程序片段中的划线处填上适当的表达式,使之逆序输出数组元素。

--------------------------------------------------------------------------------

void recur(int a[], int k)
        {
                int tmp;
                if(_____)
                {
                        recur(_____, _____);
                        tmp = a[0];
                        a[0] = a[k-1];
                        a[k-1] = tmp;
                }
        }

--------------------------------------------------------------------------------

这道题目要用递归的思想完成数组元素的逆序排列,我们先来复习一下有关递归函数一般解题思路。

一般而言,递归函数要有一个恰当的返回条件,以便到达那个条件的时候返回,不至于无穷嵌套进去,因此这个返回条件一定要在某个时候成立。另外,递归解决问题的思路就是:如果我要完成A任务,我必须先完成B任务,而要完成B任务,我又必须完成C任务……以此类推,就像经典的汉诺塔问题一样,到最后只需要解决掉最简单的那个任务即可,以此返回便能达到目的。如下图:

回到这道题目来,如果给出一个数组{1,2,3,4,5,6,7,8},又假设此时令k=6,即要让前6个元素逆序,我们可以这么分解问题:要让1,2,3,4,5,6逆序,我可以先让2,3,4,5逆序,只要它们逆序了,我只需交换1和6即可;而要解决这第二个问题,我可以先让3,4逆序,只要它们逆序了,我只需交换2和5即可,最后我只需交换3和4即可。因此交换序列中的中间两个元素成为我们用递归思想解决这道题的第一步。

首先我们来确定返回条件,这个好办,只要k值大于等于2,我们才有交换的必要,否则根本不需要交换。这个应该没啥异议的,if语句里面填的应该就是k>1或者k>=2。

下面是递归调用自身的时候,究竟需要传递什么参数。前面已经分析过,我们在这道题中要一步步像剥洋葱一样地剥开这个数组,而且我们注意到程序中最后三条语句是 a[0] 跟a[k-1] 在相互交换,因此这里的 a[0] 必定是原来数组不断往后移动得来的,也就是说第一个参数应该是 a+1 ,这样,每次递归调用的时候 a[0] 就会依次往后移动。

从程序中可以看出,当最终从返回条件退出递归时要交换的是 a[0] 和 a[k-1] ,因此这里的k就应该是子序列的长度(也就是每一次“剥洋葱”之后的长度),显然,每“剥”一次“洋葱”序列的长度就减2(序列头和序列尾除去),所以第二个参数应该每次减2,即k-2,所以答案是:

--------------------------------------------------------------------------------

 1 void recur(int a[], int k)
 2         {
 3                 int tmp;
 4                 if(_k>1 )
 5                 {
 6                         recur(_a+1_, _k-2_);
 7                         tmp = a[0];
 8                         a[0] = a[k-1];
 9                         a[k-1] = tmp;
10                 }
11         }
时间: 2024-10-16 06:32:28

递归逆序的使用的相关文章

算法题:链表的递归逆序

#include <iostream> using namespace std; struct Node { int data; Node *next; Node(int d = int()) :data(d), next(NULL){} }; class Clist { public: Clist(int a[], int n) :first(NULL) { int i = 0; Node *p = NULL; for (; i < n; i++) { Node *s = new No

C++单链表递归逆序

#include <iostream> using namespace std; struct Node { int data; Node *next; Node(int d = int()) :data(d), next(NULL){} }; class List { public: List() { first = NULL; } void Insert(int a[], int n) { Node *p = first; for (int i = 0; i < n; i++) {

C++ 递归和非递归实现链表逆序

测试环境:vs2010  windows7 逆序分别采用递归调用和链表头插法实现逆序. 具体代码如下: #include<iostream> #include<stdlib.h> using namespace std; class LinkList { private: struct Node { struct Node *next; int value; }; Node *phead; void reverse_use_recursion(Node *pnode) { if(p

用递归正/逆序打印一个数组,以及调用返回的过程理解

1 #include <stdio.h> 2 /* 3 题目:用递归正/逆序打印数组的元素,以及递归调用的过程理解 4 正序打印数组解题思路:第一:数组元素是连续的.知道第一个元素的地址,就能推算出第二个元素的地址.以此类推 5 第二:数组的结束条件:i = sizeof(arr)/4 -1; 此时的值为arr[sizeof(arr)/4-1]; 6 第三:后一个元素的值的下标 = 前一个元素的值的下标+1 (通项公式) 7 */ 8 void arr1(int *p,int n,int *p

C++链表逆序打印节点

#include <iostream> #include <stack> using namespace std; template<typename Type> struct Node { Type data; Node *next; Node(Type d = Type()):data(d),next(NULL){} }; template<typename Type> class List { public: List() { head = NULL;

单链表逆序的三种方法

一.不使用额外存储空间的逆序 LinkList ReverseLink(LinkList L) { LinkList *next; LinkList *prev = NULL; LinkList *head = L->next; while(head != NULL) { next = head->next; head->next = prev; prev = head; head = next; } L->next = prev return L; } 二.头插法逆序 LinkL

&quot;Coding Interview Guide&quot; -- 仅用递归函数和栈操作逆序一个栈

[题目] 一个栈依次压入1.2.3.4.5,那么从栈顶到栈底分别为5.4.3.2.1.将这个栈转置后,从栈顶到栈底为1,2,3,4,5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能使用其它数据结构 [分析] 栈是一种操作受限的数据结构,只能从某一端进行插入和删除和访问元素.能进行插入删除和访问等操作的一端称为“栈顶”,相对的另一端,不能进行任何栈操作,称为栈底.栈中除了栈顶元素外,其它的栈元素都是不允许访问的.所以想要访问栈中其它元素,则只能将将栈中元素依次弹出直到该元素成为栈顶元素

只使用递归实现栈的逆序操作

2017-06-23 20:36:02 刚开始思考这个问题的时候陷入了一个误区,就是以为只能用一个递归完成. 然而事实上,可以使用两个递归来完成这个功能. 具体思考是这样的,首先递归其实是将问题规模缩小了,每次处理更小的问题.针对这题来说,更小的问题应该是去除底部那个数后的逆序再加上最后的数. 当然,你可能会问,什么不是去掉最上面的数,然后将它再放到最前面,理由很简单,栈是一种后进先出的数据结构,这种类型的数据结构适合的是在尾部添加数据,而非在首部添加数据,所以更清晰的或者说更适合栈的操作是先把

字符串逆序输出--递归

说到递归,很容易想到n!,斐波那契数列(数兔子问题),当然这些都是很好理解的问题.个人认为,最能反映递归实质的是汉诺塔和字符串逆向输出问题.汉诺塔问题只需要思考一步,其他难题就交给计算机吧,这很好的证明了递归就是懒人专用算法.仅凭这一点,就足以掩盖递归效率低下的缺陷.我们都知道,递归就是函数调用自身的过程.在c语言中,函数调用自身和调用其他函数,没有一点区别.都是保存现场,函数调用,恢复现场的过程,这是通俗的说法,用我们专业的术语来说,递归的实质就是入栈和出栈的过程.解释到这里,用递归实现字符串