《数据结构与算法 Python语言描述》 读书笔记

已经发布博客

《数据结构与算法 Python语言描述》 读书笔记

第二章 抽象数据类型和Python类

2.1 抽象数据类型abstract data type:ADT 

2.1.1

使用编程语言提供的数据组合机制(元组,列表等)对处理复杂程序里的数据组织问题是不够的。

2.1.2 抽象数据类型的概念

把数据定义为抽象的对象集合,为他们定义合法操作,不暴露内部实现细节。

数据类型的变动性,表示数据被创建后是否可以变化。

2.1.3 抽象数据类型的描述 

抽象数据类型的结构:

1 一个ADT描述由一个头部和按照一定格式给出的一组操作描述构成。

2 头部给出类型名字,最前面是关键词ADT,表明抽象数据类型。

3操作形式描述给出操作名字,参数类型,参数名字

4 各个操作的实际功能用自然语言描述,说明这个操作具体能做什么。

2.2 Python的类

2.2.1 有理数类

rational有理数

gcd:greatest commen divisor最大公约数

2.2.2 类定义进阶                                                           

类机制定义的类型和Python系统内部类型用法相同。

静态方法:在类里定义的普通函数

2.3  类的定义和使用

2.3.1 基本的类定义和使用

2.3.2 实例对象:初始化和使用

P46

2.3.3 

静态方法:@staticmethod:实际就是定义在类里面的没有self的普通函数,

类方法:@classmethod:这种方法必须有一个表示其调用类的参数,习惯用cls作为参数名,还可以有任意多个其他参数。

isinstance(obj, cls) 函数来判断一个对象是否是一个已知的类型,类似 type()。 

isinstance() 与 type() 区别:

type() 不会认为子类是一种父类类型,不考虑继承关系。

isinstance() 会认为子类是一种父类类型,考虑继承关系。 

如果要判断两个类型是否相同推荐使用 isinstance()。

语法

以下是 isinstance() 方法的语法:

isinstance(object, classinfo)

参数

object -- 实例对象。

classinfo -- 可以是直接或间接类名、基本类型或者有它们组成的元组。

返回值

如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。。

实例

以下展示了使用 isinstance 函数的实例: 

>>>a = 2

>>> isinstance (a,int)

True

>>> isinstance (a,str)

False

>>> isinstance (a,(str,int,list))    # 是元组中的一个返回 True

True

2.3.4 继承

虚函数:通过动态约束确定调用关系的函数

基类:父类

派生类:子类

标准函数:super()

2.4 python异常

异常都是类,所有异常的基类是BaseException.最重要的子类是Exception,内置异常类都是这个类的直接后者间接派生类。

2.4.3 内置的标准异常类

2.5类定义实例:学校人事管理系统中的类

2.5.1 问题分析和设计

学生和老师有共性也有特殊性,先定义一个公共人员类,然后从中派生出学生类和教职工类。

基于人员ADT的设计

学生ADT的设计

教职工ADT的设计

2.5.2 人事记录类的实现

2.5.3 讨论:

定义派生类的用途:

第三章 线性表

3.1 线性表的概念和表抽象数据类型

3.1.1 表的概念和性质

线性表就是有限个数据排列,第一个元素叫做首元素的下标是零,第n个元素的下标是n-1。

3.1.2 表抽象数据类型

线性表的操作

创建线性表,检查数据表,修改表,组合表,操作表元素

3.1.3 线性表的实现:基本考虑

顺序表和链接表

3.2 顺序表的实现

 3.2.1 基本实现方式

3.2.2 顺序表基本操作的实现

创建空表,简单判断操作,访问给定下标i的元素。便利操作,查找给定元素d的位置,查找给定元素d在位置k之后的第一次出现的位置。

变动操作:加入元素,删除元素,

3.2.3 顺序表的结构

两种基本实现方式

一体式结构:存储表信息的单元和元素存储区以连续的方式安排在一块存储区里。

分离式结构:

替换元素存储区:分离式结构的优点,表头不变,变换元素内容

后端插入和存储区扩充:动态顺序表技术,每次增加10个元素存储位置。

3.2.4 Python的list

tuple是不变的表,因此不支持改变其内部状态的任何操作。

list是元素个数可以变化的线性表。,可以添加,可以删除。

