数据结构是用来研究非数值计算的程序设计问题中计算机的操作对象以及它们之间的关系和操作。
一些基本概念:
- 数据是指所有能被计算机识别、存储和处理的符号的集合(包括数字、字符、声音、图像等信息)。
- 数据元素是数据的基本单位,具有完整确定的实际意义(又称元素、结点、顶点、记录等),具有若干个数据项。
- 数据项是构成数据元素的项目,是具有独立意义的不可分割的最小标识单位(又称字段、域、属性等)。
- 数据的逻辑结构是根据数据元素之间的不同逻辑关系的特性,可分为四类:(1)、集合:数据元素之间除了“同属一个集合”的关系外,没有其他联系。(2)、线性结构:一对一的关系(像线性表、栈、队列、串都是,至于数组和广义表算是一种特殊的线性表,也是线性结构)。(3)、树形结构:一对多的关系()。(4)、图状或网状结构:多对多的关系。
- 数据的物理结构又称存储结构,是数据的逻辑结构在计算机存储器内的表示(或映像),依赖与计算机。储存结构可分为四类:顺序、链式、索引和散列。
- 数据的运算是在数据的逻辑结构上定义、在数据的存储结构上实现的操作算法。最常用的数据运算有:插入、删除、修改、查找和排序。
- 数据元素之间的关系在计算机中有两种不同的表示方法:顺序映像和非顺序映像,并由此得到两种存储结构:顺序存储结构和链式存储结构。顺序映像的特点是借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系;非顺序映像的特点是借助指示元素存储地址的指针表示数据元素之间的逻辑关系。任何一个算法的设计取决于选定的数据(逻辑)结构,而算法的实现依赖于采用的存储结构。
- 数据类型:是一个值的集合和定义在这个值集上的一组操作的总称。
- 抽象数据类型:由用户定义,用以表示应用问题的数据模型。它由基本的数据类型构成,并包括一组相关的服务(或称操作),它与数据类型实质上是一个概念,但其特征是使用与实现分离,实行封装和信息隐蔽(独立于计算机)。
一般分为如下:
一些常用的预定义变量和类型:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1 //表示程序出错,运行终止。
#define OVERFLOW -2
typedef int Status //Status 表示函数的类型
typedef int ElemType //表示数据类型
算法是解决某一特定类型问题的有限运算序列,是一系列转换为输出的计算步骤。关于算法和算法分析:
- 算法:五个特性:1)有穷性:算法可在一定时间内完成的。2)确定性:算法每条都需要有明确的含义,不能产生二义性。3)可行性:算法是可被执行的。4)输入。5)输出。
- 对算法设计的要求(应尽量满足):1)正确性,包含程序没有语法错误、程序对于输入几组数据能得到满足问题需求的结果、程序对于输入几组典型的、有刁难性的数据能够得到满足问题需求的结果(一般情况下,满足这就算合格了)、程序对一切合法的输入都能产生满足问题需求的结果(实现起来很困难)。 2)可读性:方便人对算法的理解。3)健壮性:当输入数据非法时,算法也可适当地作出方应和调整,不会产生莫名其妙的输出结果。4)效率与低存储量需求:效率指算法执行的时间,存储量指算法执行过程中所需要的最大存储空间。
- 时间复杂度:算法的运行时间由算法中所有语句的频度(即该语句重复执行的次数)之和构成,由嵌套最深层语句的频度决定。其按数量级递增顺序为:常量阶、对数阶、线性阶、平方阶、指数阶 ,一般不希望用到指数阶的算法,运算量太大。同下边的空间复杂度一致。
- 空间复杂度:原地工作:若额外空间相对于输入数据量来说是常数,就称算法为原地工作。另需注意的是,若额外空间所占空间量依赖于特定的输入,则除特别指明外,均按最坏情况来分析。
语句的频度指的是该语句重复执行的次数。
线性结构的特点是:
在数据元素的非空有限集中,
- 存在唯一一个被称作“第一个”的数据元素。
- 存在唯一一个被称作“最后一个的元素”。
- 除第一个外,集合中的每个数据元素均只有一个前驱。
- 除最后一个外,集合中的每个元素均只有一个后继。
线性表的逻辑结构定义是唯一的,不依赖于计算机。线性结构反映结点间的逻辑关系是一对一的。
树形结构的特点是:
- 是一种有层次的嵌套结构,可表示从属关系、并列关系。
- 有且只有一个结点作为根,其余结点互不相交。
- 树根结点没有前驱结点,其余每个结点有且只有一个前驱结点。
- 叶子结点没有后续结点,其余每个结点的后续结点数可以是一个也可以是多个。
在数据结构中,有时会涉及到空间分配问题,这包含有两个函数:malloc 和 realloc ,这两个都在头文件 stdlib.h 中。
- malloc 函数表示动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,void* 类型表示未确定类型的指针,可以通过类型转换强制转换为任何其它类型的指针。一般需和free函数配对使用。
- realloc 函数表示动态内存调整,用法:指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。先判断当前的指针是否有足够的连续空间,如果有,扩大该指针指向的地址,并且将指针返回 (假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址);如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来指针所指内存区域(注意:原指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址,即重新分配存储器块的地址( 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址)。当内存不再使用时,应使用free()函数将内存块释放。