2013-11-11 5 views
0

Предположим, у меня есть простой abstract BinaryTree с подклассами Node и Leaf, и я хочу написать функцию, которая производит List[Leaf].Является ли этот прилив необходимым в Scala?

def getLeaves(tree: BinaryTree): List[Leaf] = 
    tree match { 
     case Leaf(v) => List(tree.asInstanceOf[Leaf]) 
     case Node(left, right) => getLeaves(left) ++ getLeaves(right) 
    } 

Есть ли способ, чтобы избежать явного asInstanceOf[Leaf] броска в Leafслучае? Если я оставлю это, я получаю диагностическое высказывание: found: BinaryTree; требуемый лист.

+0

Другой большой проблемой является то, что для больших деревьев этот код будет создавать переполнения стека. Вы должны либо сделать его хвостом рекурсивным, либо перебрать по дереву, чтобы создать список. – drexin

ответ

1

Вы можете использовать тот факт, что вы уже снесенных tree к Leaf(v) и восстановить лист:

def getLeaves(tree: BinaryTree): List[Leaf] = 
    tree match { 
     case Leaf(v) => List(Leav(v)) 
     case Node(left, right) => getLeaves(left) ++ getLeaves(right) 
    } 
+0

Я согласен, что это работает. Проблема, с которой я сталкиваюсь, заключается в том, что для каждого существующего листа требуется создание нового листа. Было бы намного лучше, если бы можно было просто использовать объект, который есть с тех пор, как он знает его Лист. – RussAbbott

3

Попробуйте этот путь

def getLeaves(tree: BinaryTree): List[Leaf] = 
    tree match { 
     case [email protected](v) => List(x) 
     case Node(left, right) => getLeaves(left) ++ getLeaves(right) 
    } 

Также обратите внимание, что ваша реализация плохо достижение максимальной эффективности поскольку вы создаете новый список в каждом узле.

она может быть исправлена ​​таким образом

def genLeaves(tree:BinaryTree) = { 
    def getLeaves0(tree: BinaryTree, acc:List[Leaf]): List[Leaf] = 
    tree match { 
     case [email protected](v) => x::acc 
     case Node(left, right) => { 
     val leftLeaves = getLeaves(left, acc) 
     getLeaves(right, leftLeaves) 
     } 
    } 
    getLeaves0(tree).reverse 
} 

Вот вы повторно все уже собранные вещи, и вы будете иметь только один список выделяется во время обхода. Вы собираете элементы в нем, когда вы проходите их, так что в конечном итоге вы окажетесь в Листе в обратном порядке (List работает как LIFO), поэтому для получения элементов в порядке, как вы его посещали, нам нужно отменить результирующий список.

+0

Я согласен, что аккумуляторный подход лучше. Я пытался понять вопрос кастинга. – RussAbbott

+0

как 'v' не используется в RHS' case x @ Leaf (v) => List (x) ', я предпочитаю более простой' case leaf: Leaf => List (leaf) ' –

8

Я видел эту конструкцию, используемую в другом месте. Кажется, это делает работу.

def getLeaves(tree: BinaryTree): List[Leaf] = 
    tree match { 
     case leaf: Leaf => List(leaf) 
     case Node(left, right) => getLeaves(left) ++ getLeaves(right) 
    } 
Смежные вопросы