软件设计 -(三)数据结构(1)


相关文档

数据结构(2)


  • 数据结构:数据元素的集合及元素间的相互关系和构造方法。
  • 逻辑结构:元素之间的相互关系是数据的逻辑结构。
  • 存储结构:数据元素及元素之间关系的存储称为存储结构(或物理结构)

数据结构按照逻辑关系的不同分为:线性结构、非线性结构(树结构、图结构)。


一、线性结构

线性结构主要用于对客观世界中具有单一前驱和后继的数据关系进行描述。特点是数据元素之间呈现一种线性关系,即元素“一个接一个排列”。

1、线性表

一个线性表是n(n≥0)个元素的有限序列

顺序存储
用一组连续的存储单元依次存储线性表中的数据元素, 逻辑上相邻的两个元素在物理地址上也相邻需预先定义(申请)存储空间,容量有限
  • 优点:随机存取;
  • 缺点:插入、删除需要移动元素。
链式存储
使用 通过指针链接起来的结点来存储数据元素。结点的数据结构包括:数据域(存储数据元素值),指针域(存储当前结点的直接前驱和直接后继的位置(称为指针或链))
  • 优点:插入、删除不需要移动元素。
  • 缺点:不能对数据元素随机访问。
链表结构
  • 单向链表(线性链表):只有一个指针域(直接后继)
  • 双向链表每个结点包含两个指针(直接前驱、直接后继)。特点是可以从表中任意结点出发,从两个方向遍历链表。
  • 循环链表:单(双)向链表的基础上令表尾结点的指针指向链表的第一个结点,构成循环链表。特点是可以从任一结点遍历整个链表。
  • 静态链表:用数组来描述线性表的链式存储结构,数组元素下标表示元素所在结点的指针。

2、栈和队列


  • 定义: 只能访问它的一端来实现数据的存储和检索的一种线性数据结构(后进先出,LIFO)。
  • 栈顶:在栈中进行插入和删除操作的称为栈顶(Top),另一端称为栈底(Bottom)。

存储结构:

  • 顺序存储(顺序栈):需预先定义 (申请)栈的存储空间(因此,栈空间容量是有限的,一个元素入栈时,需判断是否栈满,栈满则不能入栈);附设指针 top 指示栈顶元素的位置。
  • 链式存储(链栈):不必另外设置头指针,链表的头指针就是栈顶指针。

应用:表达式求值,括号匹配,将递归过程转变为非递归过程的处理。


队列

队列是一种先进先出(FIFO)的线性表。只允许在表的一端(队尾)插入元素,在另一端删除(对头)元素。

存储结构:

  • 顺序存储:需预先定义存储空间,所以队尾指针会有一个上限值(如下图3.6)。

    • 循环队列:当顺序队列队尾指针达到上限值是 , 就不能只通过修改队尾指针来实现新元素的入队操作。若将顺序队列假想成环形结构 (通过除整取余运算实现),则可维持入队、出队操作运算的简单性,称之为循环队列。

    设循环队列 Q 容量为 MAXSIZE,且 Q.rear 和 Q.front 都等于 0,则:
    入队时:Q.rear = (Q.rear + 1) % MAXSIZE
    出队时:Q.front = (Q.front + 1) % MAXSIZE

  • 链式存储:为了便于操作,给链队列添加一个头结点,并令头指针指向头结点。因此,队列为空的判定条件是头指针和尾指针的值相同,且均指向头结点。

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

3、串

串(字符串)是仅有字符构成有限序列,是一个特殊的线性表 ,其数据元素为字符。

子串的定位操作通常称为模式匹配,子串称为模式串。

