Javascript 遍历以多种方式相互连接的对象列表

Javascript 遍历以多种方式相互连接的对象列表,javascript,arrays,graph,Javascript,Arrays,Graph,我有一个充满对象的数组,其中每个对象都有指向数组中其他对象的“出口”。我想知道如何遍历这些项目并“跟踪”每个出口 基本思想是创建数组中对象的“映射” 基本上,每个对象都是这样(简化为仅显示重要部分): 从本质上讲,我希望一个算法遵循大于-1的任何方向(n、s、e、w、u、d) 我自己也试着画出来,但我很困惑当一个物体有多个出口时会发生什么 这是我的小提琴: 基本上,我希望遍历数组并在画布上为每个区域输出一个正方形-因此,如果area1向东有一个“出口”,那么我希望在area1的右侧显示一个正方形

我有一个充满对象的数组,其中每个对象都有指向数组中其他对象的“出口”。我想知道如何遍历这些项目并“跟踪”每个出口

基本思想是创建数组中对象的“映射”

基本上,每个对象都是这样(简化为仅显示重要部分):

从本质上讲,我希望一个算法遵循大于
-1
的任何方向(n、s、e、w、u、d)

我自己也试着画出来,但我很困惑当一个物体有多个出口时会发生什么

这是我的小提琴:


基本上,我希望遍历数组并在画布上为每个区域输出一个正方形-因此,如果area1向东有一个“出口”,那么我希望在area1的右侧显示一个正方形,以此类推。

