数据结构笔记-绪论

数据结构笔记

绪论

学习问题

数据结构和算法是计算机求解问题过程的两大基石。数据结构既是计算机科学研究的基本课题,又是算法研究的基础。关于数据结构的研究最早可以追溯到1972年发表的论文"数据结构笔记"。在研究数据结构之前需要先回答以下问题:

  1. 什么是数据结构?
  2. 数据结构的内容是什么?
  3. 采用什么方法研究?
  4. 采用什么工具对算法规则进行描述?
  5. 如何对算法的性能进行评价?
  6. 学习数据结构有什么用?

基本概念

数据

描述客观事物的数据,字符以及能输入机器并被处理的各种符号的集合。

数据的概念已不再是狭义的,包含数值,图像,字符,声音等各种符号。

数据元素

组成数据的基本单位。

一个数据元素可以包含一个或多个数据项,数据项是具有独立含义的最小单位,此时的数据元素通常被称为记录。

数据对象

性质相同的数据元素的集合。

可认为数据由数据对象构成,数据对象由数据元素构成。

数据结构

相互之间存在一种或多种特定关系的数据元素的集合。

数据结构研究的是数据的组织方式,可对其施加的运算及运算规则。数据的组织方式,即数据元素的集合与数据元素之间关系的集合。

数据类型

性质相同的的值集合,以及定义在该集合之上的一组操作的总称。

高级程序设计语言中的数据类型就是数据结构的实例。

本人认为可将数据类型看作程序员与计算机连接的媒介,程序员只需要理解数据类型的抽象特性,计算机负责处理复杂的字节运算,位运算等实现细节。从这个意义上讲,数据类型实现了对程序员的信息隐蔽。

抽象数据类型

性质相同的数据元素的集合,数据元素之间关系的集合以及一组操作的总称。

抽象的本质是抽取反应问题的本质点,并忽略非本质的细节。从而使得设计的数据结构更具一般性,可以解决一类问题。

与数据类型概念的区别是:抽象数据类型(ADT)不仅仅指计算机预定义的数据类型,还包含用户自定义的复杂数据类型。ADT通常就是指由用户定义且用以表示应用问题的数据模型。

描述

要包含三个方面,分别是数据元素、数据元素之间的关系和运算集合。

数据结构的内容

数据元素之间的相互关系包括三个方面:逻辑结构、存储结构和运算集合。

逻辑结构

数据元素之间逻辑关系的描述。可概括为:

  1. 线性结构 线性表、栈、队、字符串、数组、广义表
  2. 非线性结构 树、图

所谓线性结构,即数据元素之间只存在一对一的线性关系。

树结构,即数据元素之间存在一对多的层次关系。

图结构,即数据元素之间存在多对多的任意关系。

存储结构

逻辑结构在计算机中的存储映像。

包括数据元素映像和关系映像。

在计算机中的表示方法有两种:顺序映像、非顺序映像。

运算集合

常见的运算比如对数据库记录的"增、删、改、查",这就是一个运算集合。

总结

综上,数据结构的内容即:按照某种逻辑关系组织起来的一批数据,按照某种映像方式把这些数据存储到计算机当中,并在这些数据上定义一个运算集合。

算法

图灵奖获得者N.Wirth认为:算法 + 数据结构 = 程序

定义

算法是规则的有限集合,是为解决特定问题而规定的一系列的操作。

特性

  1. 有限性:有限步骤内正常结束,不能形成无限循环。
  2. 确定性:每个步骤必须由确定含义,无二义性。
  3. 可行性:原则上能精确运行,可通过已实现的基本运算执行有限次而获得相应结果
  4. 输入: 有多个或0个输入
  5. 输出: 至少有1个输出

设计要求

算法设计的目标是:正确、可读、健壮、高效、低耗。

正确性

指满足具体问题的求解需求。分为三个层次:

  1. 对于普通的几组数据可以得出满足要求的结果。
  2. 对于精心选择的典型的带有刁难性的输入可以得出满足要求的结果。
  3. 对于一切合法的输入都能得出满足要求的结果。

至少应该以是否达到第二层作为衡量一个算法是否达到正确的标准

可读性

一个良好的算法首先应该便于人们理解和交流,其次才是机器可执行。

健壮性(鲁棒性)

对非法输入具有抵抗力。

强调即使输入了非法数据,算法仍然能够识别并做出处理,而不是产生错误动作或陷入瘫痪。

高效率和低存储量

算法效率通常指算法的运行时间。

存储量指算法执行过程中所需要的最大存储空间。

这两者都与问题的规模有关。

算法描述

要将设计好的数据结构和算法转换为相应的程序,就需要采用某种编程语言进行描述。

设计实现算法的步骤

  1. 找出求解相关的数据元素之间的关系
  2. 确定在某一数据对象上施加的运算
  3. 确定数据元素的物理存储结构
  4. 选择描述算法的语言
  5. 设计实现求解的算法,并用程序设计语言描述

描述算法的语言选择

高级程序设计语言具有准确的优点,但是用于描述算法会导致细节过多的弱点。为此,可采用类语言。

算法性能评价

一种数据结构的优劣由实现其运算集合的算法体现,需要对算法的效率作性能评价。

算法分析是每一位程序设计人员应该掌握的技术。评价算法性能的标准主要从算法执行时间和占用存储空间两方面考虑。

