递归涉及的问题
JS函数传值
【机制】对象传值都是引用传值,原变量与函数参数变量之间有引用关系,即值改变,原变量的值也会改变
【例子】array,string属于对象,会改变;int不会改变
【注意!】递归时,许多时候都需要用到局部变量,而不能改变到外面的值。这时为了函数参数不受引用关系影响,就要深度赋值这些变量
function dfs(array) {
if (? > limit) {
return ;
}
var tmpArray = [];
for (var i in array) { //解决对象引用传入问题
tmpArray.push(array[i]);
}
//对tmpArray操作
dfs(tmpArray); //传tmpArray
}
遍历方式
遍历数组、对象等一定要用以下方式迭代
for (var i in array) {
array[i];
}
【错误】用以下方式有意想不到的错误,array不会被完全遍历到
for (var i=0; i<array.length; i++) {
array[i];
}
【补充】jQuery环境建议使用$.each函数:
$.each(array,function(index,value){
//index下标
//value值
})
示例
问题背景
小明来到厦门旅游,发现有很多景点,一个景点有它的官方评分(满分:100)与建议游玩的时间(单位:min),现在小明只有480分钟旅游,请问小明一共有几种路线选择,求出各个路线经过 景点的编号数组 、 路线分数(景点总分/景点个数) 、 游玩时间
测试数据说明:
景点个数
景点编号 景点评分 景点时间
测试数据:
7
1 76.16926103 120
2 66.10810811 60
3 68.10293094 30
4 93.30696203 400
5 88.32278481 90
6 76.52360588 180
7 55.05713308 360
例如输出:
1,2 71.13868457 180
1,2,3 70.12676669 210
…
递归代码
for (var i in selectedSpotsBuffer_spots) { //不会执行递归
console.log("|从:"+i+"位开始");
dfs(i,initTime,initTotal,initRoute);
}
function dfs(z, time, total, route) {
var tmpRoute = [];
for (var i in route) {
tmpRoute.push(route[i]);
}
console.log(" dfs:"+z+" "+time+" "+total+" "+tmpRoute);
var thisTime = selectedSpotsBuffer_spotsMap[ selectedSpotsBuffer_spots[z]+"" ].attributes["recommendtime"]; //取出当前点的时间与分数
var thisTotal = selectedSpotsBuffer_spotsMap[ selectedSpotsBuffer_spots[z]+"" ].attributes["total"];
console.log(" 这一次"+thisTime+" "+thisTotal);
if (time + thisTime > plannedTime) {
console.log(" time+thisTime="+(time+thisTime)+"退出");
return ;
}
tmpRoute.push(selectedSpotsBuffer_spots[z]);
time += thisTime;
total += thisTotal;
allRoute.push({ array : tmpRoute,
time : time,
total : total
});
console.log(" 这一次之后的allRoute情况:"+tmpRoute+" "+time+" "+total);
for (var i in selectedSpotsBuffer_spots) {
if (i>z) {
dfs(i,time,total,tmpRoute);
}
}
}
完整代码
<html>
<head>
<title>路线推荐算法</title>
</head>
<body>
<div id="output"></div>
</body>
<script type="text/javascript">
//模拟项目中的数据
var selectedSpots = [1]; //用户选择的景点
var selectedSpotsBuffer_spots = [5,6,9,2,10,3]; //周边景点集
var selectedSpotsBuffer_spotsMap = { //景点的数据
'1' : {
attributes : {
id : 1,
name :"白石炮台遗址",
recommendtime:120,
total:76.16926103,
x:118.13214548600001,
y:24.424820321000027
}
},
'2' : {
attributes : {
id : 2,
name :"斋盛楼",
recommendtime:0,
total:66.10810811,
x:118.1275653560001,
y:24.42838708200003
}
},
'3' : {
attributes : {
id : 3,
name :"厦门书法广场",
recommendtime:30,
total:0,
x:118.11455650700009,
y:24.430312792000052
}
},
'5' : {
attributes : {
id : 5,
name :"厦门台湾民俗村",
recommendtime:400,
total:93.30696203,
x:118.13572801700002,
y:24.433014653000043
}
},
'6' : {
attributes : {
id : 6,
name :"启明寺",
recommendtime:90,
total:88.32278481,
x:118.11964657700003,
y:24.434867303000033
}
},
'9' : {
attributes : {
id : 9,
name :"金山松石景区",
recommendtime:180,
total:76.52360588,
x:118.1344477560001,
y:24.43688852300005
}
},
'10' : {
attributes : {
id : 10,
name :"厦门台湾民俗村金山松石风景区",
recommendtime:0,
total:55.05713308,
x:118.13357146600003,
y:24.437024483000073
}
}
};
var allRoute = []; //存放所有的路线
var plannedTime = 360; //计算的时间
selectedSpotsBuffer_spots = insertSort(selectedSpotsBuffer_spots,selectedSpotsBuffer_spotsMap); //selectedSpotsBuffer_spots按分数排列
console.log("排序之后:"+selectedSpotsBuffer_spots);
var initTotal=0.0,initTime = 0;
//初始化分数与时间,考虑已选的点
var initRoute = [];
for (var i=0; i<selectedSpots.length; i++) {
initTotal += selectedSpotsBuffer_spotsMap[ selectedSpots[i]+"" ].attributes["total"]; //初始化的分数
initTime += selectedSpotsBuffer_spotsMap[ selectedSpots[i]+"" ].attributes["recommendtime"]; //初始化的时间
initRoute.push(selectedSpots[i]);
}
for (var i in selectedSpotsBuffer_spots) { //不会执行递归
console.log("|从:"+i+"位开始");
dfs(i,initTime,initTotal,initRoute);
}
function dfs(z, time, total, route) {
var tmpRoute = [];
for (var i in route) {
tmpRoute.push(route[i]);
}
console.log(" dfs:"+z+" "+time+" "+total+" "+tmpRoute);
var thisTime = selectedSpotsBuffer_spotsMap[ selectedSpotsBuffer_spots[z]+"" ].attributes["recommendtime"]; //取出当前点的时间与分数
var thisTotal = selectedSpotsBuffer_spotsMap[ selectedSpotsBuffer_spots[z]+"" ].attributes["total"];
console.log(" 这一次"+thisTime+" "+thisTotal);
if (time + thisTime > plannedTime) {
console.log(" time+thisTime="+(time+thisTime)+"退出");
return ;
}
tmpRoute.push(selectedSpotsBuffer_spots[z]);
time += thisTime;
total += thisTotal;
allRoute.push({ array : tmpRoute,
time : time,
total : total
});
console.log(" 这一次之后的allRoute情况:"+tmpRoute+" "+time+" "+total);
for (var i in selectedSpotsBuffer_spots) {
if (i>z) {
dfs(i,time,total,tmpRoute);
}
}
}
//按成绩从大到小排序
function insertSort(array,infoMap) {
var i = 1,
j, step, objectId, len = array.length;
for (; i < len; i++) {
step = j = i;
objectId = array[j];
while (--j > -1) {
if (infoMap[array[j]+""]["attributes"]["total"] < infoMap[objectId+""]["attributes"]["total"]) {
array[j + 1] = array[j];
} else {
break;
}
}
array[j + 1] = objectId;
}
return array;
}
</script>
</html>
问题记录
-
结果出错
问题:递归时操作到全局对象,导致出错
说明:
allRoute是一个数组,里面放了map,这是一个对allRoute赋值的语句。
调试语句输出的情况是这样的
也就是说allRoute里有4个对象,每个对象值是后面相应的数值。
但是结果,里面array的值全是一样,并且是最后一种1,6,2,10,3。而time,total值是正常的 -
遍历数组出错(只执行了一层,不会递归下去)
说明:selectedSpotsBuffer_spots为数组
问题:使用length遍历for (var j=z+1; j<selectedSpotsBuffer_spots.length; j++) { console.log(" 继续走"); dfs(j,time,total,tmpRoute); }
结果:
修改:
for (var i in selectedSpotsBuffer_spots) {
if (i>z) {
dfs(i,time,total,tmpRoute);
}
}