当前位置: 首页 > news >正文

数据结构与算法:绪论和线性表

本笔记来源于青岛大学王卓老师的《数据结构与算法》,是看87师兄转载的视频。
王卓《数据结构与算法》,有些内容是根据王卓老师的原话,有些是根据自己的理解总结概括的,全程用花费2-3周手打出,尽管检查了多遍,但难免有些因为检查不到位而出现的错误。而且有些因为语雀崩溃丢失了一些,后来花时间补了一点,但也有顾及不到的地方。

引入:

凭借一句话获得图灵奖的Pascal语言之父——Nicaklaus Wirth,让他获得图灵奖的这句话就是他提出的著名公式: “程序=数据结构+算法”,这个公式展示了程序的本质。

课程知识结构体系——这门课程是什么?
在这里插入图片描述
数据结构的重要性——这门课程重要吗?

数据结构是计算机软件相关专业的专业基础课
在教学计划种的地位:核心、承上启下的课程。
在这里插入图片描述

数据结构是介于数学、计算机硬件和计算软件三者之间的一门核心课程。
在这里插入图片描述

类似于武术中的“练功”科目:“练武不练功,到头一场空”
考研:必考专业课,四门专业课,共150分,《数据结构和算法》占45分(更有很多多学校只考数据结构和算法)。
找工作:面试时最主要核心内容

第一章 绪论

1.1、数据结构的研究内容

1.1.1、数据结构的核心

怎么定义数据结构的?总括的一个过程

在这里插入图片描述

1.1.2、什么是数据结构?

从历史阶段数据结构的实际例子当中引入数据结构的概念

数值计算

早期,计算机主要用于数值计算
例1、求解梁架结构中的应力。
在这里插入图片描述

例2、预报人口增长情况。
在这里插入图片描述

首先,分析问题、提取操作对象。然后,找出操作对象之间的关系,用数学语言加以描述,建立相应的数学方程。最后,求解数学方程:高斯消元法、有限元法、差分法。。。。
特点:数据元素间的关系简单,计算复杂。
——————————————————————————————————————————————

非数据计算。

随着计算机应用领域的扩展,计算机被越来越多地用于非数据计算。

例1、学生学籍管理系统

在这里插入图片描述

操作对象:每位学生的信息(学号、姓名、性别、籍贯,专业等)。
操作算法:查询、插入、修改、删除等。
操作对象之间的关系:线性关系
数据结构:线性数据结构、线性表。
类似的的还有图书管理系统、人事管理系统、仓库管理系统、通讯录等。
操作对象:若干行数据记录。
操作算法:查询、插入、修改、删除等。
操作对象之间的关系:线性关系
数据结构:线性数据结构、线性表。

例2 人机对弈问题。井字棋

在这里插入图片描述

之所以能对弈:策略已经输入计算机,可以根据当前棋盘格局,来预测棋局发展趋势,甚至最后结局。
计算机的操作对象:各种棋局状态,即描述棋盘的格局信息。
计算机的算法:走棋,即选择一种策略使棋局状态发生变化(由一个格局派生出另一个格局)。
操作对象之间的关系:非线性关系、树。 另一个树的例子。
文件系统的系统结构图
磁盘根目录下有很多子目录以及文件,每个子目录里游可以包含多个子目录以及文件,但每个字目录只有一个父目录,依此类推。
在这里插入图片描述

本问题是一种典型的树型结构问题,数据与数据成一对多的关系,是一种典型的非线性关系结构——树形结构。

例3、地图导航——求最短路径(最快路径)

引出图的概念
在这里插入图片描述

综上所述
这些问题的共性是都无法用数学的公式或方程来描述,是一些 "非数值计算”的程序设计问题。
描述非数值计算问题的数学模型不是数学方程,而是诸如之类的具有逻辑关系的数据。
数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及他们之间的关系操作的学科。
要想有效地使用计算机,就必须学习数据结构。

1.2、基本概念和术语

1.2.1、数据、数据元素、数据项和数据对象

在这里插入图片描述

数据
是能够输入计算机能被计算机处理的各种符号的集合
● 信息的载体
● 是对客观事实符号化的表示
● 能够被计算机识别、储存和加工
包括:
数值型的数据:整数、实数等。
非数值型的数据:文字、图像、图形、声音等。

数据元素

是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
也称为元素,或称为记录、结点或顶点。
在这里插入图片描述
在这里插入图片描述

数据项

构成数据元素的不可分割的最小单位
在这里插入图片描述

数据、数据元素、数据项三者之间的关系:

数据>数据元素>数据项

在这里插入图片描述


数据对象

性质相同数据元素的集合,是数据的一个子集。
在这里插入图片描述

数据元素、数据对象与数之间的关系

数据元素与数据的关系:是集合的个体
数据元素与数据的关系:集合的子集

1.2.2、数据结构(Data Structure)

数据结构

