Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 学习方框图和指针图的资源_List_Linked List_Scheme_Lisp_Nested Lists - Fatal编程技术网

List 学习方框图和指针图的资源

List 学习方框图和指针图的资源,list,linked-list,scheme,lisp,nested-lists,List,Linked List,Scheme,Lisp,Nested Lists,我目前正在努力理解方框图和指针图。如何构建它们以及如何解释它们 提供的说明如下所示。 然而,我仍然没有“明白” 我知道列表是对的组合,一对的cdr可能指向另一对。我也知道cdr指向的一对可能是另一个列表。我只是不明白如何在一张图表中把它画出来 以下是一个问题示例,供参考: (define cal (list (append (list (cons (list 1 2) (cons 3 '()))) (list (cons 4 (cons 5 '()))))

我目前正在努力理解方框图和指针图。如何构建它们以及如何解释它们

提供的说明如下所示。 然而,我仍然没有“明白”

我知道列表是对的组合,一对的cdr可能指向另一对。我也知道cdr指向的一对可能是另一个列表。我只是不明白如何在一张图表中把它画出来

以下是一个问题示例,供参考:

(define cal 
  (list (append (list (cons (list 1 2) (cons 3 '())))
                (list (cons 4 (cons 5 '())))) 
        6 
        7))
给定一个类似于上面的代码,我假设画一个方框和指针图,然后能够说出要得到列表中的任何给定数字需要什么样的car和cdr组合

同样,以下是我本应能够得出的图表,以供参考:

重申一下,我要找的是一段视频或一篇文章,可以更清楚地解释方框图和指针图的构建


提前感谢所有愿意为我指出正确方向的人。

试着从里到外开始,就像口译员会做的那样。画一个图表,比如说,
(cons 3'())
-很简单,对吧?现在,有什么东西可以指向它吗?是的,它是
(cons(列表12)(cons 3’())
的cdr。因此,当您为这个更大的表达式绘制图表时,请确保它的cdr指向您绘制的第一个子图表。要完成这个更大的表达式的绘制,您还需要为
(列表12)
绘制一个图表-与开始时一样简单


从那里开始向外工作。
append
操作是最棘手的部分,但是您链接的说明解释了
append
的工作原理。

忘记列表。没有列表。只有一对

(define cal 
  (list (append (list (cons (list 1 2) (cons 3 '())))
                (list (cons 4 (cons 5 '())))) 
        6 
        7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))  ; (list 1 2)
(define B (cons 3 NIL))           ; (cons 3 '())
(define C (cons 5 NIL))           ; (cons 5 '())
(define cal 
  (list (append (list (cons A B))
                (list (cons 4 C))) 
        6 
        7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))  
(define B (cons 3 NIL))           
(define C (cons 5 NIL))           
(define D (cons A B))
(define E (cons 4 C))
(define cal 
  (list (append (list D)
                (list E)) 
        6 
        7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))  
(define B (cons 3 NIL))           
(define C (cons 5 NIL))           
(define D (cons A B))
(define E (cons 4 C))
(define F (list D E))             ; (append (list D) (list E)) 
(define cal 
  (list F 
        6 
        7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))  
(define B (cons 3 NIL))           
(define C (cons 5 NIL))           
(define D (cons A B))
(define E (cons 4 C))
(define F (cons D (cons E NIL)))  ; (list D E)
(define cal 
  (cons F 
        (cons 6 
              (cons 7 NIL))))
每个
cons
都是一个框。每个名称都是一个指针

仅此而已。

此答案使用Common Lisp作为示例,但在模式上并没有根本的不同。另外请注意,如果您想了解打印图表的实际实现方式,可以使用Common Lisp(例如CCL或SBCL程序)

首先必须清楚要打印的结果,当源包含cons/list/append操作时,这可能会很困难。此外,由于源代码也是cons单元树,因此必须注意不要将源代码与计算后获得的值混合。 因此,这一切都是从正确评估表单开始的

评估
cal
让我们首先计算表达式。下面,我还提到直接从输入表达式绘制框,但在我看来,这有助于详细说明中间步骤。 递归计算所有表达式后,Scheme和Common Lisp中的结果相同:

((((1 2) 3) (4 5)) 6 7)
以下是如何使用公共Lisp要求系统跟踪计算。首先,要知道您无法跟踪标准函数,如
list
等。因此,让我们使用简单的包装将它们隐藏在自定义包中:

(defpackage :so
  (:use :cl)
  (:shadow #:list #:cons #:append))

(in-package :so)

(defun list (&rest args) (apply #'cl:list args))
(defun cons (&rest args) (apply #'cl:cons args))
(defun append (&rest args) (apply #'cl:append args))
然后,在REPL中,转到该软件包:

CL-USER> (in-package :so)

#<PACKAGE "SO">
现在,您可以直接输入
cal
的值,但这次使用的符号是我们要求跟踪的符号

SO> (list (append (list (cons (list 1 2) (cons 3 '())))
                (list (cons 4 (cons 5 '())))) 
        6 
        7)
然后,环境对表单求值,并打印如何调用每个函数以及它返回的结果

  0: (SO::LIST 1 2)
  0: LIST returned (1 2)
  0: (SO::CONS 3 NIL)
  0: CONS returned (3)
  0: (SO::CONS (1 2) (3))
  0: CONS returned ((1 2) 3)
  0: (SO::LIST ((1 2) 3))
  0: LIST returned (((1 2) 3))
  0: (SO::CONS 5 NIL)
  0: CONS returned (5)
  0: (SO::CONS 4 (5))
  0: CONS returned (4 5)
  0: (SO::LIST (4 5))
  0: LIST returned ((4 5))
  0: (SO::APPEND (((1 2) 3)) ((4 5)))
  0: APPEND returned (((1 2) 3) (4 5))
  0: (SO::LIST (((1 2) 3) (4 5)) 6 7)
  0: LIST returned ((((1 2) 3) (4 5)) 6 7)

((((1 2) 3) (4 5)) 6 7)
可视化为cons单元格 将列表视为cons单元格链可能会有所帮助,即将
(a b c)
转换为
(a.(b.(c.nil))
。让我们定义一个辅助函数:

(defun consprint (x)
  (if (consp x)
    (format nil
            "(~a . ~a)" 
            (consprint (car x))
            (consprint (cdr x)))
    (prin1-to-string x)))
结果如下:

SO> (consprint '((((1 2) 3) (4 5)) 6 7))
"((((1 . (2 . NIL)) . (3 . NIL)) . ((4 . (5 . NIL)) . NIL)) . (6 . (7 . NIL)))"
Draw:一种术语重写方法 使用递归的、自底向上的方法来绘制它

定义。:这里我将叶子定义为一个cons细胞,它的CAR和CDR插槽中都有原子:例如
(0.NIL)
(X.Y)
都是叶子,但不是
((0.1).2)
。请注意,这包括不正确的列表,这是我用符号替换子项时用来解释绘图方法的依据

((((1 . (2 . NIL)) . (3 . NIL)) . ((4 . (5 . NIL)) . NIL)) . (6 . (7 . NIL)))
        ^^^^^^^^^    ^^^^^^^^^          ^^^^^^^^^                 ^^^^^^^^^
上面我在所有的叶子下面画了线:你可以很容易地画出那些盒子,并用符号(A,B,…)给它们贴上标签

在下面,我用其关联框的名称替换原始单元格,并再次在新叶下划线:

((((1 . A) . B) . ((4 . C) . NIL)) . (6 . D))
   ^^^^^^^         ^^^^^^^           ^^^^^^^
然后,当有一个符号表示一个方框时,向该方框画一个箭头。例如,您定义了一个名为E的框,它对应于
(1.a)
,因此您可以绘制
[1/x]
,并将
x
连接到框
a

您获得:

(((E . B) . (F . NIL)) . G)

现在,考虑<代码>(E.B)< /代码>:它的车是一个符号,所以你需要绘制的框没有值,但是从车槽中指向箭头的输出箭头指向“<代码> e>代码>单元(就像它的CDR点到<代码> B<代码>)。 重复此过程直到终止。其余部分是可视化布局,通常是将只是原子链接列表的框水平布局

直接从表达式中提取 假设原始练习希望您从原始表达式中直接绘制方框。也可以如上所述,从叶表达式向上操作,并用表示现有框的符号替换它们的值

  • cons直接映射到长方体
  • 列表只是cons的一个重复应用,您可以通过绘制尽可能多的框来快速完成
  • append实际上会复制参数中除最后一个列表之外的所有列表,但在绘制时可以“修改”现有框。对于每个现有的框,一直跟随CDR,直到到达CDR中没有箭头的框,并将该框链接到参数中的下一个框,从而将不同的框链接在一起

还可以绘制append的实际纯功能版本,以了解结构共享和垃圾收集是如何工作的。

[注意,这个答案并不鼓励您作弊:如果您正在学习一门要求您能够绘制box&pointer di的课程
(((E . B) . (F . NIL)) . G)
raco pkg install --auto sdraw
(define cal 
  (list (append (list (cons (list 1 2) (cons 3 '())))
                (list (cons 4 (cons 5 '())))) 
        6 
        7))
(list (cons (list 1 2) (cons 3 '())))