Graph Lisp-编写计算图形节点标签的函数
考虑这样一个由节点和邻居组成的图:Graph Lisp-编写计算图形节点标签的函数,graph,lisp,common-lisp,labeling,Graph,Lisp,Common Lisp,Labeling,考虑这样一个由节点和邻居组成的图: (defparameter *graph* '((A (B C D)) (B (A C E)) (C (A B D E)) (D (A C E)) (E (B C D)))) …以及每个节点的一组标签: (defparameter *values* '((A 1)
(defparameter *graph* '((A (B C D))
(B (A C E))
(C (A B D E))
(D (A C E))
(E (B C D))))
…以及每个节点的一组标签:
(defparameter *values* '((A 1)
(B 2)
(C 3)
(D 2)
(E 1)))
我正在尝试编写一个函数,用于计算该格式的图形,并确定相邻节点是否具有相同的标签。如果我用C++或java编写这个函数,我的函数的迭代版本的逻辑可能看起来是这样的:
(defun evaluate-label (graph values)
;; for every node in graph
;; for every adjoining node
;; if (node.value == adjoiningNode.value)
;; return false
;; return true
)
…但我不确定哪种逻辑更适合Lisp,更不用说如何对其进行编码了
因此,有两个问题:
条件
。每个
对这个问题有用吗?我们可以不借助lambda表达式轻松地做到这一点吗提前感谢您的反馈 好的编程的一个重要方面,不管是哪种语言,都是好的抽象。有时,这可能是一个品味的问题,但这里有一个例子,试图应用一些抽象来解决这个问题。一旦有了图形和值,就可以定义一个返回节点值的节点值函数。然后你可以把你的问题表述为 图中是否存在与其相邻节点具有相同节点值的节点 用一些来写这并不难:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
这就是说,尽管在某些意义上这可能更为Lisp-y,但使用显式迭代与dolist编写它也同样有意义:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
使用循环,这可能会更好,它支持一些解构:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(loop for (node neighbors) in graph
thereis (find (node-value node) neighbors :key #'node-value))))
所有这些版本都可以受益于将值存储在中,例如,。用于更快检索的哈希表。在这里这样做是否有意义取决于您的需要、应用程序域等。否则,您将检索边缘标签O(2×| E |),每次执行O(| V |)遍历。例如:
(let ((table (make-hash-table)))
(flet ((node-value (node)
(multiple-value-bind (value presentp)
(gethash node table)
(if presentp value
(setf (gethash node table)
(cadr (assoc node values)))))))
;; ...
))
它通过在需要之前不查找节点值来缓存“按需”。但是,由于每个节点值都是必需的(假设提供的值列表不包含任何额外的节点),因此最好在开始时填充表。这样以后就不必进行任何检查,只需遍历值列表一次。因此:
(defun adjacent-values-p (graph values &aux (table (make-hash-table)))
(loop for (node value) in values
doing (setf (gethash node table) value))
(flet ((node-value (node)
(gethash node table)))
;; ...
))
好的编程的一个重要方面,不管是哪种语言,都是好的抽象。有时,这可能是一个品味的问题,但这里有一个例子,试图应用一些抽象来解决这个问题。一旦有了图形和值,就可以定义一个返回节点值的节点值函数。然后你可以把你的问题表述为 图中是否存在与其相邻节点具有相同节点值的节点 用一些来写这并不难:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
这就是说,尽管在某些意义上这可能更为Lisp-y,但使用显式迭代与dolist编写它也同样有意义:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
使用循环,这可能会更好,它支持一些解构:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(loop for (node neighbors) in graph
thereis (find (node-value node) neighbors :key #'node-value))))
所有这些版本都可以受益于将值存储在中,例如,。用于更快检索的哈希表。在这里这样做是否有意义取决于您的需要、应用程序域等。否则,您将检索边缘标签O(2×| E |),每次执行O(| V |)遍历。例如:
(let ((table (make-hash-table)))
(flet ((node-value (node)
(multiple-value-bind (value presentp)
(gethash node table)
(if presentp value
(setf (gethash node table)
(cadr (assoc node values)))))))
;; ...
))
它通过在需要之前不查找节点值来缓存“按需”。但是,由于每个节点值都是必需的(假设提供的值列表不包含任何额外的节点),因此最好在开始时填充表。这样以后就不必进行任何检查,只需遍历值列表一次。因此:
(defun adjacent-values-p (graph values &aux (table (make-hash-table)))
(loop for (node value) in values
doing (setf (gethash node table) value))
(flet ((node-value (node)
(gethash node table)))
;; ...
))
好的编程的一个重要方面,不管是哪种语言,都是好的抽象。有时,这可能是一个品味的问题,但这里有一个例子,试图应用一些抽象来解决这个问题。一旦有了图形和值,就可以定义一个返回节点值的节点值函数。然后你可以把你的问题表述为 图中是否存在与其相邻节点具有相同节点值的节点 用一些来写这并不难:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
这就是说,尽管在某些意义上这可能更为Lisp-y,但使用显式迭代与dolist编写它也同样有意义:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
使用循环,这可能会更好,它支持一些解构:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(loop for (node neighbors) in graph
thereis (find (node-value node) neighbors :key #'node-value))))
所有这些版本都可以受益于将值存储在中,例如,。用于更快检索的哈希表。在这里这样做是否有意义取决于您的需要、应用程序域等。否则,您将检索边缘标签O(2×| E |),每次执行O(| V |)遍历。例如:
(let ((table (make-hash-table)))
(flet ((node-value (node)
(multiple-value-bind (value presentp)
(gethash node table)
(if presentp value
(setf (gethash node table)
(cadr (assoc node values)))))))
;; ...
))
它通过在需要之前不查找节点值来缓存“按需”。但是,由于每个节点值都是必需的(假设提供的值列表不包含任何额外的节点),因此最好在开始时填充表。这样以后就不必进行任何检查,只需遍历值列表一次。因此:
(defun adjacent-values-p (graph values &aux (table (make-hash-table)))
(loop for (node value) in values
doing (setf (gethash node table) value))
(flet ((node-value (node)
(gethash node table)))
;; ...
))
好的编程的一个重要方面,不管是哪种语言,都是好的抽象。有时,这可能是一个品味的问题,但这里有一个例子,试图应用一些抽象来解决这个问题。一旦有了图形和值,就可以定义一个返回节点值的节点值函数。然后你可以把你的问题表述为 图中是否存在与其相邻节点具有相同节点值的节点 用一些来写这并不难:
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(some #'(lambda (node-descriptor)
(destructuring-bind (node neighbors)
node-descriptor
(find (node-value node) neighbors
:key #'node-value)))
graph)))
(defun adjacent-values-p (graph values)
(flet ((node-value (node)
(cadr (assoc node values))))
(dolist (node-descriptor graph)
(destructuring-bind (node neighbors) node-descriptor
(when (member (node-value node) neighbors :key #'node-value)
(return t))))))
也就是说,尽管从某种意义上说,这可能更容易口齿不清