模式匹配:朴素模式匹配算法,改进模式匹配算法(KMP


二、数组、矩阵、广义表

数组

数组是定长线性表在纬度上的扩展,即线性表中的元素又是一个线性表。

数据结构特点:

  1. 数据元素数目固定,一旦定义了一个数组结构,就不再有元素个数的增减变化
  2. 数据元素具有相同的类型。
  3. 数据元素的下标关系具有上下界的约束且下标有序。
矩阵

特殊矩阵:矩阵中元素(或非0元素)的分布有一定的规律(常见有对称矩阵、三角矩阵、对角矩阵等)。
稀疏矩阵:非0元素的个数远远少于0元素的个数,且非0元素的分布没有规律。

广义表

是线性表的推广,由0个或多个单元素或子表组成的有限序列。
与线性表区别:线性表的元素都是结构上不可分的单元素,广义表的元素既可以是单元素,也可以是有结构的表。


三、树

树是 n(n≥0)个结点的有限集合,当 n=0 时称为空树。在任一非空树(n>0)中,有且仅有一个称为根的结点。树具有递归性质(树由若干子树构成,子树由更小的子树构成)。

  • 基本概念:
    • 双亲、孩子、兄弟:结点的子树的根称为该结点的孩子;该结点称为其子结点的双亲。具有相同双亲的结点互为兄弟。
    • 结点的度:一个结点的子树的个数记为该结点的度。
    • 叶子结点:叶子结点也称为终端结点,指度为0的结点。
    • 内部结点:度不为0的结点。
    • 结点的层次:根为第一层,根的孩子为第二层,依此类推。
    • 树的高度:一颗树的最大层数记为树的高度(或深度)。
    • 有序(无序)树:若将树中结点的各子树看成是从左到右具有次序的,即不能交换,则称该数为有序树,否则称为无序树。
  • 性质
    • N 个结点的树有 N-1 条边(总度数)=> 树的节点数 = 数的总边(度)数 + 1 。

      推出下面计算公式:

      树总结点数 = ∑ ( 度数 ∗ 该度数对应结点总数 ) + 1 树总结点数 = {\sum (度数 * 该度数对应结点总数)} + 1 树总结点数=(度数该度数对应结点总数)+1

      例:一棵树,度为4的结点有7个 ,度为3的结点有5个,度为2的结点有8个,度为1的结点有10个,求叶子结点(度为0的结点)的个数?

      解:
      1. 该树总结点数 = 47 + 35 + 28 + 110 + 1 = 70
      2. 叶子结点总数 = 树的结点总数 - 非叶子结点总数 = 70 - (7+5+8+10) = 40

1、二叉树

二叉树结点的子树要区分左子树、右子树;即使只有一颗子树,也要明确指出该子树是左子树还是右子树。

  • 性质

    • 二叉树第 i 层(i ≥ 1)上最多有 2 i − 1 2^{i-1} 2i1 个结点
    • 高度为 k 的二叉树最多有 2 k − 1 2^k - 1 2k1 个结点
    • 对任何一颗二叉树,若其终端结点数为 n 0 n_0 n0度数为 2 的结点数为 n 2 n_2 n2 n 0 = n 2 + 1 n_0 = n_2+1 n0=n2+1

  • 类型

    • 满二叉树:深度为 k 的二叉树,有 2 k − 1 2^k-1 2k1个结点,称为满二叉树。
    • 完全二叉树:深度为 k,有 n 个结点的二叉树,且其每个结点都与深度为 k 的满二叉树中编号从 1 至 n 的结点一一对应
    • 非完全二叉树
      在这里插入图片描述
  • 二叉树四种遍历:前序、中序、后序、层序 [详情参考]


2、最优二叉树(哈夫曼树)


3、树和森林


树的遍历

  • 先根遍历(相当于二叉树先序遍历)
  • 后根遍历(相当于二叉树中序遍历)

树的存储结构

  • 双亲表示法:结点存储结点元素及双亲位置
  • 孩子表示法:在存储结构中用指针指示出结点的每个孩子,令每个结点的所有孩子结点构成一个用单链表表示的线性表,则n个结点的树具有n个单链表;将这n个单链表的头指针又排成一个线性表。
  • 双亲孩子表示法
  • 孩子兄弟表示法:又称为二叉链表表示法,它在链表的结点中设置两个指针域分别指向该结点的第一个孩子和下一个兄弟。
双亲表示法双亲孩子表示法孩子兄弟

4、树、森林、二叉树的相互转换

  • 树 to 二叉树:树的孩子兄弟表示法;由于树根没有兄弟,所以转换后的二叉树一定没有右子树
  • 森林 to 二叉树:先将森林每一颗树转化成二叉树,第一颗树的根作为转换后的二叉树的根,第一颗树的左子树作为转换后的二叉树根的左子树,第二颗树作为转换后的二叉树的右子树,第三个树作为转换后的二叉树右子树的右子树,依此类推。
  • 二叉树 to 树和森林:反推,如下图所示:
    二叉树to树或森林

四:图

图 G 是由集合 V 和 E 构成的二元组,记作 G = ( V , E ) G=(V,E) G=(V,E),V 是图中顶点的非空有限集合,E 是图中边的 有限集合。在图中数据元素用顶点表示,数据元素之间的关系用边表示。

  • 无向图:图中所有边都是无向的。无向图中边用 ( v i , v j ) (v_i,v_j) (vi,vj)表示。

  • 有向图:图中每条边都是有方向的。

    顶点之间的关系用 < v i , v j > <v_i,v_j> <vi,vj>表示,它说明从 v i v_i vi v j v_j vj有一条有向边(也称为弧) v i v_i vi是有向边的起点(弧尾), v j v_j vj是有向边的终点(弧头)。

  • 完全图:在具有 n 个顶点的无向图中,若每个顶点与其它 n-1 个顶点之间都有边,称为无向完全图。有 n 个顶点的有向完全图中任意两个不同顶点之间都有方向相反的两条弧存在。

  • 度、出度和入度

    • 度:顶点 v 的度是指关联与该顶点边的数目,记作 D ( v ) D(v) D(v)。若G为有向图,顶点的度表示该顶点的出度和入度之和。
    • 入度:顶点的入度是以该顶点为终点的有向边的数目,记作 I D ( v ) ID(v) ID(v)
    • 出度:顶点的出度是以该顶点为起点的有向边的数目,记作 O D ( v ) OD(v) OD(v)
  • 路径

    • 无向图G,从顶点 v p v_p vp 到顶点 v q v_q vq 的路径指存在一个顶点序列 v g , v i 1 , v i 2 , . . . , v i n , v q v_g,v_{i1},v_{i2},...,v_{in},v_q vg,vi1,vi2,...,vin,vq使得 ( v p , v i 1 ) , ( v i 1 , v i 2 ) , … , ( v i n , v q ) (v_p,v_{i1}),(v_{i1},v_{i2}),…,(v_{in},v_q) (vp,vi1),(vi1,vi2),,(vin,vq)均属于E(G)。
    • 有向图G,其路径也是有方向的,它由E(G)中的有向边 < v p , v i 1 > , < v i 1 , v i 2 > , … , < v i n , v q > <v_p,v_{i1}>,<v_{i1},v_{i2}>,…,<v_{in},v_q> <vp,vi1>,<vi1,vi2>,,<vin,vq>组成。
    • 路径的长度是路径上边(弧)的数目。第一个顶点和最后一个顶点相同的路径称为回路(环)
  • 子图:若有两个图 G = ( V , E ) G=(V,E) G=(V,E) 和 $G’=(V’,E’) $,如果 V ⊆ V V \subseteq V VV E ′ ⊆ E E' \subseteq E EE,则称 G’ 为 G 的子图。

  • 连通图和连通分量 无向图G中任意两个顶点都是连通的(两点之间存在路径),则称其为连通图。无向图G的极大连通子图称为G的连通分量。

  • 强连通图和强连通分量有向图G中,如果对于每一对顶点 v i , v j ∈ V 且 v i ≠ v j v_i,v_j∈V 且 v_i≠v_j vi,vjVvi=vj,从顶点 v i v_i vi 到顶点 v j v_j vj 和从顶点 v j v_j vj 到顶点 v i v_i vi 都存在路径,则称图G为强连通图。有向图中的极大连通子图称为有向图的强连通分量。

  • 边(弧)带权值的图称为网

  • 有向树:如果一个有向图恰有一个顶点的入度为0,其它顶点的入度均为1,则是一个有向树。


1、图的存储结构

  1. 邻接矩阵表示法

    指用一个矩阵表示图中顶点之间的关系(是否为边)。对于具有 n 个顶点的图 G=(V,E),其邻接矩阵是一个 n 阶方程,且满足:
    A [ i ] [ j ] = { 1 , 若 ( v i , v j ) 或 < v i , v j > 是 E 中的边 0 , 若 ( v i , v j ) 或 < v i , v j > 不是 E 中的边 A[i][j] = \begin{cases} 1, & 若(v_i,v_j)或<v_i,v_j>是 E 中的边 \\ 0, & 若(v_i,v_j)或<v_i,v_j>不是 E 中的边 \end{cases} A[i][j]={1,0,(vi,vj)<vi,vj>E中的边(vi,vj)<vi,vj>不是E中的边
    无向图的邻接矩阵是对称的

    网(赋权图)的邻接矩阵可定义为: W i j W_{ij} Wij 是边(弧)上的权值。

    A [ i ] [ j ] = { W i j , 若 ( v i , v j ) 或 < v i , v j > 是 E 中的边 ∞ , 若 ( v i , v j ) 或 < v i , v j > 不是 E 中的边 A[i][j] = \begin{cases} W_{ij}, & 若(v_i,v_j)或<v_i,v_j>是 E 中的边 \\ ∞, & 若(v_i,v_j)或<v_i,v_j>不是 E 中的边 \end{cases} A[i][j]={Wij,,(vi,vj)<vi,vj>E中的边(vi,vj)<vi,vj>不是E中的边

    邻接矩阵网邻接矩阵
  2. 邻接链表表示法:

    指为图的每一个顶点建立一个单链表。第 i i i 个单链表中的结点表示依附于顶点 v i v_i vi 的边(对于有向图是以 v i v_i vi的弧)。
     
    邻接链表中的结点有表结点(或边结点)和表头结点两种类型。
     
    在这里插入图片描述
     

    • 对于有 n 个顶点、e 条边的无向图来说,其邻接链表需用 n 个头结点,2e 个表结点。
    • 有向图中,为求顶点的入度,必须扫描逐个邻接表,因为第 i 个邻接链表中表结点的数目只是顶点 v i v_i vi出度(邻接链表的定义:第 i i i 个单链表中的结点表示依附于以顶点 v i v_i vi的弧)。为此,可以建立一个有向图的逆邻接链表。有向图的邻接表和逆邻接表如图3-33所示:
       
      有向图邻接链表

2、图的遍历

  • 深度优先搜索(Depth First Search,DFS)

    时间复杂度:邻接矩阵作为存储结构( O ( n 2 ) O(n^2) O(n2)),邻接表( O ( n + e ) O(n+e) O(n+e)

    从图G中任一结点v出发按深度优先搜索法进行遍历的步骤如下:

    1. 设置搜索指针p,使p指向顶点v。
    2. 访问p所指顶点,并使p指向与其相邻接的且尚未被访问过的顶点。 	
    3. 若p所指顶点存在,则重复步骤 2 ,否则执行步骤 4。
    4. 沿着刚才访问的次序和方向回溯到一个尚有邻接顶点且未被访问过的顶点,并使 p 指向这个未被访问的顶点,然后重复步骤 2 ,直到所有的顶点均被访问为止。
    

    该算法的特点是尽可能先对纵深方向搜索,因此可以得到其递归遍历算法。

  • 广度优先搜索(Breadth First Search,BFS)

    从图中的某个顶点v出发,在访问了v之后依次访问v的各个未被访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。若此时还有未被访问的顶点,则另选图中的一个未被访问的顶点作为起点,重复上述过程,直到图中所有的顶点都被访问到为止。

3、生成树及最小生成树

  • 生成树

    • 连通图的生成树是该图的极小连通子图。在生成树中任意加一条边,必然产生回路。(生成树不存在回路)
    • 图的生成树不是唯一的。从不同的顶点出发,选择不同的存储方式,用不同的求解方法,可以得到不同的生成树。
    • 按深度和广度优先搜索进行遍历将得到不同的生成树,分别称为深度优先生成树和广度优先生成树。
       

    例如,图3-37所示的是图 3-36(a) 的一棵深度优先生成树和一棵广度优先生成树。

    生成树搜索生成树
  • 最小生成树

    对于连通,边是带权值的,生成树的各边也带权值,把生成树各边的权值总和称为生成树的权,把权值最小的生成树称为最小生成树

    • 普利姆(Prim)算:时间复杂度 O ( n 2 ) O(n^2) O(n2),与图中边无关,适合求解稠密的网的最小生成树。
    • 克鲁斯卡尔(Kruskal)算法:贪心算法,时间复杂度 O e l o g e Oeloge Oeloge,与图中顶点数无关,适合求边稀疏的图的最小生成树。
    在这里插入图片描述在这里插入图片描述

4、拓扑排序和关键路径

在工程领域,一个大的工程项目通常被划分为许多较小的子工程(称为活动)。显然,当这些子工程都完成时,整个工程也就完成了。

  • AOV网

    • 在有向图中,若以顶点表示活动,用有向边表示活动之间的优先关系,则称这样的有向图为以顶点表示活动的网(AOV网);在AOV网中不应出现有向环。
    • 拓扑排序
      将AOV网中的所有顶点排成一个线性序列的过程,并且该序列满足:若在AOV网中从顶点 v i v_i vi v j v_j vj,有一条路径,则在该线性序列中,顶点 v i v_i vi必然在顶点 v j v_j vj之前。
  • AOE网

    • 若在带权有向图G中以顶点表示事件,以有向边表示活动,以边上的权值表示该活动持续的时间,则这种带权有向图称为用边表示活动的网(AOE网)。AOE网中不应存在有向回路。
    • 关键路径:在从源点(入度为0的开始顶点)到汇点(出度为0的结束顶点)的路径中,长度最长的路径称为关键路径。
    • 关键活动:关键路径上的所有活动均是关键活动。

五:矩阵

  • 矩阵相乘
    矩阵 A,B 可相乘的条件是矩阵 A 的列和矩阵 B 的行数相同。
    若 A 是一个 p × q p × q p×q 矩阵,B 是一个 q × r q × r q×r 矩阵,则其乘积 C = AB 是一个 p × r p × r p×r 矩阵,且标准的两个矩阵相乘所需要的计算量为 p ∗ q ∗ r p * q * r pqr 次乘法操作。

  • 矩阵链乘

    • 单个矩阵是完全加括号的。
    • 矩阵链乘的乘积 A 是完全加括号的,则 A 可表示为两个完全加括号的矩阵链乘的乘积,B 和 C 的乘积并加括号,即 A = (BC)。
    • 矩阵链乘满足结合律, A 1 A 2 A 3 A 4 A_1A_2A_3A_4 A1A2A3A4 可以有以下完全加括号的方式: ( A 1 ( A 2 ( A 3 A 4 ) ) 、 ( A 1 ( ( A 2 A 3 ) A 4 ) ) 、 ( ( A 1 A 2 ) ( A 3 A 4 ) ) 和 ( ( A 1 4 2 ) 4 3 ) A 4 ) (A_1(A_2(A_3A_4))、(A_1((A_2A_3)A_4))、((A_1A_2)(A_3A_4))和((A_14_2)4_3)A_4) (A1(A2(A3A4))(A1((A2A3)A4))((A1A2)(A3A4))((A142)43)A4)。每一种加括号的方式确定了一个计算的次序。

    例:3 个矩阵 A 1 , A 2 , A 3 {A_1,A_2,A_3} A1,A2,A3 链乘,这3个矩阵的维数分别为10×100、100×5 和 5×50。

    • ( ( A 1 A 2 ) A 3 ) ((A_1A_2)A_3) ((A1A2)A3) 计算,所需乘法次数 = 10×100×5 + 10× 5×50=7500。
    • ( A 1 ( A 2 A 3 ) ) (A_1(A_2A_3)) (A1(A2A3)) 计算,所需乘法次数 = 100×5×50 + 10×100×50=75000。

    上面例子可看出,不同的计算次序对矩阵链乘的运算量影响是巨大的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值