我在gnu lisp工作,想要获取某个节点的路径。 我设法解决了二叉树的问题,但如果树是n-ary,则无法找到正确的递归规则。表示树(root(subtree1)(subtree2)...)。 那么,如何使用GNU Lisp获取n-ary树中节点的路径?
二进制代码:
;checks if element e is in l
(defun partof(l e)
(cond
((null l) nil)
((equal l e) T)
((atom l) nil)
(T (find T (mapcar (lambda (l) (partof l e)) l)))))
;get the path
(defun path(l e)
(cond
((null l) nil)
((equal (car l) e) (list (car l))) ;if the element is the root of subtree return it
((partof (cadr l) e) (cons (car l) (path (cadr l) e))) ;if it is in the first subtree, get the root and check in first subtree until you get to it
((partof (caddr l) e) (cons (car l) (path(caddr l) e))) ; get the root and parse the second subtree
(T nil))) ;here i can't find the rule to check in the rest of the subtrees
我也对一种全新的方式感兴趣,而不仅仅是完成这个方式。 n-ary树是这样的:(root(subtree1)(subtree2)(subtree3)...),例如(A(B(C)(D))(E(F)(G))(H( I)(J)))是一棵完整的树。
A
/ | \
B E H
/\ /\ /\
C D F G I J
答案 0 :(得分:1)
记住我对食谱的了解和信任递归",我可以提供以下内容:
CL-USER> (defun path (tree elt)
(labels ((find-path (tree elt path)
(cond ((null tree) nil)
((equal (car tree) elt) (cons elt path))
(t (some #'(lambda (sub)
(find-path sub elt (cons (car tree) path)))
(cdr tree))))))
(reverse (find-path tree elt '()))))
STYLE-WARNING: redefining COMMON-LISP-USER::PATH in DEFUN(A (B (C) (D)) (E (F) (G)) (H (I) (J)))
PATH
CL-USER> (path '(A (B (C) (D)) (E (F) (G)) (H (I) (J))) 'D)
(A B D)
请注意,我在这里一直使用SBCL,但至少应该给你一个想法......
答案 1 :(得分:1)
(defun find-path (tree node &optional path)
(if (eq (car tree) node)
(reverse (cons node path))
(reduce (lambda (p x)
(or p (find-path x
node
(cons (car tree) path))))
(cdr tree)
:initial-value nil)))
适用于GNU CLISP 2.49:
CL-USER> (defparameter *tree* '(a (b (c) (d)) (e (f) (g)) (h (i) (j))))
*TREE*
CL-USER> (find-path *tree* 'd)
(A B D)
(defun find-path* (tree x y)
(labels ((till-d (a b i)
(if (and (eq (car a) (car b))
a
b)
(till-d (cdr a) (cdr b) (1+ i))
i)))
(let* ((x-path (find-path tree x))
(y-path (find-path tree y))
(pos (till-d x-path y-path 0)))
(append (reverse (nthcdr (1- pos) x-path))
(nthcdr pos y-path)))))
像这样工作:
CL-USER> (find-path* *tree* 'd 'c)
(D B C)
CL-USER> (find-path* *tree* 'd 'g)
(D B A E G)
CL-USER> (find-path* *tree* 'b 'h)
(B A H)
CL-USER> (find-path* *tree* 'd 'd)
(D)
现在许多任务也可以很容易地解决(节点之间的距离等)。
答案 2 :(得分:-2)
/ /而不是为左右孩子调用递归函数,你必须编写一个循环来调用所有孩子,你将得到它。
package binary_tree_path;
import java.util.ArrayList;
/ * *您将获得一个二叉树(根节点)..并且给出了一个可能/可能不在树中的密钥。 您必须找到从根到节点的完整路径。
示例
A
/ \
B C
\ /
D E
/ \ \
K L M
/
Z
您已经给出了节点Z(或节点的密钥)和给定的节点A(根) 所以你的输出应该是
A B D K Z
如果M给出输出应该是 A C E M
* /
public class main_class { public static void main(String args []){
//first create tree
Node rootNode = new Node ('A' , new Node('B',null,
new Node('D',
new Node('K',
new Node('Z',null,
null),null),
new Node('L',null,null))),
new Node('C',
new Node('E',
null,
new Node('M',null,null)),null) );
ArrayList <Node> path = new ArrayList<Node>();
System.out.println(getPath(rootNode,'Z',path));
System.out.println(path);
path = new ArrayList<Node>();
System.out.println(getPath(rootNode,'M',path));
System.out.println(path);
}
static boolean getPath(Node rootNode, char key, ArrayList<Node> path ){
//return true if the node is found
if( rootNode==null)
return false;
if (rootNode.getVal()==key){
path.add(rootNode);
return true;
}
boolean left_check = getPath( rootNode.left,key,path);
boolean right_check = getPath( rootNode.right,key,path);
if ( left_check || right_check){
path.add(rootNode);
return true;
}
return false;
}
static class Node {
char val;
Node left;
Node right;
public Node( char val, Node left, Node right){
this.left=left;
this.right=right;
this.val=val;
}
public char getVal(){
return val;
}
public String toString(){
return " " + val + " ";
}
}
}