博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中递归的如果想要达到C++的传参效果的一种写法
阅读量:3916 次
发布时间:2019-05-23

本文共 4968 字,大约阅读时间需要 16 分钟。

常识:

我们都知道 Java方法的参数传递是值传递,就是说如果参数是基本数据类型,那么直接拷贝一份副本给形参,如果参数是对象,不是基本数据类型,那么拷贝对象的引用的副本,也就是相等于是拷贝了一份指向这个对象指针,这样在方法中通过形参修改对象的属性或者字段,是会对原来的对象产生影响的,因为本质上这两个是同一个对象。

问题:

C++里面的值传递是在形参中拷贝一份对象的副本,而Java中没有这种传递方式,Java中的值传递类似于C++里面的引用传递。所以C++的递归在不同深度的递归中形参中的对象是不会相互影响的,所以C++天生就帮我们做了递归层次之间的参数隔离,但是Java 会有这个问题,Java方法中的参数传递不会重新创建对象,而是引用的同一个对象,所以后面更深层次的递归就会对回溯后的形参对象产生影响。

我考虑的是怎么消除这种影响,达到和C++一样的效果。

 比如图中代码中的这个函数形参中的两个对象,一个栈,和一个列表,我怎么样可以让更深次的修改不会对回溯后的本层次造成影响呢,

我的方式是:既然这两个对象在每个层次的递归都是一样的,都是这两个对象,那么这两个对象定义成局部变量就没有什么用了,所以干脆定义成全局变量,但是在每次在本层次递归进行后,都必须进行回溯,消除递归的影响,改动后的代码如下:

我们以往的递归往往是不会在最后一个选择后进行消除回溯的,因为这没什么用,但是这里需要回溯。

这个代码完整的问题如下:

栈是一种重要的数据结构,其主要的操作包括入栈和出栈。请编写程序,对任意给定的n,输出 1,2,…,n 的所有出栈顺序。

输入:正整数 n(1≤n≤9)
输出:输出 1,2,…,n 的所有出栈顺序

例如:

 用递归的思路进行解题:每次进入递归都判断这次是入栈还是出栈

C++式写法:

1 // 栈是一种重要的数据结构,其主要的操作包括入栈和出栈。请编写程序,对任意给定的n,输出 1,2,…,n 的所有出栈顺序。 2 #define  _CRT_SECURE_NO_WARNINGS 3 #include 
4 #include
5 #include
6 using namespace std; 7 8 int n; 9 vector
> v;10 11 void dfs(int i, stack
S, vector
& temp)12 {13 // 每次进入dfs, 判断是否大于等于n, 如果大于n,存储数据,返回14 if (i > n && S.empty()){15 v.push_back(temp);16 return;17 }18 19 // 选择入栈当前元素还是出栈栈顶元素20 // 选择入栈当前元素21 if (i <= n)22 {23 S.push(i);24 dfs(i + 1, S, temp);25 S.pop(); // 消除入栈的影响26 }27 28 // 选择出栈当前元素29 if (!S.empty())30 {31 temp.push_back(S.top());32 S.pop();33 dfs(i, S, temp);34 temp.pop_back();35 }36 }37 38 int main()39 {40 // 读取数据41 scanf("%d", &n);42 // 对这个数据进行dfs递归,求出所有出栈顺序43 stack
S;44 vector
temp; // 存储一个弹出序列45 dfs(1, S, temp);46 47 for (int i = 0; i < v.size(); i++){48 for (int j = 0; j < v[i].size(); j++)49 printf("%d ", v[i][j]);50 printf("\n");51 }52 53 return 0;54 }

我把这个C++代码初步改成Java代码

1 package report2; 2  3 import java.util.ArrayList; 4 import java.util.Scanner; 5 import java.util.Stack; 6  7 // 利用递归打印所有出栈序列 8 public class Solution1_1 { 9     // 存储全排列的数组10     public static ArrayList
> ps =11 new ArrayList<>();12 public static int n;13 14 15 public static void main(String[] args) {16 // 读取输入17 Scanner in = new Scanner(System.in);18 n = in.nextInt();19 20 // 对这个数据进行dfs递归,求出所有出栈顺序21 Stack
s = new Stack<>();22 ArrayList
tmp = new ArrayList
();23 stackPopPermutation(1, s, tmp);24 25 // 打印所有的出栈序列26 for(int i = 0; i < ps.size(); i++){27 for(int j = 0; j < ps.get(i).size(); j++){28 System.out.print(ps.get(i).get(j) + " ");29 }30 System.out.println();31 }32 }33 34 // tmp参数中存储的是临时的出栈序列35 private static void stackPopPermutation(int i, Stack
s, ArrayList
tmp) {36 // 每次进入递归,判断 i 是否大于等于n, 如果大于n,存储序列,返回37 if(i > n && s.empty()){38 ps.add(tmp);39 return;40 }41 // 选择入栈当前元素还是出栈栈顶元素42 // 选择入栈当前元素43 if (i <= n)44 {45 s.push(i);46 stackPopPermutation(i + 1, s, tmp);47 s.pop(); // 消除入栈的影响48 }49 50 // 选择出栈当前元素51 if (!s.empty())52 {53 tmp.add(s.peek());54 s.pop();55 stackPopPermutation(i, s, tmp);56 // tmp.remove(new Integer(i));57 }58 }59 }

我同学的代码给我了思路,既然第一次选择后回溯可以使得全局变量回退到刚进入这个函数时的状态,那我第二次选择后再进行一次回溯是不是也可以回退到刚进入这个函数时的状态呢,这样是不是就达到了一种类似于在形参中传递了一个对象的拷贝,而非引用的拷贝呢,因为我们通过手动回溯的方式使得一个全局变量在进入递归到出递归状态没有发生变化,

S、S1、S2均表示一个全局变量的状态

S --> S1 --> 进入递归 --> 出递归 -->回溯 -- > S -- S2 -->进入递归 -- > 出递归 -- > 回溯 -- > S

最终的Java代码:

1 package report2; 2  3 import java.util.*; 4  5 // 利用递归打印所有出栈序列 6 public class Solution1 { 7  8     public static Stack
s = new Stack<>(); // 一个工作栈 9 public static LinkedList
tmp = new LinkedList<>(); // 存储一个临时的序列10 public static int n;11 12 13 public static void main(String[] args) {14 // 读取输入15 Scanner in = new Scanner(System.in);16 n = in.nextInt();17 18 // 对这个数据进行dfs递归,求出并打印所有的出栈序列19 stackPopPermutation(1);20 }21 22 // tmp参数中存储的是临时的出栈序列23 private static void stackPopPermutation(int i) {24 // 每次进入递归,判断 i 是否大于等于n, 如果大于n,存储序列,返回25 if(i > n && s.empty()){26 for(int j = 0; j < tmp.size(); j++){27 System.out.print(tmp.get(j) + " ");28 }29 System.out.println();30 return;31 }32 33 // 选择入栈当前元素还是出栈栈顶元素34 // 选择入栈当前元素35 if (i <= n)36 {37 s.push(i);38 stackPopPermutation(i + 1);39 s.pop(); // 消除入栈的影响40 }41 42 // 选择出栈当前元素43 if (!s.empty())44 {45 Integer top = s.peek();46 tmp.add(top);47 s.pop();48 stackPopPermutation(i);49 s.push(top); // 消除回溯,消除出栈的影响50 tmp.removeLast();51 }52 }53 }

转载地址:http://iidrn.baihongyu.com/

你可能感兴趣的文章
如何利用.NETCore向Azure EventHubs准实时批量发送数据?
查看>>
WPF 框架全构建环境虚拟机硬盘分享
查看>>
ABP框架 v3.0 已发布!
查看>>
使用.Net Core实现的一个图形验证码
查看>>
.NET 开源项目 StreamJsonRpc 介绍[中篇]
查看>>
Blazor带我重玩前端(三)
查看>>
基于.NetCore3.1系列 —— 认证授权方案之授权揭秘 (下篇)
查看>>
实现业务数据的同步迁移 · 思路一
查看>>
龙芯开源社区上线.NET主页
查看>>
eShopOnContainers 知多少[11]:服务间通信之gRPC
查看>>
闲谈设计模式
查看>>
平台or职位,你怎么选?
查看>>
骚年快答 | 技术中台与业务中台都是啥?
查看>>
骚年快答 | 微服务架构中的BFF到底是啥?
查看>>
设计模式之适配器模式
查看>>
如何利用Gitlab-CI持续部署到远程机器?
查看>>
.NET Core + K8S + Loki 玩转日志聚合
查看>>
ASP.NET Core中的分布式缓存
查看>>
在ASP.NET Core中创建自定义端点可视化图
查看>>
继续分享 5 个实用的 vs 调试技巧
查看>>