list采用分离式技术实现的动态顺序表。

3.2.5 顺序表的简单总结 

3.3 链接表

3.3.1 线性表的基本需要和链接表

3.3.2 单链表 

单链表:每个表结点里记录着存储下一个表元素的结点的标识和本身结点的数据项

表头变量,表头指针,表尾结点设置空链接,

基本链表操作:

创建空链表,删除链表,判断链表是否为空,

加入元素:

表首端加入,表中间插入,表尾插入。

3.4 链表的变形和操作

3.4.1 单链表的简单变形

通过继承和扩充定义新链表类

子类可以继承父类,可以定义新的方法,可以覆盖父类的方法。

任何用户定义类都是object类的子类。

初始化和变动操作

镭射机的内在一致性

3.4.2 循环单链表

最后一个节点的next域指向第一个结点。

3.4.3 双链表

单链表只能首端添加和删除,尾端加入。只能做一个方向的扫描

双链表就可以首端和尾端都进行删除和加入操作。可以做两个方向的扫描。

单链表只能找到下一个结点,要找到前一个结点,只能从表头开始扫描。

双链表可以直接找到前后两个结点,

循环双链表

3.4.4 两个链表操作

链表反转

链表排序

3.4.5 不同链表的总结

第四章 字符串 

4.1 字符集,字符串和字符串操作

字符集,

字符序

4.1.1 字符串相关概念

字符串长度,字符在字符串里的位置,字符串相等,字典序,字符串拼接,子串关系,前缀和后缀,n次幂。

4.1.2 字符串抽象数据类型

4.2 字符串的实现

4.2.1 基本实现问题和技术

4.2.2 实际语言里的字符串

4.3字符串匹配

4.3.1 字符串匹配

4.3.2 串匹配和朴素匹配算法

4.3.3 无回溯串匹配算法(KMP算法)

4.4 字符串匹配问题

4.4.1 串匹配和搜索的不同需要 

模式,字符串和串匹配

通配符和简单模式语言

正则表达式regular expression, regex,re,

4.5 python 正则表达式regular

4.5.2 基本情况 

原始字符串 

在普通字符串前面添加R或者r。其中的反斜线\不是转义字符

元字符:特殊字符

. ^ $ * + ? \ | {} [ ] () 

4.5.3  主要操作

生成正则表达式对象:re.compile(pattern, flag = 0)

r1 = re.compile("abc") 生成与abc对应的正则表达式对象,并且赋值给r1;

检索:re.search(pattern,string, flag=0)

匹配:re.match(pattern, string, flag =0)

分割:re.split(pattern,string, maxsplit =0, flags =0)

找出所有匹配串:re.findall(pattern, string, flags=0)

4.5.4 正则表达式的构造

字符组 

某些正则表达式可以和一组字符中的任何一个字符匹配,叫做字符组描述。

字符组描述符[...],和方括号中的任意字符都可以匹配,没有顺序。

区间形式:[0-9]匹配所有十进制数字

[a-zA-Z]匹配所有字母

特殊形式[^...]匹配所有没有列在中括号里的东西,字符组求补。

原点字符(.):通配符,匹配任何字符

a..b匹配a开头,b结尾的所有四个字符串

re采用转义串的形式定义了一些常用字符组。

\d 匹配所有十进制数字

\D 匹配所有非十进制数字

\s 与所有空白字符匹配,等价于[\t\v\n\f\r]

\w匹配所有字母和数字,等价于[0-9a-zA-Z]

p\w\w 表示字母p开头的三个字符

重复描述符*

a* 表示匹配n个连续的a,n>=0

re.split('[ ,]*','1 2, 3    4,  , ,5') 得到['1', '2', '3', '4', '5'] 可以与空格或者逗号匹配

贪婪匹配:模式与字符串里有可能匹配的最长子串匹配 re.match('ab*', 'abbbbc') 结果是abbbb

非贪婪匹配:模式与有可能匹配的最短子串匹配

+表示一次或者多次重复,不可以不重复一次

可选描述符:?  表示?前面的字符可要可不要

重复次数描述符:{n}这个符号前面的字符串可以出现n次

重复次数的范围描述符:{m,n} 前面的东西可以出现m到n次,包含,m,n次,m,n可以省略

非贪婪匹配描述符,在运算符后面加上问号?

