Skip to main content

添加用户

· One min read

sudo adduser xxx

添加到sudo 组

sudo adduser xxx sudo

  • 另外一种方式
添加sudo权限
sudo vim /etc/sudoer
1
修改前:
# User privilege specification
root ALL=(ALL:ALL) ALL

修改后
# User privilege specification
root ALL=(ALL:ALL) ALL
xxx ALL=(ALL:ALL) ALL



查看是否在用户组

id xxx

校验sudo

sudo ls -l /root

  • 如果主机名不存在
  • 添加主机名 sudo vi /etc/hosts 把报错的主机名加进去,如下
  • 127.0.0.1 xxxx

配置SSH

sudo vim /etc/ssh/sshd_config


修改前:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

修改后:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
PermitRootLogin yes
StrictModes yes
#MaxAuthTries 6
#MaxSessions 10


2024/javascript

· One min read

let 和 const 命令

var 之前,我们写js定义变量的时候,只有一个关键字: var var 有一个问题,就是定义的变量有时会莫名奇妙的成为全局变量。

例如这样的一段代码: 运行打印的结果是如下: 可以看出,在循环外部也可以获取到变量i的值,显然变量i的作用域范围太大了,在做复杂页面时,会带来很大的问 题。

 let for(var i = 0; i < 5; i++){ console.log(i); } console.log("循环外:" + i) 1 2 3 4 

let 所声明的变量,只在 let 命令所在的代码块内有效。 我们把刚才的 var 改成 let 试试: 结果: 这样,就把变量的i的作用域控制在了循环内部。 const const 声明的变量是常量,不能被修改,类似于java中final关键字。 可以看到,变量a的值是不能修改的。

2024/jvm 参数

· 2 min read

-XX:MetaspaceSize=1536m -XX:MaxMetaspaceSize=1536m

Metaspace 区域位于堆外,所以它的最大内存大小取决于系统内存,而不是堆大小,我们可以指定 MaxMetaspaceSize 参数来限定它的最大内存。

Metaspace 是用来存放 class metadata 的,class metadata 用于记录一个 Java 类在 JVM 中的信息,包括但不限于 JVM class file format 的运行时数据:

1、Class 结构,这个非常重要,把它理解为一个 Java 类在虚拟机内部的表示吧;

2、method metadata,包括方法的字节码、局部变量表、异常表、参数信息等;

3、常量池;

4、注解;

5、方法计数器,记录方法被执行的次数,用来辅助 JIT 决策;

6、 其他

虽然每个 Java 类都关联了一个 java.lang.Class 的实例,而且它是一个贮存在堆中的 Java 对象。但是类的 class metadata 不是一个 Java 对象,它不在堆中,而是在 Metaspace 中。

-Xlog:gc*=debug:file=C:\Users\duan\Desktop\gclogs/gc%t.log:utctime,level,tags:filecount=50,filesize=100M -Xlog:jit+compilation=info:file=C:\Users\duan\Desktop\gclogs/jit_compile%t.log:utctime,level,tags:filecount=10,filesize=10M -Xlog:safepoint=debug:file=C:\Users\duan\Desktop\gclogs/safepoint%t.log:utctime,level,tags:filecount=10,filesize=10M

2024/smart原则

· One min read

构建自己的学习树,可以帮助我们系统地输入,系统地输出,自上而下地规划,自下而上地修葺,同时我们还可以随时调用以解决遇到的问题,如图1-6所示。

SMART的具体释意为, Specific——具体的, Measurable——可度量的, Attainable——可实现的, Relevant——(和其他目标)有相关性的, Time-bound——有时限的。

