《大话数据结构》参考

参考:数据结构与算法系列 https://mp.csdn.net/postlist/list/all?undefined=all&cate=8660447

【笔记】《大话数据结构》https://blog.csdn.net/jianbinzheng/article/details/79858736

写在前面
第1章 数据结构绪论
第2章 算法
第3章 线性表
第4章 栈与队列
第5章 串
第6章 树
第7章 图
第8章 查找
第9章 排序


写在前面
快速的过了一遍,对于初学者来说讲的很细,很有助于理解;对于有一定基础的人可能会觉得叙述太墨迹。。。

第1章 数据结构绪论
程序设计=数据结构+算法
数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
数据元素:是组成数据的、有一定意义的基本单元,在计算机中通常作为整体处理,也称为记录
数据项:一个数据元素可以由若干个数据项组成,是数据不可分割的最小单位
数据对象:是性质相同(同数量类型的数据项)的数据元素的集合,是数据的子集
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合
逻辑结构:是指数据对象中数据元素之间的相互关系。集合结构、线性结构、树形结构、图形结构
物理结构:是指数据的逻辑结构在计算机中的存储形式。顺序存储结构、链式存储结构
数据类型:是指一组性质相同的值的集合及定义再此集合上的一些操作的总称
抽象数据类型(Abstract Data Type, ADT):是指一个数学模型及定义在该模型上的一组操作

第2章 算法
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作
算法的特性:输入输出(输入>=0个,输出>=1个);有穷性;确定性;可行性
算法的设计要求:正确性、可读性、健壮性
算法的效率度量:事后统计、事前估算
算法的时间复杂度定义:进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级,算法的时间复杂度,也就是算法的时间量度,计作T(n)=O(f(n))T(n)=O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。
推导大O阶的方法:用1替换加法;只保留最高阶项;最高阶项系数为1
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)O(1)<O(log⁡n)<O(n)<O(nlog⁡n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
第3章 线性表
线性表(List):零个或多个数据元素的有限序列(顺序)
线性表的抽象数据类型Operation:InitList/ListEmpty/ClearList/GetElem/LocateElem/ListInsert/ListDelete/ListLength
线性表的顺序存储结构:指的是用一段地址连续的存储单元以此存储线性表的数据元素——一维数组;插入删除为O(n),查询为O(1)

线性表的链式存储结构:数据域、指针域、结点、头指针、后继指针地址;
每个结点只包含一个指针域的叫做单链表;插入删除为O(1),查询为O(n)

静态链表:用数组描述的链表。每个元素存储数据和指向下一个位置的索引
循环链表:头尾相接的单链表称为单循环链表,建成循环链表(circular linked list)
双向链表:每个结点分别指向前驱和后继的链表——空间换时间
第4章 栈与队列
栈(stack)是限定仅在表尾进行插入和删除操作的线性表;栈顶(top)、栈底(bottom)、后进先出(Last In First Out, LIFO);入栈、出栈
栈的抽象数据类型Operation:InitStack/DestroyStack/ClearStack/StackEmpty/GetTop/Push/Pop/StackLength
栈的顺序存储结构——顺序栈

两栈空间共享,top1+1=top2则栈满,用于同类型、空间需求相反的关系

栈的链式存储结构——链栈,单链表的头结点作为栈顶

栈的应用——递归:斐波那契数列
栈的应用——四则运算表达式:1)中缀表达式转后缀表达式;2)后缀表达式(逆波兰,RPN)运算求结果;
9+(3−1)×3+10÷29+(3−1)×3+10÷2
9 3 1 − 3 ×+ 10 2÷+9 3 1 − 3 ×+ 10 2÷+
队列(queue)是只允许在一端进行插入操作,在另一端进行删除操作的线性表;先进先出(FIrst In First Out, FIFO)
队列的抽象数据类型
Operation:InitQueue/DestroyQueue/ClearQueue/QueueEmpty/GetHead/EnQueue/DeQueue/QueueLength
循环队列,头尾相接的顺序存储结构,解决存储空间问题,front表示队头、rear表示队尾;
QueueLen=(rear−front+QueueSize)%QueueSizeQueueLen=(rear−front+QueueSize)%QueueSize
队列的链式存储结构——链队列
第5章 串
串(string)是由零个或多个字符组成的有限序列,又名字符串
串的抽象数据类型Operation:StrAssign/StrCopy/ClearString/StringEmpty/StrLength/StrCompare/Concat/SubString/Index/Replace/StrInsert/StrDelete
串的顺序存储结构、链式存储结构(每个结点多个字符)
串的模式匹配算法——子串的定位操作。1)朴素方法,每次推进一格;2)KMP模式匹配,跳过子串中前几个与第一个字符不一致的;3)KMP模式匹配改进,再跳过子串本身与第一个字符串一致的