数据元素不是孤立存在的,他们之间存在着某种关系,数据元素相互之间的关系称为结构。
是指相互之间存在一种或多种特定关系的数据元素集合。
或者说,数据结构是带结构数据元素的集合。

数据结构包括以下三个方面的内容:

1、数据元素之间的逻辑关系,也成为逻辑关系
2、数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或者数据的储存结构
3、数据的运算和实现,即对数据元素可以施加的操作以及着些操作在相应的储存结构上的实现。


数据结构的两个层次
逻辑结构

● 描述数据元素之间的逻辑关系
● 与数据的存储无关,独立于计算
● 是从具体问题抽象出的数学模型

物理结构(存储结构)

● 数据元素及其关系在计算机存储器中的结构(存储方式)
● 是数据结构在计算机中的表示

逻辑结构与存储结构的关系

● 存储结构是逻辑关系的映像与元素本身的映像。
● 逻辑结构是数据结构的抽象,存储结构是数据结构的实现。
● 两者综合起来建立了数据元素之间的结构关系。


逻辑结构的种类
划分方法一

1、线性结构:有且只有一个开始和一个终端节点,并且所有结点都最多只有一个直接前趋和一个直接后继。 例如:线性表、战队列、串。
在这里插入图片描述

2、非线性结构:一个结点可能有多个直接前趋和直接后继。 例如:树、 图。
在这里插入图片描述

划分方式二——四类基本逻辑结构

在这里插入图片描述

1、集合结构:结构中的数据元素之间除了同属于一个集合的关系外,无任何其他关系。
2、线性结构:结构中的数据元素之间存在着一对一的线性关系。
3、树形结构:结构中的数据元素之间存在着一对多的层次关系。
4、图状结构或网状结构:结构中的数据元素之间存在着多对多的任意关系。


存储结构的种类(四种基本的存储结构)

在这里插入图片描述

顺序存储结构:

● 用一组连续的存储单元依此存储数据元素,数据元素之间的逻辑关系由元素的存储位置来表示。
● C语言中用数组来实顺序存储结构

在这里插入图片描述

注解:在前面的元素就存储在前面(比如bat在前面就存在前面),在后面的元素存储在后面(比如eat在后面就存在后面),中间的就存在中间。

链式存储结构:

● 用一组任意的存储单元存储数据元素,数据元素之间的逻辑关系用指针来表示。
● C语言中用指针来实现链式存储结构。
在这里插入图片描述

注解:怎么保证就是访问的时候就是以(bat、cat、eat,…,mat)这样的呢?存储的时候既存储了前一个元素本身,又存储了下一个元素的地址,这样访问的时候就能保证是(bat、cat、eat,…,mat)这样的,而不是其他样子了。前一个的值+下一个值的地址体会这样的思想,能够把这个和那个区分开来,尤其是在所含元素相同的情况下

索引存储结构:

● 在存储结点信息的同时,还建立附加的索引表
● 索引表中的每一项称为一个索引项
● 索引项的一般形式是:(关键字,地址
● 关键字是能唯一标识一个结点的哪些数据项。
● 若每个结点在索引表中都有一个索引项,则该索引表称之为稠密索引(Dense Index)。若一组结点在索引表中只对应一个索引项,则该索引表称为为稀疏索引(Sparse Index)。
在这里插入图片描述

散列存储结构:

● 根据结点的关键字直接计算出该结点的存储地址。
在这里插入图片描述

1.2.3、抽象类型和抽象数据类型

引入概念:

● 在使用高级程序设计语言编写程序时,必须对程序中出现的每个变量、常量或表达式,明确说明他们所属的数据类型
在这里插入图片描述

● 一些最基本的数据结构可以使用数据类型来实现,如数组、字符串等;
● 而另一些常用的数据结构,如栈、队列、树、图等,不能直接用数据类型来表示。
● 高级语言中的数据类型明显地或隐含地规定了在程序执行期间的变量和表达中所有可能的取值范围,以及在这些数值范围上所允许进行的操作。
在这里插入图片描述

● 数据类型的作用:约束变量和常量的取值范围和约束变量和常量的操作

数据类型(Data Type)

● 定义:数据类型是一组性质相同的值的集合以及定义这个值集合上的一组操作的总称。
在这里插入图片描述

抽象数据类型(Abstract Data Type,ADT)

抽象:抽象是从众多的事物中抽取出共同的本质性的特征,而舍弃其非本质的特征的过程。具体地说,抽象就是人们在实践的基础上,对于丰富的感性材料通过去粗取精、去伪存真、由此及彼、由表及里的加工制作,形成概念、判断、推理思维形式,以反映事物的本质和规律的方法。
在这里插入图片描述

定义抽象数据类型是指一个数学模型以及定义在此数学模型上的一组操作。包括:以下三部分
● 由用户定义,从问题抽象出数据模型(逻辑结构)
● 还包括定义早期数据模型上的一组抽象运算(相关操作)
● 不考虑计算机内的具体存储结构与运算的具体实现算法。
形式定义:(比较严谨的定义)
在这里插入图片描述

定义格式
在这里插入图片描述

其中:数据对象、数据关系的定义用伪代码描述。基本操作的定义格式为:
在这里插入图片描述

基本操作定义格式说明
参数表:赋值参数 只为操作提供输入值。引用参数 以&打头,除课提供输入值外,还将返回操作结构。
初始条件:描述操作执行之前数据结构和参数应满足的条件,若部满足,则操作失败,并返回相应出错信息。若初始条件为空,则省之。
操作结果:说明操作正常完成之后,数据结构的变化状况和应返回的结果。
抽象数据类型(ADT)定义的举例:Circle的定义
在这里插入图片描述

问题描述:在高级语言中,没有复数类型,但是可以借助已有的数据类型解决复述类型的问题。
在这里插入图片描述

Complex抽象数据类型的基本操作:
在这里插入图片描述

概念小结:(1.1-1.2内容总结)

在这里插入图片描述

1.3、抽象数据类型的表现与实现

1.3.1、抽象数据类型的表现

抽象数据类型怎么定义呢?它有它的固定格式。
在这里插入图片描述

一个问题抽象为要给抽象数据类型后,仅是形式上的抽象定义,还没有达到问题解决得目的,要实现这个目标,就要把抽象的变成具体的,即抽象数据类型在计算机上实现,变成一个能用的具体的数据类型。

1.3.2、抽象数据类型的实现

在这里插入图片描述

抽象数据类型可以通过固有的数据类型(如整形、实型、字符型等)来表示和实现。即利用处理器中已存在的数据类型来说说明新的结构,用已经实现的操作来组合新的操作。
在本课程的学习过程中,我们使用的类C语言(介于伪码和C语言之间)作为描述工具。其描述见教材P10-11。但是上机时要用具体语言实现,如C或C++等
在这里插入图片描述

例如:抽象数据类型“复数”的实现

在这里插入图片描述

注:

Complex是我们定义的一个结构类型
带*:指针变量,它是指向Complex类型的指针。
不带*:Complex类型的普通变量。

求下列表达式的值
在这里插入图片描述

注解:add(z1,z2,z3):意思式把复数z1和复数z2相加后的值放到z3里面。后面multiply()同理。

1.4、算法和算法分析

在这里插入图片描述

1.4.1、算法的定义:

对于特定的问题求解方法步骤的一种描述,它式指令的有限序列。其中每个指令表示一个或多个操作。
在这里插入图片描述

——————————————————————————————————————————————

1.4.2、算法的描述:

自然语言:英语、中文
在这里插入图片描述

流程图:传统流程图、NS流程图
在这里插入图片描述

伪代码:类语言:类C语言
程序代码:C语言程序、Java语言程序…
——————————————————————————————————————————————

1.4.3、算法与程序:

算法:是解决问题的一种方法或一个过程,考虑如何将输入转换成输出,一个问题可以有多种算法。
程序:是用某种程序设计语言对算法的具体操作。
在这里插入图片描述

——————————————————————————————————————————————

1.4.4、算法特性:

一个算法必须具备以下5个重要特性。
有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。
确定性:算法中的每一条指令必须有确切的含义,没有二义性,在任何条件下,只有唯一的一条执行路径,即对于相同的输入只能得到相同的输出。
可行性:算法是可执行的,算法描述的操作可以通过已经实现的基本操作执行有限次来实现。
输入:一个算法有零个或多个输入。
输出:一个算法有一个或多个输出。
——————————————————————————————————————————————

1.4.5、算法设计的要求:

正确性(Correctness)
在这里插入图片描述

可读性(Readability):站在人阅读交流的角度制定的要求
在这里插入图片描述

健壮性(Robustness)
在这里插入图片描述

高效性(Efficiency)
在这里插入图片描述

对于同一个问题,可以有许多不同的算法。究竟如何来评价这些算法的优劣程序呢?———————算法分析

1.4.6、算法分析:

算法分析的目的是看算法实际是否可行,并在同一问题存在多的算法时可进行性能上的比较,以便从中挑选出比较优的算法。
一个好的算法首先要具备正确性、然后时健壮性、可读性、在几个方面都满足的情况下,主要考虑算法的效率,通过算法的效率高低来评判不同算法的优劣程度。算法效率考虑以下2个方面:
时间效率:指的时算法所耗的时间;
空间效率:指的时算法执行过程所耗费的村春空间。
有时候两者存在矛盾,这个要视具体情况综合评定。
——————————————————————————————————————————————

1.4.7、算法时间效率的度量

算法时间效率可以依据该算法编制的程序在计算机上执行所消耗的时间来度量。有以下2种度量方法。
事后统计:将算法实现,测算其时间和空间的开销。其缺点是:编写程序实现算法将花费较多的时间和精力;所得实验结果依赖于计算机的软硬件等环境因素,掩盖算法本身的优劣。
事前分析:对算法所消耗资源的一种估算方法
事前分析方法:
一个算法的运行时间是指一个算法在计算机上运行所消耗的时间大致可以等于计算机执行一种简单的操作(如赋值、比较、移动等)所需要的时间与算法种进行的简单操作次数乘积。简单概括为以下公式。

算法运行时间=一个简单操作所需的时间x简单操作次数
也即算法种每条语句的执行时间之和 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/cac448e66b594a5190bb31439ab9ada1.png)