选择描述符:|,匹配任何其中一个。 a|b|c,可以匹配a,或者b,或者c

首尾描述符:

行首描述符:^,表示以^后面的字符开头的一行字符串

re.search('^for','books\n for children')找到了for children,因为换行后导致for开头了一个新行

行尾描述符:$表示用$后面的字符结尾的一行字符串

re.search('^books','books\n for children')找到books,匹配成功

串首描述符:\A

串尾描述符:\Z 

单词边界

匹配对象

匹配的子串:mat.group()

匹配起始位置:mat.start()

匹配结束位置:mat.end()

匹配区间:mat.span() 开始和结束位置得到的二元组

模式里的组:group

正则表达式对象

正则表达式的使用

本章总结 

第五章 栈和队列 stack and queue

5.1 概述

栈和队列主要用于在计算过程中保存临时数据,是使用最多的缓存机制。

运算过程中产生的中间数据暂时不用或者用不完,这些事先无法确定的数据项复杂的机制存储和管理,称作缓存机制。

5.1.1 栈,队列和数据使用顺序

元素的存入和取出操作

栈:先进后出模式,类似从书堆取书

堆:先进先出,类似超市排队付款

5.1.2 应用环境

缓存结构

计算过程分为一些顺序进行的步骤

进程会不断产生中间数据

有些数据不能立即使用,但是将来可能会使用

数据项数不能事先确定

5.2 栈,概念和实现

5.2.1 栈抽象数据类型

栈的线性表实现

后进先出LIFO

栈顶实行插入,删除操作,访问弹出都是栈顶元素。

栈底

5.2.2 栈的顺序表实现

5.2.3 栈的链接表实现

5.3 栈的应用

栈是最简单的数据结构

辅助存储结构,保证后进先出的顺序存取

5.3.1 符号应用:括号匹配问题

5.3.2 表达式的表示,计算和变换

表达式和计算的描述

后缀表达式的计算

中缀表达式到后缀表达式的转换

中缀表达式的求值

5.3.3 栈与递归

在定义中引用了定义本身,称作递归定义。 也就是重复使用本身的意思。

阶乘函数的递归计算用了程序运行栈

栈与递归函数调用

栈与函数调用*

递归与非递归

递归函数与非递归函数

简单背包问题

5.4 队列 queue

一种容器,可以存入,访问,删除元素

5.4.1 队列抽象数据类型

先进先出类型。FIFO

5.4.2 队列的链接表实现

5.4.3 队列的顺序表实现

基于顺序表实现队列的困难。

循环顺序表

5.4.4 队列的list实现

5.4.5 队列的应用

文件打印:待打印文件都需要缓存。

万维网服务器:淘宝交易高峰期请求高出平时许多倍。服务器系统不可能立即处理这些请求,就会把来不及的请求放入待处理请求队列

采取先来先服务原则

Windows系统和消息队列:

离散时间系统模拟:

5.5 迷宫求解和状态空间搜索

5.5.1 迷宫求解:分析和设计

5.5.2 求解迷宫的算法

迷宫的递归求解

栈和回溯法

5.5.3 迷宫问题和搜索

5.6 几点补充

5.6.1 几种和栈或者队列相关的结构

双端队列 

测试题:

某表达式的前缀形式为"+-*^ABCD/E/F+GH",它的中缀形式为() 

  A^B*C-D+E/F/G+H

  

  A^B*(C-D)+(E/F)/G+H

  

  A^B*C-D+E/(F/(G+H))

  

  A^B*(C-D)+E/(F/(G+H))

  

 There is a sequence of n numbers 1, 2, 3,.., n and a stack which can keep m numbers at most. Push the n numbers into the stack following the sequence and pop out randomly. Suppose n is 2 and m is 3, the output sequence may be 1, 2 or 2, 1, so we get 2 different sequences. Suppose n is 7 and m is 5, please choose the output sequences of the stack: 

  1, 2, 3, 4, 5, 6, 7

  

  7, 6, 5, 4, 3, 2, 1

  

  5, 6, 4, 3, 7, 2, 1

  

  4, 5, 6, 3, 7, 2, 1

  

  1, 7, 6, 5, 4, 3, 2

  

  3, 2, 1, 7, 6,5, 4

  

  一个栈的入栈序列为ABCDE,则不可能的出栈序列为() 

  ECDBA

  

  DCEAB

  

  DECBA

  

  ABCDE

  

  如果进栈序列为e1,e2,e3,e4,则不可能的出栈序列是( )  A.e2,e4,e3,e1