您正在遍历一个图形。这里的要点是:

  • 你可以通过多种方式到达某个“房间”;因此,您需要跟踪您已经访问过的房间,这样您就不会再次尝试跟踪它们的出口
  • 由于每个房间都有多个出口,所以您需要在每次访问其中一个出口时记住稍后再回来尝试其他出口 一种简单的方法是使用递归访问所有出口,同时在已访问的房间上存储一些标志:

    var visitRoom = function(rooms, roomId) {
      if (roomId === -1)
        return;
    
      var room = rooms[roomId];
      if (room.visited)
        return;
    
      room.visited = true;
      doSomethingWithRoom(room);
    
      visitRoom(rooms, room.n);
      visitRoom(rooms, room.e);
      visitRoom(rooms, room.s);
      visitRoom(rooms, room.w);
      visitRoom(rooms, room.u);
      visitRoom(rooms, room.d);  
    };
    
    visitRoom(rooms, 0); // assuming you're starting at the first room
    
    这里的问题是:

    • 存储
      room.visted
      有点混乱,因为它使用遍历算法所需的中间状态污染原始数据

    • 此代码假定每个房间的ID等于其在阵列中的索引。如果不是这样,您可能希望找到一种通过房间ID获取房间的方法。在这种情况下,房间ID和房间对象之间的映射比数组更有用

    • 递归方法会在足够大的映射中耗尽堆栈内存。这可以通过使用迭代方法来解决,在迭代方法中,您不必通过递归访问房间,而是将其ID添加到要访问的房间列表中,然后继续访问列表中的第一个房间,直到该房间为空。与存储递归调用的堆栈帧相比,保留未访问房间的列表占用的内存更少

    以下是解决这些问题的另一种方法:

    var visitAll = function(rooms) {
      var toVisit = [0];
      var visited = {};
    
      while (toVisit.length > 0) {
        var roomId = toVisit.pop();
    
        var room = findRoomById(rooms, roomId); 
    
        doSomethingWithRoom(room);
        visited[roomId] = true;
    
        ["n", "s", "e", "w", "u", "d"].forEach(function(exit) {
          var exitId = room[exit];
          if (exitId !== -1 && !visited[exitId])
            toVisit.push(exitId);
        });    
      }
    }
    
    var findRoomById = function(rooms, roomId) {
      // do whatever you need to find the room with the correct ID
      return rooms[roomId]; 
    }
    
    var doSomethingWithRoom = function(room) {
      // do what you want here; this will be called once per visited room
    }
    
    visitAll(rooms);
    

    如果还希望跟踪每个房间的空间坐标,也可以在第一次遇到每个房间时,根据前一个房间的坐标和所遵循的出口方向,为每个房间指定其位置

    这实际上取决于您想要如何处理多个出口

    var dirs = ["n", "e", "s", "w", "u", "d"];
    var visited = {};
    for(var i = 0; i < Areas.length; i++){
      for (var j = 0; j < dirs.length; j++) {
        if(Areas[i][dirs[j]] > -1){
          doSomething(array[i].id, dirs[j], array[i][dirs[j]);
        }
      };
    }
    
    function doSomething(roomID, exitDirection, exitID){
    
      //Called for every exit for every room.
    
      if(visited[exitID]!== true){
        visited[exitID] = true;
    
        //Do whatever unique stuff you want to do here.
        //This will get called for every new exit room but you may not want that if you're building doors or something.
      }      
    }
    
    var dirs=[“n”、“e”、“s”、“w”、“u”、“d”];
    var={};
    对于(变量i=0;i-1){
    doSomething(数组[i].id,dirs[j],数组[i][dirs[j]);
    }
    };
    }
    函数doSomething(roomID、exitDirection、exitID){
    //要求每个房间的每个出口。
    如果(已访问[exitID]!==true){
    已访问[exitID]=真;
    //做任何你想在这里做的独特的事情。
    //每一个新的出口房间都会被要求这样做,但如果你正在建造门或其他东西,你可能不想这样做。
    }      
    }
    

    这将为每个元素添加一个“其他”字段、一步一步包含所有可访问元素的结构化多维对象,以及一个包含可访问元素的简单列表的分配器数组

    var Chernarus = [
        {
            id: 0,
            name: "stary sobor",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:-1,s:3,e:1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 1,
            name: "novy sobor",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:-1,s:2,e:-1,w:0,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 2,
            name: "mogilevka",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:1,s:3,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 3,
            name: "dubky",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:2,s:4,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 4,
            name: "novo selky",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:3,s:5,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 5,
            name: "chernogorsk",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:4,s:-1,e:-1,w:6,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        }
    ];
    
    var toCheck=["n","s","e","w"];
    var maxSteps=100;
    
    function getOthers(element,recursion,alreadyDone,alreadyArr) {
    
        if(recursion>maxSteps) return "TOO MANY:INFINITE?";
        if(Chernarus[element]==undefined)  return "NOT FOUND: "+element;
        var item=Chernarus[element];
        if(alreadyDone[element]!=undefined) return element+" ALREADY DONE";
        alreadyDone[element]=true;
        alreadyArr.push(element);
        var out={};
        for (var ch=0;ch<4;ch++) {
            var tc=toCheck[ch];
            var dir=item[toCheck[ch]];
            if(dir>0) {
                out[tc]={pos:dir,others:getOthers(dir,recursion+1,alreadyDone,alreadyArr)};
            }
        }
        return out;
    }
    
    
    for (var i=0;i<Chernarus.length;i++) {
        var allothers=[]
        Chernarus[i]['others']=getOthers(i,1,[],allothers);
        Chernarus[i]['allothers']=allothers;
    }
    
    
    
    
    
    
    
    alert(dump(Chernarus,""));
    
    function dump(obj,spc) {
        if(obj==undefined) return "<undefined>";
        if((typeof obj)=="object") { // obj instanceof Array || obj.toString()=="[object Object]"
            var out="";
            for(var it in obj) if(obj.hasOwnProperty(it)) {
                out+=spc+it+"= {\n";
                out+= dump(obj[it],spc+"    ");
                out+=spc+"}\n";
            }
            return out;
        } else return spc+(obj.toString())+"\n";
    }
    
    var Chernarus=[
    {
    id:0,
    名称:“stary sobor”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:1,s:3,e:1,w:1,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    },{
    id:1,
    姓名:“novy sobor”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:1,s:2,e:1,w:0,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    },{
    id:2,
    名称:“莫吉列夫卡”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:1,s:3,e:1,w:1,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    },{
    id:3,
    姓名:“dubky”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:2,s:4,e:1,w:1,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    },{
    id:4,
    名称:“novo selky”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:3,s:5,e:1,w:1,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    },{
    id:5,
    名称:“切尔诺戈尔斯克”,
    说明:“,
    气味:“,
    对象:[],
    项目:[],
    衣服:[],
    食物:[],
    路障:[],
    n:4,s:1,e:1,w:6,
    u:-1,d:-1,
    z:0,
    背景:“img/center.jpg”
    }
    ];
    var-toCheck=[“n”、“s”、“e”、“w”];
    var maxSteps=100;
    函数getOthers(元素、递归、alreadyDone、alreadyArr){
    如果(递归>最大步骤)返回“太多:无限?”;
    如果(Chernarus[element]==未定义)返回“未找到”:+element;
    var项目=Chernarus[元素];
    if(alreadyDone[element]!=undefined)返回元素+“已完成”;
    alreadyDone[element]=true;
    推力(元件);
    var out={};
    对于(变量ch=0;ch0){
    out[tc]={pos:dir,others:getOthers(dir,递归+1,alreadyDone,alreadyArr)};
    }
    }
    返回;
    }
    
    对于(var i=0;i您是否在遍历所有对象后试图找到最终位置?@closure-基本上我希望遍历数组并在画布上为每个区域输出一个正方形-因此,如果area1有一个“出口”向东,那么我希望在数组右侧显示一个正方形
    var Chernarus = [
        {
            id: 0,
            name: "stary sobor",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:-1,s:3,e:1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 1,
            name: "novy sobor",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:-1,s:2,e:-1,w:0,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 2,
            name: "mogilevka",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:1,s:3,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 3,
            name: "dubky",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:2,s:4,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 4,
            name: "novo selky",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:3,s:5,e:-1,w:-1,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        },{
            id: 5,
            name: "chernogorsk",
            description: "",
            smell: "",
            objects: [],
            items: [],
            clothes: [],
            food: [],
            barricades: [],
            n:4,s:-1,e:-1,w:6,
            u:-1,d:-1,
            z:0,
            bg:"img/centre.jpg"
        }
    ];
    
    var toCheck=["n","s","e","w"];
    var maxSteps=100;
    
    function getOthers(element,recursion,alreadyDone,alreadyArr) {
    
        if(recursion>maxSteps) return "TOO MANY:INFINITE?";
        if(Chernarus[element]==undefined)  return "NOT FOUND: "+element;
        var item=Chernarus[element];
        if(alreadyDone[element]!=undefined) return element+" ALREADY DONE";
        alreadyDone[element]=true;
        alreadyArr.push(element);
        var out={};
        for (var ch=0;ch<4;ch++) {
            var tc=toCheck[ch];
            var dir=item[toCheck[ch]];
            if(dir>0) {
                out[tc]={pos:dir,others:getOthers(dir,recursion+1,alreadyDone,alreadyArr)};
            }
        }
        return out;
    }
    
    
    for (var i=0;i<Chernarus.length;i++) {
        var allothers=[]
        Chernarus[i]['others']=getOthers(i,1,[],allothers);
        Chernarus[i]['allothers']=allothers;
    }
    
    
    
    
    
    
    
    alert(dump(Chernarus,""));
    
    function dump(obj,spc) {
        if(obj==undefined) return "<undefined>";
        if((typeof obj)=="object") { // obj instanceof Array || obj.toString()=="[object Object]"
            var out="";
            for(var it in obj) if(obj.hasOwnProperty(it)) {
                out+=spc+it+"= {\n";
                out+= dump(obj[it],spc+"    ");
                out+=spc+"}\n";
            }
            return out;
        } else return spc+(obj.toString())+"\n";
    }