每条语句执行一次所需要的时间,一般是随机器而异的。取决于机器的指令性能、速度以及编译的代码质量。是由机器本身软硬件环决定的,它于算法无关。所以,我们可以假设执行每条语句所需要的时间均为单位时间。此时对算法的运行时间的讨论就可以转换为讨论算法中所有语句的执行次数,即频度之和了。这就可以独立于不同机器的软硬件环境分析算法的实际爱你性能了。
——简化来讲,每条语句执行一次所需要时间由计算机软硬件决定,它与算法无关,所以就把其时间化为单位时间“1”来看,所以上面公式就为“算法运行时间=每条语句频度x1,看算法运行时间就看每条语句频度就行了。
例如:两个nxn矩阵相乘的算法可描述为:
在这里插入图片描述

我们把算法所耗费的是时间定义为该算法每条语句的频度之和,则上述算法的时间消耗T(n)为:
在这里插入图片描述

为了便于比较不同算法的时间效率,我们仅比较它们的数量级数量级越大的越不好
在这里插入图片描述

若某个辅助函数f(n),使得当n趋近于+∞时,T(n)/f(n)的极限值为不等于0的常数,则称f(n)是T(n)的同量级函数。记作T(n)=O(f(n)),称为O(f(n))为算法的渐进时间复杂度(O是数量级的符号),简称时间复杂度

对于求解矩阵相乘问题,算法耗费时间:
在这里插入图片描述

n ->∞时,T(n)/n3 ->2,这表示n充分大时,T(n)与n3n^3n3是同阶或同数量,引入大“O”记号,则T(n)可记作:
T(n)=O(n3)T(n) = O(n^3)T(n)=O(n3)
这个公式就是求解矩阵相乘问题的算法渐进时间复杂度。
一般情况下,不必计算所有操作的执行次数,而只考虑算法中的基本操作执行的次数,它就是规模n的某个函数,用T(n)T(n)T(n)表示。

1.4.8、算法时间复杂度定义

算法中基本语句重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作:T(n)=O(f(n))T(n) = O(f(n))T(n)=O(f(n))
T(n)=O(f(n))T(n) = O(f(n))T(n)=O(f(n))表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称为渐进时间复杂度。
基本语句重复执行的次数:
(1)算法中重复执行次数和算法中执行时间成正比的语句。
(2)对算法运行时间的贡献最大。
(3)执行次数最多。
问题规模n:n越大算法的执行时间越长
(1)排列:n为记录数
(2)矩阵:n为矩阵的阶数
(3)多项式:n为多项式的项数
(4)集合:n为元素个数
(5)树:n为数的结点个数
(6)图:n为图的顶点数或边数
在这里插入图片描述

1.4.9、分析算法算法时间的基本方法

定理1:若F(n)=amnm+...+a1n1+a0F(n) = a_mn^m + ... +a_1n^1 + a_0F(n)=amnm+...+a1n1+a0是m次多项式,则T(n)= O(nmn^mnm)。忽略所有的低次幂和最高次幂系数,体现出增长率的含义。
1、找出语句频度最大的那条语句作为基本语句。
2、计算基本语句的频度得到问题规模n的某个函数f(n)。
3、取其数量级用符号“O"表示。
例如:todo没有理解
在这里插入图片描述

1.4.10、算法时间复杂度分析(例题)todo

在这里插入图片描述

在这里插入图片描述

1.4.11、算法时间复杂度计算

请注意:有的情况下,算法中基本操作执行的次数还随问题输入输入数据集不同而不同。

在这里插入图片描述

最好的情况:1次。最坏的情况:n。平均时间复杂度为:O(n)。
最坏时间复杂度:指在最坏的情况下,算法的时间复杂度。
平均时间复杂度:指在所有可能输入实例在等概率出现的情况下,算法的期望运行时间。
最好时间复杂度:指在最好情况下,算法时间复杂度。
一般总是考虑在最坏的情况下的时间复杂度,以保证算法你运行时间不会比它更长。
对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则,计算算法的时间复杂度:
加法法则:
T(n)=T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n)))T(n) = T1(n) + T2(n) = O(f(n)) + O(g(n)) = O(max(f(n),g(n)))T(n)=T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n)))
乘法法则:
T(n)=T1(n)∗T2(n)=O(f(n))∗O(g(n))=O(f(n)∗g(n))T(n) = T1(n) * T2(n) = O(f(n)) * O(g(n)) = O(f(n)*g(n))T(n)=T1(n)T2(n)=O(f(n))O(g(n))=O(f(n)g(n))

