数据结构和算法基础

数据结构与算法

labuladong的算法小抄
数据结构—java实现
https://www.acwing.com/problem/content/description/1/ 算法题库
LeeCode
一、 基本概念
1.数据结构是研究非数值计算的程序设计问题中操作对象以及之间关系的学科
2.能被计算机程序处理的符号都可称之为数据;数据结构(Data Structure DS)是数据及数据元素的组织形式
3.数据结构一般有四种基本形式:集合结构(数据元素在同一个集合中,此外再无其他关联关系) 线性结构(有序的数据元素集合,队列,线性表等) 树状结构(一对多的关系) 图形结构(多对多的关系)
4.数据逻辑结构,与在计算机中的物理存储没有关系,通常分为线性结构和非线性结构(集合 图 树等结构)
5 数据物理结构(存储结构) 分顺序和链式两种,
(1)顺序存储的特点是数据元素在存储器中的相对位置体现数据元素相互间逻辑关系,占用一整片连续空间,一般使用数组即可实现
(2)链式存储在物理上可能不连续,因此除了保存元素本身,还要保存与其有关的其他元素的地址,通过地址才能访问到其他元素
(3)顺序存储的基础上延伸出索引存储和散列存储,索引存储就是除了数据意外再增加索引文件,把一个大顺序表分成几个顺序子表,提高查找效率;散列存储就是在数据元素和存储地址之间建立某个映射关系,通过元素本身快速定位到地址
(4)数据结构主要描述的是数据元素之间的逻辑关系、数据在物理上的存储方式和数据的运算等内容
6.数据结构本身就是抽象的 , 抽象数据类型(ADT)包括三要素:数据对象(存储的是什么)、数据关系(逻辑关系)、基本操作(crud、参数列表、初始化、操作结果等),ADT可作为一个对象整体去研究,与java的面向对象是契合的,即一个抽象数据类型可表示为一个类
7.算法 是指在有限的范围内,为解决某种问题而采取的方法和步骤的完整描述,是有穷的规则序列,为某一特定问题而生,特征:有穷性(若干步骤后能有结果返回)、确定性(每个步骤 有 确定含义,相同输入带来相同输出)、可行性(通过已实现的基本运算可得到结果)
8.算法效率分析
(1)时间复杂度,一般我们只需要比较哪个算法时间多哪个时间少即可,比较时忽略机器影响,时间复杂度与规模n正相关,如树中n是节点数,排序中n为元素个数 ;
定义:通常把算法中基本操作重复执行的次数作为算法的时间复杂度
i.不同算法的优劣比较主要以其增长趋势为准,因此一般采用数量级的形式表示 :
T(n)=O(f(n)) O表示Order的第一个字母 称之为大O表示法低阶或者常数通常会被忽略不写
ii.一般在比较函数时 f(n)<g(n)比较的的是相对增长率,通常含更高阶的的函数增长率越大,时间复杂度往往不是精确的执行次数,而是估算的数量级,体现当规模n趋近于无穷时,算法的执行时间的变化趋势
iii 一般在分析时间复杂度时,由于基本操作重复执行的次数就是时间复杂度,因此一般只关注随着规模n增大,执行语句次数变化最快的语句即可分析出

eg:
for(i=1;i<n;i++){
sout(111);
for(j=1;j<n;j++){}
}

明显语句次数变化最快的是二层循环内部,因此可忽略sout打印语句,复杂度:O(n^2)
iv 求时间复杂度其实是求执行次数对规模n的函数即 x=f(n)
iamge
v.常见数量级的时间复杂度
在这里插入图片描述

vi.算法复杂度计算的过程
参考:https://www.cnblogs.com/wangzheming35/p/12929095.html
假设执行m次结束,结束条件肯定与n有关系,然后推出来m与n的关系,即m=f(n),则可以得到复杂度O(n)
eg:

void fun(int n)
{
    int x=n,y=0;
    while(x>=(y+1)*(y+1))
        ++y;
}

设 执行m次结束,结束的临界条件为n=x=(y+1)^2,如果能求出执行后m与y的关系,就能得到m与n的关系,其中的m就是算法复杂度
在这里插入图片描述

