传引用与传值导致的程序运行速度的差异
在LeetCode刷算法题的过程中,发现了以个有趣的现象:同样的算法思路,代码也基本相同,但是算法时间就是较低。由于运用的回溯算法,算法实现利用了递归,故考虑是否是因为在递归的调用时,传递参数等造成时间差异,故对比自己的代码与示例代码,发现问题确实出在这里。
代码分析
算法提如下,可用回溯算法求解,具体题目连接:https://leetcode-cn.com/problems/combination-sum/description/
这是本人所写的函数实现:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> cur;
combinationSum(candidates,target,0,cur,0,res);
return res;
}
void combinationSum(vector<int>& candidates, int target,int i,vector<int>& cur,int sum, vector<vector<int>>& res)
{
if(sum>target)
return;
if(sum == target)
{
res.push_back(cur);
return;
}
for(int j=i;j<candidates.size(); j++)
{
cur.push_back(candidates[j]);
combinationSum(candidates,target,j,cur,sum+candidates[j],res);
cur.pop_back();
}
}
};
执行结果,只是达到了56%的结果。
对比排在前面得的代码:
可见这里代码与自己的代码内容上大同小异,关键不同在与函数声明上,在递归函数的声明上,我的代码是:
void combinationSum(vector<int>& candidates, int target,int i,vector<int> cur,int sum, vector<vector<int>>& res)`
排名靠前的代码声明为:
void bfs(vector<vector<int>> &res,vector<int> &tmp,vector<int> &candidtes,int sumtmp,int target,int start)
其差异在我的代码中vector cur是以传值方式传参,后者是传引用,个人理解为传值时每次递归调用都要在内存中新建立一个vector 来保存cur传入的值,但是传引用直接在cur原始位置操作,不需要进行新建变量与赋值,节省了代码运行的空间与时间开销。
实验验证
基于以上分析,这里把自己的代码稍作修改,将原函数改为:
void combinationSum(vector<int>& candidates, int target,int i,vector<int> &cur,int sum, vector<vector<int>>& res)`
提交后发现确定实现了对代码性能的优化。
深入剖析
指针:指针就是一个变量,如果非要说是一个特殊的变量也不为过,因为指针的初始化和解引用等不同的操作方式而已。就内存的分布来说,指针和一个变量在内存中存放是没有任何区别的,无非指针存放的是变量的地址。
传值:传值无非就是实参拷贝传递给形参,单向传递(实参->形参),赋值完毕后实参就和形参没有任何联系,对形参的修改就不会影响到实参。在传值是,会新建一个形参,并把实参的只拷贝给形参。
传地址:为什么说传地址也是一种传值呢?因为传地址是把实参地址的拷贝传递给形参。还是一句话,传地址就是把实参的地址复制给形参。复制完毕后实参的地址和形参的地址没有任何联系,对实参形参地址的修改不会影响到实参**, 但是对形参地址所指向对象的修改却直接反应在实参中,因为形参指向的对象就是形参的对象。**
传引用:传引用本质没有任何实参的拷贝,一句话,就是让另外一个变量也执行该实参。就是两个变量指向同一个对象。这是对形参的修改,必然反映到实参上。传引用没有变量的创建与拷贝过程。