一、数据结构的基本概念
数据: 所有能够输入到计算机中,能够被程序处理的描述客观事物的符号。
数据项: 有独立含义的最小单位,也叫做数据域(可以类比为结构体的成员变量)
数据元素: 组成数据的有一定意义的基本单位,也叫节点、记录。一个数据元素由若干个数据项组成。(可以类比为结构体变量)
数据结构: 相互之间存在一种或多种特定关系的数据元素的集合。(可以类比为结构体数组)
二、数据的逻辑结构和存储(物理)结构
数据的逻辑结构:
集合: 数据元素同属于一个集合,但元素之间没有任何关系
线性结构: 数据之间存在一对一的关系 (表)
树型结构: 数据之间存在一对多的关系 (树)
图型结构: 数据之间存在多对多的关系 (图)
数据的存储结构:
顺序存储: 数据存储在连续的内存中,用数据元素的相对位置来表示关系
优点: 支持随机访问(通过下标访问),访问效率高,适合频繁查找的数据
缺点: 空间利用率低、对内存要求高、插入、删除不方便(删除插入数据前需要移动相邻元素)
链式存储: 数据存储在相互独立(没有关系)的内存中,每个数据元素(指针)中增加一个数据项用于存储其他元素的地址,以此表示数据元素之间的关系。
优点: 空间利用率高、对内存要求低、插入、删除方便(删除插入数据只需要修改指针,不影响其他元素间的关系),适合频繁插入删除的数据
缺点: 不支持随机访问(只能通过遍历访问),访问效率低
每种逻辑结构采用什么物理存储方式没有明确规定,通常根据实现的难易程度以及空间、时间方面的要求,来选择最合适的物理存储结构
三、表型结构
3.1 顺序表与链式表
顺序表:
数据项:
存储元素的内存首地址
表的容量
元素的数量
注意:
1、不要越界
2、时刻保持元素的连续性
优点:支持随机访问,修改、访问、排序的效率比较高,大块的连续内存不容易产生内存碎片
缺点:对内存要求较高(内存连续),插入、删除元素时不方便、效率低
链式表:
节点的数据项:
数据域:可以是若干个各种类型的数据项
指针域:指向下一个节点
由若干个节点通过指针域连接在一起,形成链式表
不带头节点:第一个节点的数据域存储的是有效的数据
缺点:添加删除时有可能会改变第一个指针节点的指针指向,参数需要传递二级指针,删除第一个节点时还需要额外处理。
带头节点的:第一个节点不使用,仅仅只是用来指向第一个有效的节点
注意:操作需要从第二个节点(也就是第一个有效数据节点)开始,下标也是
特殊的链表
1、单链表
原因:尾添加效率低、非法下标判断也很低
节点:
数据域
指针域
链表数据项:
头指针
尾指针
节点数量
2、静态链表
节点:
数据域
游标
静态链表的节点存储在连续的内存中,通过下标访问下一个节点
这种链表在插入删除时只需要修改游标的值,而不用重新申请、释放内存从而达到链式表结构的效果
3、循环链表
链表的最后一个节点的next不再指向NULL,而是指向头结点,这种链表叫做单向循环链表,简称循环链表
好处是可以通过任意一个节点遍历整个链表
4、双向链表
节点:
数据域
前驱指针
后继指针
链表的数据项
头节点
节点数量
双向链表的特点:
1、从任意节点都可以遍历整个链表
2、删除、增加不需要定位代操作节点的上一个
3、如果已知节点数量,操作已知位置的节点,可以选择从前到后或者从后到前进行遍历,从而提高链表的操作效率
3.2 功能受限的表(栈和队列)
栈:只有一个进入口的表结构,先进后出,FILO
顺序栈:
数据项:
存储元素的内存首地址
栈的容量
栈顶位置
注意:
栈顶指向顶部的第一个数据,称为满增栈
栈顶指向接下去入栈的位置,称为空增栈
栈顶指向顶部的第一个数据,称为满减栈
栈顶指向接下去入栈的位置,称为空减栈
链式栈:
数据域:
栈顶
节点数量
队列:一个端口进,另一个端口出,先进先出FIFO
顺序队列:
储存元素的内存首地址
容量
队头
队尾 //接下去入队的位置
顺序队列是由一维数组+队头位置front+队尾位置rear组成,入队时rear+1,出队是front+1。
为了能让队列反复使用,要把一维数组想象成一个环,因此rear、front+1后要用队列容量求余
队空:front == real
队满:
1、font == (real+1)%cal
代价是空一个位置不能使用(常考)
2、添加元素个数标记
计算元素个数公式:(rear-front+cal)%cal
链式队列:
由若干个节点组成的队列
数据项:
队头指针
队尾指针
节点数量
四、树型结构
树的基本概念
一种层次关系(一对多)的数据结构。
有且仅有一个特定的节点,该节点没有前趋,被称为根节点。
剩余的n个互不相交的子集构成,其中每个子集都是一棵树,被称为根节点的子树。
注意:树形结构具有递归性(树中有树)
树的专业术语
节点:组成树的基础元素,一个节点也可以是一颗树
节点的度:该节点子树(该节点下一级的节点数)的数量
树的度:树中的节点数量
节点的层次:根节点的层次为1,它的孩子层次为2,孩子的孩子层次为3,以此类推
树的深度:树的最大层次数
叶子节点:节点的度为0的节点
双亲和孩子:节点的子树都称为孩子节点,该节点就是他们的双亲节点
兄弟:具有同一个双亲节点的节点,被称为兄弟节点
祖先:从根节点出发到该节点,中间经过的所有节点都称为它的祖先
子孙:一个节点的子树中的任意一个节点都称为它的子孙
堂兄弟:双亲在同一层的节点,称为堂兄弟节点
森林:n个互不相交的树的集合称为集合
树的存储
树可以顺序存储、链式存储,还可以混合存储,由于存储的信息不同,有以下三种常见的表现方式
1:双亲表示法: 顺序
位置 data 双亲的位置
0 A -1
1 B 0
2 C 0
3 D 1
4 E 1
5 F 2
6 G 3
7 H 4
8 I 4
优点:方便找双亲
缺点:不方便找孩子
2:孩子表示法:
顺序:浪费空间,每个sub_arr(大小为树节点数-1)
位置 data sub_arr(存储孩子的位置的数组)
0 A 1,2
1 B 3,4
2 C 5
3 D 6
4 E 7,8
5 F
6 G
7 H
8 I
顺序+链式:节约空间
位置 data sub_arr(存储孩子的位置的数组)
0 A 1->2->NULL
1 B 3->4->NULL
2 C 5->NULL
3 D 6->NULL
4 E 7->8->NULL
5 F NULL
6 G NULL
7 H NULL
8 I NULL
优点:方便找孩子
缺点:不方便找双亲
兄弟表示法
双亲只存储第一个孩子节点,然后链式指向所有的兄弟节点
优点:可以方便查询到所有兄弟节点
缺点:查询双清亲比较麻烦
二叉树
二叉树是一种常用的数据结构,处理起来比较方便,而且普通树可以转换成二叉树使用
定义:节点度最多为2
二叉树的性质:
完全二叉树:
满二叉树:每一层节点都是满的
性质1:二叉树的第i层(i>1)上至多有2^(i-1)个节点
性质2:深度为h的二叉树中至多是2^h-1个节点
性质3:在任意一个二叉树中,有n0个叶子节点,n2个度为2的节点,则必有n0=n2+1
性质4:具有n个节点的完全二叉树深度为log2X+1,(以2为底,x的对数,结果+1)
性质5:若对一个有n个节点的完全二叉树进行编号(1<=i<=n),那么对于编号为1(i>=1)的节点:
当i=1时,该节点为根,它无双亲节点
当i>1时,该节点双亲节点的编号为i/2
当2i<=n,则有编号2i的左节点,否则没有左节点
当2i+1<=n,则有编号为2i+1的右节点,否则没有右节点
二叉树的存储
顺序存储:必须按照完全二叉树的格式存储节点,空位置使用特殊数据替代
数据项:
存储节点的内存首地址
容量
注意:通过编号的关系来找到双亲、孩子节点
链式存储:由一个个节点组成,通过左右子树指针指向自己左右子树
节点数据项:
数据:
左子树指针
右子树指针
二叉树的遍历:
前序:根 左 右
中序:左 根 右
后序:左 右 根
注意:根据前序+中序 或者 后序+中序 可以还原出一颗树,但是前序+后序无法还原
层序:从上到下、从左到右遍历一棵树,需要配合队列使用(出队一个节点,将它的子节点全入队)
五、图型结构
图型结构:由有穷且非空的顶点和顶点之间的边组成的集合
通常表示:G(V,E) G表示一个图,V是图中顶点(元素)集合,E是图中边(元素之间的关系)的集合
无向图:
边用(A,B)方式表示,点与点之间是互通的
在无向图中,任意两个顶点之间都有边,该图称为无向完全图,边数:(n-1)n/2
有向图:
边用<A,B>方式表示,仅表示从A点到B点有边,有向图中边也叫弧,A是弧尾,B是弧头
在有向图中,任意两个顶点之间都有方向相反的两条弧,这种图称为有向完全图,边数:(n-1)n
注意:不讨论顶点到自身的边与重复出现的边
点多边少的图叫做稀疏图,反之叫做稠密图。
图中顶点到顶点中间的边如果带上数据,这些数据叫做边的权重,带权重的图称为带权图,也叫网
依附于顶点的边的数量称为该顶点的度,有向图中度又分为出度(从该顶点出发的弧的数量)、入度(指向该顶点的弧的数量)
路径:从顶点到另一个顶点中间经过的所有的边叫做路径,边的数量叫做该路径的长度
环:图中有某个顶点最后能通过边绕回该点
回路:专指有向图,从某点出发,最终又有弧能够回到该点,如果该点只有输出、没有输入时,该点一定没有回路
注意:顶点序列中不重复出现的路径称为简单路径
如果顶点V到顶点V1之间有路径,则称V和V1是连通的,如果图中任意两个顶点之间是连通的,称为连通图。
如果一个图中有n个顶点,那么至少需要n-1条边能够到达连通图,如果仅需要n-1条边的连通图,也叫做生成树。
如果在配上权重,又叫最小生成树