本文已参与「新人创作礼」活动,一起开启掘金创作之路。
@TOC
1.0 算法的基本概念
算法 + 数据结构 = 程序 抽象数据类型 = 数据模型 + 定义在该模型上的一组操作 ADT(Abstract Data Type)= DS(Data Structrue) + OP(Operation)
一个数据类型的实现分为三个阶段: 1。 抽象数据类型(抽象的)定义阶段,比如:整数 2。虚拟数据类型(虚拟的)表示阶段,比如:C语言的整数 3。物理数据类型(物理的)实现阶段,比如:机器语言
1.1 数据的逻辑结构
1.1.1 根据数据元素之间的关系,有四类基本的逻辑结构:
- 线性结构
- 树形结构
- 图状结构
- 集合结构
(1)图书管理(线性结构)
(2)人机对弈(树形结构)(上层的结点可以和下层多个结点相邻接,但下层结点只能和上层的一个结点相邻接)
(3)交通信号灯(图状结构)(任何两个结点都可以相邻接)
(4)集合结构(任意两个结点之间都没有邻接关系)
1.2 数据的存储结构
1.2.1 表示数据元素之间的关联方式主要有顺序存储方式和链式存储方式。
(1) 顺序存储方式 是指所有存储结点存放在一个连续的存储区里。 利用结点在存储器中的相对位置来表示数据元素之间的逻辑关系。 (2) 链式存储方式 是指每个存储结点除了含有一个数据元素外, 还包含指针, 每个指针指向一个与本结点有逻辑关系的结点, 用指针表示数据元素之间的逻辑关系。 除了上述两种存储方式之外,还有索引存储方式和散列存储方式。
一个算法在执行期间所需要的存储空间量应包括以下三个部分: (1) 程序代码所占用的空间; (2) 输入数据所占用的空间; (3) 辅助变量所占用的空间, 在估算算法空间复杂度时, 一般只需要分析辅助变量所占用 的空间。
1.3 算法分析
评价一个算法的好坏:
时间复杂度、空间复杂度 如:T(n)=O(n的2次方 ),这种表示法称为大 O 表示法,它的含义是:当 n 充分大时,算法的执行 时间与 n的2次方 成正比。
空间复杂度 空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。 通常可记为: S(n) =0(g(n)) 其中, g(n)为问题规模 n 的某个函数。
2.0 线性表
2.1 基本概念
基本特征: 线性表中结点具有一对一的关系, 如果结点数不为零,
除起始结点没有直接前驱外, 其他每个结点有且仅有一个直接前驱;
除终端结点没有直接后继外, 其他每个结点有且仅有一个直接后继。
线性表的合并和归并的区别:
合并:只是将两个线性表合并为一个线性表,并不保证是有序的。
归并:要求两个线性表合并之后,仍然有序。
2.2 线性表的顺序存储
2.2.1 线性表顺序存储的类型定义
是指所有存储结点存放在一个连续的存储区里。
数据元素在线性表中的邻接关系决定它们在存储空间中的存储位置, 即逻辑结构中相邻的结点其存储位置也相邻。
用顺序存储实现的线性表称为顺序表。一般使用数组来表示顺序表。
2.2.2 顺序存储的特点
- 存储空间必须是连续的,预分配的。
- 逻辑顺序与物理顺序一致,用物理的相邻来表示逻辑上的线性关系。
- 任意相邻元素之间无空闲空间,且相距为小写的L
- 已知基地址,可以计算出任意元素的存储地址。
Loc(ai) = base + (i+1)*l
在高级语言中,数组是采用 顺序存储 的。
2.2.3 线性表的基本运算在顺序表上的实现
(1)顺序表的插入运算 InsertSeqlist (SeqList L,DataType x,int i)
在顺序表第 i 个元素之前插入一个元素x。使长度为为 n 的线性表,变为长度为 n+1 的线性表。
插入算法的基本步骤是:
首先将结点 ai ~ an 依次向后移动一个元素的位置, 这样空出第 i 个数据元素的位置;
然后将 x 置入该空位, 最后表长加 1。
如果内存满了,无法向后移动一个位置,则需要增量+10,然后再重复上述步骤。
(2)顺序表的删除运算 DeleteSeqlist(SeqList L,int i) 将线性表的第 i 个数据元素删去,使长度为 n 的线性表,变为长度为 n-1 的线性表。 删除运算的基本步骤是: 1。结点 a i+1 ,...,a n 依次向左移动一个元素位置 (从而覆盖掉被删结点 a i ); 2。表长度减 1。此处无需考虑溢出,只判断参数 i 是否合法即可。
2.2.4 顺序存储的优缺点
优点:
- 逻辑顺序与物理顺序一致
- 随机存取
缺点:
- 插入、删除操作要移动元素
- 存储空间是预先分配的,不灵活,空间浪费;
- 表的存储空间难以扩充;
2.3 线性表的链接存储
使用任意(不是连续的)存储空间单元来存放线性表的各个元素,使用指针来表示元素之间的逻辑关系(谁是谁的前驱/后继)。
线性表的链接存储是指它的存储结构是链式的。
存放一个数据元素占用的空间为:
数据域:存放数据元素
指针域:存放相关元素的地址信息
2.3.1 链式存储的特点
- 存储空间不一定连续;
- 逻辑关系是由指针来体现的;(顺序存储是通过物理的相邻来体现逻辑关系的)
- 逻辑上相邻,物理上不一定相邻;
- 非随机存取(顺序存取),即访问任何一个元素的时间不同;
类似 磁盘(是顺序存取的) 和 CD(可以随意点播) 的区别
2.3.2 链式存储的分类
线性表常见的链式存储结构有:
- 单链表存储结构(最简单)
- 双链式存储结构
- 循环单链式存储结构
- 循环双链式存储结构
**单链式存储结构:**存放元素的同时,存放其后继(或前驱)元素的信息
存放信息:
**双链式存储结构:**存放元素的同时,存放其后继和前驱元素的信息
存放信息:
**循环单链式存储结构:**将最后一个元素的后继指向第一个元素的存储地址。
**循环双链式存储结构:**将最后一个元素的后继指向第一个元素的存储地址,将第一个元素的前驱指向最后一个元素的存储地址。
2.3.3 线性表的基本运算在链式表上的实现
(1)单链表的插入运算 将给定值为 x 的元素插入到链表 head 的第 i 个结点之前。 步骤: (1) 先找到链表的第 i-1 个结点 q。 (2) 生成一个值为 x 的新结点 p, p 的指针域指向 q 的直接后继结点 (3) q 的指针域指向 P
注意: 链接操作 p->next=q->next 和 q->next=p 两条语句的执行顺序不能颠倒, 否则结点*q 的链域值 (即指向原表第 i 个结点的指针) 将丢失。
(2)单链表的删除运算
将链表中第 i 个结点从链表中移出, 并修改相关结点的指针域。
将 ai 结点移出后,需要修改该结点的直接前驱结点的指针域, 使其指向移出结点 ai 的直接后继结点。
注意: free(p)是必不可少的(表示释放空间), 因为当一个结点从链表移出后, 如果不释放它的空间, 它将变成一个无用的结点, 它会一直占用着系统内存空间, 其他程序将无法使用这块空间。
(3)单链表的归并(指将两个有序的线性表,合并为一个有序的线性表) 注意:当两个线性表非空时,不另外新开辟空间,只需将原来两个链表中的结点之间的关系解除,重新按元素值将所有结点连接成一个链表。
2.3.4 单链表与双链式的特点
- 具有单链表的特点
- 前驱操作简单O(1)
- 任何位置插入、删除都简单了(已知该位置指针)