本文章依据《算法导论》所编写,涵盖书中重点内容,用于期末复习。
祝大家 不挂科!
插排:
INSERTION-SORT(A)
1. for j = 2 to length[A]
2. key = A[j]
3. i = j - 1
4. while i > 0 and A[i] > key
5. A[i + 1] = A[i]
6. i = i - 1
7. A[i + 1] = key
归并排序:
MERGE-SORT(A, p, r)
1. if p < r
2. q = (p + r) / 2 // 计算中间位置
3. MERGE-SORT(A, p, q) // 递归地对左半部分进行排序
4. MERGE-SORT(A, q+1, r) // 递归地对右半部分进行排序
5. MERGE(A, p, q, r) // 合并左右两个已排序的子数组
MERGE(A, p, q, r)
1. n1 = q - p + 1 // 左子数组的长度
2. n2 = r - q // 右子数组的长度
3. 创建临时数组 L[1...n1+1] 和 R[1...n2+1]
4. for i = 1 to n1
5. L[i] = A[p + i - 1] // 将左子数组复制到临时数组 L
6. for j = 1 to n2
7. R[j] = A[q + j] // 将右子数组复制到临时数组 R
8. 设置 L[n1+1] 和 R[n2+1] 为无穷大
9. i = 1
10. j = 1
11. for k = p to r
12. if L[i] ≤ R[j]
13. A[k] = L[i]
14. i = i + 1
15. else
16. A[k] = R[j]
17. j = j + 1
归并排序的时间复杂度为O(nlogn),其中n是待排序数组的长度。归并排序是一种稳定的排序算法,对于任何输入数据都可以保证最坏情况下的时间复杂度为O(nlogn)。
O记号:渐近上界
Ω记号:渐近下界
Θ记号:渐近紧确界
最大子数组问题:
1、暴力求解:时间复杂度为O(n^3),其中n是数组的长度。
2、分治策略:最大子数组问题可以使用分治策略解决,通过将问题划分为更小的子问题来求解。具体步骤如下:
3、递归求解:分治策略是递归的,通过不断地将问题划分为更小的子问题,最终求解整个问题。递归的终止条件是子数组只有一个元素时,直接返回该元素作为最大子数组。
4、时间复杂度分析:使用分治策略求解最大子数组问题的时间复杂度为O(nlogn),其中n是数组的长度。这是因为每次递归将问题的规模缩小一半,并且在每一层递归中的操作时间复杂度为O(n)。
用主方法求解递归式
用主方法(Master Theorem)是一种常用的求解递归式的方法,它可以给出递归算法的时间复杂度的上界。
主方法的一般形式如下:
T(n) = a * T(n/b) + f(n)
其中,T(n)表示问题规模为n时算法的执行时间,a表示递归产生的子问题的个数,n/b表示每个子问题的规模,f(n)表示除去递归调用之外剩余操作的执行时间。
主方法基于以下三种情况的假设,针对不同的情况,给出了递归算法的时间复杂度的上界:
使用主方法求解递归式时,我们需要确定递归式中的a、b和f(n)的值,然后根据上述三种情况中的哪一种情况符合,得出递归算法的时间复杂度的上界。
需要注意的是,主方法并不适用于所有类型的递归式,仅适用于符合上述三种情况的递归式。对于其他类型的递归式,可能需要使用其他方法进行求解。
HEAPSORT(A)
BUILD-MAX-HEAP(A) // 构建最大堆
for i = A.length downto 2
exchange A[1] with A[i] // 将最大值放到数组末尾
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A, 1) // 对剩余元素进行最大堆的调整
具体过程如下:
BUILD-MAX-HEAP(A)
:首先将待排序的数组A构建为一个最大堆。从数组的中间位置开始,向前遍历每个非叶子节点,对每个节点执行MAX-HEAPIFY
操作,将其和其子树调整为最大堆。通过这个过程,整个数组A将满足最大堆的性质。
排序过程:从数组的最后一个元素开始,逐步将最大堆的根节点(即最大值)与当前位置的元素进行交换。每次交换后,将堆的大小减1,并对交换后的根节点执行MAX-HEAPIFY
操作,将其与其子树调整为最大堆。重复执行这个过程,直到堆的大小减为1。
BUILD-MAX-HEAP(A):用于构建最大堆的辅助函数。
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = floor(A.length/2) downto 1
MAX-HEAPIFY(A, i)
MAX-HEAPIFY(A, i):用于维护最大堆性质的辅助函数。
MAX-HEAPIFY(A, i)
left = 2i // 左子节点的索引
right = 2i + 1 // 右子节点的索引
largest = i // 初始化最大值的索引为当前节点
// 检查左子节点是否存在且大于当前节点的值
if left ≤ A.heap-size and A[left] > A[i]
largest = left
// 检查右子节点是否存在且大于当前最大值的节点
if right ≤ A.heap-size and A[right] > A[largest]
largest = right
// 如果最大值不等于当前节点,进行交换
if largest ≠ i
exchange A[i] with A[largest]
// 对交换后的子节点递归调用 MAX-HEAPIFY,确保子树也满足最大堆的性质
MAX-HEAPIFY(A, largest)
该算法从数组的中间位置开始,向前遍历每个非叶子节点,并对每个节点执行MAX-HEAPIFY
操作,将其和其子树调整为最大堆。A.heap-size
用于表示当前堆的大小。
堆排序的时间复杂度为O(nlogn),其中n是待排序数组的大小。构建最大堆的过程的时间复杂度为O(n),而每次交换和调整堆的操作的时间复杂度为O(logn)。
优先队列
QUICKSORT(A, p, r)
// 对数组 A[p...r] 进行快速排序
if p < r
q = PARTITION(A, p, r) // 将数组划分为两个子数组,并获取基准元素的位置
QUICKSORT(A, p, q-1) // 对左子数组进行递归排序
QUICKSORT(A, q+1, r) // 对右子数组进行递归排序
PARTITION(A, p, r)
// 将数组 A[p...r] 划分为两个子数组,并返回基准元素的位置
x = A[r] // 选择最后一个元素作为基准元素
i = p - 1 // i 是小于等于基准元素的子数组的边界
for j = p to r-1
if A[j] <= x
i = i + 1
exchange A[i] with A[j] // 将小于等于基准元素的元素交换到左侧
exchange A[i+1] with A[r] // 将基准元素放在正确的位置上
return i + 1 // 返回基准元素的位置
快速排序的时间复杂度为平均情况下的 O(nlogn),其中 n 是待排序数组的大小。它是一种原地排序算法,不需要额外的存储空间
计数排序:
CountingSort(array, k):
n = length(array) // 获取数组长度
count = new Array[k] // 创建计数数组,长度为待排序元素的最大值加1
output = new Array[n] // 创建输出数组,用于存储排序结果
// 初始化计数数组
for i = 0 to k-1:
count[i] = 0
// 统计待排序元素的出现次数
for j = 0 to n-1:
count[array[j]] = count[array[j]] + 1
// 计算每个元素的最终位置
for i = 1 to k-1:
count[i] = count[i] + count[i-1]
// 将元素放入正确的位置
for j = n-1 to 0:
output[count[array[j]] - 1] = array[j]
count[array[j]] = count[array[j]] - 1
return output
基数排序:
桶排序:
BUCKET-SORT(A)
1. n = length[A]
2. 创建一个空的数组 B[0..n-1]
3. 对数组 A 中的每个元素 A[i] 进行循环
a. 创建一个空的链表 B[i]
4. 对数组 A 中的每个元素 A[i] 进行循环
a. 将元素 A[i] 插入链表 B[⌊nA[i]⌋] 中
5. 对数组 B 中的每个链表 B[i] 进行循环
a. 对链表 B[i] 进行插入排序
6. 将链表 B[0],B[1],...,B[n-1] 依次连接起来形成一个新的链表 C
7. 返回链表 C 中的所有元素作为排序结果
最小值和最大值:
为了找到最小值,必须要做 n - 1 次比较。同时找到最小值和最大值,至多是 3|n/2| 向下取整次 比较。
期望为线性时间的选择算法:
RANDOMIZED-SELECT(A, p, r, i)
1. 如果 p = r,则返回 A[p] 作为第i小的元素
2. q = RANDOMIZED-PARTITION(A, p, r) // 将数组 A[p..r] 划分为两个子数组,返回主元的位置 q
3. k = q - p + 1 // 计算主元在当前划分中的相对位置
4. 如果 i = k,则返回 A[q] 作为第i小的元素
5. 如果 i < k,则递归调用 RANDOMIZED-SELECT(A, p, q-1, i) 在左侧子数组中寻找第i小的元素
6. 否则,在右侧子数组中寻找第 (i - k) 小的元素,即调用 RANDOMIZED-SELECT(A, q+1, r, i-k)
插入:
RB-INSERT(T, z)
1. y = NIL // 初始化一个空节点作为插入节点的父节点
2. x = T.root // 从根节点开始向下搜索
3. while x ≠ NIL // 在树中找到适当的位置插入节点
4. do y = x
5. if z.key < x.key
6. then x = x.left
7. else x = x.right
8. z.p = y // 将插入节点的父节点指向 y
9. if y = NIL // 如果 y 为空,说明插入的是根节点
10. then T.root = z
11. else if z.key < y.key // 将 z 插入到正确的位置
12. then y.left = z
13. else y.right = z
14. z.left = NIL // 初始化插入节点的左子节点为空
15. z.right = NIL // 初始化插入节点的右子节点为空
16. z.color = RED // 新插入的节点为红色
17. RB-INSERT-FIXUP(T, z) // 调整红黑树以维持平衡性
钢条切割:
CUT-ROD(p, n)
1. if n == 0 // 钢条长度为 0,返回收益 0
2. then return 0
3. q = -∞ // 初始化最大收益为负无穷
4. for i = 1 to n // 尝试不同的切割位置
5. do q = max(q, p[i] + CUT-ROD(p, n - i)) // 递归调用,计算最大收益
6. return q // 返回最大收益
15.2 矩阵链乘法
定义子问题: 首先,我们定义子问题来解决矩阵相乘的分割点。对于矩阵链 Aᵢ, Aᵢ₊₁, …, Aⱼ,我们将其划分为两个子链 Aᵢ, Aᵢ₊₁, …, Aₖ 和 Aₖ₊₁, Aₖ₊₂, …, Aⱼ,其中 i ≤ k < j。
确定状态: 定义子问题的状态为矩阵链的起始位置 i 和结束位置 j。
定义状态转移方程: 我们使用 m[i, j] 表示计算矩阵链 Aᵢ, Aᵢ₊₁, …, Aⱼ 的最小乘法次数。那么,我们可以得到以下状态转移方程: m[i, j] = min {m[i, k] + m[k+1, j] + pᵢ×pₖ₊₁×pⱼ},其中 i ≤ k < j。
这个状态转移方程的意思是,对于每个分割点 k,我们计算分割点前半部分和分割点后半部分的乘法次数,并将它们加起来,再加上当前分割点的乘法次数 pᵢ×pₖ₊₁×pⱼ。然后,我们在所有可能的分割点 k 中选择最小的乘法次数作为 m[i, j] 的值。
确定边界条件: 最小子问题的解为单个矩阵的乘法次数为 0,即 m[i, i] = 0(对于所有 i)。
计算最优解: 使用自底向上的迭代方法,从小规模的问题开始计算,逐步扩展到整个矩阵链。我们通过填充一个表格来保存中间结果和最小乘法次数。首先计算单个矩阵的乘法次数为 0,然后按照从小到大的顺序计算所有子问题的最小乘法次数。最终,我们将获得整个矩阵链的最小乘法次数 m[1, n]
15.3 动态规划原理
动态规划的原理和基本步骤:
16.1 活动选择问题
问题:
假设有一个会议室和一组预定了开始时间和结束时间的活动。现在要求你设计一个算法,选择出最大可能的相互兼容的活动子集,使得可以同时进行最多的活动。请使用贪心算法解决这个问题,并给出算法的思路和伪代码。
答案:
算法思路:
伪代码:
GreedyActivitySelection(start, end):
n = length(start)
activities = []
activities.append(0) // 加入第一个活动
k = 0
for i = 1 to n-1:
if start[i] >= end[k]:
activities.append(i)
k = i
return activities
这个算法的时间复杂度为 O(n log n),其中 n 是活动的个数。通过这个贪心算法,可以选择出最大相互兼容的活动子集,使得可以同时进行最多的活动。
16.2 贪心算法原理
问题:
考虑一个背包问题,背包的容量为W,有n个物品,每个物品有自己的重量和价值。现在要设计一个算法,选择出最优的物品组合放入背包,使得背包中物品的总价值最大化。使用贪心算法解决该问题,并给出算法的思路和伪代码。
答案:
算法思路:
伪代码:
GreedyKnapsack(weights, values, W):
n = length(weights)
value_per_unit = []
for i = 0 to n-1:
value_per_unit[i] = values[i] / weights[i]
sort(value_per_unit, weights, values) // 按单位价值排序
total_value = 0
remaining_capacity = W
for i = 0 to n-1:
if weights[i] <= remaining_capacity:
total_value = total_value + values[i]
remaining_capacity = remaining_capacity - weights[i]
return total_value
这个算法的时间复杂度为 O(n log n),其中 n 是物品的个数。通过这个贪心算法,可以选择出最优的物品组合放入背包,使得背包中物品的总价值最大化。然而,请注意贪心算法在0-1背包问题中不一定能得到最优解的情况。
16.3 赫夫曼编码
问题描述:
赫夫曼编码用于将给定的文本数据进行压缩,以减少存储空间和传输带宽。赫夫曼编码的核心思想是将出现频率较高的字符用较短的编码表示,而将出现频率较低的字符用较长的编码表示。
赫夫曼树:
赫夫曼编码的基础是赫夫曼树。赫夫曼树是一种特殊的二叉树,其中每个叶子节点表示一个字符,而每个非叶子节点表示一个字符出现的频率。赫夫曼树的构建过程通常使用优先队列(最小堆)来选择频率最低的两个节点,并将它们合并为一个新节点,直到只剩下一个根节点为止。
赫夫曼编码的构建:
构建赫夫曼编码的过程可以分为以下步骤:
赫夫曼编码的性质:
赫夫曼编码的应用:
赫夫曼编码在数据压缩领域广泛应用,尤其在文本文件压缩中效果显著。通过使用赫夫曼编码,可以大大减小文件的大小,节省存储空间和传输带宽。
BFS——广度优先搜索
BFS(G, s):
1. for each vertex u ∈ G.V - {
s} // 初始化所有顶点的状态
2. u.color = WHITE // WHITE表示未访问
3. u.d = ∞ // 从起始顶点s到顶点u的最短距离
4. u.π = NIL // 从起始顶点s到顶点u的前驱节点
5. s.color = GRAY // 起始顶点s标记为灰色,表示已访问但未完成探索
6. s.d = 0 // 起始顶点s到自身的最短距离为0
7. s.π = NIL // 起始顶点s没有前驱节点
8. Q = ∅ // 创建一个空队列Q
9. ENQUEUE(Q, s) // 将起始顶点s入队
10. while Q ≠ ∅ // 队列不为空时继续循环
11. u = DEQUEUE(Q) // 取出队列的头部节点u
12. for each v ∈ G.Adj[u] // 遍历u的邻接节点v
13. if v.color == WHITE // 如果邻接节点v未被访问
14. v.color = GRAY // 标记为灰色,表示已访问但未完成探索
15. v.d = u.d + 1 // 更新起始顶点s到顶点v的最短距离
16. v.π = u // 设置顶点v的前驱节点为u
17. ENQUEUE(Q, v) // 将顶点v入队
18. u.color = BLACK // 当u的邻接节点都被探索完成后,将u标记为黑色,表示已完成探索
DFS——深度优先搜索
DFS(G):
1. for each vertex u ∈ G.V // 初始化所有顶点的状态
2. u.color = WHITE // WHITE表示未访问
3. u.π = NIL // 从起始顶点s到顶点u的前驱节点
4. time = 0 // 初始化时间变量
5. for each vertex u ∈ G.V // 遍历所有顶点
6. if u.color == WHITE // 如果顶点u未被访问
7. DFS-VISIT(u) // 调用DFS-VISIT进行深度优先探索
DFS-VISIT(u):
1. time = time + 1 // 增加时间变量,表示顶点u被发现的时间
2. u.d = time // 记录顶点u的发现时间
3. u.color = GRAY // 标记顶点u为灰色,表示正在访问中
4. for each vertex v ∈ G.Adj[u] // 遍历顶点u的邻接节点v
5. if v.color == WHITE // 如果邻接节点v未被访问
6. v.π = u // 设置顶点v的前驱节点为u
7. DFS-VISIT(v) // 递归调用DFS-VISIT对顶点v进行深度优先探索
8. u.color = BLACK // 当u的所有邻接节点都被探索完成后,将u标记为黑色
9. time = time + 1 // 增加时间变量,表示顶点u的探索完成时间
10. u.f = time // 记录顶点u的探索完成时间
22.4 拓扑排序
拓扑排序是一种对有向无环图(DAG)进行排序的算法,它将图中的节点按照一定的顺序进行排列,使得所有的有向边从排在前面的节点指向排在后面的节点。
拓扑排序是一种非常有用的算法,通过确定节点之间的依赖关系,可以有效地解决任务调度等问题。它要求图是有向无环图,因此在使用拓扑排序之前需要先判断图是否是有向无环图。如果是有向无环图,拓扑排序可以给出一种满足依赖关系的节点排序顺序。
这一章介绍了解决连接图中所有顶点的最小生成树问题的算法。下面是对该章节的概述:
问题:
给定下面的无向图和边的权重,使用Prim算法找出最小生成树,并计算最小生成树的总权重。
图示:
4 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)----- (4)
2
答案:
最小生成树的边集合为:{(0, 1), (1, 2), (2, 4), (3, 0)}
最小生成树的总权重为:14
解释:
注意:在Prim算法中,起始顶点的选择可能会影响最终的最小生成树,但最小生成树的总权重是唯一的。在本题中,起始顶点为0,可以得到上述的最小生成树和总权重。
题目:使用Kruskal算法和Prim算法分别求解以下无向带权图的最小生成树。
给定以下无向带权图(使用邻接矩阵表示):
A B C D E
----------------------
A | 0 4 0 0 0
B | 4 0 7 8 0
C | 0 7 0 9 14
D | 0 8 9 0 10
E | 0 0 14 10 0
a) 使用Kruskal算法求解最小生成树,并给出最小生成树的边集合和总权重。
b) 使用Prim算法求解最小生成树,并给出最小生成树的边集合和总权重。
答案:
a) Kruskal算法求解最小生成树的过程:
b) Prim算法求解最小生成树的过程:
注意:这是一个示例题目,实际的最小生成树问题可能会更复杂,需要根据具体图的情况进行求解。
这一章介绍了解决从一个源节点到其他所有节点的最短路径问题的算法。
24.3 Dijkstra算法
Dijkstra(G, w, s):
Initialize-Single-Source(G, s) // 初始化节点距离和前驱节点
S = {
} // 已确定最短路径的节点集合
Q = G.V // 所有节点的集合
while Q is not empty:
u = Extract-Min(Q) // 从Q中选择距离最小的节点u
S = S U {
u} // 将节点u加入已确定最短路径的集合
for each v in G.Adj[u]: // 遍历u的邻接节点v
Relax(u, v, w) // 松弛操作,更新节点v的最短距离
return dist[] // 返回最短距离数组
Relax(u, v, w):
if dist[v] > dist[u] + w(u, v): // 如果通过节点u可以得到更短的路径
dist[v] = dist[u] + w(u, v) // 更新节点v的最短距离
prev[v] = u // 更新节点v的前驱节点
Initialize-Single-Source(G, s):
for each v in G.V:
dist[v] = infinity // 初始化节点v的距离为正无穷大
prev[v] = NIL // 初始化节点v的前驱节点为空
dist[s] = 0 // 源节点的距离为0
——————————————送上四道经典LeetCode题
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
// class Solution {
// public int[] twoSum(int[] nums, int target) {
// int len = nums.length;
// for(int i = 0; i < len; i++){
// for(int j = i + 1; j < len; j++){
// if(nums[i] + nums[j] == target){
// return new int[]{i,j};
// }
// }
// }
// return new int[0];
// }
// }
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
Map<Integer, Integer> hashtable = new HashMap<Integer,Integer>();
for(int i = 0; i < len; i++){
if(hashtable.containsKey(target - nums[i])){
//i为0 此时key为2,找有没有7,7对应的val为hashtable.get(7);
return new int[]{
i , hashtable.get(target - nums[i])};
}
hashtable.put(nums[i],i); //key 2,val 0;;; key 7,val 1;;; key 11,val 2......
}
return new int[0];
}
}
给定一个非负整数数组 nums
,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
class Solution {
public boolean canJump(int[] nums) {
int len = nums.length;
int most = 0; //最大位置的下表
for(int i = 0; i < len; i++){
if(i <= most){
//此时的位置在most位置之前,要替换更新most
most = Math.max(most , i + nums[i]); //此时的i跳num[i]后 是否比most大
if(most >= len-1){
//只要当 能跳到的最大位置(most) 到达/超过 最后一个位置的下标 就ture
return true;
}
}
}
//遍历完了 还不能超过最后位置
return false;
}
}
给你一个 n x n
矩阵 matrix
,其中每行和每列元素均按升序排序,找到矩阵中第 k
小的元素。
请注意,它是 排序后 的第 k
小元素,而不是第 k
个 不同 的元素。
你必须找到一个内存复杂度优于 O(n2)
的解决方案。
暴力解:
class Solution {
public int kthSmallest(int[][] matrix, int k) {
int n = matrix[0].length;
int[] sor = new int[n * n];
int index = 0;
//把二维数组每一个放入一维数组
for(int[] row : matrix){
//遍历二维数组每一行
for(int num : row){
//遍历每一行的每一个
sor[index] = num;
index++;
}
}
//重新排序
Arrays.sort(sor);
return sor[k-1]; //返回第k小的元素
}
}
给你一个 只包含正整数 的 非空 数组 nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
class Solution {
public boolean canPartition(int[] nums) {
int len = nums.length;
//算出总和,为奇数,false
int sum = 0;
for(int n : nums){
sum += n;
}
if(sum % 2 == 1) return false;
//创建二维数组,0-1 背包问题。行:数组索引,列:容量
int target = sum/2;
boolean[][] dp = new boolean[len] [target + 1];
//先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满
if(nums[0] <= target){
dp [0] [nums[0]] = true;
}
//再填后面几行
for(int i = 1; i < len; i++){
for(int j = 0; j <= target; j++){
//从上一行把结果抄下来,再修正
dp[i][j] = dp[i-1][j];
if(nums[i] == j){
dp[i][j] = true;
continue;
}
if(nums[i] < j){
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
}
}
}
return dp[len-1][target];
}
}
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象