则 n=(m+1)^2 ==>m=O(n开方)
二、线性表
1.线性表 是最简单的数据结构,具有线性关系,元素前后有前驱后继的关系,同时有明显的第一个节点和最后一个节点,可逻辑的表示为:(a1,a2,…ai-1,ai,an),每个数据都有且仅有一个直接后继,称下标i为元素a在线性表中的位序
2.线性表的顺序表示,直接用物理上一组连续的存储单元来存放数据(顺序存储),任意数据元素的存放位置从起始位置开始,与元素下标成正比,可根据位序访问任意表中元素,即随机 存取的存储结构
3.线性表的链式存储,存储一般通过节点存储,节点里包括数据以及它的前驱后继
三、栈和队列
1.栈和队列是线性表的子集
2.栈限定在表尾部进行插入和删除操作的线性表,允许操作的一端成为栈顶,另一端为栈底 :LIFO
3.顺序栈,以顺序存储的方式存放栈式数据结构,设指针top指向栈顶元素的位置,top初始值为-1,表示空栈,每次入栈top+1
4.链式栈,不需要头节点,直接是top指向第一个数据节点即可
5队列队头和队尾 队头出队,队尾入队,必须有一个头指针和一个尾指针,队空的判断方式是top=rear
6如果是正常 数组的话,队头出,队尾入队,则会发生已经出队的空位置无法有效利用,会出现假溢出的情况,一般顺序队列都会做成循环队列,为了能够区分队空和队满的情况,将队列末端的元素空间保留,也就是说length长队列,实际放的元素为length-1个
(1)循环队列初始化时 front和rear都指向下标为0的位置,入队时,rear后移一位,front位置不变,出队时,rear不变,front后移一位
(2)后移时 rear=(rear+1)%capacity
;front+(front+1)%capacity;这是考虑到循环的情况
(3)队空的判断是 front=rear;队满的判断是: front=(rear+1)%capacity
7.链队列,不存在假移除的情况
⦁ 四、串的使用
⦁ 1.串由0或者多个字符串组成的有限序列,记为:s=‘a1a2…an’ s为串名,n为串长,其中任意连续字符串组成的子序列称为子串,n为长度,子串在主串中的位置用子串中第一个字符在主串中的位置表示,串只能用单引号括起来,但是单引号本身不计入串中,两串相等是说长度一样,且对应位置的字符一样
⦁ 2. 串在java中的实现就是String
⦁ 五、广义表
⦁ 1.广义表是线性表的一种推广,数据可以是单个数据(单元素,可称之为原子),也可是一个广义表(称为子表)。非空表的第一个元素称为表头,其余元素组成的子表称之为表尾, 最外层包含的元素个数称之为广义表的长度,广义表中包含的括弧的重数称为深度,原子深度为0,空表深度为1,广义表使用大写字母
⦁ eg:C = (a,(b,c,d)) 长度为2,深度为2,表头为Head© =a Tail© = ((b,c,d)) //这里的两重括号主要是组成子表
⦁ 3.实现上通常使用链式存储结构,以下是存储原子节点和表节点的结构
在这里插入图片描述
在这里插入图片描述
⦁ 六、树和二叉树
⦁ 1.树是若干节点组成的有限集合,只有一个根结点,其余节点可划分为不相交的集合,每个集合称为根的子树,若树的结点个数为0,则称为空树,根结点没有前驱节点,其余节点有且仅有一个前驱节点
⦁ 2.树的所有节点可以由0个或者多个后继结点
⦁ 3.树相关的术语
⦁ (1)结点:树中的元素包括数据项和若干指向其子树的分支
⦁ (2)结点的度:结点拥有的子树的个数
⦁ (3)叶子节点:度为0的节点,分支节点:度不为0
⦁ (4)孩子、父、兄弟、祖先、子孙
⦁ (5)结点层数:规定树的根结点层数为1,其余结点层数等于双亲结点层数+1
⦁ (6)树的深度:所有节点的层数中最大层数称为深度
⦁ (7)树的度:树中各节点度的最大值称为树的度
⦁ (8)有序树和无序树
⦁ 树中任意节点的子节点之间没有顺序关系;兄弟节点之间无顺序的树称为无序树,兄弟节点有顺序的树称为有序树
⦁ 4.二叉树
⦁ (1)每个结点最多拥有2个子树的树结构,二叉树结点个数为0时则为空二叉树,二叉树是有序的,若左右颠倒则成为另一个二叉树**,只有一个子树也要区分左子树还是右子树,五种形态**:
在这里插入图片描述

⦁ (2)满二叉树:所有叶子节点在同一层上,同时所有分支节点都存在左子树和右子树
在这里插入图片描述

