零.前言
又开了一个坑,记录自己数据结构的学习。本文章基于的书是清华大学版的严蔚敏《数据结构》C语言版。
一.基本概念和术语
数据
: 数据是对客观事物的符号表示,在计算机科学中是指所有能输入到计算机中并被计算机程序处理的符号总称。
数据元素
:是数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。有时候,一个数据元素可以由若干个数据项
组成,比如我们常见的结构体等。
数据对象
:是性质相同的数据元素的集合,是数据的一个子集。例如我们常见的整数数据对象N={-1,0,1,2···}
数据结构
:这个概念,没有一个被一致公认的定义。所以在清华大学严蔚敏版的《数据结构》中说道:数据结构
是相互之间存在的一种或多种特定关系的数据元素的集合。在任何问题中,数据元素都不可能孤立存在,且在它们之间存在着某种关系。这种元素互相之间的关系称为结构
。一般来说有下列常见的四种基本结构:
- 集合:除了“同属于一个集合”的关系外,结构中的数据元素没有其他的关系。
- 线性结构:数据中的元素之间存在一个对一个的关系。
- 树形结构:结构中的数据元素之间存在着一个对多个的关系。
- 图状或网状结构:存在多个对多个的关系。
听起来和数据库的基本对应关系差不多哎。
数据结构的定义时对数据对象的一种数据描述,可以理解为抽象出来的数学模型,用于描述其逻辑关系,所以这又被称为数据的逻辑结构
。
数据结构在计算机中的表示(也就是说在你内存里存的地方),又称为物理结构
或储存结构
。
常见的储存结构有顺序储存结构
和链式储存结构
。前者的物理位置是连续的,后者的储存顺序不一定是连续的,而且需要通过某种特殊的方式,将其串联起来
数据类型
:数据类型是和数据结构密切相关的一个概念,一般用于刻画程序操作对象的特性。所以数据类型是一个值的集合和定义在这个值集上的一组操作的总称。顾名思义,也就是说,数据类型可能包括变量和操作这些变量集的函数。这和类
的概念很接近。
抽象数据类型(abstract data type)
:简称ADT
,是一个数学模型以及定义在该模型上的一组操作。
二.如何表示抽象数据类型
其他的都好说,跟着C语言的风格走就行。而ADT伪代码我们可以了解一下格式,放一个例子:
ADT 抽象数据类型名 {
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
}ADT 抽象数据的类型名
其中
基本操作名 (参数表)
初始条件:<初始条件描述>
操作结果:<操作结果描述>
例如:
ADT List {
数据对象: D={ai | ai ∈ ElemSet, i = 1,2,3,4···,n, n≥0}
数据关系: R1={<ai-1,ai> |ai-1, ai-1 ∈ ElemSet, i = 2,3,4···,n}
基本操作:
ListEmpty(L)
初始条件:线性表L已存在。
操作结果:若L为空表,返回True,否则返回False。
···
}
三.算法和算法分析
1.算法
算法有一下五个重要特性:
- 有穷性: 一个算法总是在有穷步后结束,且每一步都可以在有穷的时间内完成。(当然这个有穷是指时间能让你接受,而不是能足够大但不是无穷的那种数学定义)。
- 确定性:每一条指令都有明确的含义,不能让读者产生二义性。且任何条件下只有一条执行路径,即同一种输入同一种输出。
- 可行性:一个算法是能行的,即算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的。
- 输入:一个算法必须要有零个或多个输入。
- 输出:一个算法必须要有一个或多个输出。
2.算法的设计要求
一个好的算法一般要考虑达到一下几个目标:
-
正确性:正确性一般又包含了一下几个方面:
①.程序没有语法错误
②.程序对于几组输入数据能够满足规格说明要求的结果。
③.程序要对于精心挑选的典型、苛刻而带有刁难性的输入能够得出满足规格说明要求的结果。
④.对于一切合法输入,都能得出满足规格说明要求的结果。
-
可读性:算法主要是用来给人看的,所以要让其他人读的懂。
-
健壮性:简而言之就是如果输入非法,能够做出恰当的操作来处理,而不是输出莫名其妙的结果或者让程序变成奇奇怪怪的样子。
-
效率和低储存量需求:简而言之就是花的时间越少越好,占用的内存越少越好。也就是说
时间复杂度
和空间复杂度
要小
3.算法效率的度量
一般来说 我们写算法一般要有事前估算
和事后统计
。
一般情况下,算法中基本操作重复执行的次数是问题规模n的某函数f(n),算法的时间度量度记作
T
(
n
)
=
O
(
f
(
n
)
)
T(n) = O(f(n))
T(n)=O(f(n))
它表示,随着问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度
,简称时间复杂度
三个例子:
-
{++x; s = 0;}
-
for (i = 1; i <= n; ++j) { ++s; }
-
for (j = 1; j <= n; ++j) { for (i = 1; i <= n; i++) { ++s; } }
对于这三个例子来说,他们的复杂度分别是O(1)、O(n) 、O(n2)
4.算法的空间要求
类似于时间复杂度,本书中用空间复杂度
作为算法所需要空间的量度。记作:
S
(
n
)
=
O
(
f
(
m
)
)
S(n)=O(f(m))
S(n)=O(f(m))
可以将其中的n可以基本等同于使用的变量所占空间的大小。
至于具体如何去计算一个算法的时间复杂度和空间复杂度还需要很复杂的计算,后面会专门开一节来记录。