当前位置:   article > 正文

数据结构 第一章(绪论)

数据结构 第一章(绪论)

写在前面:

  1. 本系列笔记主要以《数据结构(C语言版)》为参考,结合下方视频教程对数据结构的相关知识点进行梳理。所有代码块使用的都是C语言,如有错误欢迎指出。
  2. 视频链接:第01周a--前言_哔哩哔哩_bilibili

一、数据结构的基本概念和术语

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

(1)数据(Data)是客观事物的符号表示,是所有能输入计算机中并被计算机程序处理的符号的总称,如数学计算中用到的整数和实数,文本编辑中用到的字符串,多媒体程序处理的图形、图像、声音及动画等通过特殊编码定义后的数据。

(2)数据元素(Data Element)是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理,用于完整地描述一个对象。在有些情况下,数据元素也称为元素、记录等。

(3)数据项(Data Item)是组成数据元素的、有独立含义的、不可分割的最小单位,例如学生基本信息表中的学号、姓名、性别等都是数据项。

(4)数据对象(Data Object)是性质相同的数据元的集合,是数据的一个子集。不论数据元素集合是无限集(如整数集),或是有限集(如字母字符集),还是由多个数据项组成的复合数据元素(如学生表)的集合,只要集合内元素的性质均相同,都可称之为一个数据对象。

2、数据结构

(1)数据结构(Data Structure)是相互之间存在一种或多种特定关系的数据元素的集合,换句话说,数据结构是带“结构”的数据元素集合,“结构”是指数据元素之间存在的关系。

(2)数据结构包括逻辑结构和存储结构两个层次,逻辑结构是数据结构的抽象,存储结构是数据结构的实现。

①逻辑结构:

        数据的逻辑结构是从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的,因此数据的逻辑结构可以看作从具体问题中抽象出来的数学模型。

        数据的逻辑结构有两个要素,一是数据元素,二是关系。根据数据元素之间关系的不同特性,数据的逻辑结构通常有4类基本逻辑结构:

        [1]集合结构:数据元素之间除了“属于同一集合”的关系外,没有其它关系。例如,确定一名学生是否为班级成员,只需将班级看作一个集合结构。

        [2]线性结构:数据元素之间存在一对一的关系。例如,将学生信息数据按照其入学报到的时间先后顺序进行排列,将组成一个线性结构。

        [3]树结构:数据元素之间存在一对多的关系。例如,在班级的管理体系中,班长管理多个组长,每位组长管理多名组员,从而构成树结构。

        [4]图结构或网状结构:数据元素之间存在多对多的关系。例如,多位同学之间的朋友关系,任何两位同学都可以是朋友,从而构成图结构或网状结构。

        线性结构有且仅有一个开始结点和一个终端结点,并且所有结点都最多只有一个直接前趋和一个直接后继,如线性表、栈、队列、串。集合结构、树结构和图结构都属于非线性结构,其特点是一个结点可能有多个直接前趋和多个直接后继。

②存储结构:

        数据对象在计算机中的存储表示称为数据的存储结构,也称为物理结构。把数据对象存储到计算机时,通常要求既要存储各数据元素的数据,又要存储数据元素之间的逻辑关系,数据元素在计算机内用一个结点来表示。

        数据元素在计算机中有两种基本的存储结构,分别是顺序存储结构和链式存储结构,还有两种相对使用较少的索引存储结构和散列存储结构。

        [1]顺序存储结构:用一组连续的存储单元依次存储数据元素,数据元素之间的逻辑关系由元素的存储位置表示。C语言中用数组类型来描述顺序存储结构。

        [2]链式存储结构:用一组任意的存储单元存储数据元素,数据之间的逻辑关系用指针表示。C语言中借助指针类型类描述链式存储结构。

        [3]索引存储结构:在存储结点信息的同时还建立附加的索引表,索引表中的每一项称为一个索引项,其一般形式为“(关键字, 地址)”,其中关键字是能唯一标识一个结点的数据项,通过地址能找到存储的具体结点信息。

        [4]散列存储结构:根据结点的关键字直接计算出该结点的存储地址。

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

