Program Structure 笔记9(A) (数据抽象、序列数据的表示)

Program Structure 笔记9(A) (数据抽象、序列数据的表示)

  (作者:colinboy  Email:cybbh@163.com) 2008.5.19

(内容难免出现错误或一些专业词汇使用不当,只是个人笔记,能理解总体内容就好)

 

本节内容:

数据抽象  (pairs)  (list)

 

一个数据抽象的例子

(define (total-hand hand)

   (if (empty? hand)

       0

(+ (butlast (last hand))

       (total-hand (butlast hand)))))

 

(total-hand '(3h 10c 4d))  -->  17

上面过程如果不仔细分析,也许不能很快看出来它的作用是什么。它的作用是接收一组牌,然后计算出这组牌的大小的总和。显然此过程处理的是“牌”,但是在此过程中,我们并看不到任何关于“牌”的影子。

 

为了更容易理解上面的程序,定义出了此程序的第二版:

(define card-rank butlast)

(define card-suit last)

(define one-card last)

(define remaining-cards butlast)

(define (total-hand hand)

   (if (empty? hand)

        0

     (+ (card-rank (one-card hand))

        (total-hand (remaining-cards hand)))))

 

(total-hand '(3h 10c 4d))  -->  17

第二版中终于看到了“牌”的影子,它的功能和第一版完全一样,但是比第一版更容易阅读了,并且让人感觉到真的有一些“牌”存在了。

 

第二版相比第一版也更容易维护,例如如果我们的程序中有几百个函数都需要获取牌的大小,第一版中我们需要在这几百个函数中使用(butlast card)来获取牌的大小,设想如果现在我们想把牌的表示形式从“10c”修改称“c10”,那么我们就需要修改几百个函数来实现,但是在第二版中,我们有一个card-rank来获取牌的大小,如果牌的表示形式改变了,只需要修改card-rank就可以完成。

 

在本例中显然card应该设计成一种ADT(抽象数据类型),为了实现card,需要:

1.   选择函数(selector

上面定义的card-rank  card-suit都是选择函数,用来选择数据中的某部分。

2.   构造函数(Constructor

用来构造一个抽象数据存储,例如card

 

card的构造函数实现如下:

(define (make-card rank suit)

(word rank (first suit)))

 

(make-card 10 'club)  -->  10c

(make-card 3 'spade)  -->  3s

 

现在我们来实现一个更好的total-hand,第三版:

(define card-rank butlast)

(define card-suit last)

(define one-card last)

(define remaining-cards butlast)

(define make-hand se)

 

(define (make-card rank suit)

(word rank (first suit)))

 

(define (total-hand hand)

   (if (empty? hand)

        0

     (+ (card-rank (one-card hand))

        (total-hand (remaining-cards hand)))))

 

(total-hand (make-hand (make-card 3 'heart)

                       (make-card 10 'club)

                       (make-card 4 'diamond)))  -->  17

 

第三版和第二版相比,发现除了增加了make-handmake-card外,其他地方和第二版没有任何区别!

 

这就是数据抽象,当我们定义出选择函数和构造函数之后,如果数据的表示形式发生了改变,只需要改变选择函数和构造函数,程序其他地方几乎不用修改,使程序的可读性和可维护性更好!

 

 

例如要更改card的表示形式,不使用以前的'(10s 5h 8c), 而修改成如'(3 34 41),即根据牌的花色

顺序依次把牌表示成一个固定的数字,例如红心A表示成1,黑心A表示成14,方块A表示成27,可只把选择函数和构造函数修改成如下形式,而程序的其他部分完全不需要修改。

(define (make-card rank suit)

  (cond ((equal? suit 'heart) rank)

        ((equal? suit 'spade) (+ 13 rank))

        ((equal? suit 'diamond) (+ 26 rank))

        ((equal? suit 'club) (+ 39 rank))

  (else (error "what???"))))

 

(define (card-rank card)

   (remainder card 13))

 

(define (card-suit card)

   (nth (/ card 13) '(heart spade diamond club)))

 

一个Card ADT的层次结构如下:

|------------------------|

|         Card           |

|------------------------|

|   选择函数 构造函数    |

|------------------------|

|       内部实现         |

|------------------------|

 

最高层为抽象数据类型的名字,中间曾为展示给用户的使用接口,最底层为抽象数据的实现。

用户使用Card时只需要和中间层的用户接口交互,而不需要关心内部实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值