Idea断点调试(debug)详解

目录 1.打断点,并启动2.按钮介绍1.测试程序2.Step Over3.Step Into4.Force Step Into5.Step Out6.Drop Frame7.Run to Cursor8.Evaluate Expression9.Resume Program10.Stop11.View BreakPoints12.Mute BreakPoints 3.断点分类1.方法断点2.属性断点3.异常断点4.条件断点5.流断点6.多线程断点 1.打断点,并启动 打断点: 鼠标左键点击这里就会出现一个红点标志 (有各种形状,后续解释),就打上了一个断点。 启动: 对于已经运行过的程序,直接点击,小虫子就能启动 对于没有运行过的程序,找到程序入口(main方法)前面的三角形 ,鼠标右键启动 启动后,当我们的程序执行到断点程序处,就会出现调试界面,如下: 如果没有出现调试界面,那就是说明:根本没有执行断点处的程序。 2.按钮介绍 1.测试程序 先写一个简单的类来做测试,如下: public class TestDemo { public static int add(int a, String b) { int c = Integer.parseInt(b); return a + c; } public static char sub(int d, int e) { char res = (char) Math.abs(d - e); return res; } public static void main(String[] args) { String b = "

Qt自定义信号数据类型实践

目录 方法实践源码myworker.hmyworker.cppmain.cppwidget.hwidget.cpp搭载界面 效果 方法 1)引入头文件:#include 2)添加声明:利用宏 Q_DECLARE_METATYPE 3)注册:利用方法 qRegisterMetaType 实践 1.建结构体作为自己传输的信号(可以多加几个需要的数据。 struct MySignalParam{ QString str; QString dis; }; 添加声明 Q_DECLARE_METATYPE(MySignalParam) 3.注册 qRegisterMetaType(); 4.连接信号与槽函数 connect(&worker,SIGNAL(sendMeg(MySignalParam)),this,SLOT(receiveData(MySignalParam))); 【Qt5的写法试了一下,好像报错了,希望知道的小伙伴不吝赐教】 源码 构建一个类来定义信号 myworker.h #ifndef MYWORKER_H #define MYWORKER_H #include <QObject> struct MySignalParam{ QString str; QString dis; }; Q_DECLARE_METATYPE(MySignalParam) class MyWorker : public QObject { Q_OBJECT public: explicit MyWorker();//QObject *parent = 0); signals: void sendMeg(MySignalParam myparam); public: void myrun(); }; #endif // MYWORKER_H myworker.cpp #include "myworker.h" #include <QVariant> #include <QDebug> #include <QTime> #include <QThread> MyWorker::MyWorker() { qRegisterMetaType<MySignalParam>(); } void MyWorker::myrun() { MySignalParam signalParam; signalParam.

浅析JAVA集合框架之HashMap

文章目录 注:本文基于jdk1.8Capacity和Size的区别 数据结构什么是hash冲突什么是链表单向链表Node实体 什么是红黑树TreeNode实体 源码阅读继承与实现接口类的属性重要方法解析构造方法tableSizeFor() hash算法异或运算 ^逻辑右移 >>>取模运算 %计算桶的位置 putgetresize 参考博客: 注: 本文基于jdk1.8 XiuQiang:~ XiuQiang$ java -version java version "1.8.0_191" Java(TM) SE Runtime Environment (build 1.8.0_191-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode) Capacity和Size的区别 Capacity:容量,哈希桶数组的长度,即table.length。 Size:哈希桶数组内节点的总数。 数据结构 HashMap底层的数据结构是数组+链表+红黑树(jdk1.7是数组+链表)。 在下文中,我们将哈希桶数组里可以存储元素的位置称为桶(bucket)。同时,将桶中链表或者红黑树的节点称之为bin。(bin是依据是源码中的注释,不是我一拍脑袋随便想出来的哈) 图来自郑加威的博客:传送门 当桶中的结构为链表时,HashMap采用Node数组来存储key-value对,每一个键值对组成了一个Node实体,即bin。Node类具有Next指针,可以连接下一个Node实体,依此来解决hash冲突的问题。 什么是hash冲突 HashMap是按照Key的hash值来计算bin在HashMap中存储的位置的,即桶的位置。如果hash值相同,而key内容不相等,它们就会被放入同一个桶内。此时就要用链表来解决这种hash冲突。当桶内链表长度大于8时,链表会转化为红黑树,这种转换是有条件的,若桶的数量太少,则会直接进行扩容。欲知后事如何,请听下回分解,哈哈哈哈。 什么是链表 链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表。因为HashMap中的链表就是单向链表,下面简单就单向链表进行图解说明。其他几种链表感兴趣的同学可以自行查阅资料。 单向链表 单向链表就是通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null。 Node实体 /** * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.

Anaconda安装及配置(详细版)

1. 前言 第一次下载Anaconda往往会出现一些问题,比如不知道如何下载,或者下载过慢等问题,由此本文给出以下解决放方案,并给出图示解决。 2. 下载anaconda 首先下载anaconda,点击进入清华镜像网站,点击下载即可: 镜像网站如下图所示: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 找到最新的适合自己电脑系统的版本即可! 3. Anaconda 安装 下面的图片是很早之前的,自己下载的版本为最新的。 首先打开下载好的界面: 没什么好说的,点击 Next 即可。 用户协议,点击 I Agree。 Just me和All users的选择影响不大,最好选All users,原因大概是如果安装过Python也有该选项,需要匹配或者是当电脑设置多个用户时比较方便(不确定,总之影响不大,随便选),但是我还是选的Just me。 假如你的电脑有好几个 Users ,才需要考虑这个问题。其实我们电脑一般就一个 User,就我们一个人使用,如果你的电脑有多个用户,选择All Users。不管是选择哪个,后续的安装流程都是相同的,所以不用在这里太过纠结,这里直接选择Just Me,然后继续点击 Next 。 安装路径最好是非系统盘。当然,后续配置好环境即可。且路径中不要出现中文字符。此处最好把安装路径复制下来,无论是否修改安装路径。 一定不要在这一步勾选第一个选项配置环境,否则容易出错。我也有看勾选这个环境的教程,但从多次安装经验来看,不勾选后续自行配置环境永远没有问题,而勾选则有时报错,有时成功,比较随机。 最后等待安装即可,如下图所示(可能会等待一定的时间): 上面图片的两个勾选不选都无所谓,看你是否有需求,我没有所以就没勾。自此安装就完毕了。接下来配置环境,在cmd上检查一下就可以了。 4. 配置环境 主要有三个环境的配置: ①anaconda安装路径(为了Python检查正常): 前面安装时路径一定要记清楚,之前已提醒复制,我的是F:\anaconda ②安装路径\Scripts(为了conda检查正常): 只需在上述路径中找到Scripts,然后复制路径即可,我的路径是F:\anaconda\Scripts ③另一个路径(加不加不知道有什么区别,不影响后边的检查): 安装路径\Library,如我的是F:\anaconda\Library 上述三个环境变量都是通过:此电脑—右键—高级系统设置—环境变量—系统变量—双击path—新建这些变量即可。 5. 检查 打开anaconda prompt: 输入命令conda list: 可以看到安装好的很多包!

Rockchip PX30/RK3326 Android开机时间优化

“Rockchip_PX30RK3326_Android_0”>Rockchip PX30/RK3326 Android开机时间优化 RK的kernel是一个通用版本的kernel,为了兼容各个芯片会把每个芯片的配置和产品上面的需要的外设都配置编译,这样就会导致kernel的加载的驱动模块很多,拖慢开机速度,而这些驱动中有一些是具体产品上没有用到的,可以进行删减的。按这个思路我们可以针对每个具体的产品对kernel进行瘦身裁剪,下面以PX30和RK3326芯片平台为例进行裁剪。 具体的kernel模块加载时间和模块信息可以通过下面的文章获取 kernel打印模块驱动加载时间 裁剪前后的固件和开机时间对比 项目kernel裁剪前kernel裁剪后kernel.img固件大小31M25Muboot启动耗时871.766 ms826.115 mskernel启动完到init1.273138s1.200982sandroid启动完成29.871925s23.537320s 启动时间可以根据如下log判断: uboot启动时间 Adding bank: 0x00200000 - 0x08400000 (size: 0x08200000) Adding bank: 0x08c00000 - 0x80000000 (size: 0x77400000) Total: 826.115 ms kernel阶段 [ 1.215979] Run /init as init process [ 1.226837] init: init first stage started! android阶段 [ 23.537320] init: Service 'bootanim' (pid 151) exited with status 0 oneshot service took 19.760000 seconds in background [ 23.537402] init: Sending signal 9 to service 'bootanim' (pid 151) process group.

【Spring AOP】面向切面编程的概念,实践,原理详解

AOP概念 AOP的全名是aspect-oriented programming面向切面编程,它是面对对象编程(OOP)的一种方式 这个AOP的思想主要是指对一个事务的集中处理.将多个类都要完成的功能都在一个类中统一完成.如用户登录的校验功能,每一个页面其实都要进行这个校验,AOP技术就是单独在一个另外的类中统一的进行校验 AOP技术是一种思想,Spring AOP是这个思想的一个技术实现 AOP主要完成的事务 AOP主要可以完成以下几种事务: 统一日志记录统一方法执行时间统计统一的方法返回结果设置统一的异常处理事务的开启和提交 组成 切面Aspect 切面是由切点和通知组成的. 主要就是一个包含了一些实现功能的AOP集合类,不仅包括了切点和通知,还包含了连接点的定义 连接点 Join Point 程序中调用切面的一个位置,叫做连接点,这个连接点可以是方法调用,可以是抛出异常时,可以是修改参数时 切点 Pointcut Pointcut 的作⽤就是提供⼀组规则(使⽤ AspectJ pointcut expression language 来描述)来匹 配 Join Point,给满⾜规则的 Join Point 添加 Advice。 切点相当于保存了众多连接点的⼀个集合(如果把切点看成⼀个表,⽽连接点就是表中⼀条⼀条 的数据 通配符 AspectJ ⽀持三种通配符 * 匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数) ..匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。 + 表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的 所有⼦类包括本身 切点表达式: 切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法为: execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>) 修饰符,异常一般省略 包,类一般不省略 返回类型,方法名,参数不可以省略 通知 Advice 切点的方法体的实现就是通知. Spring AOP中有以下几种通知: 前置通知@Before 通知方法会在目标方法之前进行执行 后置通知@After 通知方法在目标方法返回之后或者异常抛出之后 返回之后通知@AfterReturning 通知方法在目标方法返回之后通知 抛异常后通知@AfterThrowing 通知方法在目标方法抛出异常之后执行

ACL的基本介绍

访问控制列表ACL(Access Control List)是由一条或多条规则组成的集合。每条规则描述报文匹配条件(报文的源地址、目的地址、端口号等)的判断语句,设备基于这些规则进行报文匹配,可以过滤出特定的报文 ACL配置完成后,必须应用在业务模块中才能生效,设备根据应用ACL的业务模块的处理策略来允许或阻止该报文通过。 ACL的组成 一条ACL的结构组成,如图1所示。 图1 ACL的结构组成 ACL名称:通过名称来标识ACL,更加方便记忆,这种ACL,称为命名型ACL。 命名型ACL实际上是“名字+数字”的形式,可以在定义命名型ACL时同时指定ACL编号。 ACL编号:用于标识ACL,也可以单独使用ACL编号,表明该ACL是数字型。 不同的ACL类型使用不同的ACL编号取值标识。 规则:即描述报文匹配条件的判断语句。 规则编号:用于标识ACL规则。可以自行配置规则编号,也可以由系统自动分配。系统按照规则编号从小到大的顺序,将规则依次与报文匹配,一旦匹配上一条规则即停止匹配。 动作:报文处理动作,包括permit/deny两种,表示允许/拒绝。 匹配项:描述每条规则的报文匹配条件(报文的源地址、目的地址、端口号等)的判断语句,设备基于这些规则的匹配项进行报文匹配 ACL的实现方式 目前设备支持的ACL,有以下两种实现方式: 软件ACL:针对与本机交互的报文(必须上送CPU处理的报文),由软件实现来过滤报文的ACL,比如FTP、TFTP、Telnet、SNMP、HTTP、路由协议、组播协议中引用的ACL。 硬件ACL:针对所有报文,通过下发ACL资源到硬件来过滤报文的ACL,比如流策略、基于ACL的简化流策略、自反ACL、用户组以及为接口收到的报文添加外层Tag功能中引用的ACL。 两者主要区别在于: 过滤的报文类型不同: 软件ACL用来过滤与本机交互的报文。 硬件ACL可以用来过滤所有报文。 报文过滤方式不同: 软件ACL是被上层软件引用来实现报文的过滤,通过软件ACL过滤报文时,会消耗CPU资源。 硬件ACL是被下发到硬件来实现报文的过滤,通过硬件ACL过滤报文时,则会占用硬件资源。 通过硬件ACL过滤报文的速度更快。 对不匹配ACL的报文的处理动作不同: 当使用软件ACL时,如果报文未匹配上ACL中的规则,设备对该报文采取的动作为deny,即拒绝报文通过; 当使用硬件ACL时,如果报文未匹配上ACL中的规则,设备对该报文采取的动作为permit,即允许报文通过。 ACL匹配项 交换机支持的ACL匹配项种类非常丰富,各种ACL规则支持的匹配项如表1所示: 表1 交换机支持的ACL 分类 规则定义描述 编号范围 基本ACL/基本ACL6 仅使用报文的源IP地址、分片信息和生效时间段信息来定义规则。 2000~2999 高级ACL/高级ACL6 既可使用IP报文的源IP地址,也可使用目的IP地址、IP协议类型、ICMP类型、TCP源/目的端口、UDP源/目的端口号、生效时间段等来定义规则。 3000~3999 二层ACL 使用报文的以太网帧头信息来定义规则,如根据源MAC(Media Access Control)地址、目的MAC地址、二层协议类型等。 4000~4999 用户自定义ACL 使用报文头、偏移位置、字符串掩码和用户自定义字符串来定义规则,即以报文头为基准,指定从报文的第几个字节开始与字符串掩码进行“与”操作,并将提取出的字符串与用户自定义的字符串进行比较,从而过滤出相匹配的报文。 5000~5999 用户ACL/用户ACL6 既可使用IP报文的源IP地址或源UCL(User Control List)组,也可使用目的IP地址或目的UCL组、IP协议类型、ICMP类型、TCP源端口/目的端口、UDP源端口/目的端口号等来定义规则。 6000~9999 匹配顺序 设备支持两种ACL匹配顺序:配置顺序(config模式)和自动排序(auto模式)。缺省的ACL匹配顺序是config模式。 配置顺序 配置顺序,即系统按照ACL规则编号从小到大的顺序进行报文匹配,规则编号越小越容易被匹配。 如果配置规则时指定了规则编号,则规则编号越小,规则插入位置越靠前,该规则越先被匹配。 如果配置规则时未指定规则编号,则由系统自动为其分配一个编号。 该编号是一个大于当前ACL内最大规则编号且是步长整数倍的最小整数,因此该规则会被最后匹配。 自动排序 自动排序,是指系统使用“深度优先”的原则,将规则按照精确度从高到低进行排序,并按照精确度从高到低的顺序进行报文匹配。规则中定义的匹配项限制越严格,规则的精确度就越高,即优先级越高,系统越先匹配。各类ACL的“深度优先”顺序匹配原则如表2所示。 表2 深度优先”匹配原则 ACL类型

细说ASCII、GB2312/GBK/GB18030、Unicode、UTF-8/UTF-16/UTF-32编码

参考: 《编码标准-GB2312 GBK GB18030》 《字符编码笔记:ASCII,Unicode 和 UTF-8》 《字体编辑用中日韩汉字Unicode编码表》 《程序员趣味读物:谈谈Unicode编码》 1. 最简单的ASCII码。 ASCII码使用1个字节记录了128个常用的字符(ASCII规定第一个bit位固定为0,2^7=128),包含控制字符(如:键盘的空格、Tab键),以及打印字符(如:数字、英文字母等)。 看下面的表格: 2. 汉字编码,从GB2312说起 1980年,为了使每个汉字有一个全国统一的代码,我国颁布了汉字编码的国家标准:GB2312-80《信息交换用汉字编码字符集》基本集,这个字符集是我国中文信息处理技术的发展基础,也是国内所有汉字系统的统一标准。 在这个标准中,我们规定使用两个字节表示一个字符,又为了兼容ASCII码,规定每个字节的首bit位固定为1。这样最终编码后的范围是:0xA1A1 - 0xFEFE(共94*94=8836个码位),其中收录了汉字6763个(其中一级汉字3755,二级汉字3008个),覆盖率达到了99.75% 。 其实,在GB2312中还有区位表的概念: 将所有的字符都分为94区,每区又有94位, 01-09 区为特殊符号10-15 区为用户自定义符号区(未编码)16-55 区为一级汉字,按拼音排序56-87 区为二级汉字,按部首/笔画排序88-94 区为用户自定义汉字区(未编码) . 示例如下: 可以通过这里查看完整的区位码列表:《区位码全表》 实际计算机存储的时候肯定不是按照区位码存的(还要避开ASCII的字符嘛),所以GB2312的存储规则如下: 注意:上面的“a”不是ASCII中的a,而是GB2312中的“a”。 另外,我们知道ASCII码的"a"其实就是0x61(即:97,01000001)。 基于以上三个字符的分析,我们新建一个文本文件并输入:“aa啊”,并另存为“ANSI”编码(其实就是GBK编码,GBK兼容GB2312,这里就把GBK当做GB2312),如下: 保存后,我们换个软件打开,观察下16进制,这里我使用editplus,如下: 这里实验的结果和我们分析的结果正好一致。 0x61:表示ASCII中的a 0xA3E1:表示GB2312中的a 0xB0A1:表示汉字“a” . 注意: 现在已经不用区位码表示了,也不用再考虑区位码到二进制存储的转换了。后面的GBK编码就是直接在GB2312的二进制存储上做的扩展。 3. 全角和半角? 对于英文字母和部分标点符号有全角和半角的区别,这是因为这些字母和符号在ASCII中已经定义了一遍,但GB2312中又把这些字母和符号重新定义了一遍(应该是因为中文排版显示不同吧),所以为了区分字母和标点符号究竟是指ASCII中的还是GB2312中的,出现了全角和半角的说法。 半角:指ASCII中的字符;全角:指GB2312中的字符; 而对于汉字来说,是没有全角和半角的区别的,因为ASCII中本就没有汉字。 4. GBK编码 GBK全称《汉字内码扩展规范》(GBK即“国标”、“扩展”汉语拼音的第一个字母,英文名称:Chinese Internal Code Specification) ,中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订。 指定它的原因? 虽然GB2312中已覆盖了99.75% 的汉字,但仍然有不少生僻字不在规范里面,作为计算机标准不能漏掉这些。 编码特点: GBK编码,是在GB2312-80标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312-80标准,支持国际标准ISO/IEC10646-1和国家标准GB13000-1中的全部中日韩(CJK)汉字,并包含了BIG5编码中的所有汉字;GBK编码方案于1995年10月制定, 1995年12月正式发布,中文版的WIN95、WIN98、WINDOWS NT以及WINDOWS 2000、WINDOWS XP、WIN 7等都支持GBK编码方案; GBK对应的区位码? 从上面GBK的描述中,没有发现区位码的信息,没错,GBK是《汉字内码扩展规范》,也就是说GBK不再使用区位码,而是直接对GB2312的转储二进制进行的扩展。 GBK是如何扩展的GB2312,为什么GB2312最多存储8836个码位,而GBK可以存储23940个? GBK在扩展GB2312的时候,移除了第二个字节首bit位必须为1的限制,且又做了其他扩展,所以GBK的编码范围是:0x8140 - 0xFEFE,最多能表示的码位:

SpringBoot Test及注解详解(含Mockito)

一、版本差异 Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库,在 Spring Boot 2.2.0 版本之前,spring-boot-starter-test 包含了 JUnit 4 的依赖,Spring Boot 2.2.0 版本之后替换成了 Junit Jupiter。 pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> 导入的依赖如下: 可以看到,SpringBootTest默认集成了以下功能: JUnit 5: Java单元测试框架Spring Test & Spring Boot Test: Spring Boot的测试工具和支持AssertJ: 流式断言Hamcrest: Hamcrest断言Mockito: Java Mock框架JSONassert: JSON断言JsonPath: XPath for JSON 二、SpringBootTest和Junit5的使用 整体上,Spring Boot Test支持的测试种类,大致可以分为如下三类: 单元测试:一般面向方法,编写一般业务代码时,测试成本较大。涉及到的注解有@Test。切片测试:一般面向难于测试的边界功能,介于单元测试和功能测试之间。涉及到的注解有 @WebMvcTest等。主要就是对于Controller的测试,分离了Service层,这里就涉及到Moc控制层所依赖的组件了功能测试:一般面向某个完整的业务功能,同时也可以使用切面测试中的mock能力,推荐使用。涉及到的注解有@SpringBootTest等。 单元测试 集成测试,不启动server,以创建项目后自动生成的默认测试类为例: @SpringBootTest class TestDemoApplicationTests { @Test void contextLoads() { } } 默认无参数的@SpringBootTest 注解会加载一个Web Application Context并提供Mock Web Environment,但是不会启动内置的server。这点从日志中没有打印Tomcat started on port(s)可以佐证。

C语言 -- 链表(企业级,侵入式链表)

目录 节点结构体的实现 初始化链表 插入链表 遍历链表 删除节点、销毁链表 用户test 侵入式链表,内核链表 普通单链表和侵入式单链表的区别在于: 普通的单链表的结点指针域指向的是下一个结点的内存首地址;侵入式单链表的结点指针域指向的是下一个结点的指针域成员变量的内存首地址。 节点结构体的实现 节点结构体只维护指针域,用户需预留4个字节空间,供我们帮助连接数据。 //节点结构体 struct LinkNode { //只维护指针域 struct LinkNode* next; }; //链表结构体 struct LList { struct LinkNode pHeader; //头结点 int m_size; //链表长度 }; //暴露给用户的 typedef void* LinkList; 初始化链表 //初始化链表 LinkList init_LinkList() { struct LList* mylist = malloc(sizeof(struct LList)); if (mylist == NULL) return NULL; mylist->m_size = 0; mylist->pHeader.next = NULL; return mylist; } 插入链表 //插入链表 void insert_LinkList(LinkList list, int pos, void* data) { if (list == NULL) return; if (data == NULL) return; struct LList* mylist = list; if (pos<0 || pos>mylist->m_size - 1) pos = mylist->m_size; //取出用户数据的前四个字节空间 struct LinkNode* myNode = data; //把void*类型的data转为一个指针,即4个字节大小 //找到待插入位置的前驱节点 struct LinkNode* pCurrent = &mylist->pHeader; for (int i = 0; i < pos; i++) { pCurrent = pCurrent->next; } //更新指针指向 myNode->next = pCurrent->next; pCurrent->next = myNode; mylist->m_size++; } 遍历链表 //遍历链表 void foreach_LinkList(LinkList list, void(*myPrint)(void*)) { if (NULL == list) return; struct LList* mylist = list; struct LinkNode* pCurrent = mylist->pHeader.

Mybatis-Plus之连表查询的基本实现

一、序言 Mybatis-Plus在设计之初是为了扩展而不是替代Mybatis,所以对于连表查询官方并没有给出解决方法,还是依托Mybatis通过XML配置文件中写SQL语句的方式。但是在多数据源适配上,还是想要消除掉XML以屏蔽不同数据库类型的查询(新增加一个数据库,不需要新增加一个XML配置)。 最后采用第三方开源工具Mybatis-Plus-Join实现连表查询,开源地址:https://github.com/yulichang/mybatis-plus-join,支持一对一、一对多的操作。 二、具体实现 引入依赖 <dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join</artifactId> <version>1.2.4</version> <exclusions> <exclusion> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclusion> </exclusions> </dependency> 之前已经分享过关于Mybatis-Plus代码分层和改造,所以修改XwMapper继承MPJBaseMapper,整体对于原由的结构没有影响。Mybatis-Plus-Join提供MPJLambdaWrapper和MPJQueryWrapper实现连表查询。MPJLambdaWrapper支持Lambda表达式查询。 使用示例: List<UserDTO> list = baseMapper.selectJoinList(UserDTO.class, new MPJLambdaWrapper<UserDO>() .selectAll(UserDO.class) .select(UserAddressDO::getTel) .selectAs(UserAddressDO::getAddress, UserDTO::getUserAddress) .select(AreaDO::getProvince, AreaDO::getCity) .leftJoin(UserAddressDO.class, UserAddressDO::getUserId, UserDO::getId) .leftJoin(AreaDO.class, AreaDO::getId, UserAddressDO::getAreaId) .eq(UserDO::getId, 1) .like(UserAddressDO::getTel, "1") .gt(UserDO::getId, 5)); 对应的SQL语句: SELECT t.id, t.name, t.sex, t.head_img, t1.tel, t1.address AS userAddress, t2.province, t2.city FROM user t LEFT JOIN user_address t1 ON t1.user_id = t.id LEFT JOIN area t2 ON t2.

c++/map函数

map函数<key,value>,其中key (键值),起到索引作用,第二个元素为value (实值);map函数可以根据key值快速找到value值,但不允许容器中有重复key值元素。 测试程序如下: #include<map> #include<string> #include<iostream> int main() { std::map<int,int> MAP; MAP[1] = 4; MAP[2] = 5; MAP[3] = 6; std::map<int,int>::iterator iter; iter = MAP.find(2);//寻找MAP[2]的对应值 if(iter != MAP.end()) { std::cout << "find,value is" << iter->second << std::endl; } else { std::cout<<"none" <<std::endl; } }

C语言 -- 动态数组&链表

目录 动态数组 动态数组的实现: 用户test 链表 目的: 链表的结构体: 链表的实现: 初始化链表 插入节点 遍历链表 删除节点 清空链表、销毁链表 用户回调函数 给用户提供接口获取链表长度 用户test 动态数组 将数组开辟到堆区,实现动态扩展。 问题: ① 用户的数据类型无法确定; ② 用户的数据无法确定创建在堆区还是栈区; ③ 不管数据在堆区还是栈上,都是在内存中,就会有地址,只需维护数据的地址就行。eg:如果数据类型是 int,则使用 int* 来指向该数据地址。 所以,这里使用万能指针 void* 来指向用户的数据地址。 第二点,我们是在堆区创建的一个数组,每一个元素都是 void* 类型的。如果要操纵这个数组,则可以使用二级指针 void** 来指向该数组的地址。 动态数组的实现: typedef struct DynamicArray { void** pAddr; //维护真实在堆区开辟的数组的二级指针 int m_Capacity; //数组容量 int m_Size; //数组大小 }dynamicArray; //初始化数组,参数:初始数组的容量。返回值:数组指针 dynamicArray* init_dynamicArray(int capacity) { if (capacity <= 0) { return NULL; } //给数组分配内存 dynamicArray* arr = malloc(sizeof(dynamicArray)); if (arr == NULL) return NULL; //数组属性初始化 arr->pAddr = malloc(sizeof(void*) * capacity); //我们维护的数据类型是void*, //这里是capacity个void*类型的数据大小,又malloc返回的是void**类型,pAddr同样是void**类型 arr->m_Capacity = capacity; arr->m_Size = 0; } //数组元素插入 void insert_dynamicArray(dynamicArray* arr, void* data, int pos) { if (arr == NULL) return; if (data == NULL) return; if (pos<0 || pos>arr->m_Size) pos = arr->m_Size; //判断数组是否满了 if (arr->m_Size == arr->m_Capacity) { //计算新的空间大小 int newCapacity = arr->m_Capacity * 2; //开辟新空间 void** newSpace = malloc(sizeof(void*) * newCapacity); //将原空间下数据拷贝到新空间下 memcpy(newSpace, arr->pAddr, sizeof(void*) * arr->m_Capacity); //释放原空间 free(arr->pAddr); //更改指向 arr->pAddr = newSpace; //更新容量 arr->m_Capacity = newCapacity; } //将新元素插入到指定位置 for (int i = arr->m_Size - 1; i >= pos; i--) //从最后边的数据开始移 { arr->pAddr[i + 1] = arr->pAddr[i]; } arr->pAddr[pos] = data; //更新数组大小 arr->m_Size++; } //遍历 void foreach_dynamicArray(dynamicArray* arr,void(*myPrint)(void*)) { if (arr == NULL) return; for (int i = 0; i < arr->m_Size; i++) { myPrint(arr->pAddr[i]); } } //删除数组中元素 //按照位置删除 void removeByPos_dynamicArray(dynamicArray* arr, int pos) { if (arr == NULL) return; if (pos<0 || pos>arr->m_Size - 1) return; for (int i = pos; i < arr->m_Size; i++) { arr->pAddr[i] = arr->pAddr[i + 1]; } arr->m_Size--; } //按照数值删除 void removeByVal_dynamicArray(dynamicArray* arr, void* data, int(*myCompare)(void*,void*)) { if (arr == NULL) return; if (data == NULL) return; for (int i = 0; i < arr->m_Size; i++) { if (myCompare(arr->pAddr[i], data))//利用回调函数让用户告诉我们如何对比数据 { removeByPos_dynamicArray(arr,i); break; } } } void destory_dynamicArray(dynamicArray* arr) { if (arr == NULL) return; //内部维护在堆区数组指针先释放 if (arr->pAddr !

Win11右键显示更多选项的关闭方法

自从更新win11系统之后,很多用户觉得用起来很不习惯,比如发现了右键菜单的样式变了,觉得操作起来感觉不一样,就想知道怎么去关闭这个功能,下面小编就来给大家讲一讲win11桌面右键菜单设置的教程。 Win11右键显示更多选项的关闭方法 方法一、电脑win11右键显示更多选项怎么关 1、打开win11搜索窗口,搜索“注册表”,点击【打开】。 2、进入注册表编辑器,定位到 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FeatureManagement\Overrides\4 。 3、点击鼠标右键,创建新的项,命名为“ 586118283”。 4、在创建的新项右侧窗格创建 5 个 DWORD值,分别为:EnabledState、EnabledStateOptions、Variant、VariantPayload、VariantPayloadKind。 5、5个DWORD值对应的数据如下图所示,修改完成后重启电脑即可。 6、结果展示。

玩转NVIDIA Jetson (25)--- jetson 安装pytorch和torchvision

在jetson上安装pytorch能够快速的帮助PC用户在熟悉的环境下进行开发,但是这个过程里边有一些坑,我建议大家参照官方给出的安装指导来进行安装,包括pytorch和包含各种网络的torchvision。官方安装如下,这个topic里会持续更新各个版本的pytorch。 PyTorch for Jetson - version 1.11 now available - Jetson & Embedded Systems / Jetson Nano - NVIDIA Developer Forums 1.安装miniforge虚拟环境 我还是建议大家用虚拟环境,不然jetson上的python环境非常容易被搞乱,具体安装方法见之前的文章。 2.安装pytorch 这里需要特别注意的一个问题就是你需要选择与你机器上jetpack相匹配的版本,千万别下错了,比如我这里用的是jetpack4.6,那我安装的pytorch就是V1.10.0版本。 下载完pytorch的whl文件后,首先apt-get install一些环境必须的前置程序,然后进入到你创建的conda环境下,使用pip命令安装Cython和pytorch。 sudo apt-get install libopenblas-base libopenmpi-dev libomp-dev pip install Cython pip install numpy xxx.whl 验证是否安装成功 import torch print(torch.__version__) print('CUDA available: ' + str(torch.cuda.is_available())) print('cuDNN version: ' + str(torch.backends.cudnn.version())) a = torch.cuda.FloatTensor(2).zero_() print('Tensor a = ' + str(a)) b = torch.randn(2).cuda() print('Tensor b = ' + str(b)) c = a + b print('Tensor c = ' + str(c)) 若上述程序执行无误,证明pytorch安装成功,并且可以调用jetson的GPU来进行运算。

Vue项目中的多语言实现—vue-i18n插件的使用

Vue项目中的多语言实现—vue-i18n插件的使用 实现的条件(原理) 1、语言标识符 2、中英文对照字典表 3、翻译官 – 根据文字标识符找到对应的语言文字并反返回 示例步骤: 1、声明相关变量 语言标识符 lang:'en'/ zh 中英文对照表 messages:{ zh:{ morning:'早上好' }, en:{ morning:'Good morning' } } 2、封装函数,充当翻译官 t t(str){ const curLang = this.messages[this.lang] return curLang[str] || str } 3、使用函数,传入文字的标识符 t('morning') vue-i18n插件实现 npm下载 npm i vue-i18n@8(最新版本不支持Vue2) 基本使用 需要单独一个多语言的实例化文件 src/lang/index.js 引入注册并导出实例化插件对象 import Vue form 'vue' import VueI18n from 'vue-i18n' // 注册 Vue.use(VueI18n) // 实例化插件 export default new VueI18n() // 里面传入对象 在 main.js中引入自己封装的,并注入到 Vue实例中 import i18n from '.

python 函数参数 必选参数 默认参数 可变参数 关键字参数

python函数参数如下 1:必选参数 2:默认参数 3:可变参数 *args 4:关键字参数 **kwargs 默认参数必须在必选参数后面 为什么?? 例子如下 def xx(a,b=3,c): print(a,b,c) xx(1,2) # 出错这里你想的是把a赋值为1 c赋值为2 实际上是a=1,b重新赋值为2 SyntaxError: non-default argument follows default argument def xx(b=3,a): print(a,b) xx(2)#这里你想的是给a赋值为2,但是b在前面所以b重新赋值为2 SyntaxError: non-default argument follows default argument 为了解决这个迷惑问题python规定默认参数必须在必选参数后面 可变参数*args 有两个功能打包和分包功能 举例打包: def xx(a,*b,c=3): print(a) print(b) print(type(b)) print(c) xx(4,5,6,7) #将5,6,7打包成元组传给参数b,b为元组 结果为: 4 (5, 6, 7) <class 'tuple'> 3 举例分包 x=[5,6,7,8] def xx(a,b,c,d,e): print(a,b,c,d,e) xx(4,*x) #这里*x 把x中每个元素分给b,c,d, e 结果为4,5,6,7,8 关键字参数 key值必须为字符串 关键字参数打包 def xx(a,b=3,**c):

Spring Data JPA 入门

1. 什么是Spring Data JPA JPA 全称 Java Persistence Api, 中文是java 持久化API。 它是当今世界上最流行的ORM (Object-Relational Mapping)框架。 当年我们都感觉传统的ORM框架hibernate 相当的难用和臃肿,特别多联表查询, 然后选择更轻量级和更直观的的Mybatise. 但其实Mybaise 并不是1个ORM框架, 它是拥抱sql的。 对熟悉sql的开发人员更加友好。 当微服务大行其道时, 业务细分下, 通常我们不会在服务中对数据库进行复制的sql查询。 这时mybasise 的优势就不大了, 很多开发人员返回了JPA 的怀抱, 代码更加面向对象是一 回事, 而且JPA也支持用SQL查询。 JPA并不是1个ORM的具体实现, JPA只是定义了1个ORM的规范, 里面只提供了接口, 所以JPA必须配合Hiberate 或者其他ORM框架来使用, 但是hibernate是最常见的。 2. JPA 相对于 Mybatise 的其他优势. Mybatise 毕竟是拥抱sql的, 决定了Mybasie 只适用于操作关系型数据库, 例如mysql , oracle, pgsql等… 而JPA可以用相同的接口规范, 用于NOSQL 数据库, 例如Redis,mongo, ES, NEO4j等… 所以JPA是更加有前景的。 在高并发环境下, 一个项目很可能不会只使用单1关系数据库, 很可能我们会用Kafka, redis 等缓存技术, 用ES进行模糊查询, 这时能统一接口规范的JPA就大有发挥空间了。 还有哦, JpaRepostory 接口默认已经帮你写好了很多方法, 例如findById findAll等, 不像mybatise要写很多这种查询接口的…

ElementUi的侧边栏操作

相信新手玩家在接触ElementUi的时候总是很难读懂ElementUi的一些基本知识 本文章主要讲述的是侧边栏如何能够伸展覆盖整个左侧 .Menu { .el-aside { height: 100%; .el-menu { height: 100%; } .el-submenu .el-menu-item { min-width: 0; } } } 加上这些样式就可以使得左边侧边栏完全展开(Menu是最外层div盒子的命名)

python01- 安装部署

一、下载python解释器 官网:https://www.python.org/downloads/ 选择一个版本部署,本次选择当前最新的,选择downloads下载 在 downloads 页面的最下方,选择你要部署什么系统中,点击下载即可 二、部署python解释器 2.1、运行python解释器EXE部署 选择自定义安装,不用推荐的 选择姜 python 添加到PATH环境中 python 可能会用到的工具 , 点击 NEXT 默认选择 2 3 4 条,将 1 5 选择,如果不选择1 5 ,只有 python 用户能使用 python 解释器修改安装路径要求:路径长度尽量不要太长、不能带中文的路径 点击 INSTALL 如下代表完成 2.2、查看 python 中的目录 python 解释器 (python.exe),将 .py 翻译成计算机能识别的语言 Python310\Scripts 目录为包管理工具,默认带有 pip.exe pip3.10.exe pip3.exe 。有什么用呢?python 为什么可以简化程序员编写代码的过程,最主要是依赖于官方或第三方写好了能实现你的需求机制的包。可以理解成 java 调用了类,类中有实现的方法。默认 python 如果要处理 word、爬虫等是不支持的,需要导入其他的包。而这里的 pip.exe pip3.10.exe pip3.exe 就是能够下载包的工具,通过(pip install 包名)后就可以用。 Python310\Lib python 解释器的功能。在通过(pip install 包名)后,下载包存入哪里呢?存入Python310\Script 目录中,通过代码区导入这个.py文件,就可以使用 三、验证 python 解释器 验证python是不是没问题,编写代码文件-解释器去运行

机器学习:聚类-闵科夫斯基距离和无序属性的VDM距离计算

我的小程序: 待办计划:给自己立个小目标吧! 距离计算是很多学习算法会涉及的内容,当然包括聚类算法,这里简单介绍下有序属性的闵科夫斯基距离和无序属性的VDM距离。 关于有序属性,大概可以这样理解:假设身高的属性有{矮,中,高},为了计算方便,我们把它们转成数字{1,2,3},1和2较接近(矮和中相差较小),1和3较远(矮和高相差较大),发现这样的转化基本可以反应原先属性间的关系。类似这样的属性(这里是身高)可以认为是有序属性,可以直接转化成数字。 关于无序属性,比如颜色这个属性,假设有{红,黄,蓝},我们不能简单的转化为{1,2,3},因为原先的属性间没有明显的大小远近等“序”的关系,如果转化为{1,2,3},当计算距离时,会无形中引入这种序的关系(红和黄更接近,红和蓝更远)。所以类似这样的属性(这里是颜色)就称为无序属性。当然,无序属性通常可以转化为向量处理,比如转化为{[1,0,0],[0,1,0],[0,0,1]}这3个属性。 有序属性的闵科夫斯基距离计算(样本x是n维向量): 当p=2时,闵科夫斯基距离转化为欧式距离: 当p=1时,闵科夫斯基距离转化为曼哈顿距离: 无序属性的距离计算可以采用VDM: 将闵科夫斯基距离和VDM结合就可以处理混合属性了: 当不同属性的重要性不同时,可以使用加权距离: 待办计划:给自己立个小目标吧! 参考资料:周志华《机器学习》

机器学习:降维算法-核主成分分析KPCA算法原理推导

我的小程序: 待办计划:给自己立个小目标吧! 说真的,刚开始接触机器学习,一看到带“核”字的算法就头疼(-…-),没高人指引,总觉得理解起来费劲,也不确定理解的对不对。可能是因为这个“核”有点抽象,没有具体形式(形式不确定),操作很风骚。当然到现在也不敢说自己有多理解,只能扯扯目前所理解到的核主成分分析KPCA。 PCA是简单的线性降维的方法,KPCA则是其非线性的扩展,可以挖掘到数据集中的非线性信息。 KPCA的主要过程是: 首先将原始数据非线性映射到高维空间;再把第1步中的数据从高维空间投影降维到需要的维数d' 可以看出,KPCA只是比PCA多了一步映射到高维空间的操作,降维的操作是一样的。所以,KPCA最终投影到的超平面也应满足PCA中的最近重构性或最大可分性。于是KPCA最终的投影向量也应满足PCA中的等式(参见:机器学习:降维算法-主成分分析PCA算法两种角度的推导): . 即: . 其中是样本点映射到的高维空间中的像。进一步得: . 其中是的第j个分量。 假设是由原始空间的样本通过映射产生,即.若映射已知,那么容易求到和投影向量,问题就解决了。但通常情况下,是不知道的具体形式的(后面会发现,我们不用知道的具体形式一样能求解!)。不管怎样,先表达出这种映射关系: 将写成: ................................................................(1) 将写成: ..................................................................................(2) 将(2)式代入(1)式得: ................................(3) 记: , . 将和代入(3)式得: ................................................................................(4) 关键的地方到了,接下来引入核函数: . 核函数本质上也就是个函数,跟y=kx没啥区别,特殊之处在于,它的计算结果表达了变量在高维空间的内积值。就是说,本来是在高维空间(甚至无限维空间)计算的内积,可以在原始较低维的空间通过核函数计算得到。 有常见的几种核函数,到底选用哪种核函数,可能需要去尝试,看哪种核函数产生的效果好(比如在KPCA中,就是看哪种核函数带来的降维效果更好)。 之所以引入核函数,可以认为有两方面原因: 映射关系未知;映射到的高维空间维数可能非常高(甚至无限维),在高维空间计算开销太大,十分困难。 核函数对应的核矩阵为: . (4)式两边左乘得: , 把核矩阵K代入上式,可得: : 两边去掉K,得: . (这里还是没搞清楚,为什么能直接去掉K,理论上K是可逆矩阵时才能直接消去。但核函数确定的核矩阵只要求是半正定的,半正定矩阵又不一定是可逆的。这里去掉K的依据是什么?望博友指点。) 可以看到,通过核函数的这一波操作,原始空间到高维空间的映射变得无形了,最终得到的式子并没有看到映射的影子,这就是“核”操作的风骚之处。我们不知道映射的具体形式,我们也不用知道它的形式。 显然,上式是特征分解问题,取K的最大的d'个特征值对应的特征向量即可。 对于新样本x,其投影后第维坐标为: . 可以看到,KPCA需要对所有样本求和,计算开销还是挺大的。 待办计划:给自己立个小目标吧! 参考资料:周志华《机器学习》 参考博文: 核主成分分析(Kernel Principal Component Analysis, KPCA)的公式推导过程 机器学习:核函数和核矩阵简介 相关博文:机器学习:降维算法-主成分分析PCA算法两种角度的推导

最详细移动硬盘安装linux过程,装在移动硬盘上的linux系统不能在另一台电脑启动的解决办法

我的小程序: 待办计划:给自己立个小目标吧! 背景是这样的:家里有一台台式电脑,学校实验室有一台笔记本,都是windows系统。为了方便做实验,需要安装linux系统。但不想在电脑上装双系统,第一是因为电脑都比较老了,笔记本都用了7、8年了,怕装双系统直接拖垮电脑;第二是因为麻烦,两台电脑要装两次系统,搭两次开发环境。于是就想做一个移动硬盘的linux系统(我安装的是linuxmint19.1),搭一次开发环境,能在学校和家里统一使用,而且可以协同工作,不用刻意复制工作文件。哇塞,爽歪歪啊~ 但,理想很丰满,现实很残酷!前前后后单是装系统就倒腾了有3、4天,足以在两台电脑装两次系统,搭两次开发环境了~还不错,最终还是装好了。人生就是这样,只有经过痛苦的磨练才能成长。就像《求是》杂志上的一篇文章说的,要多当几次热锅上的蚂蚁才有可能成为优秀的共产党干部! 最终的解决方案是这样的: 一个16G的U盘(当然,4G已经足够),用win32diskimager把下载下来的linuxmint19.1.iso写入U盘。 一块1T的移动硬盘,用DiskGenius分区,如下图(这里要特别强调,不要在linuxmint安装时分区和格式化,而是提前分区和格式化,否则无法安装成功): 主分区(0)用于a电脑挂载/boot目录,主分区(1)用于b电脑挂载/boot目录,逻辑分区(4)用于公共的根目录/,逻辑分区(5)用于公共的交换空间,另外留出500多G的空间当作普通的移动硬盘使用,藏藏小电影什么的~ 下面记录一些安装的主要步骤: 先在a电脑上安装linuxmint,把U盘和移动硬盘插在a电脑上,选择u盘启动;点击桌面的“install linuxmint”,...,勾选安装图形界面;然后就到了让你选安装方式,有“与现有系统共存”,“其他选项”什么的,这里选的是最后一个“其他选项”;它会弹窗提醒你说是否要卸载已有分区,选择否,不卸载;选好后就到了挂载分区的地方,会列出分区表(包括电脑本身的硬盘分区表(sda),这个不用管),我们要挂载的是移动硬盘,也就是sdb。这里把主分区(0)(sdb1)挂载到/boot目录,需要注意的是,挂载时有个勾选框让你选是否格式化,不要勾选他,也就是不要格式化(否则会报错,说什么不对齐之类的);再把逻辑分区(4)挂载到根目录/,同样不要格式化;再就是逻辑分区(5)分配到交换空间。到这里分区挂载就好了。下面选引导程序的安装分区,选的是挂载到/boot目录的sdb1。下面就是一路next就好了。同样的操作再在b电脑上安装linuxmint,不需要再分区,直接u盘启动安装,区别在于,这里把主分区(1)(sdb2)挂载到/boot目录,引导程序的安装在sdb2。 一些Tips: 一开始以为,在移动硬盘上安装一次系统能在所有电脑上使用。但现在看来是不可能的,总有一些配置的电脑启动不了。也许碰巧,你要使用的电脑关键配置差不多,不用装两个引导程序就可以启动。但要启动两台电脑更有保障的是上面的做法:在移动硬盘上装一个系统,但要装两个引导程序;如果为了以后扩展,应该可以预留一些空闲的空间(扩展分区),要用的时候再安装其他电脑的引导程序(这里没试过);不要联网安装linuxmint,否则会很慢,要安装语言包什么的;整个安装过程不超过30分钟,若一直卡在类似“复制已安装软件包”等等的提示中,说明分区或挂载时有问题,果断退出重新分区和挂载(不要重蹈我的失败经验:等它安装一夜都没装好);使用过Ultraiso刻录U盘,但启动时报错,貌似报的是Failed to load ldlinux.c32,后来就就改用win32diskimager制作启动盘;关于分区方案,我用的是最基本的分区:/boot,/,和swap。之前也尝试过更细的分区,比如:/boot,/,/var,/usr,/home和swap,但一直安装失败,也不知道什么原因,这里也希望大神指点~;关于运行“install linuxmint”安装程序时,安装界面过大的问题,也不用调分辨率,最简单的方法是alt+鼠标左键拖动窗口; 用win32diskimager写入U盘后,U盘的恢复教程参见:Win32DiskImager写入U盘容量变小 提示格式化。 待办计划:给自己立个小目标吧!

机器学习:核函数和核矩阵简介

我的小程序: 待办计划:给自己立个小目标吧! 核函数也就是一种函数,本质上跟其他常见的函数(如幂函数)是一样的。我们知道,幂函数有它的特点,形如的函数才能称为幂函数。同样,核函数也有他的特点,只不过它的特点更复杂一点,满足以下要求的函数才能称为核函数(定理): 令为输入空间,是定义在上的对称函数,则是核函数当且仅当对于任意数据,核矩阵K总是半正定的: . 上面的定理表明,只要一个对称函数对应的核矩阵半正定,它就能作为核函数。 常用的核函数有: 核函数的作用,就一句话:计算样本在高维空间的内积。 假如出于某些原因,我们要将样本从原始空间映射到高维空间(如在低维空间样本线性不可分,需要映射到高维空间产生线性可分的样本)。假设映射为,表示x映射后的特征向量。假设在高维空间中,正好涉及到计算内积:。这时,就可以引入核函数(涉及选择什么核函数): . 上式将在高维空间的内积转化到在原始空间计算。那为什么不直接在映射后的高维空间计算?原因有两点: 通常我们不知道映射的具体形式;映射后的空间维数可能非常高,甚至无限维,直接计算开销太大,十分困难. 这就是核函数的作用。 上面提到有5种常用的核函数,选择了不同的核函数,意味选择了不同的某种映射。因为我们不知道映射的具体形式,所以我们并不知道什么样的核函数合适。核函数的选择成为算法的“变数”。 核函数的选择有一些基本经验:例如对文本数据通常采用线性核,情况不明时可先尝试高斯核。线性核和高斯核也是最为常用的核函数。 待办计划:给自己立个小目标吧! 参考资料:周志华《机器学习》

蓝牙协议 与 BLE

蓝牙协议中文网站 https://www.bluetooth.com/zh-cn/ 安卓4.3--API LEVEL18--蓝牙4.0--BLE MTU=23字节 实际可用20 https://source.android.google.cn/docs/compatibility/4.3/android-4.3-cdd#7.4.3.-bluetooth 安卓7--API LEVEL24--蓝牙4.2--BLE MTU=247字节 实际可用244 https://source.android.google.cn/docs/compatibility/7.0/android-7.0-cdd#7_4_3_bluetooth 安卓8--API LEVEL26--蓝牙5.0--BLE MTU=512字节 实际可用509 https://source.android.google.cn/docs/compatibility/8.0/android-8.0-cdd#7_4_3_bluetooth 备注:以下资料一直没太找到看到准确数字,暂且路基,容后找到更新或者自己测试后更新 蓝牙4.2的最大MTU=247Byte(不一定正确,也有说是257Byte、也有说是241Byte),蓝牙5.0的最大MTU=512,有效的最大MTU还需要减去协议Byte、Opcode和Handler。蓝牙4.2的有效的最大MTU是244Byte(不一定正确),有兴趣的可以看看Bluetooth SIG官网https://bluetoothworldevent.com/welcome。 蓝牙4.2:1Byte(Opcode)+2Byte(Handler)+244Byte(BATT)=247Byte(不一定正确);

矩阵可对角化的充要条件及证明

我的​​​​​​​小程序: 待办计划:给自己立个小目标吧! 对角化:若方阵A相似于对角矩阵,即存在可逆矩阵P和对角矩阵D,有,则称A可对角化。 可对角化的充要条件: n*n阶矩阵A可对角化的充分必要条件是矩阵A有n个线性无关的特征向量。 充分性证明: 设A的n个线性无关的特征向量为,对应的特征值为,特征向量构成矩阵P=[].则: 将对角矩阵记为D,则上式可化简为AP = PD。因为n个特征向量线性无关,所以P=[]可逆,所以,即A可对角化。 必要性证明: A可对角化,即,可得AP = PD. 设P的列元素为,即P=[],设对角矩阵D为. 则: ; ; 由AP = PD得:.因为P可逆,显然都不为0,所以是A的特征值,是A的特征向量且线性无关。得证。 待办计划:给自己立个小目标吧! 参考资料:David.C.Lay《线性代数及其应用》

[C++11]explicit关键字的作用

explicit关键字用来修饰构造函数,防止其被隐式转换。 先来看看隐式类型转换是怎么发生的 class Cirle { public: Cirle(double f) {radius = f;} private: double radius; }; Cirle c1 = 20; //隐式调用其构造函数,成功 我们定义了一个带有一个参数的Circle类, 当定义一个Circle对象, 使用值操作符=赋值时,隐式调用了构造函数, 使得程序能够编译通过。这或许可以带来便利, 而有时却会带来意想不到的后果. explicit关键字用来避免这样的情况发生.。 采用explicit关键字 通过将构造函数声明为explicit(显式)的方式可以防止隐式转换。即,explicit构造函数必须显式调用。 class Circle { public: explicit Circle(double f) {radius = f;} private: double radius; }; Cirle c1 = 20;//编译错误,不能隐式调用其构造函数 Circle c2 = Circle (20);//显示调用成功 编译将会报错

Mongoose+express进行简单API得搭建(如何创建WebStorm后台数据)

如何创建WebStorm后台数据 1.首先创建一个文件夹,在idea目录下cmd,然后创建我们需要得写代码得文件夹 例(mkdir Person-worlds)然后 (cd Person-worlds)进入项目文件夹 (这里得idea扔到webstorm就会出现了) 2.在该文件夹下进行初始化 npm init 3.安装express和mongoose (这里我使用得是这两个版本) npm i express@4.17.1 mongoose@5.9.4 4.在pakage.json包得script路劲下添加"start": "node server.js", 为了能够监听到node(用来监视当node数据发生变化得时候进行数据重载)安装 cnpm i nodemon 5.创建server.js进行尝试服务器得启动 const express = require('express') ​ const app = express() //建立一个端口号 const port = 5000 //用于监听是否连接成功 app.listen(port,()=>{ console.log(`server.run${port}`) }) 6.进行数据库得连接 const mongoose = require('mongoose') //固定写法 mongoose.connect('mongodb://localhost:27017/community',{useNewUrlParser:true,useUnifiedTopology:true}) //回调函数 .then(()=>{ console.log('mongodb connect') //错误捕获 }).catch((err)=>{ console.log('数据传输错误',err) }) 7.在主文件下创下路由文件夹Routes,然后在创建一层Api文件夹配置上users.js,在该文件下进行API得书写 const express = require('express') const router = express.Router() //接口得请求 router.post('/register',(req,res)=>{ console.log('123',req) }) //将其进行导出 module.

格兰杰因果 / EEG脑电数据分析

(因为处理数据的时候需要用到格兰杰因果关系检验,相关的文献里又没有详细解释,但看格兰杰因果又有一些一知半解,于是自己学了一些相关的东西,整理了一下。) 格兰杰因果关系检验为2003年诺贝尔经济学奖得主克莱夫·格兰杰(Clive W. J. Granger)所开创,用于分析经济变量之间的格兰杰因果关系。他给格兰杰因果关系的定义为“依赖于使用过去某些时点上所有信息的最佳最小二乘预测的方差。” 所以说,这个格兰杰因果其实是一个时间序列计量经济学模型,但它的应用不仅限于计量经济学,比如这里我就用它来分析脑电数据。 于是,说到时间序列,我觉得吧,要想前后真正理清楚思路然后把它和我要做的东西关联起来,我决定自学一把信号与系统的比较浅显的一些概念和数学原理还有EEG脑电信号的处理。 写这个博客是记录自己的思考和学习过程,但想到它也可能有幸被人参考于是,列个大纲,可以根据需要看看。 1.信号与系统的基础概念梳理 什么是信号 定义:消息有用的部分 转换成信号的目的:便于传输、梳理 三大热点:传输、交换、处理 信号处理:特征提取、噪声消除、优化 什么是系统 定义:处理输入,生成想要的输出 信号描述 信号可表示为1/多个变量的函数 即,信号=函数 描述方式 :时域分析、频域分析、波形(函数图像) 信号分类 确定&随机周期&非周期连续(模拟信号)与离散(数字信号/抽样信号)一维&多维能量受限&功率受限 典型连续时域信号 指数信号(常用)复指数信号(可表示各种常见信号) 复指数信号可分为实、虚两部分。其中,实部包含余弦信号,代表时域,体现信号大小,振幅、波峰等。虚部则为正弦信号代表频域,体现信号方向,频率变化。 抽样信号 描述:很小区间里有很大的值 Sa函数 用处:过滤、处理(小波变换) 脑电信号的分析方法 时域分析法——自回归AR模型 自回归模型是脑电分析中常用的一个传统模型,它会根据采集到的数据的更新不断更新参数,以更好地描述数据,然后在此基础上我们就可以用这个模型来进行谱估计和特征提取等等工作。 在时域空间,AR模型可以表述为一个线性预测问题。 我们假设时间序列是 ,当前采样值为,这个采样值可以用最邻近的前p个数据x(n-p),x(n-p+1),...,x(n-1)的线性加权和来近似。 的预测值即为 其中p表示的是模型的阶数,表示的是权重。我们把预测值和实际值的差值称为前向预测的误差, 对于整个序列,定义其预测误差功率为预测误差的平方和,于是有 (假设x(1)前的值均为0) 对于参数,一般用最小二乘法估计,目的就是使得我们在用这个p阶模型拟合给定数据的时候,预测误差功率E是最小的。 (这里我就不详细写了,大概思路就是令,然后我们能得到p个方程的方程组,代入预测误差功率的那个计算公式,得到最小预测误差功率) 让我比较头秃的是这个AR参数的自相关估计法,这里定义了一个无穷实数据序列的自相关函数 ,可以看到这个东西其实就是在最小预测误差功率的计算公式当中右边括号内的项,但是我确实没理解为什么是这样(早饭吃了鸡蛋,依旧没能捣鼓出来) 所以我当机立断决定先把参考资料截图,未来可能某天就突然明白了呢。 还有一个问题就是,前面提到了这个模型有一个阶数p,那这个p应该怎么确定呢?从减小计算复杂度的层面考虑应该尽量选用低阶的模型,这个常用的方法就有预测误差准则法和赤池信息准则法AIC。 最终预测误差准则法,它定义AR模型的阶数为使得预测误差功率最小的阶数。假设p阶模型所对应的预测误差功率为, 赤池信息准则也不难理解,它的理念就是最小化信息量,但是信息量是比较抽象的一个概念,在这里可以用似然函数对数的均值估计。于是得到定义,使得这个式子最小的p就是AR模型的参数。 格兰杰因果关系检验 格兰杰因果关系检验的统计学本质是对平稳时间序列数据的一种预测。在时间序列情形下,两个经济变量X、Y之间的格兰杰因果关系定义为:若在包含了变量X、Y的过去信息的条件下,对变量Y的预测效果要优于只单独由Y的过去信息对Y进行的预测效果,即变量X有助于解释变量Y的将来变化,则认为变量X是引致变量Y的格兰杰原因。 (其实把格兰杰因果关系检验应用在EEG信号的处理问题上我是有点困惑的,因为在我参考的一些资料当中很多也都提到了进行格兰杰因果关系检验的一个前提条件是时间序列必须具有平稳性,否则可能会出现虚假回归问题,而脑电数据它并不属于平稳的时间序列,maybe分段之后会稍微好一点点?然后我还看到有一个在格兰杰因果关系检验之前首先对各个指标时间序列的平稳性进行单位根检验的东西,我个人觉得吧,这个主要是在计量经济学里会用到的,没有细看) 继续说这个格兰杰因果。上面的内容里已经说了这个AR自回归模型的东西,格兰杰因果关系检验中用到的是受约束回归的思想。就是在这里有一个向量自回归模型,它能够尝试去说明一个变量的当前值受到自身和其他变量的过去值的影响。 由于我的脑电数据是用matlab读取的,所以格兰杰因果关系检验我也想尝试用matlab去实现。 先说一下实现的思路,在这里我们也假设两个时间序列 和,然后判断X对Y是否有格兰杰因果关系。步骤如下: 首先,把时间序列 对所有的滞后项 做一个受约束的回归(不包含滞后项 ),得到受约束的残差平方和RSSR。然后,在回归式中加入滞后项 做一个无约束的回归,得到无约束的残差平方和RSSUR。 假设(我的理解就是假设这个x对y的预测没有起到帮助,也就是说我们先假设x不是y的原因)。 然后就是上面笔记中写到的去做自回归和联合回归误差的F检验,即:遵循自由度为 和 的 F分布。在这里, 是样本容量, 等于滞后项 的个数,即有约束回归方程中待估参数的个数, 是无约束回归中待估参数的个数。如果在选定的显著性水平α上计算的F值超过临界值Fα,则拒绝y原假设,我们就可以认为对有格兰杰因果关系。

从无到有的基于QT软件的DIY桌面番茄钟(上)

基于QT软件的DIY桌面番茄钟-上篇 前言参考本教程(上篇)可实现的功能: 实现细节:Day 1:需求导图:QT的安装: Day 2:创建项目:构建无边框界面(后续可添加缩放功能,未添加)增加透明度界面,新增单击界面改变界面透明度(后续统计第几个番茄钟决定用透明度来统计)代码展示: Day 3:计时器的实现参考代码: 前言 番茄工作法是个不错的方法,本想要从淘宝买一个番茄钟,但发现要99块钱,太贵了。尝试自制一个基于Windows的桌面悬浮番茄钟。 经过一番搜索,决定采用Qt方式进行DIY。计划用一周的时间进行DIY,并给出具体的实现细节。 参考本教程(上篇)可实现的功能: 计时器功能及界面变色功能:番茄钟25min(红色),休息5min(绿色)。 暂停功能:单击实现暂停与恢复暂停。 置顶功能,始终置于其它窗体上面,避免被遮挡。 后续更多功能及扩展将在**从无到有的基于QT软件的DIY桌面番茄钟(2)**中添加。具体可执行文件将在功能完全扩展后发出,需要目前的beta版本的可执行文件可在评论区留言。 实现细节: Day 1: 需求导图: QT的安装: QT官网 首先从Qt官网下载开源安装包,之后进行安装: 需要首先进行注册登录,之后进入到如下步骤 选择如下安装即可, 进入到下载页面,静静等待, Day 2: 创建项目: 创建完后如下: 创建完成后,有如下文件 Header Files tomatoclock.h Source Files main.cpptomatoclock.cpp Header Files: 用于放头文件,所有.h的声明都放在这里。 Source Files: 放源文件,所有.c,.cpp的程序实现的代码都放这里。 Resource Files: 所有的资源文件,如图标,图片,菜单,文字之类的文件都放这里。 头文件(header files)又称作预编译文件,是用户应用程序和函数库之间的桥梁和纽带。作为一种包含功能函数、数据接口声明的载体文件,用于保存程序的声明,而定义文件用于保存程序的实现。 头文件的主要作用在于调用库功能,对各个被调用函数给出一个描述,其本身不包含程序的逻辑实现代码,它只起描述性作用,告诉应用程序通过相应途径寻找相应功能函数的真正逻辑实现代码。用户程序只需要按照头文件中的接口声明来调用库功能,编译器会从库中提取相应的代码。 简单的说,头文件就是作者告诉程序从哪调用库函数的文件。 构建无边框界面(后续可添加缩放功能,未添加) 构建了一个无边框的界面,增加番茄钟的美观图,如图所示: 增加透明度界面,新增单击界面改变界面透明度(后续统计第几个番茄钟决定用透明度来统计) 代码展示: tomatoclock.h #ifndef TOMATOCLOCK_H #define TOMATOCLOCK_H #include <QWidget> #include <windows.h> #include <windowsx.h> #include <QMouseEvent> QT_BEGIN_NAMESPACE namespace Ui { class TomatoClock; } QT_END_NAMESPACE class TomatoClock : public QWidget { Q_OBJECT public: TomatoClock(QWidget *parent = nullptr); ~TomatoClock(); protected: // 声明一些函数 void mousePressEvent(QMouseEvent *e); //鼠标单击事件 void mouseMoveEvent(QMouseEvent *e); // 鼠标单击拖动窗口 private: int boundaryWidth; float Opacity; QPoint clickPos; Ui::TomatoClock *ui; }; #endif // TOMATOCLOCK_H main.

用vue+el-upload+new FormData()实现多图片上传

用vue+el-upload+new FormData()实现多图片上传 如图 <div class="relicsImage_content"> <el-upload class="upload_reilcimg" ref="uploadImg" :action="baseurl + '/antique/batch_img'" list-type="picture-card" :headers="headers" :before-upload="beforeAvatarUploadMore" :on-success="handleAvatarSuccess" :on-remove="handleRemove" :on-change="changeUpload" :show-file-list="true" accept="image/png, image/jpeg, application/pdf" :multiple="true" :auto-upload="false" > <i class="el-icon-plus" /> </el-upload> <p style="font-size: 12px; color: #ccc; margin-top: 20px"> 可上传pdf、jpg、jpeg、png格式,不能超过50M </p> </div> <div> <el-button type="primary" @click="uploadSumit()">确定</el-button> <el-button @click="reset()">重置</el-button> </div> data() { return { ssd: [], isActive: false, forma: { copyReportCode: "", }, list: [], page: 1, limit: 5, // total: 0, id: "", //代表选中某一行的id multipleSelection: [], uploadMoreimg: { fileList: [], }, url: this.

容器知识点总结

用来放其他对象或者基本数据类型(数组本身就是一种容器) 数组优势:简单的线性序列,快速访问,效率高。 劣势:不灵活。容量需要事先定义好,因此需要更加功能强大的容器。 泛型 用来规范容器里保存数据的类型,因为不规定泛型容器中可以任何object类型。本质是数据类型的参数化,可以把泛型理解为数据类型的一个占位符(形式参数),即告诉编译器,在调用泛型时必须传入实际类型。 List接口是有序、可重复的容器。 有序:List中每个元素都有索引标记。可以根据元素索引标记访问元素。 可重复:List中允许加入重复的元素。更确切地说,list通常允许满足e1.equals(e2)的元素重复加入容器。 List接口常用的实现类有三个:ArrayList(底层数组)、LinkedList(底层链表)、和 Vector(底层也是数组,只不过线程安全)。 ArrayList 底层是用数组(占用空间连续)实现的存储。特点:查询效率高,增删效率低,线程不安全 数组扩容:ArrayList默认长度10(也可以直接定义长度),如果数组满了,就会重新定义一个比原数组大1.5倍的数组,然后把原数组的元素拷贝进来。 LinkedList 底层是用双向链表(占用空间不连续)实现的存储。特点:查询效率低,增删效率高,线程不安全 (这个不用定义容量,直接添加节点就行了,然后前驱后继连接) Vector 底层是用数组实现的List,相关的方法都加了同步检查,因此线程安全,效率低。 Map接口(key-value) Map就是用来存储键值对的。Map类中存储的键值对通过键来标识,所以键对象不能重复。 Map接口的实现类有HashMap、TreeMap、HashTable、Propertties。Map中键不能重复,如果重复则覆盖value。 HashMap 底层实现采用了哈希表,哈希表的基本结构就是数组+链表,这里使用的位桶数组(默认长度16) 存储过程:第一步计算健对象的hashcode,第二步hashcode对数组长度取余数,计算出hash值,第三步生成entry对象,第四步根据hash,将Entry对象存储到数组索引位置。(如果有内容,就会在后面链表追加)。在JDK8中,当链表长度大于8时,链表就转换为红黑树,大大提高查找效率。 扩容问题:hashmap的位桶数组,初始大小为16。实际使用大小是可变的。如果位桶数组中的元素达到(0.75*数组长度),就重新调整数组大小为原来2倍大小。(扩容比较耗时,本质是定义新的更大的数组,并将旧数组挨个拷贝到新数组中) TreeMap hashmap效率比它高。是红黑二叉树的典型实现,在需要排序的Map时才选用。(类实现comparable接口,重写compareTo方法) HashTable HashTable和HashMap用法几乎一致,底层实现几乎一样,只不过HashTable的方法添加了synchronized关键字确保线程同步检查,效率较低。 HashMap:线程不安全,效率高。允许key和value为null。 HashTable:线程安全,效率低。不允许key和value为null。 Set接口 继承collection接口,Set接口中没有新增方法。 特点:无序、不可重复。无序指的是Set元素没有索引,我们只能遍历查找,可以放入一个null元素 Set常用的实现类:HashSet、TreeSet。 HashSet 是采用哈希算法实现,底层实际是用HashMap实现的(本质就是一个简化版的HashMap,都是map的key),因此,查询效率和增删效率都很高。 TreeSet 底层实际是用TreeMap实现的,内部维持了一个简化版的TreeMap,通过key来存储Set的元素。TreeSet内部需要对存储的元素进行排序。因此,对应的类需要实现comparable接口,这样才能根据compareTo()方法比较对象之间的大小,才能进行内部排序。

【学习vite + vue3 + pinia + ts】pinia应用 store的创建及应用

在根目录下新建store文件夹,在文件夹下新建index.ts文件 一. src>>store>>index.ts文件中创建store import { defineStore } from 'pinia' interface State { } export const useUserStore = defineStore('main', { state: ():State => ({ }), //类似于computed getters: { }, //类似于methods actions: { } }) 二.在组件中应用store <template> <div class="page"> 用户名: {{user.name}} <a-button type="primary" @click="changeName">修改用户名</a-button> </div> </template> 1. 读取state中的属性 <script setup lang="ts"> import { useUserStore } from '@/store' const user = useUserStore() </script> 2.state值的六种改变方式 (1)直接修改 <script setup lang="ts"> import { useUserStore } from '@/store' const user = useUserStore() const changeName = () =>{ user.

5G学习之寻呼

寻呼(一) 1.为什么需要寻呼? 为了尽可能实现低功耗,在UE没有激活业务时,会切换到节能的状态(LTE中时空闲状态,NR中空闲、非激活状态),都会缩减UE的功能(比如断开控制面连接),这时候核心网不知道UE的精确位置(在哪个小区),没办法进行数据传输。所以核心网有UE的数据到达时,需要通过某种机制找到UE 2.寻呼需要解决什么问题? 在什么范围内寻呼UE? 在什么时间寻呼UE? UE怎么简单快速有没有被寻呼、谁在寻呼? 3.寻呼的基本原理: 网络侧:NG-RAN/核心网传递过来寻呼消息,网络侧利用PDCCH指示的PDSCH承载寻呼消息 UE:在非连续周期内(DRX)对PDCCH进行监控,接受发送给自己的寻呼消息并触发RACH进入连接状态 从物理层看:寻呼消息和普通消息的流程和处理方法相同:通过PDCCH通知UE在对应的PDSCH获得用户数据(区别:寻呼PDSCH承载的是上层信令,数据传输PDSCH承载用户数据) 4.UE接收寻呼信号的流程: 计算出可能发出寻呼的位置PO、PF => 监控对应子帧的PDCCH => 存在P-RNTI => 根据PDCCH指示的RB分配和调制编码格式,从对应的PDSCH上获得寻呼消息 => 根据寻呼消息里携带的UE ID判断寻呼消息是不是寻呼的自己 名词解释: 寻呼时机(PO)是一个子帧,其中可以在PDCCH上发送寻址寻呼消息的P-RNTI。PF是一个无线电帧,可以包含一个或多个POP-RNTI:PNTI是NR中用作某种目的的临时标识符(有许多种:P-RNTI、SI-RNTI(用来标识系统信息广播)、RA-RNTI(用来标识随机接入应答)等等等等),P-RNTI用来标识寻呼和系统信息更新通知。 5.怎么得到PF、PO? 通过计算: PF:(SNF+PF_offset)mod T = (T div N)* (UE_ID mod N) PO: i_s = floor(UE_ID / N) mod Ns 参数解释: SFN:(变量)系统帧号 T:(常量)UE的非连续接收周期;如果系统设置了,则T为最小周期值,没配置就是系统默认值;意义:周期为T,则周期T内有T个系统帧 N:(变量)DRX周期T内PF的数量(称为PF密度) UE_ID:(变量)IMSI mod 1024 (IMSI:国际移动用户识别码) Ns:(变量)在一个PF的PO数目 PO:36.304 对PO的定义如下 表格解释: 当Ns=1时,在一个寻呼帧内只能有一个寻呼机位置(只有一个子帧承载寻呼消息),子帧编号为9。 当Ns=2时,在寻呼帧内可以有两个寻呼位置(其中携带寻呼消息的两个子帧),并且子帧号是4和9。 当Ns=4时,在寻呼帧内可以有四个寻呼位置(其中携带寻呼消息的四个子帧),并且子帧编号为0、4、5和9。 6.公式意义: PF:SNF mod T = (T div N)* (UE_ID mod N)

【C-数据结构与算法】408必背算法

文章目录 1. 顺序表相关1.1 快速排序1.2 二分查找 1. 顺序表相关 1.1 快速排序 #include <stdio.h> // 划分序列 int Partition(int arr[],int low,int hight) { int pivot = arr[low];// 设最左边的数为枢纽 while (low < hight) { // 从右往左,找到第一个小于pivot 的数,再将其放入low指向位置 while (low < hight && arr[hight] >= pivot) { hight--; } arr[low] = arr[hight]; // 从左往右,找到第一个大于pivot 的数,再将其放入hight指向位置 while (low < hight && arr[low] <= pivot) { low++; } arr[hight] = arr[low]; } // 最终 low 和 hight 都指向了同一个已经被使用过的元素,把pivot填入即可 arr[low] = pivot; return low;// 返回中间元素下标 } void Qsort(int arr[], int low, int hight) { if (low < hight) { int mid = Partition(arr, low, hight); Qsort(arr, low, mid - 1);// 左边区域继续划分 Qsort(arr, mid + 1, hight);// 右边区域继续划分 } } void printArr(int arr[],int arrLength) { for (int i = 0; i < arrLength; i++){ printf("

线程的执行顺序

线程的执行顺序是不确定的 调用Thread的start()方法启动线程时,线程的执行顺序时不确定的.也就是说,再同一个方法中,连续创建多个线程后,调用线程的start()方法的顺序并不能决定线程的执行顺序. public class ThreadSort { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { System.out.println("thread1"); },"thread1"); Thread thread2 = new Thread(() -> { System.out.println("thread2"); },"thread2"); Thread thread3 = new Thread(() -> { System.out.println("thread3"); },"thread3"); thread1.start(); thread2.start(); thread3.start(); } } 第一次运行 thread2 thread1 thread3 第二次运行 thread1 thread3 thread2 第三次运行 thread3 thread2 thread1 每个人执行的结果可能不一样,但是可以确认的是,每次执行的时候,线程的执行顺序可能不同.线程启动顺序并不能决定线程的执行顺序. 使用join()确保线程的执行顺序 再实际业务场景中,有时候后启动的线程可能需要依赖先启动的线程执行完成才能正确的执行线程中的业务逻辑.此时,就需要确保线程的执行顺序.可以使用Thread的join()方法来确保线程的执行顺序 public class ThreadSort { public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread(() -> { System.

第十五章 奇异值分解(SVD)

文章目录 第十五章 奇异值分解(SVD)奇异值分解的定义奇异值分解的基本定理(完全奇异值分解)紧奇异值分解与截 断奇异值分解奇异值分解的计算步骤奇异值分解的计算示例 第十五章 奇异值分解(SVD) 相关英文释义: 奇异值分解(singular value decomposition)正交矩阵 ( orthogonal matrix)矩形对角矩阵 ( rectangular diagonal matrix)奇异值 ( singular value )左奇异向量 (left singular vector)右奇异向量 (right singular vector)完全奇异值分解(full singular value decomposition)紧奇异值分解 ( compact singular value decomposition)截断奇异值分解 ( truncated singular value decomposition) 奇异值分解的定义 定义 15.1 (奇异值分解、完全奇异值分解) 矩阵的奇异值分解是指, 将一个非零的 m × n m \times n m×n 实矩阵 A , A ∈ R m × n A, A \in \mathbf{R}^{m \times n} A,A∈Rm×n, 表示为以下三个实矩阵乘积形式的运算 (1), 即进行矩阵的因子分解:

第十四章 聚类方法

文章目录 第十四章 聚类方法相似度或距离类与类之间的距离层次聚类K均值聚类kmeans算法特性 第十四章 聚类方法 相似度或距离 闵可夫斯基距离 闵可夫斯基距离 越大相似度越小, 距离越小相似度越大。 定义 14.1 给定样本集合 X , X X, X X,X 是 m m m 维实数向量空间 R m \mathbf{R}^m Rm 中点的集合, 其中 x i , x j ∈ X , x i = ( x 1 i , x 2 i , ⋯ , x m i ) T , x j = ( x 1 j , x 2 j , ⋯ , x m j ) T x_i, x_j \in X, x_i=\left(x_{1 i}, x_{2 i}, \cdots, x_{m i}\right)^{\mathrm{T}}, x_j=\left(x_{1 j}, x_{2 j}, \cdots, x_{m j}\right)^{\mathrm{T}} xi​,xj​∈X,xi​=(x1i​,x2i​,⋯,xmi​)T,xj​=(x1j​,x2j​,⋯,xmj​)T, 样本 x i x_i xi​ 与样本 x j x_j xj​ 的闵可夫斯基距离 ( Minkowski distance) 定义为

编译器和解释器

一、概念 解释器(interpreter): 是一种计算机程序,它将每个高级程序语句转换成机器代码。编译器(compiler): 把高级语言编写的程序转换成机器码,将人可读的代码转换成计算机可读的代码(0和1)。 二、两者的区别 注意:Java既是编译的又是解释的,Java代码本身被编译成目标代码。在运行时,JVM将目标代码解释为目标计算机的机器代码。 三、总结 编译器和解释器的目的是做相同的工作,但在操作过程上不同,编译器以聚合的方式获取源代码,而解释器获取源代码的组成部分,即一条一条的语句。 名词解释: 与编译原理有关… 词法分析:lexical analysis,输入源程序串,输出单词符号,即将字符序列转换为 token 序列的过程。进行词法分析的程序 or 函数叫作 词法分析器(lexical analyzer,简称lexer),也叫扫描器 (scanner)。词法分析器一般以函数的形式存在,供 语法分析器 调用。语法分析:根据高级语言的语法规则对程序的语法结构进行分析。分析上一步得到的单词符号串是否符合语言的语法规则,分析并识别各种语法成分,同时进行语法检查和错误处理,为语义分析和代码生成做准备。语义分析:基于语义规则,对语法树进行语义分析。包括变量是否定义,类型是否正确等。 主要功能包括建立符号表,进行静态语义检查,发现语义错误。 语义分析的类型:静态语义和动态语义 静态语义:在编译阶段可以检查的语义。e.g.标识符未声明。动态语义:目标程序运行时(run-time)才能检查的语义。e.g.除零、溢出错误。 语义分析的内容:类型分析、标识符相关信息提取。 语义分析的功能:检查语义错误、构造标识符属性表(符号表) 语法是上下文无关的,语义是上下文相关的。

ESP32-arduino,超好玩的定时器!

前言 嵌入式系统的主程序基本上是个大循环,如果在循环里要处理各个任务的请求的话,最粗暴的方式就是轮流查询,简称轮询, 轮询可以解决简单系统的问题,但当请求数量和处理复杂度提升的时候,难免捉襟见肘,中断就是为了解决“按需分配”的资源配置问题。 当然,中断有很几种,外部中断、定时中断等,今天我们要介绍的就是中断里的定时中断! 定时中断——定时执行的中断 直奔主题,编写一个定时中断的程序需要几步呢?我们来编写一个简单的定时器程序,每秒打印一次,如下: 首先声明一个定时器 /* timerBegin:初始化定时器指针 第一个参数:设置定时器0(一共有四个定时器0、1、2、3) 第二个参数:80分频(设置APB时钟,ESP32主频80MHz),80则时间单位为1Mhz即1us,1000000us即1s。 第三个参数:计数方式,true向上计数 false向下计数 */ timer = timerBegin(0, 80, true); 编写中断函数并绑定定时器 /* 中断服务函数,为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性 */ void IRAM_ATTR onTimer() { Serial.println('1'); } /* timerAttachInterrupt:绑定定时器 第一个参数:指向已初始化定时器的指针 第二个参数:中断服务器函数 第三个参数:true边沿触发,false电平触发 */ timerAttachInterrupt(timer, &onTimer, true); 初始化定时器,指定定时器、分频、计数方式 /* timerAlarmWrite:配置报警计数器保护值(就是设置时间) 第一个参数:指向已初始化定时器的指针 第二个参数:定时时间,这里为1000000us 意思为1s进入一次中断 第三个参数:是否重载,false定时器中断触发一次 true:死循环 */ timerAlarmWrite(timer, 1000000, true); 启用定时器 /* timerAlarmEnable:启用定时器 第一个参数:指向已初始化定时器的指针 */ timerAlarmEnable(timer); 关闭定时器 /*timerDetachInterrupt:关闭定时器 第一个参数:指向已初始化定时器的指针 */ timerDetachInterrupt(timer); hw_timer_t * timer = NULL; // 声明一个定时器 void IRAM_ATTR onTimer() { // 中断函数 Serial.

vscode中React常用快捷键汇集

快捷键 Basic Methods PrefixMethodimp→import moduleName from 'module'imn→import 'module'imd→import { destructuredModule } from 'module'ime→import * as alias from 'module'ima→import { originalName as aliasName} from 'module'exp→export default moduleNameexd→export { destructuredModule } from 'module'exa→export { originalName as aliasName} from 'module'enf→export const functionName = (params) => { }edf→export default (params) => { }met→methodName = (params) => { }fre→arrayName.forEach(element => { }fof→for(let itemName of objectName { }fin→for(let itemName in objectName { }anfn→(params) => { }nfn→const functionName = (params) => { }dob→const {propName} = objectToDescructdar→const [propName] = arrayToDescructsti→setInterval(() => { }, intervalTimesto→setTimeout(() => { }, delayTimeprom→return new Promise((resolve, reject) => { }cmmb→comment blockcp→const { } = this.

pip 下载安装时使用清华大学镜像

假如要安装numpy库,则在原来的语句上添加 -i 和镜像地址即可。 pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple 其它镜像:注意有的是http,有的是https 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://pypi.hustunique.com/ 山东理工大学:http://pypi.sdutlinux.org/ 豆瓣:http://pypi.douban.com/simple/

vivado 导入IP核并生成bit流文件

Xilinx版本:2021.2 PC系统:Windows10 前置要求:你需要有一个IP核,或者自己用vitis HLS生成IP核 1、首先解压IP核: 然后打开你的vivado软件,点击Create Project,之后设置项目名称以及项目位置。 选择RTL 项目 选择你的FPGA板子的型号,最后选择finish,等待工程的创建。 2、导入IP核,选择Create Block Design,并将名字名名为你工程的名字即可,之后点击OK 完成之后右侧就会出现大片空白,点击加号,此意为导入硬件IP核。 首先,因为本文所涉及的IP核都是基于zynq的,所以这里需要先添加一个zynq的IP核,本文选择了其中一个 选择完成之后如图所示,如果界面中出现Run Block Automation,点击运行即可,如果没有请忽略。 再然后就可以导入我们设计的IP了,如图:点击setting->IP->Repository再点击“加号”,找到你刚刚解压的IP核文件夹(第一张图),选择它 然后这里就会出现你所设计的IP核,点击OK。然后我们就将自己的IP核导入了库。 点击加号,搜索自己刚刚添加的IP核名称,并选择它 之后你就会发现,你的IP和已经导入了,如图:之后点击Run Connection Avtomation 点击OK 结果如图:我们发现线已经连好 3、创建顶层:Create HDL wrapper 点击OK,保持默认 完成之后如图: 4、生成bit流文件:点击运行Generate Bitstream,其他若无特殊要求,默认即可。这里等的时间比较长,大约十几到三十分钟。如果IP比较大、比较麻烦,可能会更长。 直到出现该弹窗,表示bitstream已经生成 点击OK后如图所示: 之后在你的项目文件夹中打开add_vivado.runs->impl_1,就可以找到相应的.bit文件 如此,该IP核的bitstream流文件就完成了,就可以拿到FPGA用了。

大华摄像头WEB集成--rstp拉流

之前没有做过类似的开发,导致走了很多坑。那就记录一下呗。 什么是rstp? RSTP就是R.S.T.P的组合。那么什么是组合.....换一句话说,有了这个组合能解决什么问题。不要行不行?..... 开玩笑的,哈哈~ rstp就是一个流。至于什么流百度一下了。 最后的成果~~~~~~~(这是html) 先熟悉一下大华web的后台界面 本片文只需要关注这RTSP就行了。看看端口号是多少~~~~~~ 因为rtsp流不能直接播放,得需要一些工具,比如我用的就是VLC media player 先打开--》 媒体--》打开网络串流--》网络 大华的rtsp地址 rtsp://user:password@ip:port/cam/realmonitor?channel=2&subtype=1 ip:web后台的IP port: 上面咱们看到的rtsp的端口,默认是554, channel: 管道 subtype: 码流 得到rtsp地址后直接放入VLC的URL中,点击播放即可。 VLC报错: 您的输入无法被打开: VLC 无法打开 MRL「rtsp://.........」。详情请检查日志。 检查URL是否写错检查服务器是否限制了地区的IP。(有些服务器只能在当省市级访问)检查你的网络环境用 telnet命令 是否能连接到服务器的554端口(有些企业的网络是屏蔽掉端口的,导致你的网络不能与摄像头所在的服务器进行通信) 上面就是我遇到过的,其他的情况不是很清楚呢! 如果能使用VLC播放器进行播放,那么还需要搭建nginx和ffmpeg 大体逻辑很简单。 ffmpeg 拉取 rstp流 然后转成m3u8视频,在通过nginx安装的m3u8模块并指向本地磁盘就能实现实时访问呢。 NGINX location / { types{ application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root 'C:\\1\\'; # ffmpeg对rstp转换后存放的m3u8文件地址 add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; } ffmpeg -rtsp_transport tcp -i "rtsp://................." -c copy -f hls -hls_time 2.

Conda使用指南

Conda介绍 conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理和环境管理。包管理与pip的使用方法类似似,环境管理则是允许用户方便滴安装不同版本的python环境并在不同环境之间快速地切换。 conda的设计理念 conda将几乎所有的工具、第三方包都当作package进行管理,甚至包括python 和conda自身。Anaconda是一个打包的集合,里面预装好了conda、某个版本的python、各种packages等。 1. 安装Anaconda。 打开命令行输入如下命令检验是否安装及当前conda的版本。 conda -V 2. conda常用的命令 查看环境中安装了哪些包,默认是base环境 conda list 查看当前存在哪些虚拟环境 conda env list conda info -e 检查更新当前conda conda update conda 3. Python创建虚拟环境 conda create -n [env_name] python=x.x 或者克隆 conda create -n your_name --clone env_name anaconda命令创建python版本为x.x,名字为env_name的虚拟环境。env_name文件可以在Anaconda安装目录envs文件下找到 4. 激活或者切换虚拟环境 打开命令行,输入python --version检查当前 python 版本。 Linux: source activate [env_name] conda activate [env_name] Windows: activate [env_name] 5. 对虚拟环境中安装额外的包 conda install -n env_name [package] # 未激活环境 conda install [package] # 如果已经激活环境 6.

用js获取当前月份的天数

本文介绍一下如何使用js获取指定时间对应月份的天数。 获取当前月份天数 我测试的时间是2022-09-01: const date = new Date() const year = date.getFullYear() const month = date.getMonth() const days = new Date(year,month+1,0).getDate() // 30 假如要获取2022-02的天数: const days = new Date(2022,2,0).getDate() // 28 注意:new Date()接收的第三个参数是0,第二个参数是人类意识中的月份(因为date.getMonth()得到的值比想象中的小1) 补充 月份是从0开始计算的: new Date('2022-01-01 13:55:33').getMonth() // 0 获取指定日期 是 星期几: new Date('2022-08-28 13:55:33').getDay() // 0 星期日(老外喜欢把一周中的星期日当成第一天,也是从0开始) 应用场景 我是在使用 echarts 时遇到了这个问题,需要按月份生成数据: 具备了上面的基础知识,就可以搞定这个问题了: function genDaysArr(timestamp) { const d = new Date(timestamp) const y = d.getFullYear() const m = d.

【深度学习】非极大抑制算法 及python代码

非极大抑制算法NMS NMS的目的是,消除多余的框,只保留最佳预测框。原理在这里不详细讲啦,没有什么很多数学公式,列举一下大概步骤: 对所有预测框按置信度进行排序找出分数最高的检测框Bmax遍历其他框,计算当前与Bmax的重叠面积如果重叠面积大于设定的阈值,则剔除继续对未处理过的预测框进行排序重复第1到5步… 搬了b站一大佬的代码,并写上了注释,有需要自取~ def nms(boxes, num_classes, conf_thres=0.5, nms_thres=0.4): #boxes: 检测的boxes及scores,维度(batch_size, all_boxes, 4+1+num_classes) #num_classes: 类别的数量 #conf_thres: 预测框的阈值, nms_thres: 极大值抑制的阈值 #取batch size bs = np.shape(boxes)[0] #将预测框(中心宽高)转成左上角右下角的形式 shape_boxes = np.zeros_like(boxes[:,:,:4]) shape_boxes[:,:,0] = boxes[:,:,0] - boxes[:,:,2]/2 shape_boxes[:,:,1] = boxes[:,:,1] - boxes[:,:,3]/2 shape_boxes[:,:,2] = boxes[:,:,0] + boxes[:,:,2]/2 shape_boxes[:,:,3] = boxes[:,:,1] + boxes[:,:,3]/2 boxes[:,:,:4] = shape_boxes output = [] #遍历每一个boxes for i in range(bs): # prediction shape (num_boxes, 4+1+num_classes) prediction = boxes[i] #获取存在物体的概率 score = prediction[:, 4] #利用mask筛选出一张图像里面置信度大于设定值的预测框 mask = score > conf_thres detection = prediction[mask] #找到这些预测框属于什么种类 #取prediction (num_boxes, 4+1+num_classes)最后一个值 # 对其求max,找出属于某种类的概率 class_conf = np.

centos7 安装frp内网穿透

一、安装服务端 找一台云服务器。下载frp wget https://github.com/fatedier/frp/releases/download/v0.35.1/frp_0.35.1_linux_amd64.tar.gz解压 tar -zxvf frp_0.35.1_linux_amd64.tar.gz修改frps.ini文件 [common] # frp监听的端口,可以改成其他的 bind_port = 8501 # 授权码,请改成更复杂的 token = 12345678 # frp管理后台端口,请按自己需求更改 dashboard_port = 8500 # frp管理后台用户名和密码,请改成自己的 dashboard_user = admin dashboard_pwd = admin enable_prometheus = true # http服务,对外暴露的端口 vhost_http_port = 8888 # frp日志配置 log_file = /var/log/frps.log log_level = info log_max_days = 3 将frps.ini配置文件cp到etc下 cp frps.ini /etc/frp将frps服务端程序cp到usr/bin下 cp frps /usr/bin配置开机启动 vim /usr/lib/systemd/system/frps.service [Unit] Description=Frp Server Service After=network.target [Service] Type=simple User=nobody Restart=on-failure RestartSec=5s ExecStart=/usr/bin/frps -c /etc/frp/frps.

技术赋能教育,聚铭网络亮相“宁创新品”系列对接活动——教育专场推介会

随着互联网技术的不断迭代和更新,教育板块的产品形式也正朝着智能化和普惠化不断迈进。科技推动创新,技术赋能教育,为持续做好全市创新产品推广工作,促进供需精准对接,助力南京产业高质量发展,8月31日,由南京市工业和信息化局主办,市财政局、教育局协办的“宁创新品”系列对接活动——教育专场推介会在新城大厦E座举行。 活动现场,市财政局相关领导介绍创新产品采购政策,市教育局发布教育类创新产品应用需求,创新产品所属企业、产业链重点企业,风投机构等相关负责人齐聚一堂。南京市工业和信息化局领导带队在聚铭网络场外展台停留,听取公司产品相关介绍。 聚铭网络解决方案总监于化农携带公司“明星产品”——聚铭安全态势感知与管控平台亮相推介会并进行现场介绍。 于化农介绍道,作为被列入《南京市创新产品应用示范推荐目录》内的创新产品,聚铭安全态势感知与管控平台基于勒索/钓鱼邮件、网页恶意篡改、数据泄露、僵木蠕恶意程序等常见的网络安全问题,通过对事件的深度分析及信息情报共享,建立全网安全态势感知,将风险集中监控,问题统一处理,同时将普遍性安全体系原理与简业校园信息系统的实际相结合,形成满足校园网安全需求的安全体系结构,以满足高效运营安全需要和高校安全规划目标。 聚铭安全态势感知与管控平台通过大数据、AI技术,结合情报应用,8大分析能力,多层次、全方位覆盖安全分析的每一个层面,适用于异常外连监控、网络攻击监测、勒索防范、挖矿分析、实名认证等多个学校典型场景。可以统一采集学校的服务器、应用系统等全网安全设备日志告警数据,对海量数据进行范式化、识别、清洗、建模等处理,发掘潜在安全风险,对校园威胁实施动态防护,提升校园运维运营效率,提升学校安全运营能力。目前已为南京大学、吉林大学、深圳大学、中国矿业大学等多个高校提供了网络安全服务。 作为国内领先的安全托管服务运营商和安全产品提供商,聚铭拥有业内首屈一指的威胁情报能力,加密恶意软件检测准确率高达99.8%,Webshell检测能力竞赛进入国内Top3。凭借先进的技术和优质的服务,目前公司产品已服务电信、教育、能源、金融、政府、医疗等行业超10000家政企客户,云端托管客户超6000家。公司在北京、南京建立了双总部中心,同时在河北、山东、湖南等地设有分支机构,业务覆盖全国32个省市地区。 以技术驱动教育创新发展。未来,聚铭将继续探索新技术、新模式,培育新动能,建设新业态,为教育领域数字化转型中的网络安全保驾护航!

如何进行CAN总线高效测试?

CAN总线自BOSCH公司发明以来,在汽车通信网络中的应用得到了广泛认可。随着汽车电子技术的发展,车上的电子模块越来越多,汽车内部的CAN总线节点也随之增多。 一般汽车内部CAN节点少则10个,多则30-40个,在对这些CAN节点进行测试的时候,工作内容复杂,且对测试人员技术要求较高。如何在保证产品质量的同时,快速推出产品,是OEM亟待解决的难题。因此,自动化测试技术作为汽车产品质量验证的重要手段变得至关重要。 针对上述问题,怿星科技自研的Neptune CAN总线自动化测试系统提供了有效的解决方案,下面跟着小编详细了解一下。 CAN总线测试内容 首先,简单介绍一下CAN总线测试内容。通常情况下CAN总线测试分为物理层测试、数据链路层测试、应用层测试、容错性测试几个部分。 01 物理层测试主要有以下内容,其中位时间、信号跳变斜率、电阻测试关注较多,也比较容易出问题。在后文详细介绍位时间和信号跳变斜率测试。 测试点 测试目的 测试条件 显隐性电平 CAN总线对逻辑信号的识别依赖于信号电平,若CANH和CANL线上电平过高或过低,都会影响总线状态的判断,则需要验证在显性、隐性状态时,CANH 和 CANL 线上电平是否满足设计要求 示波器 信号跳变斜率 验证DUT的 CAN电平信号上升/下降斜率是否满足设计要求 示波器 高低压通信范围 验证DUT的高压和低压通信工作范围是否满足设计要求 _ 位时间 总线波特率与位时间成反比,位时间由波特率确定,要求误差±0.5%,测试验证DUT的位时间是否满足设计要求 示波器 终端电阻 ISO11898-2要求在高速CAN总线两端接终端电阻(一般为120Ω)以消除反射,对低速CAN没有端接要求。因此,需要验证DUT终端电阻和非终端电阻配置是否符合设计要求 万用表 地偏移 验证DUT在地电压发生偏移时,通信是否正常 地漂电源 ▷ 位时间测试 在介绍位时间测试之前,先简单回顾一下CAN数据帧格式,如下图所示: 测试目的 主要验证DUT发送报文的位时间精度以及DUT对接收到的报文的位时间精度容错能力。 测试方法 通常选取DUT发送的其中1个CAN标准数据帧,使用示波器抓取整帧报文波形,计算从测试起始位到测试结束位的间隔时间,然后求平均值。测试起始位和结束位可以是帧起始位、仲裁段位、控制段位、数据段位、CRC段位、ACK段、帧结束位等。 测试结果 下面是使用示波器自动抓取的测试截图(从SOF起始位到ID段的结束位,测量方式为差分信号输入): ▷ 跳变斜率测试 测试目的 主要验证DUT的CAN总线信号上升斜率和下降斜率是否满足要求。 测试方法 通常选取DUT发送的其中1个CAN标准数据帧,使用示波器抓取整帧报文波形(包括CANH、CANL以及CANH和CANL之间差分信号波形),然后分析计算仲裁段或数据段内的所有跳变沿变化时间(信号从10%上升到90%或者从90%下降到10%间隔时间)。 测试结果 下面是使用示波器自动抓取的测试截图(测量方式为差分信号输入): 02 数据链路层测试主要有以下内容,其中采样点、BusOff测试关注较多,在后文详细介绍采样点测试。 测试点 测试目的 测试条件 采样点 验证DUT的采样点设置是否满足设计要求 VH6501干扰仪 ACK应答 验证开启/关闭总线ACK应答时,DUT通信处理机制是否满足设计要求 _ 报文重发 验证DUT产生发送错误后,能否立即重发该报文 VH6501干扰仪 BusOff 验证DUT快恢复策略是否满足设计要求 VH6501干扰仪 高负载 验证在总线高负载情况下,DUT是否会出现丢帧现象