数据结构与算法设计分析—— 数据结构及常用算法_数据结构和算法-程序员宅基地

技术标签: 数据结构与算法设计分析  算法    队列  循环队列  数据结构  

一、常用的数据结构

(一)线性结构

1、顺序表与链表

线性表是线性结构,是包含n个数据元素的有限序列,通过顺序存储的线性表称为顺序表,它是将线性表中所有元素按照其逻辑顺序,依次存储到指定存储位置开始的一块连续的存储空间里;而通过链式存储的链表中,每个结点不仅包含该元素的信息,还包含元素之间的逻辑关系的信息。

  • 顺序表实现简单,可以随机存取,其存储密度大,但是执行插入、删除操作需要移动大量元素,效率低,另外其存储空间需事先分配,容易造成空间浪费或溢出。
  • 链表不支持随机存取,只能顺序存取,通过指针来体现元素之间的逻辑关系,存储密度比顺序表小,其执行插入、删除操作不需要移动元素,只需修改指针,效率高,另外它还支持动态分配存储空间,不会造成空间浪费或溢出。

2、栈

栈是一种只允许在一端进行插入或删除操作的线性表(限制在表尾),所以是一种特殊的线性表,它与队列具有相同的逻辑结构,都属于线性结构,区别在于对其中元素的处理不同,栈遵循的原则是先进后出(FILO),即后进的元素先被取出来,它是被限制存取点的线性结构。

由于它是一种线性表,所以也有两种方式:顺序存储结构和链式存储结构,即对应顺序栈链式栈,另外,栈的插入操作称为进栈,栈的删除操作称为出栈

3、队列

队列与栈一样,它也是一种特殊的线性表,其操作受限,它与栈具有相同的逻辑结构,都属于线性结构,区别在于其中元素的处理不同,队列只允许在一端进行插入,且只允许在另一端进行删除,队列遵循的原则是先进先出(FIFO),即先入队列的元素最先离开,与日常生活中的排队是一样的。

同样,也有两种方式存储队列,顺序存储结构和链式存储结构,即对应顺序队列链队列,另外若将顺序队列的一维数组首尾相连形成一个环状,即称为循环队列,也就是在逻辑上视为一个环连接起来。

4、串

串也是一种特殊的线性表,由零个或多个字符组成的有限序列,其数据元素就是字符,串的数据元素必须是单个字符。由任意多个连续的字符组成的子序列称为串的子串,包含子串的串称为主串,线性表是以单个元素进行相关操作,而串是以子串进行相关操作的。

通过静态数组实现定长顺序存储,一组地址连续的存储单元存储串值的字符序列,其中每个串都被分配一个固定长度的ch[MAXLEN]数组,即串的顺序存储结构,同时,也可以使用动态分配函数malloc()和free()来进行串的堆分配存储,其分配的存储空间是动态的。串的链式存储结构中,分为两个域和线性表一样,若通过单链表存储,则data域存储字符,next域存储指向下一个结点的指针。

(二)非线性结构

1、树与二叉树

(1)
树是一种非线性结构,它是树形结构,是含有n个有限元素的数据元素集合(其中n≥0,n=0时为空树),由m(m≥0)棵互不相交的树的集合称为森林。例如,线性结构中的数据元素之间是“一对一”的关系,而树形结构中的数据元素之间是“一对多”的关系。树满足两个条件,一个树有且只有一个根结点,其中根结点没有前驱结点,除了根结点其他所有结点都只有一个前驱结点;剩下的结点为m(m≥0)个互不相交的非空集合,其中每个集合又可以称为一棵树,即根的子树。

树中两个结点之间的路径由两个结点间所经过的序列构成,路径长度是路径上所经过的边的个数,而树的路径长度是指根结点到每个结点的路径长的总和。树中结点的子结点(孩子)个数称为该结点的度,而树中结点的最大度数称为树的度
(2)二叉树
二叉树是一种特殊的树,与普通的树相比,普通树中结点的后继结点可以是任意多个,而二叉树中结点的后继结点最多只能有两个,另外有两种特殊的二叉树,满二叉树和完全二叉树,满二叉树是完全二叉树的特例,可以说若一棵树是满二叉树,则它必是完全二叉树,但不能说一个完全二叉树必是满二叉树。