(3)完全二叉树:如果二叉树中叶子节点只出现在最后一层和次一层,且最后一层的节点依次从左到右分布(即必须先有左子树再有右子树),则此二叉树称为完全二叉树

  1. 二叉树的顺序存储
    用一组连续的存储单元存放树节点,二叉树节点从上到下从左到右的顺序存储,一般虐泉二叉树和满二叉树采用顺序存储节省空间,且能够利用数组元素下标值确定几点在二叉树中的位置以及节点关系,一般的二叉树要采用数组存储,则需要将树增加空节点改造成以上两种,浪费空间,不适宜用数组存储

6.二叉树链式存储结构,有两种形式
(1)二叉链表存储,每个节点存左右子树,左右位置无子树则对应填充为null;节点描述为: Node lChild;T data ; Node rChild;也可以使用头结点指针的方式存储二叉链表; 二叉链表存储的关键是确定根节点
(2)三叉链表存储
每个节点由 lchild data rchild和parent组成,但是增加了parent节点的空间开销
ps:一般均使用二叉链表存储二叉树
7.树的存储结构
顺序和链式都可存储,但是要求既要能存储本身数据,也要能够反映各节点之间逻辑关系,
常用的是孩子兄弟表示法,在树中每个节点除了信息外,还能增加两个分别指向该节点的第一个孩子节点和下一个兄弟节点的指针
在这里插入图片描述
8.二叉树的应用:huffman树与huffman编码
二叉树路径长度是指根节点到每个叶子结点的路径长度之和,如果叶子结点都带权,那么路径长度与叶子结点权值的乘积叫做二叉树的带权路径长度,相同权值的叶子结点不同的二叉树形状最终的带权路径长度(WPL)是不同的,哈夫曼树就是最小带权路径长度的树,
构造思想是将越大权值的叶子结点越靠近根节点,权值小的原理根节点,
构造过程:所有叶子结点作为一个集合,从集合中选取最小和次小的节点用于构造新二叉树,该二叉树根节点是这里两个节点的权值相加之和,然后将新的根节点放入最初的集合中,再将集合中选取的以上两个节点剔除,重复以上过程,直到剩下一个节点,即新树的根节点
在这里插入图片描述
9.⦁ 二叉树的性质
⦁ 性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1)。
⦁ 性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1)。
⦁ 性质3:包含n个结点的二叉树的高度至少为log2 (n+1)。
⦁ 性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。即叶子节点和单分支节点数量的关系
⦁ 七、图
⦁ 1.图中数据元素称为顶点,图示顶点集合(V)和顶点关系集合(E)组成,记为G=(V,E)
⦁ 2.无向图和有向图表示方法:
有向图表示<x,y> 含义为:从顶点x向y发出边,x为始点(弧尾),y为终点(弧头),有向边也称为弧
在这里插入图片描述

⦁ 2.如果用n表示顶点数目,e表示图中边,
⦁ 则对于无向图,有:
⦁ 0<=e<=n(n-1)/2,当e=n(n-1)/2时,该无向图称之为完全图;
⦁ 对于有向图有:0<=e<=n(n-1),当e=n(n-1)时,该图称之为有向完全图
⦁ 3.如果图的边带权值,比如(时间、距离等)则称为网;两个图 G1=(V1,E1);G2=(V2,E2);如果V2是V1子集,E2是E1的子集则称图G2是图G1的子图;邻接点:无向图中两顶点之间存在一条边则两顶点互称邻接点,顶点的边的数目称为度 记ID(A)=1,如上图A和D ;有向图中有出度和入度,出度OD是以顶点为弧尾的弧的数量,入度ID相反,订单的度为TD(V)=OD(V)+ID(V);如上图TD(A)=OD(A)+ID(A)=2+1=3
⦁ 4.图中两个顶点间的路径称为顶点间的序列,路径中包含的边的数目称为路径长度,如上述A到E路径为{A,D,E},长度为3,当然路径不唯一,若序列中第一个和最后一个顶点相同,该序列称为回路;序列中顶点不重复出现的路径称为简单路径,;简单回路:除第一个和最后一个顶点相同外,其余顶点不重复出现,称为简单回路
⦁ 5.图的存储结构-邻接表
⦁ 邻接表是图的一种顺序存储和链式存储结合的存储方法,图中每个顶点V存放在数组中,将所有邻接于V的顶点链表组成单链表,称为顶点V的邻接表,邻接表中包括两个数据结构:顶点节点(data存v数据+firstArc指向V的第一个邻接点的边节点);边节点(abjVex指向邻接点序号,nextArc指向下一个邻接点的边节点,info存权值相关信息)
在这里插入图片描述