追踪目标是否完成,那就是OKR工作法。OKR(Objectives and Key Results)即目标与关键成果法,是一套明确目标、跟踪目标及其完成情况的管理工具和方法,由英特尔公司创始人之一安迪·葛洛夫(Andy Grove)发明。目标是设定一个确定的时间段内要达成的任务(

学习方式主要分为视、听、说、想、写、画。为了保证学习效率,我们需要采用多种感官联合学习的方式,即同时刺激多个感官,这样记忆会比较深刻。

2024/弱引用

· One min read
 WeakReference<String> weakCar = new WeakReference<String>("abc");
log.error(weakCar.get());

2024/算法的时间复杂度和空间复杂度

· 8 min read

算法(Algorithm)是指用来操作数据、解决程序问题的一组方法。对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但在过程中消耗的资源和时间却会有很大的区别。

那么我们应该如何去衡量不同算法之间的优劣呢?

主要还是从算法所占用的「时间」和「空间」两个维度去考量。

  • 时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。

  • 空间维度:是指执行当前算法需要占用多少内存空间,我们通常用「空间复杂度」来描述。

因此,评价一个算法的效率主要是看它的时间复杂度和空间复杂度情况。然而,有的时候时间和空间却又是「鱼和熊掌」,不可兼得的,那么我们就需要从中去取一个平衡点。

下面我来分别介绍一下「时间复杂度」和「空间复杂度」的计算方式。

时间复杂度

我们想要知道一个算法的「时间复杂度」,很多人首先想到的的方法就是把这个算法程序运行一遍,那么它所消耗的时间就自然而然知道了。

这种方式可以吗?当然可以,不过它也有很多弊端。这种方式非常容易受运行环境的影响,在性能高的机器上跑出来的结果与在性能低的机器上跑的结果相差会很大。而且对测试时使用的数据规模也有很大关系。再者,并我们在写算法的时候,还没有办法完整的去运行呢。

因此,另一种更为通用的方法就出来了:「 大O符号表示法 」,即 T(n) = O(f(n))

我们先来看个例子:

for(int i \= 0; i <= n; i++){  j \= i; j ++; }

通过「 大O符号表示法 」,这段代码的时间复杂度为:O(n) ,为什么呢?

在大O符号表示法中,时间复杂度的公式是: T(n) = O( f(n) ),其中f(n) 表示每行代码执行次数之和,而 O 表示正比例关系,这个公式的全称是:算法的渐进时间复杂度

我们继续看上面的例子,假设每行代码的执行时间都是一样的,我们用1颗粒时间来表示,那么这个例子的第一行耗时是1个颗粒时间,第三行的执行时间是 n个颗粒时间,第四行的执行时间也是 n个颗粒时间(第二行和第五行是符号,暂时忽略),那么总时间就是 1颗粒时间 + n颗粒时间 + n颗粒时间 ,即 (1+2n)个颗粒时间,即: T(n) = (1+2n)*颗粒时间,从这个结果可以看出,这个算法的耗时是随着n的变化而变化,因此,我们可以简化的将这个算法的时间复杂度表示为:T(n) = O(n)

为什么可以这么去简化呢,因为大O符号表示法并不是用于来真实代表算法的执行时间的,它是用来表示代码执行时间的增长变化趋势的。

所以上面的例子中,如果n无限大的时候,T(n) = time(1+2n)中的常量1就没有意义了,倍数2也意义不大。因此直接简化为T(n) = O(n) 就可以了。

常见的时间复杂度量级有:

  • 常数阶O(1)

  • 对数阶O(logN)

  • 线性阶O(n)

  • 线性对数阶O(nlogN)

  • 平方阶O(n²)

  • 立方阶O(n³)

  • K次方阶O(n^k)

  • 指数阶(2^n)

上面从上至下依次的时间复杂度越来越大,执行的效率越来越低。

下面选取一些较为常用的来讲解一下(没有严格按照顺序):

  1. 常数阶O(1)
    无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1),如:

    int i \= 1; int j \= 2; ++i; j++; int m \= i + j;

    上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度。

  2. 线性阶O(n)
    这个在最开始的代码示例中就讲解过了,如:

    for(i\=1; i<=n; ++i) {  j \= i; j++; }

    这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。

  3. 对数阶O(logN)

还是先来看代码:


int i \= 1; while(i<n) { i \= i \* 2; }

从上面代码可以看到,在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)

  1. 线性对数阶O(nlogN)

线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是 O(nlogN)。

就拿上面的代码加一点修改来举例:

for(int m\=1; m < n; m++) {  i \= 1; while(i<n) { i \= i \* 2; } }
  1. 平方阶O(n²)

平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。
举例:

for(int x\=1; i<=n; x++) {  for(i\=1; i<=n; i++) { j \= i; j++; } }

这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的n改成m,即:


for(int x\=1; i<=m; x++) { for(i\=1; i<=n; i++) { j \= i; j++; } }

那它的时间复杂度就变成了 O(m*n)

  1. 立方阶O(n³)K次方阶O(n^k)

参考上面的O(n²) 去理解就好了,O(n³)相当于三层n循环,其它的类似。

除此之外,其实还有平均时间复杂度、均摊时间复杂度、最坏时间复杂度、最好时间复杂度的分析方法,有点复杂,这里就不展开了。

空间复杂度

既然时间复杂度不是用来计算程序具体耗时的,那么我也应该明白,空间复杂度也不是用来计算程序实际占用的空间的。

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。

