数据结构
数据结构
[TOC]
第一章 绪论
1.数据结构的基本概念
1.基本概念和术语
1.数据
信息的载体,是描述客观事物属性的数,字符及所有能被计算机识别和处理的符号的集合
2.数据元素
数据的基本单位,由数据项组成,不可分割的最小单位
3.数据对象
具有相同性质的数据元素的集合,数据的一个子集
4.数据类型
一个值的集合和定义在集合上的一组操作的总称
原子类型 值不可再分
结构类型 值可以再分
抽象数据类型
5.抽象数据类型
1.定义: 一个数学模型和定义在模型上的一组操作
2.特点: 定义仅取决于它的一组逻辑特性,与在计算机内部如何表示和实现无关
3.表示: (数据对象,数据关系,基本操作集)
6.数据结构
1.结构: 数据元素之间的相互关系
2.定义: 相互之间存在一种或多种特定关系的数据元素的集合
3.内容: 逻辑结构,存储结构,数据的运算
逻辑结构: 一个算法的设计
存储结构: 一个算法的实现
2.数据结构三要素
1.数据的==逻辑结构==
1.定义: 数据元素之间的逻辑关系,与存储无关,独立于计算机
2.分类
- 线性结构
1、线性表 一对一
- 非线性结构
1、集合 同属一个集合
2、树 一对多
3、图/网状 多对多
2.数据的==存储结构==
1.定义: 数据结构在计算机中的表示(又称映像/物理结构)
2.包括: 数据元素的表示和关系的表示
3.分类
==顺序存储==
优点: 随机存取,元素占用最少存储空间
缺点: 只能使用相邻的一整块存储单元,产生较多的外部碎片
==链式存储==
优点: 不会出现碎片现象
缺点: 存储指针占用额外的存储空间; 只能顺序存取
==索引存储==
定义: 建立附加的索引表,每项称为索引项(关键字,地址)
优点: 检索速度快
缺点: 占用较多存储空间; 增加和删除数据要修改索引表,花费较多时间
==散列存储==
定义: 根据元素的关键字直接计算出该元素的存储地址(Hash存储)
优点: 检索,增加和删除结点都很快
缺点: 若散列函数不好,出现元素存储单元冲突,会增加时间和空间的开销
3.数据的运算
1.运算的定义: 针对逻辑结构,指出运算的功能
2.运算的实现: 针对存储结构,指出运算的具体操作步骤
题目总结
==易错:==
1.属于逻辑结构 有序表
2.循环队列是用顺序表表示的队列,是数据结构,不是抽象数据结构
3.不同结点的存储空间可以不连续,但结点内的存储空间必须连续
4.两种不同的数据结构,逻辑结构和物理结构可以完全相同,但数据的运算不同
2.算法和算法评价
1.算法的基本概念
1.定义: 对特定问题求解步骤的描述,指令的有限序列
2.==特性==
1.有穷性
2.确定性
3.可行性
4.输入
5.输出
3.==好的算法==
1.正确性
2.可读性
3.健壮性
4.效率与低存储量需求
2.算法效率的度量
1.时间复杂度O(n)
定义: 衡量算法随着问题规模增大,算法执行时间增长的快慢
2.空间复杂度S(n)
1.定义: 衡量算法随着问题规模增大,算法所需空间增长的快慢
2.算法原地工作: 算法所需要的辅助空间为常数,即O(1)
题目总结
1、==易错==
1.将长度为m,n的两个升序链表,合并为m+n的降序链表(取较小元素,头插法)
2.时间复杂度计算
1.sum += ++i; O(n^1/2) 第k次: sum = 1+2+3+…+k ≥n
2、2.i=i*2 O(log₂n)
3.递归算法
- 1.T(n)=2T(n/2)+n (n>1) (n=1时: T(n)=1) O(nlog₂n)
- 2.设n=2^k,先根据递归条件,找到T(2^k)的通式,再转化为n,即得到时间复杂度
3.同一个算法,实现的语言的级别越高级,执行效率越低
第二章 线性表
1.线性表的定义和基本操作
1.线性表的定义
1.定义: 相同数据类型的有限序列
2.注意: 线性表是逻辑结构,顺序表和链表指存储结构
2.线性表的基本操作
1.注意: & 表示C++中的引用,若传入指针型变量且在函数体内要进行改变,要用到指针变量的引用(C中用指针的指针也可以)
2.主要操作
2.线性表的顺序表示
1.顺序表的定义
1.顺序表需要三个部分
- ==存储空间的起始位置==
- ==顺序表最大存储空间==
- ==顺序表当前的长度==
2.==静态分配==
1 |
|
3.==动态分配==
1 |
|
4.动态分配语句
C语言: ==L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);==
C++: ==L.data=new ElemType[InitSize];==
5.注意: 动态分配不是链式存储,同样属于顺序存储结构,物理结构没有变化:随机存取方式,只是分配的空间大小可以在运行时决定
6.特点: 随机访问,存储密度高,插入和删除需要移动大量元素
2.顺序表上基本操作的实现
1.==插入操作 O(n)==
1 | bool ListInsert(SqList &L, int i, ElemType e){ |
2.==删除操作 O(n)==
1 | bool ListDelete(SqList &L, int i, ElemType &e){ |
3.==按值查找(顺序查找) O(n)==
1 | int LocateElem(SqList L, ElemType e) { |
4、==初始化顺序表==
1 | void InitList(Sqlist &L) { |
题目总结
==1、易错==
1.线性表必须是有限序列
2.在顺序表的第i个位置插入一个数,i的合法取值: 1≤i≤n+1 在第n+1个位置插入相当于在表尾追加
==2、算法==
1.将顺序表的所有元素逆序
算法思想:扫描顺序表L的前班部分元素,对于元素L.date[ i ] (0 <= L.length / 2),将其与后半部分的对应元素L.data[L.length - i - 1]进行交换
1 | void Reverse(SqList &L){ |
2.顺序表(非有序)删除所有值为x的数据元素
用k记录顺序表L中不等于x的元素个数(既需要保存的元素个数),扫描时将不等于x的元素移动到下标k的位置,并更新k值。扫描结束后修改L的长度
1 | void del_x_l(SqList &L, Elemtype x){ |
3.有序顺序表删除给定值s与t之间的所有元素
1 | bool Del_S_t2(SqList &L, ElemType s, ElemType t){ |
4.有序表删除所有其值重复的元素
1 | bool Delete_Same(SeqList &L){ |
5.将两个有序表合并为一个有序表,由函数返回结果
1 | bool Merge(SeqList A, SeqList B, SeqList &c){ |
3.线性表的链式表示
1.单链表的定义
1.结点类型的描述
2.特点: 浪费空间,非随机存取
3.头指针和头结点区别
1.不管带不带头结点,头指针始终指向链表的第一个结点
2.头结点是带头结点的链表中的第一个结点,通常不存储信息
4.引入头结点的优点
1.在链表第一个位置上的操作和其他位置上的一致
2.无论链表是否为空,头指针都指向头结点的非空指针,空表和非空表处理一致
单链表定义
1 | typedef struct LNode{ //定义单链表结点类型 |
2.单链表上基本操作的实现
1.头插法建立链表
1 | LinkList List_HeadInsert(LinkList &L){ //逆向建立单链表 |
2.尾插法建立链表
1 |
3.按序号查找结点值
4.按值查找表结点
5.插入结点操作
前插操作: 先找到前一个结点,时间复杂度为O(n)
扩展: 将前插操作转化为后插操作,然后交换两个结点的数据,时间复杂度为O(1)
6.删除结点操作
先找到前驱节点,再删除结点,O(n
扩展: 先和后继结点交换数据,再删除后继结点,O(1)
7.求表长操作
计算数据结点的个数
3.双链表
1.双链表中结点类型的描述
2.插入操作
3.删除操作
4.循环链表
1.==循环单链表==
1.判空条件: 头结点的指针是否指向头指针
2.对单链表在表头和表尾操作时: 不设头指针仅设尾指针,效率更高
2.==循环双链表==
判空条件: 头结点的prior域和next域都指向头指针
5.静态链表
1.定义: 用数组描述链式存储结构,也有数据域和指针域.指针是结点的相对地址(数组下标),又称游标
2.形式
3.结束标志: next==-1
4.注意
1.和顺序表一样,也要预先分配一块连续的内存空间
2.插入和删除只需要修改指针,不需要移动元素
3.在不支持指针的高级语言(Basic)中很巧妙
6.顺序表和链表的==比较==
1.存取方式
顺序表可顺序存取,可随机存取. 链表只能从表头顺序存取
2.逻辑结构与物理结构
3.查找,插入和删除
1.按值查找
无序时,都为O(n)
有序时,顺序表可以折半查找,O(log₂n)
2.按序号查找
顺序表为O(1),链表为O(n)
4.空间分配
5.怎样选取存储结构
1.基于存储的考虑
难以估计长度和存储规模时用链表,但链表的存储密度较低
2.基于运算的考虑
经常做按序号访问数据元素用顺序表
3.基于环境的考虑
顺序表容易实现,链表基于指针
较稳定选顺序表,动态性较强选链表
题目总结
1、==易错==
1.链式存储结构比顺序存储结构更方便地表示各种逻辑结构
2.顺序存储不只能用于存储线性结构,还能存储图和树的结构(满二叉树)
3.静态链表需要分配较大的连续空间,插入和删除不需要移动元素
4.若用单链表表示队列,应选用带尾指针的循环链表
5.给定一维数组,建立一个有序单链表的最低时间为O(nlog₂n)
先对数组进行排序,再构造单链表
6.链表常用操作为在最后一个元素之后插入,删除第一个元素,最节省时间的是
1.不带头结点且有尾指针的单循环链表
2.即使是双链表,只要不带尾指针,都要找到尾结点,时间为O(n)