⦁ 5无向图邻接表性质:第i个链表中节点数目为第i个顶点的度;所有 链表中节点的数目的一半为图中边的数目(因为每条边实际都存储两次);占用的存储单元为n+2e(n为顶点,e为边数)
⦁ 6.有向图,第i个 的邻接表节点数只是顶点v的出度,对于入度,一半再建立一张有向图的逆邻接表,如图为出边表和入边表
在这里插入图片描述

⦁ 7.有向图的邻接表的性质:第i个链表中节点数目为顶点i的出度,逆邻接表中为顶点的入度,所有链表中节点数目为图中弧的数目,占用的存储单元为n+e
8.图的遍历–深度优先搜索 从一个顶点访问邻接点,然后再访问该邻接点的邻接点,以此类推
广度优先搜索 先访问顶点的所有邻接点,再访问某个邻接点的所有邻接点,每个顶点加个是否访问的标志位
第七章 查找
1.查找相关概念
数据项是某个标识单位,也称之字段,数据元素是若干数据项构成的数据单位,字段和对象的关系
2.查找表是同类型数据元素构成的集合;静态查找表:只判断数据是否存在和查找属性值操作;动态查找表:除了静态操作以外还有插入和删除操作;
3.衡量各种查找算法的优劣标准是最多比较次数称为最大查找长度(MSL)和平均比较次数称为平均查找长度(ASL)ASL一般可认为元素出现的概率是相等的
4.静态查找表:一般是线性表,顺序存储或者链式存储都可
5.顺序查找平均查找长度(第一个比较1次,第二个比较2次,依次类推)为 (1+n)/2,查找长度的量级n就是时间复杂度即: O(n)
⦁ 6.折半查找即二分查找,效率较高,但是要求 必须顺序存储且有序(即数组存储且有序的线性表采用二分查找效率高),平均查找长度时log2(n)数量级,时间复杂度为O(log2n),折半查找比顺序查找效率高,但是要求顺序存储并有序
⦁ 7.动态查找表:对于定值key,表中存在key则成功,否则插入key,在查找中动态插入和删除操作
⦁ (1)二叉排序树,此动态查找表当二叉树接近满二叉树时,深度为log2n,最坏查找时间复杂度为O(log2n),与折半查找相同,而当二叉树接近于单分支树时,深度为n,最坏复杂度为O(n),因此二叉树构造尽量向满二叉树靠近,查找效率最高
⦁ (2)平衡二叉树:首先是一个二叉排序树左右子树深度之差的绝对值不超过1,同时左右子树也是平衡二叉树,左子树深度-右子树深度称为平衡因子,可知平衡二叉树平衡因子只能是0 -1 1,它的平均查找长度与其深度(log2(n)+1)同数量级(也同完全二叉树)
⦁ (3)平衡二叉树的构造:构造排序树时,插入节点先判断是否因插入节点破坏了树的平衡,如果是则找出最小不平衡子树,保证排序树的前提下调整最小不平衡子树3节点连接关系,达到新的平衡,称为AVL树,最小不平衡子树:距离插如节点最近,且平衡银子绝对值大于1的节点作根节点的子树,调整最小不平衡子树的4种情况:

在这里插入图片描述
在这里插入图片描述



⦁ (4)B-树
⦁ i.顺序查找、折半查找以及平衡二叉树等都只适合数据保存在计算机内存中的情况。B树是一种平衡多路查找树,插入和删除易于平衡,查找效率高,适合组织文件动态索引结构,常用于文件系统
⦁ ii.B树的查找在这里插入图片描述
与二叉排序树类似

在这里插入图片描述


⦁ iii.在节点间按照指针搜索,而节点内则可顺序或者折半查找
⦁ B-树插入和删除也比较快

(5)红黑树是一种自平衡的二叉排序树,AVL树保持平衡,但是旋转太耗时了,而红黑树没有AVL那么的平衡,因此插入删除效率高(不需要旋转),但AVL树查找能比红黑树效率高
红黑树特点:
(1)每个节点是黑或者红;(2)根节点是黑;(3)叶子节点是黑;(4)如果一个节点是红色,则子节点必须黑色,即两个红色不碰面;(5)任意一个节点到每个叶子节点的路径都包括相等数量的黑节点
尽管左右子树的层数差好多,但是其中所包括的黑节点的层树是相等的(性质5)因此叫红黑树为黑色完美平衡树
红黑树的自平衡通过 左旋 右旋和变色来实现