1、数据类型

(1)在程序设计语言中,每一个数据都属于某种数据类型,类型明显或隐含地规定了数据的取值范围、存储方式以及允许进行的运算,数据类型是一个值的集合和定义在这个值集上的一组操作的总称。

(2)在使用高级程序语言编写程序时,必须对程序中出现的每个变量、常量或表达式,明确说明它们所属的数据类型。

2、抽象数据类型

(1)抽象数据类型(Abstract Data Type,ADT)一般指由用户定义的、表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称,具体包括3个部分——数据对象、数据对象上关系的集合以及对数据对象的基本操作的集合。

(2)抽象数据类型的定义格式如下:

ADT 抽象数据类型名

{

        数据对象:<数据对象的定义>

        数据关系:<数据关系的定义>

        基本操作:<基本操作的定义>

}ADT 抽象数据类型名

①在C语言中,基本操作常用自己编写的子函数实现,因为结构体中不能定义函数,而在C++中,基本操作可以用自己编写的子函数实现,也可以在定义的数据结构中实现,因为C++除了可以用结构体实现数据结构外,还可以用类实现数据结构,而类中可以定义函数。

②基本操作有两种参数:赋值参数只为操作提供输入值;引用参数除了可提供输入值外,还将返回操作结果。

(3)一些最基本的数据结构可以用数据类型实现,如数组、字符串等;而另一些常用的数据结构,如栈、队列、树、图等,不能直接用基本数据类型表示。

三、算法和算法分析

1、算法的定义及特性

(1)算法时对特点问题求解方法和步骤的一种描述,它是指令的有限序列,其中每个指令表示一个或多个操作。

(2)一个算法必须满足以下5个重要特性:

有穷性。一个算法必须总是在执行有穷步后结束,且每一步都必须在有穷时间内完成。

确定性。对于每种情况下所应执行的操作,在算法中都有确切的规定,不会产生二义性,算法的执行者或阅读者都能明确其含义及如何执行。

可行性。算法中的所有操作都可以通过将已经实现的基本操作运算执行有限次来实现。

输入。一个算法有0个或多个输入,当用函数描述算法时,输入往往是通过形参表示的,在它们被调用时,从主调函数获得输入值。

输出。一个算法有一个或多个输出,它们是算法进行信息加工后得到的结果,无输出的算法没有任何意义,当用函数描述算法时,输出多用返回值或引用类型的形参表示。

2、评价算法优劣的基本标准

(1)正确性。在合理的数据输入下,好的算法能够在有限的运行时间内得到正确的结果。

(2)可读性。一个好的算法,首先应便于人们理解和相互交流,其次才是机器可执行性。可读性强的算法有助于人们对算法的理解,而难的算法容易隐藏错误,且难于调试和修改。

(3)健壮性。当输入的数据非法时,好的算法能适当地做出正确反应或进行相应处理,而不会产生一些莫名其妙的输出结果。

(4)高效性。高效性包括时间和空间两个方面:时间高效是指算法设计合理,执行效率高,可以用时间复杂度来度量;空间高效是指算法占用存储容量合理,可以用空间复杂度来度量。(需要说明的是,时间效率和空间效率往往是矛盾的)时间复杂度和空间复杂度是衡量算法的两个主要指标。

3、算法的时间复杂度

(1)衡量算法效率的方法主要有两类:事后统计法和事前分析估算法。

①事后统计法需要先将算法实现,然后测算其时间和空间开销。这种方法的缺陷很显然,一是必须把算法转换成可执行的程序,二是时空开销的测算结果依赖于计算机的软硬件等环境因素,这容易掩盖算法本身的优劣。

②事前分析估算法通过计算算法的渐近复杂度来衡量算法的效率,比较常用。