1.4.12、算法时间效率的比较

当n取得很大时,指数时间算法和多项式时间算法在所需时间上非常悬殊。

在这里插入图片描述

时间复杂度T(n)按数量递增顺序为:
在这里插入图片描述

1.4.13、渐进空间复杂度

空间复杂度:计算你所需存储空间的度量,记作:S(n)=O(f(n))S(n) = O(f(n))S(n)=O(f(n))
其中n为问题的规模(或大小)。
算法本身要占据的空间,输入/输出,指令,常数,变量等
算法要使用的辅助空间。

1.4.14、算法空间复杂分析例题todo

例:将一个数组a中的n个数逆序存放到原数组中。
在这里插入图片描述

1.4.15、设计好算法的过程

在这里插入图片描述

第二章 线性表

知识回顾
在这里插入图片描述

2.1、线性表的定义和特点

2.1.1、引入概念:

线性表是具有相同特性的数据元素的一个有限序列。涉及到的概念有:起始结点(线性起点)、终端结点(线性终点)、数据元素、下标、空表、直接前趋、直接后继。
在这里插入图片描述

2.1.2、线性表(Linear List):

由n(n>=0)个元素的(结点)a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an组成的有限序列。
● 其中数据元素的个数n定义为表的长度。
● 当n=0时称为空表,注意列表是从a1a_1a1开始的。
● 将非空的线性表(n>0)记作:(a1,a2,...,ana_1,a_2,...,a_na1,a2,...,an
● 这里的数据元素ai(1<=i<=n)a_i(1<=i<=n)ai(1<=i<=n)只是一个抽象的符号,其具体含义在不同的情况下可以不同,见下例。

例1 :分析26个英文字母组成的英文表。
A、B、C、...、ZA、B、C、...、ZABC...Z)此英文表中数据元素都是字母,元素间关系是线性。
例2 :分析学生情况登记表
在这里插入图片描述

例3 :某单位历年拥有计算机的数量(6、17、28、50、92、188)
例4 :12星座(白羊、金牛、双子、巨蟹、狮子、处女、天秤、天蝎、射手、魔蝎、水瓶、双鱼)
总结:同一线性表中的元素必定具有相同特性,数据元素间的关系是线性关系。

2.1.3、线性表的逻辑特征:

从上例子可看出线性表的逻辑特征是:
● 在非空的线性表,有且仅有一个开始结点a1a_1a1,它没有一个直接前趋,而且仅有一个直接后继a2a_2a2
● 有且仅有要给终端结点an,它没有直接后继,而仅有一个直接前趋aaan-1;
● 其余的内容结点ai(2<=i<=n−1)a_i(2<=i<=n-1)ai(2<=i<=n1)都是有且仅有一个直接前趋aaan-1和一个直接后继aaai+1;
总结:线性表是一种典型的线性结构。

2.2、案例引入todo

2.2.1、一元多项式的运算:

一元多项式的运算:实现两个多项式加、减、乘运算
在这里插入图片描述

但是有些多项式并不是每一个项都有,如果按照前面这种存储方式,就会浪费很大的存储空间,那这样的多项式该怎么表示呢?特例——稀疏多项式
**在这里插入图片描述

2.2.2、稀疏多项式的运算

稀疏多项式的表示:解决方法式是再引入一个指标,在前面只用系数的基础上,加上一个指数这个指标描述,就能进行它们之间的运算了。用(系数,指数)表示

稀疏多项式的运算
在这里插入图片描述

第一步:稀疏多项式中提取系数和指数两个指标
线性表A=((7,0),(3,1),(9,8),(5,17))
线性表B=((8,1),(22,7),(-9,8))
第二步:
创建一个新数组c
分别从头遍历比较a和b的每一项
遵循规则:
● 指数相同:对应系数相加,若其和不为0,则在C中增加一个新项。
● 指数不相同:则将指数比较小的项复制到c中
一个多项式已遍历完毕时,将另一个剩余项一次复制到c中即可。
但数组c多大合适呢?分配多了浪费空间(比如按照多项式的和定义,线性表A有4项,线性表B有3项,共计7项,这些为0的项不占空间,就浪费空间),分配少了又怕装不下。 ——解决方法如下。
在这里插入图片描述

顺序存储结构存在问题:存储空间分配不灵活,运算的空间复杂度高。——>使用链式存储结构
多项式相加的优化——链式存储结构
在这里插入图片描述

2.2.3、图书管理系统

在这里插入图片描述

需要的功能:(1)查找 (2)插入 (3)删除 (4)修改 (5)排序 (6)计数
那么这些需要的功能怎么实现呢?也可以使用线性表来实现。
把图书表抽象为线性表,表中的每本图书抽象线性表中的数据元素。
怎么存储它呢?可以用顺序存储方式,也就是数组存储方式,也可以使用链式存储方式。但是那种存储方式比较好
呢?
在这里插入图片描述