空间复杂度比较常用的有:O(1)、O(n)、O(n²),我们下面来看看:

  1. 空间复杂度 O(1)
    如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
    举例:
 int i \= 1; int j \= 2; ++i; j++; int m \= i + j;

代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)

  1. 空间复杂度 O(n)
    我们先看一个代码:
   int\[\] m \= new int\[n\] for(int i\=1; i<=n; ++i) {  j \= i; j++; }

这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)

常用算法时间复杂度和空间复杂度查询

排序算法

平均时间复杂度

最好情况

最坏情况

空间复杂度

稳定性

冒泡排序

O(n2)

O(n)

O(n2)

O(1)

稳定

选择排序

O(n2)

O(n2)

O(n2)

O(1)

不稳定

插入排序

O(n2)

O(n)

O(n2)

O(1)

稳定

希尔排序

O(nlogn)

O(nlog2n)

O(nlog2n)

O(1)

不稳定

归并排序

O(nlogn)

O(nlogn)

O(nlogn)

O(n)

稳定

快速排序

O(nlogn)

O(nlogn)

O(n2)

O(logn)

不稳定

堆排序

O(nlogn)

O(nlogn)

O(nlogn)

O(1)

不稳定

计数排序

O(n+k)

O(n+k)

O(n+k)

O(k)

稳定

桶排序

O(n+k)

O(n+k)

O(n2)

O(n+k)

稳定

基数排序

O(n * k)

O(n * k)

O(n * k)

O(n+k)

稳定

开启远程控制

· One min read
  • 控制面板
  • 系统和安全
  • 系统
  • 允许远程访问
  • 在弹窗中勾选 允许远程协助连接这台计算机

本地账户

  1. 如果没有帐户,添加本地账户
  2. 双击本地账户,选择【隶属于】,点击【添加】》〉》【高级】〉》〉【立即查找】》〉》在下方结果页找到 【Remote Desktop。Users】。
  3. 选择然后点击确认,保存修改
连接的设置如下,本地用户直接是用户名和本地用户密码

网关一般是内网网段的第一个 如 192.168.31.1

Microsoft 帐户

  1. 设置成管理员
  2. 删除PIN ,设置密码,关闭仅允许
  3. 使用 Microsoft 帐户和密码登录,
  4. 登录成功后可以再把PIN 设置回来

远程用户连接,直接说远程的邮箱和密码

act

· One min read

act 是一个用于在本地运行 GitHub Actions 的工具。它允许开发人员在本地测试和调试 GitHub Actions,而无需将代码推送到 GitHub 上。

GitHub

· 3 min read

Cytoscape.js: 这是一个功能强大且广泛使用的开源图可视化库。它提供了丰富的 API 来操作和样式化节点和边,支持多种布局算法(如 force-directed, grid, concentric 等),并且具有良好的交互性。它也容易与前端框架(如 React, Vue.js)集成。 Vis.js: 另一个流行的开源库,专注于动态的、基于浏览器的网络可视化。它提供了易于使用的 API 和多种内置的布局算法。Vis.js 的渲染性能也相当不错,尤其对于中等规模的数据集。 Sigma.js: 一个专门为绘制大型网络图而设计的 JavaScript 库。它使用了 WebGL 进行渲染,因此在处理大量节点和边时性能表现出色。Sigma.js 也提供了插件机制来扩展其功能。 G6 (by AntV): 这是蚂蚁集团 AntV 旗下的图可视化引擎。它提供了丰富的图元素、布局算法和交互功能,并且在性能和易用性方面都做了优化。G6 也支持自定义节点、边和布局。 VivaGraphJS: 一个轻量级的 JavaScript 图形绘制库,专注于性能。它提供了多种布局算法,并且可以自定义渲染器以适应不同的可视化需求。 也适用于图数据,但更通用的可视化库:

Plotly.js: 虽然 Plotly.js 是一个通用的图表库,但它也支持创建网络图 (scattergl with edges)。它提供了声明式的 API 和丰富的交互功能。 ECharts (by Apache): 类似于 Plotly.js,ECharts 是一个功能强大的通用图表库,也支持关系图。它具有高度的可定制性和丰富的图表类型。 mxGraph (now draw.io/diagrams.net): 这是一个更成熟和商业化的图编辑和可视化库。它提供了强大的图形编辑功能和多种布局算法,适用于构建复杂的图表和流程图。虽然不是完全免费和开源,但其核心是开源的。 React 相关的库:

react-force-graph: 一个基于 React 和 Three.js 的组件,用于创建 3D 力导向图。非常适合展示节点之间的关系和网络结构。 nivo: 一个构建在 D3 和 React 之上的数据可视化库,提供了一系列的图表组件,包括网络图等。