第6章 树
树(Tree)是n(n≥0)个结点的有限集。n=0时称为空树。在任意一棵非空树种:(1)有且仅有一个特定的称为根(Root)的结点;(2)当n>1时,其余结点可分为m(M>0)个互不相交的有限集T1,T2,...,TmT1,T2,...,Tm,中每一个集合本身又是一棵树,并且称为根的子树(SubTree)
度:结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也成为内部结点。树的度是树内各结点的度的最大值。
结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)
同一个双亲的孩子之间互称兄弟(Sibling),结点的祖先是从根到该结点所经分支上的所有结点。
以某结点为根的子树中的任一结点都称为该结点的子孙
结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。
双亲再同一层的结点互为堂兄弟
树中结点的最大层次称为树的深度(Depth)或高度
森林(Forest)是m(m≥0)棵互不相交的树的集合
树的抽象数据类型Operation:InitTree/DestroyTree/CreateTree/ClearTree/TreeEmpty/TreeDepth/Root/Value/Assign/Parent/LeftChild/RightSibling/InsertChild/DeleteChild
树的存储结构:双亲表示法、孩子表示法、孩子兄弟表示法
二叉树(Binary Tree)是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成
二叉树的五个基本结构

斜树,所有结点都只有左子树或都只有右子树的二叉树
满二叉树,二叉树所有结点都存在左子树和右子树,所有叶子结点都在同一层,称为满二叉树
完全二叉树,对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点再二叉树中位置完全相同,则这棵二叉树称为完全二叉树
二叉树性质1:在二叉树的第i层上至多有2i−12i−1个结点(i≥1)
二叉树性质2:深度为k的二叉树至多有2k−12k−1个结点(k≥1)
二叉树性质3:对任何一棵二叉树T,如果其终端结点数为n0n0,度为2的结点数为n2n2,则n0=n2+1n0=n2+1
二叉树性质4:具有n个结点的完全二叉树的深度为⌊log2n⌋+1⌊log2⁡n⌋+1
二叉树性质5:如果一棵有n个结点的完全二叉树的结点按层序编号,对任一结点i有:
1)i=1,根结点;i>1,双亲结点为⌊i2⌋⌊i2⌋
2)若2i>n2i>n,则i无左孩子;否则左孩子为2i2i
3)若2i+1>n2i+1>n,则i无右孩子;否则右孩子为2i+12i+1
二叉树的顺序存储结构,一般用于完全二叉树
二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次或仅被访问一次
前序遍历:中左右;中序遍历:左中右;后序遍历:左右中;层序遍历:按层从左至右;
已知前序遍历和后序遍历,是不能确定一颗二叉树的
按某种遍历顺序,指向前驱或后继的指针称为线索,加上线索的二叉树链表称为线索链表,相应的二叉树称为线索二叉树;把二叉树已某种次序变为线索二叉树的过程称为线索化
线索二叉树等于把二叉树变为一个双向链表,如中序遍历
树转二叉树:加线、去线、层次调整