● 选择适当的存储结构
● 实现此存储结构上的基本操作
● 利用基本操作完成功能
这样的图书信息管理系统可以这样处理,那么相类似的也可以,比如,教师管理系统,员工管理系统,商品管理系统等等。
总结:(以上三个案例的总结2.2.1-3)
● 线性表中数据元素的类型可以为简单类型,也可以为复杂类型。
● 许多实际应用问题所设计的基本操作有很大相似性,不应为每个具体应用单独编写程序。
● 从具体应用中抽象出共性的逻辑结构和基本操作(抽象数据类型),然后实现其存储结构和基本操作

2.3、线性表的类型定义

2.3.1、线性表的类型定义

抽象数据类型线性表的定义如下
在这里插入图片描述

2.3.2、基本操作(一)

1、初始化线性表 InitLIst(&L) (Initialization List)
操作结果:构造一个空的线性表L。
2、销毁线性表 DestroyList(&L)
初始条件:线性表L已经存在。
操作结果:销毁线性表L。(从内存中)
3、清除线性表 ClearList(&L)
初始条件:线性表L已经存在
操作结果:将线性表L重置为空表。(内存中线性表本身还存在,但是表中没有元素)

2.3.3、基本操作(二)

4、判断线性表是否为空 ListEmpty(L)
初始条件:线性表L已经存在。
操作结果:若线性表L为空(n=0),则返回TURE;否则返回为FALSE。
5、求线性表的长度 ListLength(L)
初始条件:线性表L已经存在。
操作结果:返回线性表L中的数据元素个数。

2.3.4、基本操作(三)

6、获取线性表中的元素 GetElem(L,i,&e);
初始条件:线性表L已经存在,1<= i <= ListLength(L)。
操作结果:用e返回线性表L中的第i个数据元素的值。
7、查找定位线性表中元素 LocateElem(L,e,compare())
初始条件:线性表L已经存在,compare()是数据元素判定函数。(compare()可判定这个元素x(x>e,x<e,x=e等等)取决于实际情况)
操作结果:返回L中第1个与e满足compare()的数据元素的位序。这样的数据元素不存在则返回值为0。

2.3.5、基本操作(四)

8、求线性表L中一个元素的前趋 PriorElem(L,cur_e,&pre_e)
初始条件:线性表L已经存在。
操作结果:若cur_e是线性表L的数据元素,且不是第一个,则pre_e返回它的前趋,否则操作失败,pre_e无意义。
9、求线性表L中一个元素的后继 NextElem(L,cur_e,&next_e)
初始条件:线性表L已经存在。
操作结果:若cur_e 是线性表L的数据元素,且不是第最后一个,则用next_e返回它的后继,否则操作失败,next_e无意义。

2.3.6、基本操作(五)

10、线性表中插入一个元素 ListInsert(&L,i,e)
初始条件:线性表L已经存在,1<=i<= ListLength(L) +1。(可以插在第一个位置,即i=1,也可以插入到最后一个位置,即n+1)。
操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加一。
插入元素e之前(长度为n):(a1,a2,...,a(a_1,a_2,...,a(a1,a2,...,ai-1,ai,...,an)a_i,...,a_n)ai,...,an)
插入元素e之后(长度为n+1):(a1,a2,...,a(a_1,a_2,...,a(a1,a2,...,ai-1,e,ai,...,an)a_i,...,a_n)ai,...,an)

2.3.7、基本操作(六)

11、删除线性表中的一个元素 ListDelete(&L,i,&e)
初始条件:线性表L已经存在,1<= i <= ListLenght(L)。
操作结果:删除线性表L的第i个数据元素,并用e返回其值,线性表L的长度减一。
删除前(长度为n):(a1,a2,...,a(a_1,a_2,...,a(a1,a2,...,ai-1ai,aa_i,aai,ai+1,...,an),...,a_n),...,an)
删除后(长度n-1):(a1,a2,...,a(a_1,a_2,...,a(a1,a2,...,ai-1,a,a,ai+1,...,an),...,a_n),...,an)
12、遍历(访问)线性表中每个元素 (&L,visited())
初始条件:线性表L已经存在
操作结果:依此对线性表中每个元素调用visited()。不管是干什么,是删除也好,插入也罢,但是要对线性表中的每个元素都要一个挨一个操作一遍。
总结:
以上所提及的运算是逻辑结构上定义的运算。只是给出这些运算的功能是“做什么”,至于“如何做”等实现细节,只有待确定了存储结构之后才考虑。
后续课程中将学习线性表的存储及在才存储结构上各种操作的实现。

2.4、线性表的顺序表示和实现

2.4.1、线性表的顺序存储表示

线性表的顺序表示又称顺序存储结构或顺序映像。
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
在这里插入图片描述

