力扣46 全排列 引发对JAVA对象引用的思考

先简单说一下本题思路:

数据结构:栈

算法:递归

使用深度遍历,得到全排列。要使用一个标记数组来标记某个数在本次递归中是否被使用,然后在下次递归前要取消标记。

java 复制代码
class Solution {
    private  int[] flag;
    private List<List<Integer>> v = new ArrayList<>();
    private List<Integer> vv = new ArrayList<>();
    
    public List<List<Integer>> permute(int[] nums) {
        flag = new int[nums.length];
        dfs(nums);
        return v;
    }

    private void dfs(int [] nums){
        if(vv.size() == nums.length){
            // v.add(vv);
            v.add(new ArrayList<>(vv));
            return;
        }

        for(int i = 0; i < nums.length; i++){
            if(flag[i] == 0){
                flag[i] = 1;
                vv.add(nums[i]);
                dfs(nums); 
                vv.remove(vv.size()-1);
                flag[i] = 0;
            } 
        }
    }
}

重点看我注解的这段代码,之前用c++写程序习惯了,但是换到JAVA导致结果一直是空。仔细思考和查了下资料:

通过执行 v.add(vv);,实际上添加的是对列表 vv 的引用,而不是当前内容的快照。因为在整个 DFS 过程中 vv 不断被修改,所以在 v 中的所有条目最终都会成为同一个列表的引用------而一旦递归完成,这个列表就会是空的。

改成v.add(new ArrayList<>(vv))确保了存储在 v 中的每个排列在被添加到列表时都准确反映了当时的实际状态,而不是最后都指向同一个(最终为空的)列表 vv。

在Java中,对象(包括那些实现了List接口的对象,如ArrayList)是通过引用来操作的。将vv添加到v中时,若是直接添加vv,实际上添加的是vv这个列表的引用,而不是它此刻的内容拷贝。这意味着,随后对vv的所有修改(添加元素、删除元素等操作),都会反映在v中所保存的这个引用所指向的同一个列表对象上。

再向下引申一点,在c++中为什么直接用v.push_bcak(vv)就可以呢?

这是因为C++在这种情境下执行的是对象的复制(copy),而不是引用(或指针)的复制。对于C++的std::vector(或大多数标准容器),push_back方法会创建一个参数的副本,并将这个副本存入容器中。因此,在C++中不需要显式地从vv创建一个新的std::vector对象就可以直接使用push_back(vv),因为push_back便已自动完成了这一复制工作。

这种差异归根结底是由于Java和C++对对象和容器的操作语义不同。Java中的对象赋值通常是引用赋值,而C++中的赋值(包括容器中元素的插入)则是创建对象副本的复制操作。这也反映了Java和C++在内存管理和对象模型方面的根本区别。

相关推荐
222you1 小时前
MyBatis-Plus当中BaseMapper接口的增删查改操作
java·开发语言·mybatis
保持低旋律节奏1 小时前
算法——冗余!哈希表、vector、string适配器的混合使用
数据结构·算法·散列表
weixin_457760002 小时前
OpenCV 图像处理基础算法详解(一)
图像处理·opencv·算法
纪莫2 小时前
技术面:MySQL(一条SQL在MySQL的执行过程?、MyISAM和InnoDB的区别?数据库事务机制?)
java·数据库·java面试⑧股
闲人编程2 小时前
Python协程的演进:从yield到async/await的完整历史
java·前端·python·async·yield·await·codecapsule
帅中的小灰灰2 小时前
C++编程建造器设计模式
java·c++·设计模式
做怪小疯子2 小时前
LeetCode 热题 100——链表——相交链表
算法·leetcode·链表
动感小麦兜3 小时前
应用-常用工具部署命令
java·开发语言
日日行不惧千万里3 小时前
IDEA 是用什么开发的?
java·ide·intellij-idea
while(努力):进步3 小时前
5G与物联网:连接万物的数字化未来
leetcode