森林转二叉树:每棵树转二叉树、分别作为前一个的根结点的右子树
从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称做路径长度。树的路径长度就是从树根到每一结点的路径长度之和。
带权路径长度WPL最小的二叉树称做哈夫曼树
按照频率从小到大排序,两两合并组成二叉树新结点,最后合并为哈夫曼树。左分支为0,右分支为1,对应编码为哈夫曼编码
第7章 图
图(Graph)是由顶点的有穷非空集合和顶点之间的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是顶点集合,E是边的集合
无向边:顶点之间的边没有方向,用()表示,组成无向图
有向边:顶点之间有方向,也称弧,用<>表示,组成有向图
无向完全图,无向图中任意两点都存在边。共n×(n−1)2n×(n−1)2条边
有向完全图,任意两个顶点间存在互为相反的两条弧
有很少条边的称为稀疏图,反之称为稠密图
带权的图称为网
子图
同一条边的两个点互为邻接点;边依附/关联于这两个点;度是顶点关联的边的数目;入度是有向图中指向该点的边的数目;出度是发射出的数目;
路径是点到点之间的顶点序列;路径的长度是路径上边/弧的数目;第一个点点和最后一个顶点相同的路径称为回路/环;顶点不重复的路径称为简单路径;只在首尾点不重复的回路称为简单回路/简单环;
无向图中,存在点到点之间的路径则称为两点连通,图中任意两点连通的称为连通图;最大连通子图称为连通分量;有向图中称为强连通图、强连通分量
无向图中连通且有n个顶点n-1条边叫生成树,有向图中一个顶点入度为0其余顶点入度为1的叫有向树,一个有向图由若干棵有向树构成生成森林
图的抽象数据类型Operation:CreateGraph/DestroyGraph/LocateVex/GetVex/PutVex/FirstAdjVex/NextAdjVex/InsertVex/DeleteVex/InsertArc/DeleteArc/DFSTraverse/HFSTraverse
图的存储结构
1)邻接矩阵:点数组+二维矩阵
2)邻接表:数组+链表
3)十字链表:有向图nice
4)邻接多重表:
5)边集数组
图的遍历:从图中某一顶点出发遍历图中其余顶点,且使每一个顶点仅被访问一次
深度优先遍历,DFS;适合找到精确目标;
广度优先遍历,BFS;适合找到相对优解;
最小生成树:把构造联通网的最小代价生成树称为最小生成树
Prim算法:假设N=(P,{E})N=(P,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0} (u0∈V),TE={}U={u0} (u0∈V),TE={}开始,重复执行:在所有u∈U,v∈V−Uu∈U,v∈V−U的边(u,v)∈E(u,v)∈E中找一条代价最小的边(u0,v0)(u0,v0)并入集合TE,同时v0v0并入U,直至U=VU=V为止。此时TE中必有n-1条边,则T=(V,TE)T=(V,TE)为N的最小生成树;O(n2)O(n2)
Kruskal算法:假设N=(V,{E})N=(V,{E})是连通网,则令最小生成树的初始状态为只有n个顶点的无边的非连通图T={V,{}}T={V,{}},图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。直至T中所有顶点都在同一连通分量上为止;O(eloge)O(elog⁡e)
克鲁斯卡尔算法适合边少的稀疏图;普里姆算法适合稠密图
最短路径:两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点时终点
Dijkstra算法:求解点到点的最短距离。用数组D表示距离和数组P表示前驱,通过迭代更新点到起点的最短距离实现。复杂度O(n2)O(n2)
Floyd算法:求解所有的任意两点间的最短距离,用三层循环迭代更新点和点之间的最短距离。复杂度O(n3)O(n3)
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的有限关系,这样的有向图为顶点表示活动的网,称为AOV网(Activity On Vertex Network)。网中点序列,从顶点V1到顶点V2有路径,则V1必在V2前面,这样的顶点序列称为一个拓扑序列
拓扑排序,就是对一个有向图构造拓扑序列的过程,可能的结果包括顶点全部输出——不存在环的AOV网;顶点未全部输出,存在环,非AOV网。方法:从入度为0的顶点开始输出,并删除此点和相关弧,直至不存在入度为0的点为止。
带权的有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,称为AOE网(Activity On Edge Network)
路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,关键路径上的活动叫关键活动。缩短整个工序工期必须从从缩短关键路径入手
第8章 查找
查找(Searching)就是根据给定的某个值,在查找表中确定一个起关键字等于给定值的数据元素(或记录)
查找表(Searching Table)是由同一类型的数据元素(或记录)构成的集合
关键字(Key)是数据元素中某个数据项的值,也称键值;若关键词可以唯一标识一个记录称为主关键字,识别多个的称为次关键字
静态查找表(Static Search Table)只作查找操作的查找表
动态查找表(Dynamic Search Table)在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素
顺序查找(Sequential Search)又叫线性查找,即逐个的查找,时间复杂度最好/最差/平均:O(1)/O(n)/O(n)O(1)/O(n)/O(n)
有序表——折半查找(Binary Search),又称二分查找:每次中中点分割缩小范围;时间复杂度O(logn)O(log⁡n)
有序表——插值查找(Interpolation Search),根据插值公式确定分割点,插值公式key−a[low]a[high]−a[low]key−a[low]a[high]−a[low];时间复杂度O(logn)O(log⁡n);适合表教长且关键字分布均匀
有序表——斐波那契查找(Fibonacci Search),根据斐波那契数列确定分割点;时间复杂度O(logn)O(log⁡n)
索引:就是把一个关键字与它对应的记录相关联的过程,索引由若干索引项组成,索引项应包含关键字和其对应的记录在存储器中的位置
线性索引就是将索引项集合组织为线性结构,也称为索引表
稠密索引:指在线性索引中,将数据集中的每个记录对应一个索引项;数据可能无序,索引项有序