线性表的第1个数据元素a1a_1a1的存储位置,称作为线性表的起始位置或基地址。
顺序存储结构:
例如:线性表(1,2,3,5,6)的存储结构:
在这里插入图片描述

线性表顺序存储结构占用一片连续的存储空间。知道某个元素的存储位置就可以计算其他元素的存储位置。
顺序表中元素存储位置的计算:
在这里插入图片描述

如果每个元素占8个存储单元,ai存储位置是2000单元,则ai+1存储位置是? 2008单元
假设线性表的每个元素需占l个存储单元,则第i+1个数据元素的存储位置和第i个元素的存储位置之间满足关系:
LOC(ai+1) = LOC(ai) + l
由此,所有数据元素的存储位置均可由第一个数据元素的存储位置得到:
LOC(ai) = LOC(a1) + (i-1) * l (LOC(a1)为基地址)

2.4.2、线性顺序结构的图示:

在这里插入图片描述

顺序表的特点:以物理位置相邻表示逻辑关系。任一元素均可随机存取。(优点)
在这里插入图片描述

一维数组的定义方式:类型说明符 数组名[常量表达式]
说明:常量表达式中可以包含常量和符号常量,不能包含变量。即C语言中不允许对数组的大小动态定义。
此时就存在一个矛盾:需要线性表长可变(删除),但是数组长度不可动态定义。这时候该怎么办呢?———>用一个变量表示顺序表的的长度属性。定义模板如下:
在这里插入图片描述

2.4.3、多项式的顺序存储结构类型定义

在这里插入图片描述

怎么样定义这个线性表呢?定义例子如下:

在这里插入图片描述
在这里插入图片描述

2.4.4、补充:类C语言有关操作

2.4.4.1、补充:元素类型说明

顺序表类型定义
在这里插入图片描述

ElemType是什么?它代表的是线性表中元素的类型,这个元素的类型是什么类型,它就指什么类型的。如果里面存放的是‘a’,‘b’,'c’那ElemType就是Char类型;如果数组存放的是多项式系数,而系数是小数,那ElemType就是float类型。根据处理的问题具体情况而修改。如果不想修改,另一个办法是事先把这个类型定义一下。如下:
在这里插入图片描述

2.4.4.2、补充:数组定义

在这里插入图片描述

数组静态分配的我们知道,但是碰到数组动态分配的这种定义的方法就不太了解了?
第一种(左)数组的存储空间是静态分布的,我们定义在那儿定义数组之后,那里所占的空间就确定了,data[MaxSize]里面存放的是什么呢?是data[0]首元素的地址,也就是这个数组的的首地址或者基地址。既然里面是存放地址的,那第二种(右)数组可以用指针变量来定义,当这样定义之后,那么这样的数组有多大呢?我们就可以用内存动态分配的函数来分配内存,我们用有这样的一个顺序表类型,再用这样的顺序类型定义了一个变量L。
在这里插入图片描述

这个L就是我们的顺序表了,这个L就有两个成员,一个是ElemType *data,用来存放顺序表中的元素,还有一个就是L.length,存放我们当前的顺序表当中的个数。那怎么为这个动态的数组分配空间呢?我们就可以利用这样的分配函数就可以分配空间了。

2.4.4.3、补充:C语言的内存动态分配

在这里插入图片描述

malloc(m)函数,开辟m字节长度的地址空间,并返回这段空间的首地址。
注解:即老师说的,听了能够对概念有所启发的内容,但是这部分内容往往有些冗余,可能一个词语反复说好多遍,而且因为写笔记的人往往听力有些问题,再加上一些自己的理解不到位,有些笔记甚至是错误的,但这是值得的。
注解:通俗来讲,就是分配内存的,它的参数m要求是一个整数,也就是分配空间的字节数,总共需要多少个字节,所以要求参数是一个整数。
sizeof(x)运算,计算变量x的长度。
注解:sizeof(x)MaxSize这里面分配了多少个字节呢?我们要放MaxSize个元素,这个MaxSize可能是100,也可能是1000,根据需要。那么其中一个元素需要多大的空间呢?假设一个元素是8个字节,那么sizeof(ElemType)就写成8,sizeof(ElemType)MaxSize=1008=800,就写800。但是每个都需要我们算出来那就非常麻烦,所以有一个计算字节大小的运算,那就是sizeof(ElemType),sizeof(ElemType)可以计算一个变量,或者是计算一个类型,这个括号里面的参数ElemType既可以是类型,也可以是变量。如果这个类型是字符char型那么这里sizeof(ElemType)便是1,如果是整型int,在32位操作系统当中就是4个字节。就这样sizeof(ElemType)可以通过自己来计算。
注解:假设sizeof(ElemType)MaxSize=1008=800字节的空间,那么这800字节存什么东西,存200个整数,还是100实数呢?还是存系数,指数呢?到底是怎么划分?分成200个小空间,还是100个小空间?就要依靠前面的(ElemType
)来解决,是怎么划分的,是通过类型划分的,如果是char,一个元素1个字节,就划分为800/1=800个空间;如果是int,一个元素4个字节,就划分为800/4=200个空间。号是什么意思?是一个指针,要放到这个数组当中【L.data=(ElemType)malloc(sizeof(ElemType)MaxSize)】,数组【L.data】这个元素是什么东西呢?是首元素的地址【看前面定义ElemType data】,所以要转换成这个类型的指针,(ElemType)此出的"()"是强制类型转换。如果(int)那就强制转换成int,如果是(int)那就是强制转成指向整型的指针。这样就活得了后面一整大片【(ElemType*)malloc(sizeof(ElemType)*MaxSize)】的基地址,知道了基地址就可以对后面的元素操作了。
free§函数,释放指针p所指变量的存储空间,即彻底删除一个变量。
注解:这里讲得是分配内存,如果后面不需要了就可以释放掉,释放内存空间呢?用的就是free§函数。

