数据结构可以分为逻辑结构和物理结构
物理结构是指数据的逻辑结构在计算机中的存储形式。
逻辑结构是指线性结构和非线性结构。
非线性存储结构可分为树结构和图结构
1.树结构
树结构主要用来表示一对多的关系
树是n个结点的有限集;
结点的高度,指的是从结点到叶子结点最长路径的长度;(从上到下数)
所以根结点的高度也是树的高度(即树的最长的长度);
结点的深度,指的是从结点到根结点路径的长度;(从下到上数)
树的遍历
a.前序遍历
即按父结点第一,左子结点第二,右子节点第三的优先级遍历;
输出结点,再看是否有子结点,有则将此优先级代入;
按照这个优先级直到完成遍历
b.中序遍历
即按左子结点第一,父结点在第二,右子节点第三的优先级遍历;
在输出结点之前,看是否有子结点,有则将此优先级代入,没有则输出;
按照这个优先级直到完成遍历
c.后续遍历
即按左子结点第一,右子节点第二,父结点第三的优先级遍历;
在输出结点之前,看是否有子结点,有则将此优先级代入,没有则输出;
按照这个优先级直到完成遍历
树的表示法
孩子兄弟表示法
以二叉链表作为树的存储结构;结点中的俩个链域分别指向该结点的第一个孩子结点和下一个兄弟结点;
二叉树是指每个结点最多有2个子结点的树。
二叉树的顺序存储结构只适合近似满二叉树,i/2为i的左子树,i/2+1为i的右子树;
线索二叉树
即每个结点存在2个指针,还有一个存储数据部分,俩个指针分别指向左右子树;
将叶子结点或者缺少左、右子树的指针利用起来,分别指向前驱结点和后继结点;
二叉搜索树
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;
每个结点中的元素都大于其左子树任一结点的-------------元素(当该结点的左子树不为空时),即该结点的左子树全部小于该结点;
链表的快速插入与删除操作,还是因为它是使用指针来存储逻辑关系的;
只有左或右子树时:只要删除完结点后,将它的左子树或右子树整个移动到删除节点的位置就可以;
有左右子树时:找到须要删除的结点的直接前驱或者直接后继,用直接后继(或用直接前驱)来替换结点,然后删除结点即可
插入时,如果该值不存在,则寻找合适的位置插入
数组快速查找的优势,是因为它将存储的数据按照比结点数据小或大进行分流(左右子树);在查找时能够避免很大部分不在搜索范围内的数据;
平衡二叉排序树在查找时是二叉搜索树中效率最高的;
散列技术
散列技术的方法指的是不同于顺序查找、二分查找、二叉排序树及B-树上的查找。它不以关键字的比较为基本操作,采用直接寻址技术。
即使用一个hash函数将要存储的数据进行hash运算,最后得出hash值,将该hash值用来与要存储的数据进行绑定,通过该hash值直接查找到数据;
但是hash值可能会造成冲突,就是2个不同数据最后经过Hash函数运算后,hash值相同;
散列函数构造方法:
1.除余法
散列函数:h(key)=key%m,
一般情况下,选m为小于或等于表长b的最大质数。
2.数乘法
3.平法取中法
4.基数转换法
5.随机数法
解决hash值冲突:
1.线性探查法
即冲突时,一直往后面一个一个查找,当有空时,插入即可;
2.二次散列法
3.随机重新散列法
4.双重散列法
优先级树和堆:
使用插入函数时,先将新插入的元素放在堆的最底层,然后再调整。
删除最小元素时,要删除最底层最右边的叶子结点,将其存放的元素放入根结点,并调整位置,即将最小的元素放在根结点。
并查集
1.UFunion(A,B,U);将并查集A和B合并,并将结果取名为A或B;
2.UFfind(e):查找包含元素e的集合,并返回该集合名字。
3.图结构
特点:
图也是非线性存储结构,是研究数据元素之间的多对多的关系。
在这种结构中,任意俩个元素之间可能存在关系。
即结点之间的关系可以是任意的,图中任意元素之间都可能相关。
图:记为G=(V,E);
E记为E(G)={(v1,v2);(v2,v3);…};
V为G的顶点集合,是有穷非空集;
E为G的边集合,是有穷集。
即图可以没有边,但至少要有一个顶点;
有向图:图G中的每条边都是有方向的;
无向图:图G中的每条边都是无方向的;
完全图:图G任意俩个顶点都有一条边相连接;
n个顶点的无向图有n(n-1)/2条边,称为无向完全图
n的顶点的有向图有n(n-1)条边,称为有向完全图
顶点的度:
无向图中顶点v的度为关联于该顶点的边的数目,记为D(v)。
有向图,则以顶点v为终点的边的数目,称为v的入度,记为ID(v);
以顶点v为起点的边的数目,称为v的出度,记为OD(v);
顶点v的度则为该顶点的入度与出度之和,即D(v)=ID(v)+OD(v)。
有向图和无向图中,e=1/2*(D(v1)+D(v2)+…+D(vn))。
简单回路:即只有一条路径且起点与终点相同;
连通图:如果图中任意一对顶点都是连通的(即每个顶点都能通过路径找到另一个顶点),则称此图是连通图;
连通图生成树:无向图中,n个顶点,n-1条边,这样的连通子图称为生成树。
连通分量:即在无向图中,非连通图的极大连通子图叫做连通分量。
权和网:
在无向图中,每条边都带一个权,则称为赋权无向图。
有向图中,每条边都带一个权,则称为赋权有向图。
赋权图也称为网络;
图的表示法
1)邻接矩阵表示法(数组)
用一个二维数组,即图的邻接矩阵来存储图中各边的信息;
即二维数组中,行号代表对应的(起始)顶点,列号代表对应的(终点)顶点;
当值为1时,证明从该行号到该列号(顶点到顶点)存在边;
为0时,则不存在边;
有向图的邻接矩阵不对阵,无向图的邻接矩阵是对称的;
网络的邻接矩阵(带权)
存在边的话,它的值为一个整数;不存在边则是无穷;
2)邻接表表示法(数组加链表)
用一个数组来存储(起始)顶点和指针,且指针指向单链表;
用一个单链表来存储对应(起始)顶点与其他相关联的(终点)顶点;
即单链表是用来存储与(起始)顶点之间存在边的(终点)顶点的;
图的遍历
图的算法都需要系统地访问图的每一个顶点。
1)广度优先搜索(BFS):
Breadth_First Search
基本思想:仿树的层次遍历过程。
即一层一层的进行遍历;
深度优先搜索(DFS):
Depth_First Search
基本思想:仿树的先序遍历过程
最短路径
单源最短路径
给定一个赋权有向图F=(V,E),其中每条边的权是一个非负实数。
还给定V中的一个顶点,称为源。
计算从源到图G的其他所有顶点的最短路径长度。
经过迭代产生出最短路径;
刚开始为源点到各顶点之间的有向边的权值;
第一次迭代则是将最小权值的顶点进行迭代;
第二次则是将第二小权值的顶点进行迭代,从第一次开始就有可能更新源点到其他顶点之间的权值;
以此类推,直至最后出现从源点到各顶点的最短距离;
最小生成树:
在图的所有生成树中,权值和最小的生成树称为最小生成树。
Prim(普利姆)算法
设:N = (V,E)是个连通网;
另设U为最小生成树的顶点集,TE为最小生成树的边集。
构造步骤:
(1)初始状态:U={u0},(u0∈V),TE={},
(2)从E中选择顶点分别属于U、V-U俩个集合、且权值最小的边(u0,v0),将顶点v0归并到集合U中,边(u0,v0)归并到TE中;
(3)直到U=V为止。此时TE中有n-1条边,T=(V,{TE})就是最小生成树。
即从选出初始顶点后,一直都是从选择的顶点处寻找权值最小的边(经过的顶点和边不能再经过),然后将顶点和边移到新集合;直到最后得出最小生成树。
Kruskal(克鲁斯卡尔)算法
设G=(V,E)是具有n个顶点的连通网,T=(U,TE)是其最小生成树。
初值:U =V,TE={}.
对G中的边按权值大小从小到大依次选取。
(1)选取权值最小的边(vi,vj),若边(vi,vj)加入到TE后形成回路,则舍弃该边(vi,vj);否则,将该边并入到TE中,即TE=TE∪{(vi,vj)}。
(2)重复(1),直到TE中包含有n-1条边为止。
即将权值最小的边加入,然后判断是否形成回路;一直加到n-1条边为止。