完全二叉树中,叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。

  • 二叉树也是含有n个有限元素的数据元素集合(其中n≥0,n=0时为空二叉树),由一个根结点以及两个不相交的非空树,分别称为左子树右子树组成,二叉树是一个特殊的有序树(其中结点的各子树从左到右有序),其中左右子树的次序不能任意交换,同样,左子树和右子树也是二叉树。
二叉树名称 特点
满二叉树 深度(高度)为h,具有2h-1个结点的二叉树,其中每层结点都是满的`
完全二叉树 树中除最后一层外,其余层的结点都是满的二叉树,或结点的右子树缺少连续的若干个结点

(3)二叉树的存储结构
二叉树的存储结构也分为顺序存储结构和链式存储结构,二叉树的顺序存储结构通过使用一组地址连续的存储单元数组进行存储,二叉树的链式存储结构通过链表实现,一个二叉树链表结点由数据域和指针域组成,除了data数据域用于存放结点的信息外,每个结点含有两个指针,左指针域lchild右指针域rchild,分别指向该结点的左孩子结点和右孩子结点,它们用于存放该结点左/右子树的地址,当左/右子树不存在,其指针域为空。
在这里插入图片描述
双亲表示法

  • 顺序存储结构中的双亲表示法是通过采用一维数组来存储树中的结点,其中每个结点被赋予一个结构体类型,包含data域和parent域,分别存储结点的数据域存储该结点双亲的数组下标
    在这里插入图片描述

孩子链表表示法

  • 链式存储结构中的孩子链表表示法是将所有结点存放在一个顺序表中,每个数据元素有两个域,分别是该结点的数据域和存放该结点的第一个孩子的地址,同时为树中每个结点都构建一个单链表,它也有两个域,分别是存放该孩子结点在顺序表中的数组下标和存放下一个孩子的地址。
    在这里插入图片描述

通过孩子链表表示法可以很容易地找到该结点的孩子结点,但是若要找到结点的双亲则较为麻烦,需遍历n个结点中孩子链表指针域所指向的n个孩子链表。

孩子兄弟表示法

  • 同时,链式存储结构中还有一种称为孩子兄弟表示法, 是采用二叉链表,其中包含三个域,分别是数据域和两个指针,即*child指向第一个孩子结点的地址、*brother指向该结点的下一个兄弟结点的地址。
    在这里插入图片描述

这种方法的缺点是若从当前结点查找其双亲结点较为麻烦,解决方法是为每个结点增设一个parent域用于指向其父结点。

2、图

图和树一样,也是一种非线性结构,线性结构中的数据元素之间是“一对一”的关系,树形结构中的数据元素之间是“一对多”的关系,而图中的数据元素之间是“多对多”的关系,每个数据元素可以有多个直接前驱和多个直接后继,即图的结构是网状结构,可以将图定义由一个非空的顶点集合V(顶点集)和一个描述顶点之间关系——边的有限非空集合E(边集)所组成的一种数据结构,记为G=(V,E),其中图的顶点集V不一定为空,而图的边集E可以为空。

图与线性表、树不一样,线性表、树可以为空表、空树,但图不能为空图。

(1)无向图和无向完全图

  • 按照图中的边是否有方向性,可以分为有向图和无向图。
    无向图中每条边都没有方向,一般用圆括号“()”表示两个顶点之间的,若边中带有数据信息,则称为,(vi,vj)表示顶点vi和顶点vj之间的无向边,若一个无向图中,若每个顶点都有一条边连接,则称为无向完全图

(2)有向图和有向完全图

  • 有向图中每条边都有方向,一般用尖括号“<>”表示两个顶点之间的首尾关系,<vi,vj>表示从顶点vi到顶点vj,同样,若弧中带有数据信息,也称为。<vi,vj>其中第一项vi称为弧尾,第二项vj称为弧头,也称为顶点vi邻接到顶点,若一个有向图中,若每个顶点都有互相相反的两条弧连接,则称为有向完全图

(3)

  • 在无向图中,对于一个顶点,其边的个数称为该顶点的度,记为TD(v),而在有向图中,对于一个顶点,该结点的度等于顶点的入度+顶点的出度,该结点的弧头数目称为入度,记为ID(v);结点的弧尾数目称为出度,记为OD(v),即TD(v)=ID(v)+OD(v)。

(4)路径、路径长度和简单路径

  • 路径,即一个顶点到另一个顶点经过的顶点序列,路径上边或弧的数目称为路径长度;若顶点序列中的各顶点不同,则称这样的路径称为简单路径

(5)回路和简单回路

  • 在一个路径中,若起始结点与结束结点相同,则称该路径为一个回路;另外,除了第一个结点和最后一个结点外,若顶点序列中的各顶点不同,则称这样的路径称为简单回路

(6)连通图和强连通图

  • 连通图指的是无向图,强连通图指的是有向图:
无向图
连通图
有向图
强连通图

连通图

  • 在无向图中,若一个顶点到另一个顶点存在路径,则称这两个结点是连通的。若无向图中任意两个结点都是连通的(任意两个结点之间有路径),则称该图为连通图,否则为非连通图;无向图的极大连通子图称为连通分量
    在这里插入图片描述

强连通图

  • 在一个有向图中,任意两个不同的顶点都存在相互之间的路径,则称为强连通图,其中任意顶点到其他顶点都有路径,但不一定有弧;同样,有向图的极大强连通子图称为强连通分量
    另外,有向完全图一定是强连通图,但强连通图不一定是有向完全图,因为有向完全图中每个顶点都有互相相反的两条弧连接。
    在这里插入图片描述

(7)距离

  • 若从一个顶点到另一个顶点之间的最短路径存在,这称该路径的长度为该结点到另一个结点的距离,若两个结点之间不存在路径,则记距离为无穷(∞ )。

(8)图的存储结构

邻接矩阵

  • 图的邻接矩阵存储结构用于表示顶点之间的相邻关系,其中通过一个一维数组存储顶点,一个二维数组存储顶点之间的相邻关系,一个顶点数为n的图的邻接矩阵是n×n(n行n列),即一个方阵,用邻接矩阵方法来表示一个图需要n2个存储空间,它只与图中的顶点数有关,其空间复杂度为O(n2)。
    在这里插入图片描述
    在这里插入图片描述

邻接表

  • 邻接表方法采用顺序存储结构和链式存储结构来存储图,对于图中每个顶点vi,将所有邻接于vi的顶点连成一个单链表,即这个单链表就称为顶点vi的邻接表,另外还需将所有顶点的邻接表放进数组中,通过邻接表存储图所用的空间大小取决于图的顶点数和边的个数,顶点数n决定了顶点表的空间大小,边的个数决定了边表结点的空间大小。由于图G=(V,E),即需要在邻接表中定义两种结点结构,即顶点表和边表,另外若边上带有权值,则还需中边表上添加一个信息代表权值。顶点表中除了数据域用于存储顶点信息,还有指向第一条与其邻接顶点的指针域;边表中由邻接点域和指向下一条邻接边的指针域组成。
    在这里插入图片描述

邻接多重表

  • 邻接多重表是一种链式存储结构,用于表示无向图,邻接多重表也是由顶点表和边表组成,每个顶点由两个域组成,data域用于存储顶点的信息,firstedge域用于指向第一条与其邻接的边,顶点表的结构如下:
data firstedge

由于无向图的特点,一条边两个结点,所以每个边结点同时连接在两个链表中,相对于邻接表,邻接多重表同一条边只需一个结点表示,边表的结构如下:

mark ivex ilink jvex jlink info

首先,mark域为标识域,用于表示该边是否被访问过;ivex和jvex为该边邻接的两个顶点在图中的位置;ilink和jlink用于指向下一个邻接顶点ivex和jvex的边;info用于指向和边相关的各种信息的指针域。

十字链表

  • 十字链表也是一种链式存储结构,用于表示有向图,data域用于存储顶点的信息,firstin和firstout域分别指向以该顶点弧头或弧尾的第一个弧结点,顶点表的结构如下:
data firstin firstout

十字链表中在表示弧时将其视为一个结点,tailvex和headvex域,分别表示弧的弧尾和弧头在图中的位置,hlink指向弧尾相同的下一条弧,tlink 指向弧头相同的下一条弧,info用于指向该弧的信息,从而使相同的弧尾和弧头分别在不同的一个链表上,弧结点表的结构如下:

tailvex headvex hlink tlink info

3、集合

集合是一种非线性结构,集合的内容即数学上的集合概念,例如,集合的表示、空集、集合之间的关系、集合之间的运算等等,这里不再赘述。

二、算法的基本概念

(一)算法的定义

通常将解决问题的确定方法和有限步骤称为算法,在计算机中,指的是对特定问题求解步骤的一种描述,是若干条指令的有穷序列。

(二)算法的特性

算法具有以下五个特性:
(1)输入
(2)输出
(3)确定性
(4)可行性
(5)有穷性

(三)算法与数据结构

程序=算法+数据结构,设计一个具有正确性、可读性、健壮性、高效率(执行速度快,时间复杂度低)和低存储(不费内存,空间复杂度低)的算法,再加上合适的数据结构,从而构成一个良好的程序。

三、算法设计步骤

(1)算法描述
(2)数学模型选择
(3)算法的详细设计
(4)算法的程序实现和测试
(5)算法分析

四、算法的效率分析

(一)时间复杂度

1、时间复杂度的定义
时间复杂度是对算法运行时间的数量级,有两种度量方法,分别是事后统计法事前分析估算法。通常,对一个算法的时间复杂度考察三个方面,即最好情况、平均情况和最坏情况,从而对应最好时间复杂度、平均时间复杂度和最坏时间复杂度,其中平均时间复杂度是指所有输入在等概率的情况下,该算法的期望运行时间,例如直接插入排序:

排序算法 空间复杂度 平均时间复杂度 最好时间复杂度 最坏时间复杂度
直接插入排序 O(1) O(n2) O(n) O(n2)

最好情况下,即元素都有序,此时只需比较元素而不需移动元素,最好时间复杂度为O(n),而最坏情况下,即排好的序列刚好与初始序列相反,呈逆序排列,则此时比较次数和移动次数都到达最大值,最坏时间复杂度为O(n2),而考虑平均情况下,总的比较次数和移动次数约为n2/4,故直接插入排序的平均时间复杂度为O(n2)。
2、时间复杂度的规则
(1)常数规则
C为一个正常数,O[Cf(n)]=O[f(n)]。
(2)加法规则
O[f(n)]+O[g(n)]=O[max(f(n),g(n)]。
(3)乘法规则
O[f(n)]×O[g(n)]=O[(f(n)×g(n)],例如下列代码:

count=0;				//执行一次
for(k=1;k<=n;k*=2)		//执行log2n次
	for(j=1;j<=n;j++)	//循环n次
		count++;

第一行代码执行一次,根据加法规则,该程序的运行时间由for循环决定,假设最外层m次循环结束,则有2m+k=n,可得:m=log2n,所以执行执行log2n次,另外,内层for循环n次,根据乘法规则,所以该程序段的时间复杂度为O(n)=n×log2n=nlog2n。

3、常见的时间复杂度的大小比较
时间复杂度为O(1) 常数阶算法的效率最高,而像O(2n) 、 O(n!) 、 O(nn)这类的算法的效率最低。
O(1) < O(log2n) < O(n) < O(nlog2n) < O(n2) < O(n3) < O(2n) < O(n!) < O(nn)
根据其图像,如下:
在这里插入图片描述

(二)空间复杂度

空间复杂度是指定义该算法所需要耗费的存储空间,根据其规模函数f(n),可记为O[f(n)],若算法需要的存储空间是常量,则其空间复杂度为O(1)。例如,由于快速排序代码中的递归进行需要栈来辅助,所以其需要的空间较大。其空间复杂度与递归层数(栈的深度)有关,为O(递归层数):

若将n个要排序的元素组成一个二叉树, 这个二叉树的层数就是递归调用的层数(栈的深度), 由于在n个结点的二叉树中,其最小高度=⌊ log2n⌋ (以2为底n的对数然后再向上取整,取比自己大的最小整数), 其最大高度=n。

所以,可知最好情况下,即最小高度,为⌊ log2n ⌋,最好空间复杂度为O(log2n);而最坏情况下,即最大高度,为n层,最坏空间复杂度为O(n);故平均情况下,为O(log2n)。

(三)渐进时间复杂性

设算法的运行时间为T(n),若存在T*(n),使得:
lim ⁡ n → ∞ T ( n ) − T ∗ ( n ) T ( n ) = 0 \lim\limits_{n \rightarrow ∞ }\frac{T(n)-T*(n) }{T(n)} = 0 nlimT(n)T(n)T(n)=0
则称T*(n)为算法的渐进性态或渐进时间复杂性,当规模充分大时,T(n)和T*(n)近似相等。

五、渐近符号

(一)渐近上界Ο

通常使用的大O表示法,O的含义是T(n)或S(n)的数量级,可定义为T[n] = O(f(n))或者S[n] = O(f(n)),则称函数T(n)以f(n)或S(n)以f(n)为界,通过这种方法来评估算法的时间复杂度和空间复杂度时是从当问题规模充分大的条件上所得到的一个上界,其阶数越低,评估的结果越精确。

(二)渐近下界Ω

渐进下界的表示方法刚好与渐进下界相反,用Ω进行表示,它反映的是复杂度的一个下界,其阶数越高,评估的结果越精确。

(三)渐近精确界Θ

渐近精确界是当问题规模n满足一定条件的范围内时,函数T(n)和f(n)的阶数相同,通过Θ进行表示。

六、递归算法

一个递归算法必须包括终止条件递归部分,例如,n的阶乘是一个递归算法,该递归算法停止条件是n=0,函数可定义如下:
n ! = { 1 ,n=0 n ( n − 1 ) ! ,n>0 n!= \begin{cases} 1& \text{,n=0}\\ n(n-1)!& \text{,n>0} \end{cases} n!={ 1n(n1)!n=0n>0

递归算法求解问题的一般步骤如下:
(1)分析问题,寻找递归关系
(2)找出停止条件
(3)设计递归算法

例如,下列递归程序段是n次阶乘,一共执行n次递归调用fact()函数,所以即为O(n):

int fact(int n){
    
	if(n<=1)
		return 1;
	return n*fact(n-1)
}

例如,二叉树的先序、中序、后序遍历中每一次函数调用都会在内存栈中分配空间,都运用了递归算法。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43085848/article/details/133410877

智能推荐

JWT(Json Web Token)实现无状态登录_无状态token登录-程序员宅基地

文章浏览阅读685次。1.1.什么是有状态?有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?服务端保存大量数据,增加服务端压力 服务端保存用户状态,无法进行水平扩展 客户端请求依赖服务.._无状态token登录

SDUT OJ逆置正整数-程序员宅基地

文章浏览阅读293次。SDUT OnlineJudge#include<iostream>using namespace std;int main(){int a,b,c,d;cin>>a;b=a%10;c=a/10%10;d=a/100%10;int key[3];key[0]=b;key[1]=c;key[2]=d;for(int i = 0;i<3;i++){ if(key[i]!=0) { cout<<key[i.

年终奖盲区_年终奖盲区表-程序员宅基地

文章浏览阅读2.2k次。年终奖采用的平均每月的收入来评定缴税级数的,速算扣除数也按照月份计算出来,但是最终减去的也是一个月的速算扣除数。为什么这么做呢,这样的收的税更多啊,年终也是一个月的收入,凭什么减去12*速算扣除数了?这个霸道(不要脸)的说法,我们只能合理避免的这些跨级的区域了,那具体是那些区域呢?可以参考下面的表格:年终奖一列标红的一对便是盲区的上下线,发放年终奖的数额一定一定要避免这个区域,不然公司多花了钱..._年终奖盲区表

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

随便推点

Awesome Mac:收集的非常全面好用的Mac应用程序、软件以及工具_awesomemac-程序员宅基地

文章浏览阅读5.9k次。https://jaywcjlove.github.io/awesome-mac/ 这个仓库主要是收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师。有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章《工具武装的前端开发工程师》,于是建了这么一个仓库,持续更新作为补充,搜集更多好用的软件工具。请Star、Pull Request或者使劲搓它 issu_awesomemac

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue

推荐文章

热门文章

相关标签