文章目录
第七章 数据结构与算法
第一节 数组与矩阵
数组
数组类型 | 存储地址计算 |
---|---|
一维数组 a [ i ] a[i] a[i] | a [ i ] a[i] a[i]的存储地址为: a + i ∗ l e n a+i*len a+i∗len ( i i i 是下标; l e n len len 表示所占的字节数) |
二维数组 a [ i ] [ j ] a[i][j] a[i][j] |
a
[
i
]
[
j
]
a[i][j]
a[i][j]的存储地址(按行存储)为:
a
+
(
i
∗
n
+
j
)
∗
l
e
n
a+(i*n+j)*len
a+(i∗n+j)∗len a [ i ] [ j ] a[i][j] a[i][j]的存储地址(按列存储)为: a + ( j ∗ m + i ) ∗ l e n a+(j*m+i)*len a+(j∗m+i)∗len |
例题:已知5行5列的二维数组a中的各元素占两个字节,求元素 a [ 2 ] [ 3 ] a[2][3] a[2][3] 按行优先存储的存储地址?
解: a + ( 2 ∗ 5 + 3 ) ∗ 2 = a + 26 a+(2*5+3)*2 = a+26 a+(2∗5+3)∗2=a+26
稀疏矩阵
稀疏矩阵 | 示意图 | 计算存储地址 |
---|---|---|
上三角矩阵 | 在矩阵中下标分别为 i 和 j 的素, 对应的一维数组的下标计算公式为: ( 2 n − i + 1 ) × i / 2 + j (2n-i+1)×i/2+j (2n−i+1)×i/2+j | |
下三角矩阵 | 在矩阵中下标分别为 i 和 j 的元素, 对应的一维数组的下标计算公式为: $ (i+1)*i/2+j$ |
第二节 数据结构的定义
基本概念
数据结构是带有结构特性的数据元素的集合,它研究的是数据的逻辑结构和数据的物理结构以及它们之间的相互关系,并对这种结构定义相适应的运算,设计出相应的算法,并确保经过这些运算以后所得到的新结构仍保持原来的结构类型
数据逻辑结构
线性结构:顺序表
非线性结构:树,图
第三节 线性表
- 顺序表
- 链表
- 单链表 【插入删除结点】
- 循环链表
- 双向链表 【插入删除结点】
性能类别 | 具体项目 | 顺序存储 | 链式存储 |
---|---|---|---|
空间性能 | 存储密度 | =1,更优 | <1 |
容量分配 | 事先确定 | 动态改变,更优 | |
时间性能 | 查找运算 | O(n/2) | O(n/2) |
读运算 | O(1),更优 | O[(n+1)/2],最好情况为0, 最坏情况为n | |
插入运算 | O(n/2),最好情况为0, 最坏情况为n | O(1),更优 | |
删除运算 | O[(n+1)/2] | O(1),更优 |
广义表
1,广义表是n个表元素组成的有限序列,实现线性表的推广
2,通常用递归的形式进行定义,记做Ls=( a1,a2,…,ai,…,an)。
L=(a,b) ----> L是长度为2的广义表,它的两个元素都是原子,因此它是一个线性表
广义表的深度:一个表的"深度"是指表展开后所含括号的层数。
基本运算: 取表头head(Ls)和取表尾tail(Ls)
- 若有:
L
S
1
=
(
a
,
(
b
,
c
)
,
(
d
,
e
,
f
,
g
)
)
LS1 = (a,(b,c) ,(d,e,f,g) )
LS1=(a,(b,c),(d,e,f,g))
h e a d ( L S 1 ) = a head(LS1)=a head(LS1)=a ------> 取头的话,只能取到第一个元素
t a i l ( L S 1 ) = ( ( b , c ) , ( d , e , f , g ) ) tail(LS1)=((b,c),(d,e,f,g)) tail(LS1)=((b,c),(d,e,f,g)) ------>取尾的话,只能取到除了第一个元素的其他元素 - 表 L S 1 LS1 LS1的长度为3,深度为 4(小括号里最多的数)
- 如何取得 b b b 字母?-----> h e a d ( h e a d ( t a i l ( L S 1 ) ) ) head(head(tail(LS1))) head(head(tail(LS1)))
线性表
1,线性表是n(n>=0)个数据元素构成的有限序列,表中除第一个元素外的每一个元素,有且只有一个前件,除最后一个元素外,有且只有一个后件。(就是一条线按顺序来)
2,通常,线性表可以采用顺序存储和链式存储,一般用顺序存储结构。线性表的顺序存储又叫做顺序表,线性表的链式存储又叫做线性链表。顺序表的特点:
- 线性表中所有元素所占的存储空间是连续的;
- 线性表中数据元素在存储空间中是按照逻辑顺序依次存放的;
- 可以随机访问数据元素
- 做插入,删除时需要移动大量元素,因此线性表不便于插入和删除元素
栈和队列
1,栈是特殊的线性表,是限定在一端进行插入和删除的线性表。
特点:(像羽毛球筒,子弹夹之类的)
- 栈是只能在栈顶进行插入和删除
- 栈的修改原则是“先进后出”或“后进先出”
- 栈底指针(bottom)不变,栈中元素随栈顶指针(top)的变化而动态变化
- 栈具有记忆功能
- 栈支持子程序调用
2,栈的运算:
Bottom=49,top=30,栈中的元素有49-30+1=20个
3,队列是指允许在一端进行插入,而在另一端进行删除的线性表,队头指针(front)和队尾指针(rear)
特点:(类似于排队)
- 队列只允许在队尾进行插入,而在队头进行删除
- 队列的修改原则是先进先出或后进后出
- 队列中元素随队头指针和队尾指针的变化而动态变化
循环队列就是将队列存储空间的最后一个位置绕道第一个位置,形成逻辑上的环状空间
第三节 树与二叉树
1,树是N(N>0)个元素的有限集合。它有且仅有一个为根的元素;其余元素是互不相交的子树。
2,常用术语:
父结点,子节点,根结点,叶子结点(没有前件的是根结点,没有后件的是叶子结点)
结点的度、树的度(一个结点所拥有的后件的个数,称为该结点的“度”。例如图中A结点有3个度。所有结点中最大的度,称为“树的度”)
树的深度(如图中树的深度为4。看层数)
子树(以某结点的子节点为根,独立出来所构成的树。例如图中的B
3,二叉树:是一个有限的结点集合,给集合或者为空,或者由一个根结点及其两颗互不相交的左右二叉子树所组成。特点:
- 非空二叉树只有一个根结点;
- 每一个结点最多有两颗子树,且分别称为该结点的左子树与右子树
特殊二叉树
1,满二叉树(除了最后一层之外,每一层上的结点数均达到最大值)
二叉树的性质
- 非空二叉树只有一个根结点,每个节点最多有两颗子树,分别称左子树和右子树。
- 在二叉树的第K层上,最多有 2 K − 1 2^K-1 2K−1个结点
- 深度为m的二叉树最多有 2 m − 1 2^m-1 2m−1个结点
- 度为0的结点(叶子结点)总比度为2的结点多一个。如图所示,度为0的结点是D,E,F。共有3个,度为2的结点是A,B共有两个。
- 有N个结点的二叉树深度至少为[log2n]+1。如图所示,有6个结点的二叉树,深度(层数)至少为log26+1≈3
二叉树的遍历是指按照一定的顺序,不重复的访问二叉树的结点。技巧:看根的位置!
- 前序遍历:访问根结点→前序遍历左子树→前序遍历右子树(【根】左右)
- 中序遍历:中序遍历左子树→访问根结点→中序遍历右子树(左【根】右)
- 后序遍历:后序遍历左子树→后续遍历右子树→访问根结点(左右【根】)
如图所示,
前序遍历访问顺序为:ABDECF
中序遍历的访问顺序为:DBEAFC
后序遍历的访问顺序为:DEBFCA
第四节 图
完全图
在无向图中,若每对顶点之间都有一条边相连,则称该图为完全图
在有向图中,若每对顶点之间都有二条有向边相互连接,则称该图为完全图。
图的存储——邻接矩阵
用一个n节方阵R来存放图中各结点的关联信息,其矩阵元素 R i j R_{ij} Rij定义为
R i j = { 1 − 若 顶 点 i 到 顶 点 j 有 邻 接 边 0 − 若 顶 点 i 到 顶 点 j 无 邻 接 边 R_{ij} = \begin{cases} 1-若顶点i到顶点j有邻接边\\ 0-若顶点i到顶点j无邻接边 \end{cases} Rij={1−若顶点i到顶点j有邻接边0−若顶点i到顶点j无邻接边
图的存储——邻接表
首先把每个顶点的邻接顶点用链表示出来,然后用一个一维数组来顺序存储上面每个链表的头指针。
图的遍历
图的拓扑排序
我们把用有向边表示活动之间开始的先后关系。这种有向图陈威用顶点表示活动网络,简称AOV网络
图的最小生成树
最短路径:
第五节 排序与查找
散列表查找的基本思想是:已知关键字集合U ,最大关键字为m ,设计一个函数Hash ,它以关键字为自变量,关键字的存储地址为因变量,将关键字映射到一个有限的、地址连续的区间T[0…n-1]中,这个区间就称为散列表,散列查找中使用的转换函数称为散列函数。
其他知识点
1、分治法
求解一个复杂问题可以将其分解成若干子问题,子问题在分解成更小的问题,直到可以直接求解为止。
前提:
- 问题能够按照某种方法分解为若干个规模较小、相互独立且与原问题类型相同的问题;
- 子问题足够小时可以直接求解;
- 能够将子问题的解组合成原问题的解。
相关算法:
- 二分搜索
- 归并排序
- 快速排序
2、贪心法
贪心法是求解最优化问题的一种设计策略。贪心法通过分步决策来求解问题。在对问题求解时,总是做出在当前这一步看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
最优化问题:问题给出某些约束条件,满足这些约束条件的解称为可行解;为了衡量可行解的好坏,问题还给出了目标函数,使目标函数取最大(小)值的可行解称为最优解。
贪心法在每一步上用作决策依据的选择准则被称为最优量度标准或贪心准则,这种量度标准通常只考虑局部最优性。
贪心法基本要素
**最优度量标准:**所谓贪心法的最优度量标准,是指可以根据该度量标准,实行多步决策进行求解,虽然在该度量标准下所做的这些选择都是局部最优的,但最终得到的解却是全局最优的。选择最优度量标准是使用贪心法求解问题的核心问题。贪心算法每步做出的选择可以依赖以前做出的选择,但绝不依赖将来的选择,也不依赖子问题的解。也正是如此,贪心法的特征是自顶向下,一步一步地做出贪心决策。
最优子结构:当一个问题的最优解中包含了自问题的最优解时,则称该问题具有最优子结构特性。一个可用贪心法求解的问题往往呈现最优子结构性质。
并不是所有具有最优子结构特性的问题,都可以有幸的找到最优量度标准,此时可以考虑采用动态规划法求解。
相关算法
- 一般背包问题
- 霍夫曼树
- 最小代价生成树问题
- Dijkstra算法
Prim算法从扩展顶点开始,每次总是“贪心的”选择与当前顶点集合中距离域短的顶点,
Kruscal算法从扩展边开始,每次总是“贪心的”选择剩余的边中最小权重的边,
因此两个算法都是基于贪心策略进行的
3、动态规划法
定义
动态规划法:与贪心法类似,动态规划法也是一种求解最优化问题的算法设计策略。它也采取分布决策的方法。但与贪心法不同的是,动态规划法每一步决策依赖子问题的解。直观上,为了在某一步做出决策,需要先求若干子问题,这就使得动态规划法是自底向上的。
按照多部决策方法,一个问题的活动过程可以分成若干阶段,每个阶段可能包含一个或多个状态。多部决策求解方法就是从初始状态开始做出每个阶段的决策,形成一个决策序列,该决策序列也成为策略。对于每一个决策序列,可以用一个数值函数(目标函数)衡量该策略的优劣。问题求解的目标是获取最优决策序列(最优策略)。
动态规划法基本要素
最优子结构特性:和贪心法相同。
重叠子问题:动态规划法的子问题往往是重叠的,如果采用与分治法类似的直接递归会非常费时。为了避免重复计算,动态规划法一般采用自底向上的方式进行计算,并保存已经求解的子问题的值。当这些子最优解值被重复引用时,无需重新计算。
设计动态规划法步骤
刻画最优解的结构特性;
递归定义最优解值;
自底向上方式计算最优解值;
根据计算得到的信息构造一个最优解。
相关算法
- 多段图问题
- 关键路径问题
- Floyd算法
- 最长公共子序列问题
- 0/1背包问题
4、回溯法
定义
使用剪枝函数的深度优先生成状态空间树中的节点的求解方法称为回溯法;
- 显示约束和解空间:规定每个分量xi取值的约束条件称为显式约束。对给定的一个问题,显示约束规定了所有可能的元组,他们组成问题的候选解集,被称为该问题实例的解空间。
- 隐式约束和判定函数:隐式约束给出了判定一个候选解是否为可行解的条件。一般需要从问题描述的隐式约束出发,设计一个判定函数,程序根据判定函数判断一个解是否为可行解。
- 最优解和目标函数:目标函数,也称代价函数,用来衡量每个可行解的优劣。使目标函数取得最大(小)值的可行解为问题的最优解。
- 剪枝函数:为了提高搜索效率,在搜索过程中使用约束函数,可以避免无谓地搜索那些已知不含答案状态的子树。如果是最优化问题,还可以使用限界函数剪去那些不可能含有最优解的子树。约束函数和限界函数目的相同,都是为了剪去不必要搜索的子树,减少问题求解所需实际生成的状态结点数,他们统称为剪枝函数。
条件
- 它的解具有n-y元组的形式;
- 问题提供显式约束来确定状态空间树,并提供隐式约束来判定可行解;
- 能设计有效的约束函数缩小检索空间
回溯法相关算法
- n-皇后问题
- 子集和数问题
- 图的着色问题
- 哈密顿环问题
5、分支界限法
定义
广度优先生成结点,并使用剪枝函数的方法称为分枝限界法
相关算法
- 15迷问题
- 带时限作业排序
数据挖掘
数据挖掘就是应用一系列技术从大型数据库或数据仓库中提取人们感兴趣的信息和知识,这些知识或信息是隐含的,事先未知而潜在有用的,提取的知识表示为概念、 规则、规律、模式等形式。
也可以说,数据挖掘是一类深层次的数据分析。常见和应用最广泛的数据挖掘方法如下。
- 决策树:决策树方法是利用信息论中的互信息(信息增益)寻找数据库中具有最大信息量的属性字段,建立决策树的一个结点,再根据该属性字段的不同取值建设树的分支;在每个分支子集中重复建立树的下层结点和分支的过程。国际上最早的、也是最有影响的决策树方法是Quiulan研究的ID3方法。
- 神经网络:神经网络方法是模拟人脑神经元结构,完成类似统计学中的判别、 回归、聚类等功能,是一种非线性的模型,主要有三种神经网络模型:前馈式网络、反馈式网络和自组织网络。人工神经网络最大的长处是可以自动地从数据中学习,形成知识,这些知识有些是我们过去未曾发现的,因此它具有较强的创新性。神经网络的知识体现在网络连接的权值上,神经网络的学习主要表现在神经网络权值的逐步计算上。
- 遗传算法:**遗传算法是模拟生物进化过程的算法,它由三个基本过程组成:繁殖(选择)、交叉(重组)、变异(突变)。**采用遗传算法可以产生优良的后代,经过若干代的遗传,将得到满足要求的后代即问题得解。
- 关联规则挖掘算法:关联规则是描述数据之间存在关系的规则,形式为 “A1A2…An=>B1B2…Bn”。一般分为两个步骤:求出大数据项集、用大数据项集产生关联规则。
除了上述的常用方法外,还有粗集方法,模糊集合方法,Bayesian Belief Netords ,最邻近算法(K-nearest Neighbors Method,kNN)等。
6,其他
在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的。出现概率髙的字符使用较短的编码,出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而到无损压缩数据的目的。
敏捷方法中,重构是一种重新组织技术,重新审视需求和设计,重新明确地描述它们以符合新的和现有的需求,可以简化构件的设计而无需改变其功能或行为