使用这些动态分配函数的时候,要知道这些函数在哪里,就在<stdlib.h>,所以需要加载上上头文件:<stdlib.h>

2.4.4.4、补充:C++的动态存储分配

在这里插入图片描述

有时候也会借助C++语法,为什么?C++的语法可以让我们的算法写得更简短。有的同学会说好不容易把C的写法搞懂了,又怎么开始用C++的啦,这个遵循的原则是怎么方便怎么来,只要能够描述把算法描述清楚即可,也是C++的使得算法更简洁的这个优点,有些算法会用C++来表示。


文章转载自:

http://gUQYUoxg.dqbpf.cn
http://JaTrHRY2.dqbpf.cn
http://99vR30aK.dqbpf.cn
http://8iOwYffO.dqbpf.cn
http://H8aJzFST.dqbpf.cn
http://j3Mekrie.dqbpf.cn
http://RVCuAKF3.dqbpf.cn
http://Nj06a82Z.dqbpf.cn
http://y0GGMZLY.dqbpf.cn
http://voSfJYrS.dqbpf.cn
http://rxcqCoex.dqbpf.cn
http://8UhFdszZ.dqbpf.cn
http://It7G0QTG.dqbpf.cn
http://GOGKPEA9.dqbpf.cn
http://iH8CPYQr.dqbpf.cn
http://QWd0AtuE.dqbpf.cn
http://v2IHkeBs.dqbpf.cn
http://187oa3Py.dqbpf.cn
http://WqNq9C8w.dqbpf.cn
http://iS6uGZz2.dqbpf.cn
http://bLccxt0z.dqbpf.cn
http://9ns8fN06.dqbpf.cn
http://TUJZdd3z.dqbpf.cn
http://HTqhCdBN.dqbpf.cn
http://ktVrfx7f.dqbpf.cn
http://fFh8lDi0.dqbpf.cn
http://jCUWyJcT.dqbpf.cn
http://o36joiGg.dqbpf.cn
http://sRyaje2W.dqbpf.cn
http://LnU8ekkB.dqbpf.cn
http://www.dtcms.com/a/379490.html

相关文章:

  • ToDesk企业版高效助力睿尔博汽车信息服务!
  • 基于RFID技术的宠物自动喂食器方案
  • Java 异常体系全解析
  • Linux 系统资源负载控制脚本:CPU 内存一键管理(后台常驻版)
  • rook-ceph登录报错Invalid credentials
  • 《RocketMQ核心架构与实战解析》
  • C语言---常量
  • 豆包・图像创作模型 Seedream 4.0 正式发布!
  • OCSP(Online Certificate Status Protocol,在线证书状态协议)
  • 深度学习(六):代价函数的意义
  • 【lite.ai.toolkit】【深度学习】【Ubuntu 20.04】C++ 轻量级AI模型工具箱的编译、安装、使用教程
  • 远程创意协作新方式:cpolar助力Drawnix跨地域团队协作
  • 深入理解 Linux 内核进程管理
  • 企业跨区域组网新解:SD-WAN技术打造安全稳定网络体系
  • 单身杯2 web
  • 《Learning Langchain》阅读笔记12-RAG(8):RAG的优化策略
  • daily notes[43]
  • LRU缓存详解:用C语言实现高效数据管理
  • 灵码产品演示:软件工程架构分析
  • 硬件电路-陀机
  • swiper插件的使用
  • mysql的各种锁
  • Java大厂面试实录:AIGC与虚拟互动场景下的微服务与AI落地(附知识详解)
  • Kafka 学习笔记
  • 机械零件极限应力线图
  • 萤石安全生产监管解决方案:构建企业安全智能化防护网
  • sqlmap常用命令
  • MID认证:全球电力计量市场的通行证与中国协议兼容性分析
  • STM32开发(USART:IIC总线)
  • Spring框架中用到的设计模式