算法的性能与问题的规模相关,并与输入实例的初始状态有关。问题规模即算法的输入量,一般用整数表示。可以说算法效率是问题规模的函数。

时间性能分析

算法的执行时间指的是算法中所有语句执行时间的总和。每一条语句的执行时间等于该条语句执行的次数乘以执行一次所需要的时间。

每条语句的实际执行时间随硬件不同而改变,是难以估计的。因此,度量一个算法的效率应当根据算法中语句的执行次数。

语句频度

指一条语句在算法中的重复执行次数。

算法的时间耗费就是所有该算法中所有语句频度之和。

渐进时间复杂度

为比较同一问题的不同算法的时间耗费,通常以基本操作的语句频度之和作为度量标准。所谓基本操作,指的是对所研究问题而言是基本运算的操作。

语句频度之和f(n)是问题规模n的函数,而算法的时间复杂度T(n)是该算法的时间度量,记作:T(n) = O(f(n)),其中O的含义是数量级。这表明随着问题规模n的增大,算法执行时间的增长率与语句频度之和的增长率相同,因此叫做渐进时间复杂度,简称时间复杂度。

假如:
f ( n ) = 2 n 3 + n 2 + n f(n) = 2n^3 + n^2 +n


T ( n ) = O ( 2 n 3 + n 2 + n ) T(n) = O(2n^3 + n^2 + n)

n f ( n ) / n 3 = C C 当n趋近于无穷大时,f(n)/n^3 = C,C为常数


O ( n 3 ) O(n^3)是该算法的渐进时间复杂度

T ( n ) = O ( n 3 ) T(n) = O(n^3)

可以看到,算法的渐进时间复杂度一般是算法中语句频度最大者。

渐进时间复杂度从宏观上对算法的时间质量进行评价。算法分析时往往不将时间复杂度和渐进时间复杂度进行区分。

常用算法时间复杂度

按照时间复杂度从低到高(通常情况下):

  1. 对数型
    O ( l o g 2 n ) O(log_2 n)

O ( 1 ) O(1)

  1. 二维型
    O ( n l o g 2 n ) O(nlog_2 n)

  2. 平方型
    O ( n 2 ) O(n^2)

  3. 立方型
    O ( n 3 ) O(n^3)

  4. 指数型

O ( 2 n ) O(2^n)

最坏时间复杂度

最坏情况下的(渐进)时间复杂度,即可能的最大时间复杂度。

一般情况下,讨论的都是最坏时间复杂度。即当算法时间复杂度收到输入实例的初始状态影响时,认为最坏时间复杂度为该算法的时间复杂度。

平均时间复杂度

指所有可能的输入实例均等概率地出现时的时间复杂度。

空间性能分析

程序运行时占用的空间包括:常量、变量、指令、输入实例数据。需要讨论的是算法运行时涉及到的辅助存储空间。即算法占用的空间指算法实际占用的辅助空间单元个数。

空间复杂度

空间复杂度S(n)定义为算法占用空间单元个数的数量级,它是问题规模n的函数。记作:
S ( n ) = O ( f ( n ) ) S(n) = O(f(n))
算法的时间复杂度与空间复杂度合称为算法的复杂度。

数据结构与程序设计

编写程序仅仅掌握语言规则是不够的,还必须掌握数据的组织、存储和运算。数据结构是在积累的程序设计经验的基础上形成的,是提高程序设计的能力的基础。

Wirth认为"程序 = 算法 + 数据结构",可理解为"程序结构 = 控制结构 + 数据结构"。

结构化程序设计

定义

使程序具有合理的结构以保证程序的正确性的程序设计方法。

目的

以良好的静态结构保证程序动态执行的正确性,使得程序易于理解、调试和维护。

构成单元

顺序、选择和重复三种控制结构。应限制goto语句以减少对单入口单出口原则的破坏。

设计方法

  1. 自顶向下,逐步求精。即将问题分为若干个层次,逐步解决。
  2. 功能独立的模块化结构。即把复杂问题分为相对独立、功能单一的问题模块。
  3. 仅使用三种控制结构。

面向对象程序设计

面向对象 = 对象 + 类 + 继承 + 通信。

对象

问题中涉及到的实体、事件等。由一组属性和定义在这组属性之上的服务构成。

具有相同属性和服务的对象归为同一类。

特点

封装、继承、多态。(抽象)

与结构化开发的区别

结构化开发是面向过程的开发方法,首先考虑系统需要实现的功能并考虑输入和输出,按照自顶向下的方法完成功能模块结构的设计。如果需求发生变更,就会涉及到多个模块的修改。

面向对象开发首先考虑实体、事件等对象,包括对象的属性和行为。从而建立起对象的结构和事件执行序列,据此再建立起类的继承关系结构。最后,类之间通过消息传递完成设计的功能。如果需求变更,只需要修改类中的服务即可。具有更高的可修改性、可维护性和可理解性。

数据结构的基本操作

  1. 插入
  2. 删除
  3. 更新
  4. 查找
  5. 排序

根据操作的性质可分为加工型操作引用型操作,前者改变原始的值,后者不改变。这与Java中的引用类型基本类型对应。

发布了14 篇原创文章 · 获赞 0 · 访问量 728

猜你喜欢

转载自blog.csdn.net/qq_38878217/article/details/104737127