分块索引:对分块有序的数据集,每块对应一个索引项;其中块内无序、块间有序;索引项包括最大关键码、块内记录个数、块首指针

倒排索引:索引项包括次关键码、记录号表;记录号表存储具有相同次关键字的所有记录的记录号(可以指向记录的指针或者是该记录的主关键字)

二叉排序树(Binary Sort Tree),又称二叉查找树,具有性质:左子树为空或所有结点的值小于根结点;右子树为空或所有结点的值大于根结点;其左右子树也是二叉排序树
中序遍历二叉排序树即为有序序列
二叉排序树若为平衡,则查找效率同折半;若严重入斜树,则同顺序查找
平衡二叉树(Self-Balancing Binary Search Tree),是一种二叉排序树,其中每一个结点的左子树和右子树高度差最多为1,也称AVL树
左子树的深度减去右子树的深度称为平衡因子BF(Balance Factor)
距离插入点最近的,且平衡因子的绝对值大于1的结点为根的子树,称为最小不平衡子树;插入新值后需要调整树的平衡性

多路查找树(multi-way search tree)其每个结点的孩子树可以多于两个,且每个结点可以存储多个元素
2-3树:每个结点由两个(2结点)或三个(3结点)孩子,2结点有一个元素,3结点有两个元素;且所有叶子结点在同一层上
2-3-4树:相比2-3树,包括了4结点——三个元素四个孩子
B树(B-tree)是一种平衡的多路查找树,2-3树和2-3-4树是B树的特例,结点最大的孩子数目是B树的阶(order)

B树的应用:处理的数据量很大,无法一次性装入内存,使B树的阶数与硬盘存储的页面大小相匹配;则可以根结点存于内存,查找时只需读取两次硬盘即可;B树的数据结构就是为内外存数据交互准备的
B+树,解决B树遍历的时候也面来回跳转的问题,适合范围查找;在叶结点上保存父节点的值(叶子结点包含全部信息);叶子结点指向下一个叶子结点

散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key);f称为散列函数,又称哈希(Hash)函数;采用散列技术,将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash Table)
散列技术是一种存储方法,也是一种查找方法,记录之间不存在逻辑关系,适合于查找与给定值相等的记录;不适合一个关键字对应多个记录的查找、不适合范围查找
若两个关键字key1≠key2,f(key1)=f(key2)key1≠key2,f(key1)=f(key2),这种现场称为冲突(collision)把key1和key2称为散列函数的同义词
散列函数构造——直接定址法,适合查找表较小的且连续的情况,取关键字的线性函数值做散列地址,如
f(key)=a×key+bf(key)=a×key+b
散列函数构造——数字分析法,适合处理关键字位数较大且若干位分布均匀的情况,抽取关键字的一部分作为散列存储位置
散列函数构造——平方取中法,适合于不知道关键字分布且位数不大的情况,关键字取平方在截取部分,如1234,平方1522756,取中227
散列函数构造——折叠法,适合不知道关键字分布且位数较大的情况,折叠求和,如9876543210分为四组求和987+654+321+0=1962
散列函数构造——除余留数法,最常用,p常取不大于m的最大质数
f(key)=key mod p (p≤m)f(key)=key mod p (p≤m)
散列函数构造——随机数法,适合关键字长度不等
散列冲突处理——开放定址法,冲突时,寻找下一个空的散列地址,也称线性探测法。容易造成堆积现象(非同义词争夺一个地址),可采用二次探测法;或采用随机探测法
fi(key)=(f(key)+di) mod m (di=1,2,3,...,m−1)fi(key)=(f(key)+di) mod m (di=1,2,3,...,m−1)
fi(key)=(f(key)+di) mod m (di=12,−12,22,−22,...,q2,−q2,q≤m/2)fi(key)=(f(key)+di) mod m (di=12,−12,22,−22,...,q2,−q2,q≤m/2)
fi(key)=(f(key)+di) mod m (di为随机数列)fi(key)=(f(key)+di) mod m (di为随机数列)
散列冲突处理——再散列函数法,通过多个散列函数进行,一个冲突换一个

散列冲突处理——链地址法,冲突位置用链表接续

