目录
前言
提示:笔记内容为寒假自学篇,具体情况会根据实际课程进行补充调整
《数据结构与算法基础》(青岛大学—王卓)
pascal语言之父——Nicklaus Wirth:“程序=数据结构+算法”,该公式展示出了程序的本质。
该课程是计算机软件相关专业的专业基础课,教学计划中的核心,起承上启下的作用。
- 勤于思考
- 多做练习
- 多上机
- 善于寻求帮助
- 不怕困难、不放弃
提示:以下是笔记正文内容,下面案例仅供参考
一、数据结构的基本概念
(一)、数据结构的研究内容
- 数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科。
- 数学模型无法用数学公式或方程来描述,而是诸如树、表、图之类具有逻辑关系的数据。
(二)、基本概念和术语
1、数据、数据元素、数据项和数据对象
- 数据:能输入计算机且能被计算机处理的各种符号的集合。
- 信息的载体
- 对客观事物符号化的表示
- 能够被计算机识别、存储和加工
- 数值型数据
- 非数值型数据
- 数据元素:数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。简称为元素,或称为记录、节点或顶点。
- 一个数据元素可由若干个数据项组成。
- 数据项:构成数据元素不可分割的最小单位。
- 数据对象:性质相同的数据元素的集合,是数据的一个子集。
2、数据结构
- 数据结构:数据元素相互之间的关系。
- 相互之间纯在一种或多种特定关系的数据元素集合。
- 带结构的数据元素的集合。
- 逻辑结构:数据元素之间的逻辑关系。是数据结构的抽象,与数据的存储无关,是从具体问题抽象出来的数学模型。
- 物理结构或存储结构:数据元素及其关系在计算机内存中的表示(又称为映像)。存储结构是逻辑关系的映像与元素本身的映像,是数据结构的实现。
- 运算和实现:对数据元素可以施加的操作以及这些操作在相应的存储结构上的实现。
3、数据类型和抽象数据类型
- 数据类型:一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称。
- 作用
- 约束变量或常量的取值范围
- 约束变量或常量的操作
- 作用
- 抽象数据类型:一个数学模型(逻辑结构)以及定义在此数学模型上的一组操作(运算)。
- 形式定义(D,S,P)
- D是数据对象
- S是D上的关系集
- P是对D的基本操作。
- 定义格式
- 数据对象、数据关系的定义用伪代码描述 。
- 形式定义(D,S,P)
(三)抽象数据类型的表示与实现
抽象数据类型=数据的逻辑结构+抽象运算(运算的功能描述)
(四)算法和算法分析
- 定义:对特定问题求解方法和步骤的一种描述,是指令的有限序列。其中,每个指令表示一个或多个操作。
- 描述
- 自然语言
- 流程图
- 伪代码:类语言:类C语言
- 程序代码
- 算法与程序
- 算法特性
- 有穷性
- 确定性
- 可行性
- 输入:0个或多个
- 输出:1个或多个
- 算法设计的要求
- 正确性:程序对于精心选择的、典型、苛刻且带有刁难性的几组输入数据能够得出满足要求的结果。
- 可读性
- 健壮性:当输入非法数据时,算法恰当地作出反应或进行相应处理,而不是产生莫名其妙的输出结果。
- 处理出错的方法,不应是中断程序的执行,而应是返回一个表示错误或错误性质的值,以便在更高的抽象层次上进行处理。
- 高效性
- 算法分析
- 目的:看算法是否可行,并在同一问题存在多种算法时可行性能上的比较,以便从中挑选出比较优的算法。
- 评判标准:算法的效率
- 时间效率
- 空间效率
- 算法时间效率的度量
- 事后统计
- 事前分析
- 算法运算时间=∑每条语句频度
- 算法时间度的渐进表示法
它表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称渐进时间复杂度。
一般情况下,不必计算所有操作的执行次数,而只考虑算法中基本操作执行的次数。
时间复杂度是由嵌套最深层语句的频度决定的。
- 分析算法时间复杂度的基本方法
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取其数量级用符号“O”表示
- 算法时间复杂度
- 最坏时间复杂度(一般考虑)
- 平均时间复杂度
- 最好时间复杂度
- 加法法则
- 乘法法则
- 算法时间效率的比较
- 渐进空间复杂度
- 算法要占据的空间
- 算法本身要占据的空间:输入/输出、指令、常数、变量等
- 算法要使用的辅助空间
- 算法要占据的空间
二、基本的数据结构
(一)、线性结构
有且仅有一个开始和一个终端结点,并且所有结点都最多只有一个直接前趋和一个直接后继。
1、线性表
①定义和特点
- 线性表:具有相同特性的数据元素的一个有限序列。
- 表的长度:数据元素的个数n
- 空表:n=0
- 非空线性表:(a1,a2,……,an)
- a为抽象符号,其具体含义在不同情况下不同
- 同一线性表中的元素必定具有相同特性,数据元素间的关系是线性关系
- 逻辑特征
②线性表的顺序表示和实现
- 定义:逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
- 逻辑上相邻,物理上也相邻
- 依次存储,地址连续——中间没有空出存储单元
- 知道某个元素的存储位置就可以计算其他元素的存储位置
- 元素存储位置的计算
- 特点:以物理位置相邻表示逻辑关系。任一元素均可随机存取。
- 优缺点
- 优点
- 存储密度大
- 可以随机存取表中任一元素
- 缺点
- 在插入、删除某一元素时,需要移动大量元素
- 浪费储存空间
- 属于静态存储形式,数据元素的个数不能自由扩充
- 优点
- 顺序存储表示
- 用一维数组表示顺序表
- 用一变量表示顺序表的长度属性
- 基本操作的实现
- 初始化操作,建立一个空的线性表L
- 销毁已存在的线性表L
- 将线性表清空
- 在线性表L中的第i个位置插入新元素e
- 删除线性表L中第i个位置元素,用e返回
- 若线性表为空,返回true,否则false
- 返回线性表L的元素个数
- L中查找与给定值e相等的元素,若成功返回该元素在表中的符号,否则返回0
- 将线性表L中的第i个位置元素返回给e
【 补充】类C语言有关操作
- 元素类型说明
- 数组定义
- 数组静态分配
- 数组动态分配
- C语言的内存动态分配
- C++的动态存储分配
- C++中的参数传递
- 传值方式(参数为整型、实型、字符型等): 把实参的值传送给函数局部工作区相应的副本中,函数使用这个副本执行必要的功能。函数修改的是副本的值,实参的值不变。
- 传地址
- 参数为指针变量:形参变化可能影响实参
- 参数为引用类型
- 参数为数组名:传递的是数组的首地址,对形参数组所做的任何改变都将反映到实参数组中
③ 线性表的链式表示和实现
- 有关术语
- 结点:数据元素的存储映像。由数据域和指针域两部分组成。
- 链表:n个结点由指针链组成一个链表。它是线性表的链式存储映像,称为线性表的链式存储结构。
- 单链表、双链表、循环链表
- 单链表(线性链表):结点只有一个指针域的链表。
- 双链表:结点有两个指针域的链表。
- 循环链表:首位相接的链表。
- 头指针、头结点和首元结点
- 头指针:指向链表中第一个结点的指针。
- 首元结点:链表中存储第一个数据元素a1的结点。
- 头结点:在链表的首元结点之前附设的一个结点。
- 特点
- 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻
- 访问时只能通过指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个节点和最后一个节点所花费的时间不等
单链表
- 定义和表示: 单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。若头指针名是L,那么把列表称为表L。
- 存储结构
- 基本操作的实现
- 初始化
- 取值——取单链表中第i个元素的内容
- 从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。因此,链表不是随机存取结构。
- 从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。因此,链表不是随机存取结构。
- 按值查找——根据指定数据获取该数据所在的位置(地址)
- 从第一个结点起,依次和e比较;
- 如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址;
- 如果查遍整个链表都没有找到其值和e相等的元素,则返回0或“NULL”。
- 按值查找——根据指定数据获取该数据位置序号
- 插入——在第i个结点前插入值为e的新结点
- 首先找到ai-1的存储位置p,生成一个数据域为e的新结点s;
- 插入新结点:①新结点的指针域指向结点ai,②结点ai-1的指针域指向新结点。
- 删除——删除第i个结点
- 首先找到ai-1的存储位置p;
- 保存要删除的ai的值,令p→next指向ai+1;
- 释放结点ai的空间。
- 单链表的查找、插入、删除算法时间效率分析
- 查找: 因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为O(n)。
- 插入和删除:因线性链表不需要移动元素,只要修改指针,一般情况下,时间复杂度为O(1)。但是,如果要在单链表中进行前插或删除操作,由于要从头查找前驱结点,所耗时间复杂度为O(n)。
- 首先找到ai-1的存储位置p,保存要删除的ai的值,令p→next指向ai+1,释放结点ai的空间。
- 建立单链表:头插法——元素插入在链表头部,也叫前插法
- 从一个空表开始,重复读入数据;
- 生成新结点,将读入数据存放到新结点的数据域中;
- 从最后一个结点开始,依次将各结点插入到链表的前端。
- 建立单链表:尾插法——元素插入在链表尾部,也叫后插法
- 从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针r指向链表的尾结点;
- 初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点后,r指向新结点。
- 初始化
- 【补充算法1】——判断链表是否为空
- 空表:链表中无元素,头指针和头结点仍在。
- 算法思路:判断头结点指针域是否为空
- 【补充算法2】——单链表的销毁:链表销毁后不存在
- 算法思路:从头指针开始,依次释放所有结点
- 算法思路:从头指针开始,依次释放所有结点
- 【补充算法3】——清空链表
- 链表仍存在,但链表中无元素,称为空链表(头指针和头结点仍在)。
- 算法思路:依次释放所有结点,并将头结点指针域设置为空
- 【补充算法4】——求单链表的表长
- 算法思路:从首元结点开始,依次计数所有结点
循环链表
- 优点:从表中任一结点出发均可找到表中的其他结点。
- 注意
- 由于循环列表中没有NULL指针,故涉及遍历时,就不再判断p或p→next是否为空,而判断它们是否等于头指针。
- 表的操作常常是在表的首尾位置上进行。
双向链表
④应用
- 线性表的合并
- 有序表的合并
2、栈和队列
①定义和特点
- 定义:两种常用的、重要的数据结构。
- 特点:限定插入和删除只能在表的“端点”进行的线性表。栈和队列是线性表的子集(是插入和删除位置受限的线性表)
- 栈——后进先出
- 栈的应用
- 数制转换
- 表达式求值
- 括号匹配的检验
- 八皇后问题
- 行编辑程序
- 函数调用
- 迷宫求解
- 递归调用的实现
- 队列——先进先出
- 队列的常见应用
- 脱机打印输出:按申请的先后顺序依次输出
- 多用户系统中,多个用户排成队,分时地循环使用CPU和主存
- 按用户的优先级排成多个队,每个优先级一个队列
- 实时控制系统中,信号按接收的先后顺序依次处理
- 网络电文传输,按到达的时间先后顺序依次进行
②栈
- 相关概念
- 定义:限定只能在表的一端进行插入和删除运算的线性表(只能在栈顶操作)
- 栈是仅在表尾进行插入、删除操作的线性表。
- 表尾称为栈顶Top;表头称为栈底Base
- 插入元素到栈顶(即表尾)的操作,称为入栈PUSH。
- 从栈顶(即表尾)删除最后一个元素的操作,称为出栈POP。
- 逻辑结构:与线性表相同,仍为一对一关系。
- 存储结构:用顺序栈和链栈存储均可,但以顺序栈更常见。
- 运算规则:只能在栈顶运算,且访问结点时依照后进先出(LIFO)的原则。
- 实现方式:关键是熟悉入栈和出栈函数,具体实现依照顺序栈或链栈的不同而不同。
- 定义:限定只能在表的一端进行插入和删除运算的线性表(只能在栈顶操作)
- 示意图
- 栈与一般线性表的区别:仅在于运算规则不同。
- 表示和操作的实现
- 栈的抽象数据类型的类型定义
- 初始化操作:构造一个空栈S。
- 销毁栈操作:栈S被销毁。
- 判断S是否为空栈:若栈S为空栈,则返回TRUE,否则FALSE。
- 求栈的长度:返回S的元素个数,即栈的长度。
- 取栈顶元素:用e返回S的栈顶元素。
- 栈置空操作:将S清为空栈。
- 入栈操作:插入元素e为新的栈顶元素。
- 出栈操作:删除S的栈顶元素an,并用e返回其值
- 顺序栈的表示和实现
- 存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元一次存放自栈底到栈顶的数据元素。栈底一般在低地址端。
使用数组作为顺序栈存储方式的特点:简单、方便、但易产生溢出(数组大小固定)
- 存储方式:同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元一次存放自栈底到栈顶的数据元素。栈底一般在低地址端。
- 栈的抽象数据类型的类型定义
- 栈与递归
- 递归的定义
- 若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的。
- 若一个过程直接地或间接地调用自己,则称这个过程是递归的过程。
- 递归的应用
- 数学函数:阶乘函数,2阶Fibonacci数列……
- 数据结构:二叉树,广义表……
- 求解问题:迷宫问题,Hanoi塔问题……
- 递归问题——用分治法求解
- 能将一个问题转变成一个新问题,而新问题与原问题的解法相同或类同,不同的仅是处理的对象,且这些处理对象是变化有规律的。
- 可以通过上述转化而使问题简化。
- 必须有一个明确的递归出口,或称递归的边界。
- 递归的优缺点
- 优点:结构清晰,程序易读。
- 缺点:时间开销大。
- 递归的定义
③队列
- 相关概念
- 定义:只能在表的一端进行插入运算,在表的另一端进行删除运算的线性表(头删尾插)
- 逻辑结构:与线性表相同,仍为一对一关系。
- 存储结构:用顺序队和链队存储均可,但以循环顺序队更常见。
- 运算规则:只能在队首和队尾运算,且访问结点时依照先进先出(FIFO)的原则。
- 实现方式:关键是掌握入队和出队操作,具体实现依照顺序队或链队的不同而不同。
- 表示和操作的实现
- 队列的顺序表示——用一维数组base
- 解决假上溢的方法
- 将队中元素依次向队头方向移动:浪费时间
- 引入循环队列:利用%运算
- 队列的链式表示
3、串、数组和广义表
①串
- 定义
- 串:零个或多个任意字符组成的有限序列。
- 子串:串中任意个连续字符组成的子序列(含空串)。
- 真子串:不包含自身的所有子串。
- 主串:包含子串的串。
- 字符位置:字符在序列中的序号。
- 子串位置:子串第一个字符在主串中的位置。
- 空格串:由一个或多个空格组成的串,与空串不同。
- 串相等:当且仅当两个串的长度相等并且各个对应位置上的字符都相同。所有的空串是相等的。
- 模式匹配算法
- 目的:确定主串中所含子串(模式串)第一次出现的位置(定位)。
- 应用
- 搜索引擎
- 拼写检查
- 语言翻译
- 数据压缩
- 种类
- BL算法:简单匹配算法。采用穷举法的思路
- KMP算法
②数组
- 特殊矩阵的压缩存储
- 矩阵的常规存储:将矩阵描述为一个二维数组。
- 矩阵的常规存储的特点:
- 可以对其元素进行随机存取;
- 运算非常简单;
- 存储密度为1。
- 不适宜常规存储的矩阵:
- 值相同的元素很多且呈某种规律分布;
- 零元素多。
- 矩阵的压缩存储:
- 为多个相同的非零元素只分配一个存储空间;
- 对零元素不分配空间。
- 矩阵的压缩:若多个数据元素的值相同,则只分配一个元素值的存储空间,且零元素不占存储空间。
- 对称矩阵
- 三角矩阵
- 稀疏矩阵
③广义表
- 定义:n≥0个元素a0,a1,……,an-1的有限序列,其中每一个ai或者是原子,或者是一个广义表。
- 性质
- 广义表中的数据元素有相对次序;一个直接前驱和一个直接后继。
- 广义表的长度定义为最外层所包含元素的个数。
- 广义表的深度定义为该广义表展开后括号的重数。
- 广义表可以为其他广义表共享。
- 广义表可以是一个递归的表。
- 广义表是多层次结构,可以是单元素,也可以是子表,而子表的元素还可以是子表。
- 基本运算
- 求表头
- 求表尾
(二)、非线性结构
一个结点可能有多个直接前趋和直接后继。
1、树
2、图
三、基本的数据处理技术
(一)、查找技术
(二)、排序技术
总结
提示:这里对笔记进行总结
- 概念性强、抽象
- 算法灵活、不易掌握
- 逻辑性强、算法设计很烧脑