Как вывести вложенные списки обходом в ширину?

Есть 2 множества: объекты и связи. Связей для каждой пары объектов по две в обе стороны и есть кольца:

let objects = [
   {id: 1, title: "obj1"},
   {id: 2, title: "obj2"},
   {id: 3, title: "obj3"},
];

let relations = [
   {id1: 1, id2: 2, title:"1-2"},
   {id1: 2, id2: 1, title:"2-1"},

   {id1: 2, id2: 3, title:"2-3"},
   {id1: 3, id2: 2, title:"3-2"},

   {id1: 1, id2: 3, title:"1-3"},
   {id1: 3, id2: 1, title:"3-1"},
];

Надо построить дерево вложенных списков от любого из объектов. Рекурсией (обходом в глубину) это делается очень просто:

   function makeTree(id, visited) {
      let result = "";
      let obj = objects.find(z=>z.id==id);
      if (visited.indexOf(id)==-1) {
          visited.push(id);
          result += `<li><b>${obj.title}</b><ul>`;
          for (let rel of relations.filter(z=>z.id1 == id)) {
              result += makeTree(rel.id2, visited);
          }
          result += "</ul></li>";
      } else {
          result += `<li><i>${obj.title}</i></li>`; //повторы
      }
      return result;
   }

   document.getElementById("tree").innerHTML = makeTree(1, []);

результатом этого кода будет:

<ul id="tree">
   <li><b>obj1</b>
      <ul>
         <li>
            <b>obj2</b>
            <ul>
               <li><i>obj1</i></li>
               <li>
                   <b>obj3</b>
                   <ul>
                       <li><i>obj2</i></li>
                       <li><i>obj1</i></li>
                   </ul>
               </li>
            </ul>
        </li>
        <li><i>obj3</i></li>
      </ul>
   </li>
</ul>

Но мне надо сделать то же самое обходом в ширину, чтобы связи, которые ближе к корню раскрывались быстрее. Т.е. чтобы obj3 развернулся сразу внутри obj1 а не внутри obj2. Не знаю, как объяснить понятнее, чтобы результат стал такой:

<ul id="tree2">
    <li>
        <b>obj1</b>
        <ul>
            <li><b>obj2</b>
                <ul>
                    <li><i>obj3</i></li>
                </ul>
            </li>
            <li><b>obj3</b>
                <ul>
                    <li><i>obj2</i></li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

Как в принципе работает поиск в ширину с очередью я понимаю:

function makeTree2(id) {
    let result = "";
    let q = [], visited=[];
    q.push(id);
    while (q.lenght>0) {
        let objid = q.shift();
        visited.push(objid);
        let obj = objects.find((z) => z.id == id);
        
        //result += ?
        
        for (let rel of relations.filter((z) => z.id1 == objid)) {
            if (visited.indexOf(rel.id2) == -1) {
                q.push(rel.obj2);
            }
        }
    }
    return result;
}

Но как из него выплюнуть вложенный html — нет.

Полный код на CodePen


Ответы (0 шт):