散列冲突处理——公共溢出区法,为冲突关键字简历一个公共的溢出区来存放,适合冲突数据少的情况
如果没有冲突,散列的查找时间为O(1)
第9章 排序
假设含有n个记录的序列为{r1,r2,...,rn}{r1,r2,...,rn},其相应的关键字分别为{k1,k2,...,kn}{k1,k2,...,kn},需确定1,2,…,n的一种排列p1,p2,...,pnp1,p2,...,pn,使其相应的关键字满足kp1≤kp2≤...≤kpnkp1≤kp2≤...≤kpn(非递增或非递减)关系,即使得序列称为一个按关键字有序的序列{rp1,rp2,...,rpn}{rp1,rp2,...,rpn},这样的操作就称为排序
排序的稳定性:关键字相同的两条记录,排序后顺序保持不变即为稳定,否则不稳定
内排序是整个排序过程都在内存中进行;外排序是排序过程再内外村之间多次交换数据进行
基本有序:小的关键字基本在前面,大的基本在后边,不大不小的基本在中间
内排序分类:
1)插入排序:直接插入排序、希尔排序
2)交换排序:冒泡排序、快速排序
3)选择排序:简单选择排序、堆排序
4)归并排序
冒泡排序
1)思想:两辆比较相邻记录,反序交换,直至没有反序记录;
2)优化:若某一次迭代中,后续未发生过交换,则全部停止;
3)复杂度:平均O(n2)O(n2),最好O(n)O(n),最坏O(n2)O(n2),空间O(1)O(1),稳定
简单选择排序
1)思想:每次从剩余序列中找最小的数值,置换到最前面
2)复杂度:平均O(n2)O(n2),最好O(n2)O(n2),最坏O(n2)O(n2),空间O(1)O(1),稳定
直接插入排序
1)思想:逐渐扩充有序表,每次为记录寻找插入位置,即依次后移有序表中较大数字
2)复杂度:平均O(n2)O(n2),最好O(n)O(n),最坏O(n2)O(n2),空间O(1)O(1),稳定
希尔排序
1)思想:步长大于1的插入排序,并逐渐降低步长至1
2)复杂度:平均O(nlogn)~O(n2)O(nlog⁡n)~O(n2),最好O(n1.3)O(n1.3),最坏O(n2)O(n2),空间O(1)O(1),不稳定
堆:完全二叉树;每个结点的值都小于或等于其左右孩子结点的值,为大顶堆;每个结点值都小于或等于其左右孩子结点的值,为小顶堆
堆排序
1)思想:如大顶堆,每次将堆顶元素移走(或和末尾交换),剩余元素重新构造堆,反复执行直至有序序列
2)复杂度:平均O(nlogn)O(nlog⁡n),最好O(nlogn)O(nlog⁡n),最坏O(nlogn)O(nlog⁡n),空间O(1)O(1),不稳定
3)分析:构建堆需要O(n),之后每次调整需要O(logi)
归并排序
1)思想:将序列二分拆分为子序列为1的大小,两两排序归并,直到重新获得n长度的有序序列
2)复杂度:平均O(nlogn)O(nlog⁡n),最好O(nlogn)O(nlog⁡n),最坏O(nlogn)O(nlog⁡n),空间O(n)O(n),稳定
快速排序
1)思想:每次排序将记录分割为两部分,一部分均比另一部分小,再分别对两部分排序
2)复杂度:平均O(nlogn)O(nlog⁡n),最好O(nlogn)O(nlog⁡n),最坏O(n2)O(n2),空间O(nlogn)~O(n2)O(nlog⁡n)~O(n2),不稳定
3)优化:三数取中、尾递归
排序的总结:
1)最好情况看,若待排序列基本有序,则不考虑4中复杂算法,考虑冒泡和插入
2)最坏情况看,堆排序与归并排序更好
3)空间复杂度看,在乎内存使用时,不应选择归并和快排
4)稳定性看,在乎稳定性时,归并好
5)数量上看,n越小越简单,n越大越改进
6)要减少移动次数时,简单选择才比较好

---------------------
作者:煎饼证
来源:CSDN
原文:https://blog.csdn.net/jianbinzheng/article/details/79858736
版权声明:本文为博主原创文章,转载请附上博文链接!

大话数据结构与算法 https://blog.csdn.net/qq_22820783/article/details/86815112

原文地址:https://www.cnblogs.com/highpointengineer/p/10953953.html