红黑树的查找与二叉排序树查找一样,即2分查找 O(log2N)
红黑树插入=二叉查找树插入+自平衡
插入操作就是在二叉排序树上的插入操作,插入后的自平衡分多种情况
删除操作也要自平衡,分多种情况
参考:
https://www.jianshu.com/p/e136ec79235c
(6)二叉搜索树,容易单一方向倾斜,极端变成链表,查询的效率会降低
AVL 平衡二叉搜索树,左右子树的深度差不超过1,以维持其二叉树的特征,增加了左旋和右旋,删除和新增会旋转,成本很高
红黑树,特殊的一种接近于AVL树的树,旋转次数会变少,在查询和旋转次数之间平衡,非黑即白;根节点是黑;叶子节点是黑(Null节点);从一个节点到子节点所有路上 相同数据的黑节点;从 叶子节点到根节点的所有路径上不能有连续的红色节点
以上二叉树的问题在于:二叉树分支只有2个,树的深度会很深,造成io次数变多
(7)B+树
B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用,且非叶子节点每一个上都有关键字,且关键字升序排列;
节点中存储指针(指向下一个节点(磁盘块)),键值即表中主键
与B树的区别在于,B树非叶子节点还会存数据,而B+则所有数据都在叶子节点存储
优化在于:B树非叶子节点存储data的话,一个磁盘块存不了太多索引和指针,这样在查找时,就需要读取更多的磁盘块,IO,效率很差,而B+树能够更多的在一个磁盘块上存储更多的键和指针,减少非叶子节点的IO次数
动画演示过程
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

8.哈希表
(1)概念:预先知道关键字和存储位置的关系H,H(key)作为key在表中的位置,H称为Hash函数,该表称为hash表,hash冲突:key1!=key2,但是H(key1)==H(key2);冲突很难避免,只能当发生冲突时使用处理冲突的方法解决,根据hash函数和冲突处理方法将一组key值映射到有限个地址的过程称为散列或者哈希,存储key值的表称为hash表
(2)hash冲突处理方法
i 开放定址法:
Hi=(H(key)+di)%m;Hi表示第i次产生的哈希函数,m为hash表长,di为增量序列,di三种取法:线性探测再散列 di=cxi,最简单可取c=1;二次探测再散列,di=12;-12,22,-22…±k^2(k<m/2);随机探测散列 di取伪随机数
ii.链地址法:将hash表定义为一个m个头指针组成的指针数组T,把hash地址相等的关键字放在同一个链表中,即hash后的地址为i的关键字放在T[i]所指向的单链表中,hashMap中的解决方式就是链地址法,eg:
在这里插入图片描述
(3)hash表查找取决于不同的处理冲突的方法,影响其ASL的因素有:处理冲突的方法和装填因子(a=n/m)n是记录数,m是表长度,当然记录太多而表长小的话自然就容易冲突了,因此可选一个合适的 a,使得ASL不会太大
第八章
1.排序: 稳定排序:相等的数字排序完后,顺序不变;否则就是非稳定排序
2.排序的时间开销由比较和移动数据的次数衡量
3.插入排序 按照关键字大小插入到前面已经排好序的子表中的合适位置
(1).直接插入排序
最好情况是已经有序,复杂度是O(n),n个记录值只需比较n次,移动0次,最坏情况是完全逆序,移动和比较的次数都是O(n^2),直接插入排序是一种稳定排序,关键值相同的元素相对位置不会变化
(2).希尔排序
现将整个表分为若干子序列,对子序列分别进行直接插入排序,待基本有序后再进行一次大的直接插入排序,大大减少移动次数, 过程:取整正数d1(0<d1<n),将全部记录分为d1组,即距离为d1整倍数的元素分为一组,然后组内排序,接着d2<d1重复上述直到di=1;一般n个记录的序列取:d1=n/2; d2=d1/2;d3=d2/2;…di=di-1/2 di=1;
5.选择排序
(1)简单选择排序,待排序序列为(r1,r2…rn),首选在(r1,r2…rn)中选出最小

  • 记录与r1交换,然后在(r2…rn)中选最小与r2交换,然后在(ri…rn)中选最小与ri交换,直到i=n
  • 不稳定排序 eg: 5 5* 2 第一次就会将5挪到5*后面,因此不稳定
    (2)堆排序 一般用于基数较大的文件排序,内存数据排序不是很理想, 因为要建堆
    6.归并排序(二路归并)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值