B.e4,e3,e2,e1

C.e1,e2,e3,e4

D.e3,e1,e4,e2

解析:

. e1进,e2进,e2出,e3进,e4进,e4出,e3出,e1出

.e1进,e1出,e2进,e2出,e3进,e3出,e4进,e4出

第六章 二叉树和树

复杂结构中的最简单一类结构。

结点保存数据

树根,前驱,后继

6.1 二叉树:概念和性质

二叉树每个结点至多关联到两个后继结点。

6.1.1 概念和性质

左子树和右子树

小圆圈代表二叉树的结点

几个基本概念:

空树

单点树

父结点

子结点

从父结点到子节点的边

传递关系:祖先/子孙关系

兄弟结点

祖先结点

子孙结点

树叶结点

分支结点

结点的度数:子结点的个数

路径,结点的层和树的高度

一条路径,路径的长度

路径唯一:从根节点到任意结点

二叉树是层次结构

树根是最高元素

路径长度就是结点层数

高度或者深度是树中结点的最大层数

二叉树性质 

长度为n的表里只能容纳n个结点,但是高为h的二叉树中容纳2的h次方个结点。

满二叉树

扩充二叉树

内部结点

新增的外部结点

外部路径

内部路径

完全二叉树:0到h-1层都是满结点,并且h层(最底层)所有结点在最左边连续排列

6.1.2 抽象数据类型

6.1.3 遍历二叉树

深度遍历二叉树:先根序遍历,中根序遍历,后根序遍历

宽度优先遍历:逐层访问树中结点

遍历与搜索

搜索树

6.2 二叉树的list实现

6.2.1 设计和实现

6.2.2 二叉树的简单应用:表达式树

二元表达式和二叉树 

叶结点放运算对象

分支结点放运算符

构造表达式

表达式求值 

6.3 优先队列

6.3.1概念 

6.3.2 基于线性表的实现

有关实现方法的考虑

采用有组织的元素存放方式和采用无组织的元素存放方式

基于list实现优先队列

对连续表实现的分析

6.3.3 树形结构和堆

线性和树形结构

堆及其性质

数据按照优先关系递减

根节点:堆顶

小顶堆:小元素在上

大堆顶:大元素在上,优先

6.3.4 优先对列的堆实现

筛选:解决堆插入和删除的操作。分为向上和向下筛选

插入元素和向上筛选

弹出元素和向下筛选

基于堆的优先队列

构建操作的复杂性

6.3.5 堆的应用:堆排序

6.4 应用:离散事件模拟

6.4.1 通用的模拟框架

6.4.2 海关检查站系统

6.5.1 二叉树结点类 

6.5.2 遍历算法 

递归定义的遍历函数

宽度优先遍历

非递归的先根序遍历函数

通过生成器函数遍历 

非递归的后根序遍历算法

6.5.3 二叉树类 

6.6 哈夫曼树

是一种重要的二叉树

6.6.1 哈夫曼树和算法

扩充二叉树:把普通二叉树补充所有树叶

带权扩充二叉树的外部路径及其长度:给扩充二叉树的外部结点标一个数值。这个数值就是权

带权扩充二叉树的外部路径长度WPL: 

哈夫曼树定义:实数集:W,扩充二叉树T,二叉树的带权外部路径长度最小。

算法:从任意的实数集构造与之对应的哈弗曼树

6.6.2 哈夫曼算法的实现 

6.6.3 哈夫曼编码 

6.7 树和树林 

6.7.1 实例和表示 

家族关系就是树。

6.7.2 定义和相关概念 

树,树林,二叉树的关系 

树林可以和二叉树相互映射 

6.7.3 抽象数据类型和操作 

树的遍历 

搜索树

6.7.4 树的实现 

子结点引用表示,父结点引用表示,子结点表表示

6.7.5 树的Python实现

认识你是我们的缘分,同学,等等,学习人工智能,记得关注我。

微信扫一扫
关注该公众号

《湾区人工智能》

猜你喜欢

转载自blog.csdn.net/BTUJACK/article/details/84201260