《数据结构与算法》Python语言描述–裘宗燕–学习笔记(1)20191124
程序开发就是根据面对的问题,最终得到一个可以解决问题的程序的工作过程。
分析阶段;
设计阶段;
编码阶段;
检查测试阶段;
测试/调试阶段;
数据结构:研究数据之间的关联和组合的形式。
典型的数据结构:
1)集合结构:数据元素之间没有需要关注的明确关系;
2)序列结构:其数据元素之间有一种明确的先后(顺序)关系。一个复杂数据对象就是一个序列对象。序列结构还有一些变形:如环形结构和ρ形结构。
3)层次结构:数据元素分属于一些不同的层次一个上层元素可以关联着一个或者多个下层元素。
4)树形结构:层次结构中最简单的一种关系是树形关系,特点是在一个树形结构中只有一个最上层数据元素,称为根,其余元素都是根的直接或间接关联的下层元素。进一步说,除了根元素之外的每个元素,都有且仅有一个上层元素与之关联。
树形数据结构简称为树,相应的复杂数据对象称为属性对象。
5)图结构:数据元素之间可以有任意复杂的相互联系。
结构性和功能性的数据结构
上述数据结构,都对去数据元素之间的相互关系做了一些规定,元素之间确实满足某种关系才能被称为线性结构或树结构。—成为之结构性的数据结构。(这些数据结构的最重要特征是他们的结构)
另一类数据结构:他们并没有对其元素的相互关系提出任何结构性的规定,而是要求实现某种计算中非常有用的功能。作为可以包含一批数据元素的结构,最基本的要求就是支持元素的存储和使用(使用也常称为元素访问)。这个基本要求实际上是功能性的要求,而非结构性的要求,因为它完全不涉及元素如何存储,元素之间如何关联。
支持元素存储和访问的数据结构成为之容器。
内存:计算中直接使用的数据保存在计算机的内存储器中(简称内存)
内存的基本结构是线性排列的一批存储单元。每个单元的大小相同,可以保存一个单位大小的数据。
内存单元具有唯一编号,称为单元地址,简称 地址。
在python里可以通过初始化(或提供实参)给变量(或函数参数)约束一个值,还可以通过赋值修改变变量的值。这里的值就是对象,给变量约束一个对象,就是把该对象的标识(内存位置)存入该变量。
python语言中变量的这种实现方式是称为变量的引用语义,在变量里保存值(对象)的引用。采用这种饭是,变量所需的存储空间大小一致,因为其中只需要保存一个引用。
有些语言采用的是:把变量的值直接保存在变量的存储区里,称为值语义。这样一个整数类型的变量就需要保存一个整数所需的空间,一个浮点数变量就需要足够的空间存储一个浮点数,如果一个变量需要保存很大的数据对象,就需要占用更大的存储空间,例如C语言。
抽象数据类型ADT Abstract Data Type
基本思想:把数据定义为抽象的对象集合,只为它们定义可用的合法操作,而不暴露其内部实现的具体细节。
一个数据类型的操作通常可以分为三类:
1)构造操作:基于已知的信息,产生出这种类型的一个新对象。
2)解析操作:从一个对象取得有用的信息,其结果反映了被操作的对象的某方面特性。
3)变动操作:这类操作修改被操作对象的内部状态。
利用类定义实现抽象数据类型。
类对象,主要支持两种操作:属性访问(采用原点记法)和实例化
静态方法和类方法:
静态方法:def 前加修饰符@staticmethod,不需要self参数,
类方法:修饰符@classmethhod ,这种方法必须有一个表示其调用类的参数,习惯用cls作为参数。
class TOOL(object):
count = 0
@classmethod
def show_tool_count(cls):
print("工具对象的数量%d" %cls.count)
def __init__(self,name):
self.name = name
TOOL.count += 1
tool11 = TOOL("1")
tool22 = TOOL("2")
tool33 = TOOL("3")
TOOL.show_tool_count()
定义派生类式可以覆盖基类里已有的函数定义,一旦某函数在派生类里重新定义,其实例对象的方法调用解析中,就不会再去使用基本类里原来定义的方法了。
动态约束:基于方法调用时参数所表示的实例对象的类型去调用哪个----???
虚函数:通过动态约束确定调用关系的函数称为虚函数
标准函数super()
用在派生类的方法定义里,就是要求从这个类的直接基类开始做属性检索,调用父类定义过方法,避免重写时丢掉父类定义过的内容。
2.5类定义实例:学校人事管理系统中的类
两种实现模型:
1)将表中元素顺序地存储在一大块连续的存储区:顺序表
2)将表元素存放在通过连接构造起来的一系列存储块里,称为链表
python中的list和tuple就采用了顺序表的实现技术。
tuple是不变的表,不支持改变其内部状态的任何操作,其它方面与列表类似。
顺序表的特点:
1)访问元素时,效率高;
2)加入/删除操作 效率低,需要移动很多元素,操作代价高
3)只有在尾端进行插入或者删除操作时,实践复杂度O(1),但插入操作还受到元素存储区固定大小的限制。
优点和缺点都在于其元素存储的集中方式和连续性。
链表:
使用链接方式实现线性表的基本思想:
将表中的元素分别存储在一批独立的存储块内;保证从组成表结构中的任意结点都可以找到与其相关的下一个结点。
单链表:结点: 表元素+下一个结点的链接域
链表的实现:
# 链表
class LNode:
""""定义一个链表的结点类"""
def __init__(self,elem,next_ = None):
self.elem = elem
self.next = next_
# 基于单链表结点点,定义一个单链表对象的类
class LList:
def __init__(self):
"""建立一个空链表"""
self._head = None
def is_empty(self):
"""链表判空"""
return self._head is None
def prepend(self,elem):
"""头插法"""
self._head = LNode(elem,self._head)
def pop(self):
"""删除表头结点,并返回此结点里的数据"""
if self._head is None:
# raise LinkedLsitUnderfloew("IN POP")
print(" LinkedLsitUnderfloew(in pop)")
return
e = self._head.elem
self._head = self._head.next
return e
def append(self,elem):
"""在链表的最后插入元素"""
if self._head is None:
self._head = LNode(elem)
return
p = self._head
while p.next is not None:
p = p.next
p.next = LNode(elem)
def pop_last(self):
# 1.空链表
if self._head is None:
print("LinkedlistUnderFlow in pop_last")
p = self._head
# 2.只有一个结点
if p.next is None:
e = p.elem
self._head = None
return e
# 3.多个结点
while p.next.next is not None:
p = p.next
e = p.next.elem
p.next = None
return e
def find(self,pred):
"""找到满足给定条件的表元素"""
p = self._head
while p is not None:
if pred(p.elem):
return p.elem
p = p.next
return p.elem
def printall(self):
p = self._head
while p is not None:
print(p.elem,end = "")
if p.next is not None:
print('-',end = "")
p = p.next
print(' ')
mlist1 = LList()
for i in range(10):
mlist1.prepend(i)
mlist1.printall()
mlist1.pop()
print("After pop:",end = "")
mlist1.printall()
print("Is the list is empty ? ",end = "")
print(mlist1.is_empty())
mlist1.pop_last()
print("After pop_last:",end = "")
mlist1.printall()
# 尾插
for i in range(11,15):
mlist1.append(i)
mlist1.printall()
运行结果:
9-8-7-6-5-4-3-2-1-0
After pop:8-7-6-5-4-3-2-1-0
Is the list is empty ? False
After pop_last:8-7-6-5-4-3-2-1
8-7-6-5-4-3-2-1-11-12-13-14