青岛大学-王卓 数据结构与算法基础
内容目录
文章目录
第一周
1.0前言
程序=数据结构+算法
- 数据结构的基本概念(第一章绪论)
- 基本的数据结构
- 线性结构
* 线性表(第二章)
* 栈和队列(第三章)- 串(第四章)
- 数组和广义表(第四章)
- 非线性结构
- 树(第五章)
- 图(第六章)
- 基本的数据处理技术
- 查找技术(第七章)
- 排序技术(第八章)
数据结构在计算机中起承上启下的作用、核心地位
怎么学好这门课程
- 勤于思考
- 多做练习
- 多上机
- 善于寻求帮助
- 不怕困难,不放弃
1.1数据结构的研究内容
通常用计算机解决一个问题的步骤
- 具体问题抽象为数学模型
- 分析问题
- 提取操作对象
- 找出操作对象之间的关系
- 用数学语言描述==数据结构
- 设计算法
- 编程,调试,运行
一对一(信息表) 线性表
一对多(棋盘、文件系统) 树形结构
地图求最短路径 网状结构、图
描述非数值计算问题的数学模型不是数学方程,而是诸如表、树、图之类的具有逻辑关系的数据
数据结构是一门研究非数值计算的程序设计中的操作对象以及他们之间的关系和操作的学科
1.2基本概念和术语1
1.数据
- 是能输入计算机且能被计算机处理的各种符号
- 信息的载体
- 是对客观事物符号化的表示
- 能够被计算机识别,存储和加工
- 包括
- 数值类型的数据
- 非数值类型的数据:文字,图像等
2.数据元素
- 是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理
- 也简称为元素,记录,结点或顶点
- 一个数据元素可由若干个数据项组成
- 与数据的关系:是集合的个体
3.数据项
- 构成数据元素的不可分割的最小单位
数据、数据元素、数据项之间的关系:
数 据 > 数 据 元 素 > 数 据 项 数据>数据元素>数据项 数据>数据元素>数据项
例:学生表>个人记录>学号、姓名
4.数据对象
- 是性质相同的数据元素的集合,是数据的一个子集。
5数据结构
- 数据元素不是孤立存在的,他们之间存在着某种关系,数据元素相互之间的关系称为结构
- 是指相互之间存在一种或多种特定关系的数据元素集合
- 数据结构是带结构的数据元素的集合
数据结构包括以下三个方面的内容
- 数据元素之间的逻辑关系:逻辑结构
- 描述数据元素之间的逻辑关系
- 与数据的存储无关,独立于计算机
- 是从具体问题抽象出来的数学模型
- 数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或数据的存储结构
- 数据元素及其关系在计算机存储器(存储方式)
- 是数据结构在计算机中的表示
- 数据的运算和实现,即对数据元素可以施加的操作以及这些操作在相应的存储结构上的实现
逻辑结构与存储结构的关系:
- 存储结构是在逻辑关系的映像与元素本身的映像
- 逻辑结构是存储结构的抽象,存储结构是逻辑结构的实现
- 两个综合起来建立了数据元素的之间的结构关系
逻辑结构的种类
划分方式一:
线性结构
有且仅有一个开始和一个终端结点,并且所有结点都最多只有一个直接前趋和一个直接后继
例如:线性表、栈、队列、串
非线性结构
一个结点可能有多个直接前趋和直接后继
例如:树、图
划分方式二——四类基本逻辑结构
- 集合结构:结构中的数据元素之间除了同属于一个集合的关系外,无任何其他关系
- 线性结构:结构中的数据元素的之间的存在着一对一的线性关系
- 树形结构:结构中的数据元素之间存在着一对多的任意关系
- 图状结构或网状结构:结构中数据元素之间存在着多对多的任意关系
存储结构的种类
四种基本的存储结构
- 顺序存储结构
- 用一组连续的存储单元依次存储数据元素,数据元素之间的逻辑关系由原元素的存储位置来表示(数组)
- 链式存储结构*
- 用一组任意的存储单元存储数据元素,数据元素之间的逻辑关系用指针来表示(指针链表)
- 索引(index)存储结构
- 在存储结点信息的同时,还建立附加的索引表
- 散列存储结构
- 根据结点的关键字直接计算出该结点的存储方式(用于查找算法)
1.2基本概念和术语2
数据类型和抽象数据类型
- 必须对程序中出现的每个变量、常量、表达式说明他们所属的数据类型
- 高级语言中数据类型被明显或隐含地规定了可能的取值范围,以及在这些数值范围上所允许进行的操作
- 数据类型的作用
- 约束变量或常量的取值范围
- 约束变量或常量的操作
- 数据类型
- 值的集合
- 值集合上的一组操作
- 抽象数据类型(Abstra Data Type,ADT)
- 是指一个数学模型以及定义在此数学模型上的一组操作
- 由用户定义,从问题抽象出数据类型(逻辑结构)
- 还包括定义在数据模型上的一组抽象运算(相关操作)
- 不考虑计算机内的具体存储结构与运算的具体实现算法
抽象数据类型的形式定义
-
抽象数据类型可用(D,S,P)三元组表示。
-
D是数据对象
-
S是D上的关系集
-
P是对D的基本操作集
-
参数表
- 赋值参数 只为操作提供输入值
- 引用参数 以&打头,除可提供输入值外,还将返回操作结果
例如:scak(&G,n),返回G的结果
-
初始条件:操作前数据结构和参数应满足条件,若不满足,则失败,并返回出错信息。若初始条件或空,则省略
-
操作结果:说明操作正常完成,数据结构的变化状况和应返回的结果
1.3抽象数据类型的表示与实现
一个问题抽象为一个抽象数据类型后,仅是形式上的抽象定义,还没达到问题解决的目的,要实现这个目标,就要把抽象的变为具体的,即抽象数据类型在计算机上实现,变为一个能用的具体的数据类型
- 抽象数据类型可以通过固有的数据类型来表示和实现
- 即利用处理器中已存在的数据类型来说明新的结构,用已经实现的操作来组合新的操作
- 采用类C语言作为描述工具
1.4算法和算法分析1
- 算法的定义
- 对特定问题求解方法和步骤的一种描述,它是指令的有限序列,其中每个指令表示一个或多个操作
- 简而言之,算法就是解决问题的方法和步骤
- 算法的描述
- 自然语言:中英文等
- 流程图:传统流程图,NS流程图
- 伪代码:类语言:类C语言
- 程序代码:C语言程序、JAVA语言程序
- 算法与程序
- 算法是解决问题的一种方法或一过程,考虑如何将输入转换成输出,一个问题可以有多种算法
- 程序是用某种程序设计语言对算法的具体实现。
- 程序=数据结构+算法
- 数据结构通过算法实现操作
- 算法根据数据结构设计程序
- 算法特性
- 有穷性
- 确定性
- 可行性
- 输入
- 输出
- 算法设计的要求
- 正确性
- 可读性
- 健壮性
- 高效性
1.4算法和算法分析2
-
算法分析
-
一个算法首先要具备四个设计要求都满足的情况下,主要考虑算法的效率,通过算法的效率高低来评判不同算法的优劣程度
-
算法效率以下两个方面来考虑
- 时间效率:算法所消费的时间
- 空间效率:算法执行过程中所消耗的存储空间
-
算法时间效率的度量
- 事后统计
- 实验结果依赖于计算机的软硬件等环境因素,掩盖算法本身的优劣
- 事前分析
- 对算法所消耗资源的一种估算方法
- 算法运行时间=一个简单操作所需的时间*简单操作次数
- 也即算法中每条语句的执行时间之和
- 假设执行每条语句的所需的时间均为单位时间,此时对算法的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数,即频度之和了
- 算法的渐进时间复杂度
- 一般情况下,不必计算所有操作的执行次数,而只考虑算法中的基本操纵执行的次数,它是问题规模n的某个函数,用T(n)表示
- 算法中基本语句重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作:T(n)=O(f(n))
- 它表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称渐进时间复杂度
- 事后统计
1.4算法和算法分析3
分析算法时间复杂度的基本方法
- 定理一:忽略所有低次幂项和最高次幂系数,体现增长率的含义
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取其数量级用符号”O“表示
1.4算法和算法分析4
有些情况下,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同
- 最坏时间复杂度:最坏情况下,算法时间复杂度
- 平均时间复杂度:所有可能输入实例在等概率出现的情况下,算法的期望运行时间
- 最好时间复杂度:最好情况下,算法的是时间复杂度
第二周
2.1线性表的定义和特点
线性表
线性表是具有相同特性的数据元素的一个有限序列
线性起点 > 线性终点
线性表的逻辑特征是:
- 在非空的线性表,有且仅有一个开始结点a1,它没有直接钱趋,而仅有一个直接后继a2
- 有且仅有一个终端结点an,它没有直接后继,而仅有一个直接前趋,an-1
- 其余的内部结点ai(2<=i<=n-1)都有且仅有一个前趋ai-1和一个直接后继ai+1
线性表是一种典型的线性结构
2.2案例引入
一元多项式的运算(加,减,乘)
- 可以利用数组下标存储每一项的系数和次数、
- 将次数相同的系数做运算
稀疏多项式
会造成存储空间的浪费
顺序存储结构存在问题
- 存储空间分配不灵活
- 运算的空间复杂度高
- 所以可以存储链式结构
图书信息管理系统
功能
- 查找
- 插入
- 删除
- 修改
- 排序
- 计数
总结
- 线性表中数据元素的类型可以为简单类型,也可以为复杂类型
- 许多实际应用问题所涉的基本操作有很大相似性,不应为每个具体单独写一个程序
- 从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作
2.3线性表的类型定义
- lnitList(&L)
- 操作结构:构造一个空的线性表L
- DesToryList(&L)
- 初始条件:线性表L已经存在
- 操作结果:销毁线性表L
- ClearList(&L)
- 初始条件:线性表L已经存在
- 操作结果:将线性表L重置为空表
- ListEmpty(L)
- 初始条件:线性表L已经存在
- 操作结果:若线性表L为空表,则返回TURE;否则返回FAlSE
- ListLength(L)
- 初始条件:线性表L已经存在
- 操作结果:返回线性表L中的数据元素的个数
- GetElem(L,i,&e)查找
- 初始条件:线性表L已经存在,1<=i<-ListLength(L)
- 操作结果:用e返回线性表L中第i个数据元素的值
- LocateElem(L,e,compare())定位
- 初始条件:线性表L已经存在,compare()是数据元素判定函数
- 操作结果:返回L中第1个与e满足compare()的数据元素的位序,若这样的数据元素不存在则返回值为0
- PriorElem(L,cur_e,&pre_e)
- 初始条件:线性表L已经存在
- 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回他的前驱,否则操作失败;pre_e无意义
- NextElem(L,cur_e,&next_e)
- 初始条件:线性表L已经存在
- 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回他的后继,否则操作失败;next_e无意义
- ListInsert(&L,i,e)
- 初始条件:线性表已经存在,1<=i<=Listlength(L)+1
- 操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加一
- ListDlelete(&L,i,e)
- 初始条件:线性表已经存在,1<=i<=Listlength(L)
- 操作结果:删除L的第i个数据元素,并并用e返回其值,L的长度减一*
2.4线性表的顺序表示和实现1
线性表的顺序表示又称为顺序存储结构和顺序映像
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构
线性表的第一个数据元素a1的存储位置,称作线性表的起始位置或基地址
2.5线性表的顺序表示和实现2
顺序表的特点:以物理位置相邻表示逻辑关系,任一元素均可随机存取(优点)
2.4.1线性表的顺序存储表示
逻辑位序和物理位序相差1
2.4.2顺序表基本操作的实现
顺序表的查找
- 在线性表L中查找与指定值e相同的数据元素的位置
- 从表的一端开始,逐个进行记录的关键字和给定值的比较,找到,返回该元素的位置序号,未找到,返回0
顺序表的插入
- 线性表的插入运算是指在表的第i(1<=i<=n+1)个位置上,插入一个新结点e,使长度为n的线性表变为长度为n+1的线性表
- 从表的一端开始,逐个进行记录的关键字和给定值的比较,找到,返回该元素的位置序号,未找到,返回0
2.6类c语言有关操作补充1
- ElemType:非固定数据类型,在什么情况下则是什么数据类型
- 数组分配
- 静态分配:data[MaxSize];首元素存放地址[0]
- 动态分配: *data;也可以表示数组,定义的数组开始的地址
- malloc(m)函数,开辟m字节长度的地址空间,并返回这段空间的首地址
- sizeof(x)运算,计算变量x的长度
- free(p)函数,释放指针p所指变量的存储空间,即彻底删除一个变量(需要头文件<stdlib.h>)
- C++的动态分配
- new 类型名T(初值列表)
- 功能:申请用于存放T类型对象的内存空间,并依初值列表赋以初值结果值(new类型,(类型后可跟内存空间大小)出来的是一个地址,所以我们要将其赋给指针变量)
- delete指针P:释放指针P所指向的内存,P必须是new操作的返回值
- 函数调用时传送给形参表的实参必须与形参三个一致
- 类型
- 个数
- 顺序
- 参数传递有两种方式
- 传值方式(参数为整型、实型、字符型等)
- 把实参的值传送给函数局部工作区相应的副本中,函数使用这个副本执行必要的功能。函数修改的是副本的值,实参的值不变
- 传地址
- 参数为指针变量
- 参数为引用类型
- 参数为数组名
- 传递的是数组的首地址
- 对形参数组所作的任何改变都将反映到实参数组中
- 形参变化影响实参
- 换门牌(人不换)
- 传值方式(参数为整型、实型、字符型等)
- 引用:它用来给一个对象提供一个替代的名字(也可以想象成地址)
- 相当于给变量取外号或者小名,任何名字的值发生改变时,都将发生改变
- 传递引用给函数与传递指针的效果是一样的,形参变化实参也发生变化
- 引用类型作形参,在内存中并没有产生实参的副本,它直接对实参操作;而一般变量作参数,形参与与实参就占用不同的存储单元,所以形参变量的值是实参变量的副本。因此,当参数传递的数据量较大时,用引用比用一般变量传递参数的时间和空间效率都好
- 指针参数虽然也能达到与使用引用的效果,但在被掉函数中需要重复使用”指针变量名“的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须使用变量的地址作为实参