数据结构之抽象数据类型

  • 抽象数据类型(ADT)概念
    • 以面向对象编程为例,在创建一个对象的时候,要给定这个对象有哪些属性以及行为,并且可以通过一套接口描述说明这个对象用来干什么的,在给定输入的时候,产生相应的结果,并不需要知道其内部实现的具体细节。其基本思想是,把数据定义为抽象的对象集合,并赋予它们合法操作,同时,不暴露其数据的表示细节和操作的实现细节。

    • 通常对数据类型的操作可以分为三类
      • 构造操作:依据已知的一些信息,产生出这种类型的新对象。例如Python中的内置函数str(),通过str(1),将int对象产生出为str对象。
      • 解析操作:通过已知对象的特性,取出想要的结果,其结果反映了被解析对象的操作特性。如下:表示object是取分数的分子和分母。

      • 变动操作:这类操作用来修改对象的内部状态。

    • ADT是一种思想,更是一种组织程序的技术,主要有,①围绕一类数据定义程序模块;②模块的接口和实现分离;③实例化的时候,以合理的机制实现具体的数据表示和操作。以下图为例,首先是定义TCP/serial通信(Python描述)的相关数据,接下来就是把这个类型具体化。详情请见https://github.com/simonlzw/Data-Structures-and-Algorithms/blob/master/DataStructuresAndAlgorithms/AbstractionToInstantiation.py

  • Python中的类
    • 在上面我们使用了Python来描述类,并且实现了抽象类的定义与类的实例化,其中我们用到了class这个关键字,没错,这就是Python中的一种技术,利用class定义实现抽象数据类型,这个定义好的类就可以类比为系统内部类型,通过实例化,就可以产生该类型的对象。实际上,Python把内置类型都看作类。
    • class是类定义的关键字,class后面是给定的类名,其中object是AbstractDriver的父类,AbstractDriver继承自object,object是几乎python全部对象的父类,相当于树的根节点一样。
      class AbstractDriver(object): ​def __init__(self, publisher=None): self.publisher = publisher def log(self, msg): print_with_time(msg) if isinstance(self.publisher, ZmqPublisher): self.publisher.publish(msg)@abstractmethod def open(self): pass
    • 类体里面一般包括两个部分:属性和方法。其属性一般定义在__init__里面,方便在函数里调用。这里的__init__方法称作初始化方法,其目的是构造本类的新对象。在实例化一个对象时(ex:tcp_c = AbstractDriver())时,系统会自动对这个对象执行__init__方法。其中self.publisher = publisher,self.publisher表示该类的实例对象的属性,publisher表示传入的参数。
    • 私有变量:在类的定义中,以下划线_开头的属性名或者函数名都当作内部使用的名字,另外,以两个下划线__开头的名字不能在类定义之外用这个名字访问。
    • 静态方法:在函数定义的头部行之前加修饰符,静态方法的参数表中不应该有self参数,因此,调用静态方法的时候其参数表的形参都要接受外部传来的实参,这里是没有自动使用的self参数。本质上说,静态方法就是在类里面定义的普通函数,但也是该类的局部函数。
      @staticmethoddef create_cmd(cmd): if "[11]" not in cmd: cmd = "[11]" + cmd if "\r\n" not in cmd: cmd = "{}\r\n".format(cmd) return cmd
    • 类方法:在其定义行前加修饰符@classmethod,定以的这种方法必须有一个cls参数,在类方法执行时,调用它的类将自动约束到方法的cls参数,通常用类方法实现与本类的所有对象有关的操作。
      @classmethoddef create(cls, zmq_context, endpoint, polling_milliseconds=0): socket = zmq_context.socket(zmq.ROUTER) socket.bind(endpoint) return cls(socket, polling_milliseconds)
    • python中提供了一个内置函数isinstance,专门用于检查类和对象的关系,例如isinstance(obj,cls)检查obj是否为cls类的实例,若是,返回True,否则返回false。
    • 继承、基类和派生类:在定义一个新的类时,可以列出一个或者几个已有的类作为被继承类,这样就建立了新定义类与指定已有类之间的继承关系,通过继承定义出来的新类就被称为已有类的派生类(或称子类),被继承类就称为派生类的基类(即父类)。Python 中表达式issubclass (cls1,cls2)可用来检查cls1和cls2是否有继承关系,是就返回True,否则返回false。
    • 标准函数super(),用在派生类的方法定义里,它要求从这个类的直接基类开始做属性检索,而不是从这个类本身开始插找。
    • python异常处理,程序运行中发生的每个异常都有特定的名字,如valueerror、TypeError、ZeroDivisionError等,通常可以用try...except机制去处理异常
  • 类定义实例:人事管理系统中的类
    • 问题分析与设计
      • 以一个公司的人事管理系统为例,将公司人员按职能分为两类:工程类(研发,测试,维护等)以及非工程类(人事,行政,财务等等);分析这两类人员都需要记录有用的信息,这两类人员都有共通性,也有各自的特殊情况:
        • 首先:作为公司职员,都应该具有:姓名,年龄,性别,工号,职位等公共信息。
        • 作为工程类人员,应该有所属工程部,项目记录,项目起始时间等。
        • 作为非工程人员,应该有考勤,培训,报销等信息。
    • 方案设计
      • 首先是基本员工信息ADT设计,即给定职员(Staff),如下属性:姓名(name),性别(sex),年龄(age),工号(number),职位(position),同时所有员工还具有入职与离职的动作,由次可以给定如下抽象数据类型定义:

      • 然后是工程人员ADT设计,属性是项目绩效(project_bonus),做的项目(project_number),同时有开发软件(develop)的动作,如下所示

      • 最后是非工程人员ADT设计,属性基本ADT已经包含了,故只需要考虑其动作,主要有记录考勤(record_attendance),记录会议(record_meeting),财务核算(financial_accounting)等,如下所示

    • 代码调试以及DEBUG:本实例主要以理解抽象概念,明白什么是ADT,以及ADT的实例化,理解什么是继承以及派生类。
  • 总结
    • 抽象数据类型的基本思想是抽象定义与数据表示和数据操作的实现分离。
    • 定义抽象数据类型实质就是通过一组操作实现对象与外部的接口调用。
    • python的类机制中,被继承的类被称为基类,继承的类称为派生类,如果在新类的定义时不指明基类,python会自动认为其基类是object。在类定义的层次结构中,最高层的类是object,其他类都是object的派生类。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值