(2)问题规模和语句频度:

        不考虑计算机的软硬件等环境因素,影响算法时间代价的最主要因素是问题规模。问题规模是算法求解问题输入量的多少,是问题大小的本质表示,一般用整数n表示。问题规模n对不同的问题含义不同,例如,在排序运算中n为参加排序的记录数,在矩阵运算中n为矩阵的阶数,在多项式运算中n为多项式的项数,在集合运算中n为集合中元素的个数,显然,n越大算法的执行时间越长。

        一个算法的执行时间大致上等于其所有语句执行时间的总和,而语句的执行时间则为该条语句的重复执行次数和执行一次所需时间的乘积。一条语句的重复执行次数称作语句频度。

        由于语句的执行要由源程序经编译程序翻译成目标代码,目标代码经装配再执行,因此语句执行一次实际所需的具体时间是与机器的软、硬件环境(如机器速度、编译程序质量等)密切相关的,所以,所谓的算法分析并非精确统计算法实际执行所需时间,而是针对算法中语句的执行次数做出估计,从中得到算法执行时间的信息。

        设每条语句执行一次所需的时间均是单位时间,则一个算法的执行时间可用该算法中所有语句频度之和来度量

        上面的类C代码,其实现的算法是求两个n阶矩阵的乘积算法,该算法中所有语句频度之和是矩阵阶数n的函数,用f(n)表示,换句话说,该算法的执行时间与f(n)成正比。

f\left ( n \right )=2n^{3}+3n^{2}+2n+1

(3)时间复杂度的定义和计算:

        一般情况下,不必计算所有操作的执行次数,而只考虑算法中的基本操作执行的次数(基本语句重复执行的次数),它是问题规模n的某个函数,用T\left ( n \right )表示。其中基本语句指的是算法中重复执行次数和算法的执行时间成正比的语句,同时它对算法运行时间的贡献最大,执行次数最多

        为了便于比较不同算法的时间效率,可以仅比较它们的数量级(忽略所有低次幂项和最高次幂的系数),例如两个不同的算法,时间消耗分别为T_{1}\left ( n \right )=10n^{2}T_{2}\left ( n \right )=5n^{3},显然T_{1}\left ( n \right )的时间消耗更少。

        若有某个辅助函数f\left ( n \right ),使得当n趋近于无穷大时,T\left ( n \right )/f\left ( n \right )的极限值为不等于零的常数,则称f\left ( n \right )T\left ( n \right )的同数量级函数,记作T\left ( n \right )=O(f(n)),称O(f(n))为算法的渐近时间复杂度(O是数量级的符号),简称时间复杂度

        对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则计算算法的时间复杂度

(4)算法的时间复杂度分析举例:

①常量阶示例:

②线性阶示例:

③平方阶示例:

④对数阶示例:

(5)最好、最坏和平均时间复杂度:

        对于某些问题的算法,其基本语句的频度不仅仅与问题的规模相关,还依赖于其它因素。

        称算法在最好情况下的时间复杂度为最好时间复杂度,是指算法计算量可能达到的最小值;称算法在最坏情况下的时间复杂度为最坏时问复杂度,是指算法计算量可能达到的最大值;算法的平均时间复杂度是指算法在所有可能情况下,按照输入实例以等概率出现时,算法计算量的加权平均值。

        对算法时间复杂度的度量,人们更关心的是最坏情况下和平均情况下的时间复杂度,然而在很多情况下,算法的平均时间复杂度难以确定,因此通常只讨论算法在最坏情况下的时间复杂度,即分析在最坏情况下算法执行时间的上界。在后面的内容中讨论的时间复杂度除特别指明外,均指最坏情况下的时间复杂度。

4、算法的空间复杂度

(1)关于算法的存储空间需求,类似于算法的时间复杂度,采用渐近空间复杂度作为算法所需存储空间的量度,简称空间复杂度,它也是问题规模n的函数,记作S\left ( n \right )=O(f(n))

(2)一般情况下,一个程序在机器上执行时,除了需要寄存本身所用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的辅助存储空间,其中输入数据所占的具体存储量取决于问题本身,与算法无关,这样只需分析该算法在实现时所需要的辅助空间就可以了。

(3)举例:

①算法1:

②算法2:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/393574
推荐阅读
相关标签
  

闽ICP备14008679号