从列表重建N-ary树

时间:2017-05-13 15:55:38

标签: kotlin

data class Node(val ID : Long, val name : String)

我有以下三个值的有序列表(按出现顺序):ID,名称和深度。

0000 : A : 0
0001 : B : 1
0002 : C : 2
0003 : D : 2
0004 : E : 1
0005 : F : 2
0006 : G : 1
0007 : H : 1
0008 : I : 2

使用此数据集我希望将原始 N -ary树重建为Map<Node, Set<Node>>,可视化如下:

A - B - C
      - D
  - E - F
  - G
  - H - I

完成此任务的最佳(最高效和/或最可读)方法是什么?

2 个答案:

答案 0 :(得分:2)

给定orderedList: List<Triple<Long, String, Int>>,您可以遍历三元组并跟踪每个深度的当前父级,以便您可以重建树:

val tree = mutableMapOf<Node, MutableSet<Node>>()
val parents = ArrayDeque<Node>()
for ((id, name, depth) in orderedList) {
    val node = Node(id, name)
    // pop any parents from this deque as deep or deeper than this node
    while (parents.size > depth) parents.pop()
    // add node to tree
    tree[node] = mutableSetOf()
    // add node to parent's children if applicable
    tree[parents.peek()]?.add(node)
    // add node to parents stack
    parents.push(node)
}

如果您需要从字符串中构建orderedList,您可以使用以下内容(假设字符串可用作input: String):

val orderedList = input.trim().lines().map { line ->
    val components = line.split(" : ")
    val id = components.component1().toLong()
    val name = components.component2()
    val depth = components.component3().toInt()
    Triple(id, name, depth)
}

答案 1 :(得分:1)

基本思想是使用堆栈跟踪从根到当前处理的节点的轨道上的父节点:

        val input = """
0000 : A : 0
0001 : B : 1
0002 : C : 2
0003 : D : 2
0004 : E : 1
0005 : F : 2
0006 : G : 1
0007 : H : 1
0008 : I : 2
"""
        val parsedLines = input.split("\n")
                .map { it.trim() }
                .filter { it.isNotEmpty() }
                .map { line ->
                    val parsedLine = line
                            .split(":")
                            .map { it.trim() }

                    object {
                        val preOrderIndex = parsedLine[0].toInt()
                        val name = parsedLine[1]
                        val height = parsedLine[2].toInt()
                    }
                }
                .sortedBy { it.preOrderIndex }

        parsedLines.forEach { println("${it.preOrderIndex} ${it.name} ${it.height}") }

        val map = HashMap<Node,HashSet<Node>>()
        val parents = Stack<Node>()

        for (nodeDesc in parsedLines) {
            val newNode = Node(nodeDesc.preOrderIndex.toLong(), nodeDesc.name)
            map[newNode] = HashSet<Node>()

            while (parents.size > nodeDesc.height)
                parents.pop()

            if (!parents.empty()) {
                val tmp: HashSet<Node>? = map[parents.peek()]
                tmp!!.add(newNode)
            }

            parents.push(newNode)
        }

        println(map)