数据结构笔记
一、绪论
- 顺序存储结构在物理上一定是连续的
- 非顺序存储结构在物理上可以是离散的
- 数据的存储结构会影响存储空间分配的方便程度
- 运算的定义是针对逻辑结构的
- 运算的实现是针对存储结构的
二、算法
- 算法的五个特征
有穷性:算法程序的运行时间是有限的
确定性:每一条代码都有明确性的目的,对于相同的输入都有相同的输出
可能性:算法中的步骤都是可以被基本均算执行有限次
输入:丢给算法处理的数据
输出:算法处理后的结果 - “好”算法的特质
正确性:算法应能够正确地解决求解问题
可读性:算法应有良好的可读性
健壮性:算法能够处理一些异常
高效率与低储存量:算法省时、省内存;时间复杂度低,空间复杂度低
三、算法效率的度量
-
时间复杂度
表达式T(n), T:time n:问题规模
时间复杂度表达式只考虑表达式高阶部分
Eg:
T(n)=3n+3≈3n
T(n)=3n2+3n+3≈3n2
T(n)=3n3+3n2+3n+3≈3n3常对幂指阶
2. 空间复杂度
表达式S(n), T:space n:问题规模
空间复杂度表达式也只考虑表达式高阶部分
四、线性表
- 线性表具有相同数据结构(每个数据元素所占空间一样大)
- 是有限序列(有次序)
- ai表示第i个元素,第i个位序(位序从1开始)
- a1为表头元素、 an为表尾元素
- 除了a1,每一个元素有且仅有一个直接前驱;除了an,每一个元素有且仅有一个直接后驱
基本操作 | 表达形式表达形式 |
---|---|
InitList(&L) | 初始化表 |
DestroyList(&L) | 销毁链表 |
Listinsert(&L,i,e) | 插入元素 |
ListDelete(&L,i,&e) | 删除元素 |
LocateElem(L.e) | 按值查找 |
Length(L) | 求表长 |
PrintList(L) | 输出打印 |
Empty(L) | 判空 |
Tip:
什么时候要传入引用“&”——对阐述的修改结果需要“带回来”(C++中才能用“&”)
五、顺序表
- 顺序表的实现——静态分配
#define MaxSize 10 //定义最大长度
typedef struct{
ElemType date[MaxSize]; //用静态的“数组”存放数据元素 ElemType数据类型,实际自己定义
int length; //顺序表当前的长度
}SqList; //顺序表的类型定义(静态分配方式)
Eg:
Tip:
Q: 静态分配的顺序表满了怎么办
A: 重建。顺序表的表长刚开始的时候就已经确定,后续无法更改
- 顺序表的实现——静态分配
#define InitSize 10 //顺序表的初始长度
typedef struct{
ElemType date *date; //指示动态分配数组的指针
int MaxSize; //顺序表的最大容量
int length; //顺序表当前的长度
}SqList; //顺序表的类型定义(动态分配方式)
Eg:
在IncreaseSize();中将原来的数组地址复制给p 同时新建更大的数值,在将原来的数组数值复制到新数组中,再free(p);
-
顺序表的特点
(1)随机访问,在O(1)时间内即可找到第i个元素
(2)储存密度高,每个节点只能存储数据元素
(3)扩展容量不方便
(4)插入、删除不方便。每次都要移动大量元素 -
顺序表的插入与删除
(1)插入
L.date[j]=L.date[j-1];将第四个元素数据放到第五个元素位置上
(2)删除
- 顺序表的两种查找(按位、按值)
(1)按位
(2)按值
六、链表
-
单链表定义
-
typedef关键字
Eg
-
单链表的插入与删除
(1)插入
(2)后插法
(3)头插法
Tip:将已知的前节点数据放到新建节点中,再将要插入的数据放到已知节点中
(4)删除节点
(5)删除指定结点
4. 单链表的查找
(1)按位查找
(2)按值查找
-
求表长
-
双链表
(1)初始化
(2)插入
(2.1)在链尾插入
(3)双链表的删除
(4)双链表的遍历
-
循环单链表
10.循环双链表
- 静态链表
(1)定义
Tip :头结点游标为-1,寻找节点靠游标排序来实现
七、顺序表与链表的比较
- 都属于线性表,都是线性结构
- 顺序表:优点支持随机存储,存储密度高; 缺点:开辟大量连续空间分配不方便,不方便改变存储上线
- 链表:优点离散的小空间,分配方便,方便改变存储上线;缺点:不可随机存储,存储密度低