如何排序对象? (画家算法)

时间:2019-01-28 18:29:15

标签: javascript algorithm sorting topological-sort

所以我得到了4个矩形,我试图应用一种排序算法(painters algorithm)来知道我需要先绘制(在3d中)哪个形状,然后再绘制哪个形状。

注意相机在右下角:

正确的顺序为:紫色,红色,蓝色,绿色(用于绘制当然颠倒的顺序)。

img


因此,我已经实现了一种算法,该算法可以创建如下内容: 列出的每个对象都有正确的前辈和前辈

ITEM:  red
  predecessor: -
  successor: -
ITEM:  green
  predecessor: -
  successor: red
ITEM:  blue
  predecessor: green
  successor: red
ITEM:  purple
  predecessor: blue, green
  successor: blue, red

如何根据上述信息对商品进行排序以获取正确的订单?任何帮助将不胜感激。

let digraph = {
  red: {
    predecessor: [],
    successor: []
  },
  green: {
    predecessor: [],
    successor: ["red"]
  },
  blue: {
    predecessor: ["green"],
    successor: ["red"]
  },
  purple: {
    predecessor: ["blue", "green"],
    successor: ["blue", "red"]
  }
}

let itinerary = {}
for (let e of Object.keys(digraph)) {
  if (digraph[e].successor.length != 0) itinerary[e] = digraph[e]
}

//console.log(itinerary)
let sorted_pile = []
let overflow = 0;
while (Object.keys(itinerary).length) {
  overflow++;
  if (overflow > 40) {
    console.error("OVERFLOW");
    break;
  }
  let key = Object.keys(itinerary)[0],
    entity = itinerary[key];
  delete itinerary[key];
  sorted_pile.push(key)
  let successors = digraph[key].successor
  for (succ of successors) {
    digraph[succ].predecessor = digraph[succ].predecessor.filter(function(item) {
      return item !== key;
    })
    if (digraph[succ].predecessor.length === 0) itinerary[key] = digraph[succ]
  }
}

console.log(sorted_pile)

修改

let tile_entities = [
    {x: 8, y: 0, w: 1, h: 5, id: "rot"},
    {x: 5, y: 0, w: 2, h: 1, id: "gruen"},
    {x: 7, y: 0, w: 1, h: 1, id: "blau"},
    {x: 4, y: 5, w: 4, h: 2, id: "lila"},
]

1 个答案:

答案 0 :(得分:0)

我认为这可以满足您的要求,但是我先从输入内容的变更版本开始。对其进行转换很容易,但是您可以直接从当前流程中生成此输入。 (请注意,successor信息是不需要的,因为它是从predecessors派生的)

const isEmpty = arr => arr.length == 0 
const removeIndex = (n, arr) => arr.slice(0, n).concat(arr.slice(n + 1))

const sortDigraph = (
  digraph, 
  sorted = [], 
  idx = digraph.findIndex(node => isEmpty(node.predecessor)),
  nodeName = (digraph[idx] || {}).name
) => isEmpty(digraph)
  ? sorted
  : sortDigraph(
    removeIndex(idx, digraph).map(({name, predecessor}) => ({
      name,
      predecessor: predecessor.filter(n => n !== nodeName)
    }), digraph),
    sorted.concat(nodeName)
  )
  
let digraph = [
  {name: 'red', predecessor: []},
  {name: 'green', predecessor: []},
  {name: 'blue', predecessor: ["green"]},
  {name: 'purple', predecessor: ["blue", "green"]}
]

console.log(sortDigraph(digraph))

基本思想是,您可以从没有前任的任何一个开始,然后从其他链接中删除任何到它的前任链接,然后重复该过程。只要您的图是非循环的,就应该可以正常工作。如果必须处理Painter算法的更复杂的情况,那么您将需要先分解节点,然后再尝试。