更快,更好的冒泡排序
冒泡排序优化基础知识:冒泡排序 | IT蛋的个人博客 (xcscx.github.io)
// 冒泡排序的基本实现
class Main {
public static void bubbleSort(int[] arr) {
int len = arr.length;
// i用于记录已经放好的最大值数组
for(int i = 0; i < len-1; i++) {
// 用于向后冒泡,依次交换大值
for(int j = 0; j < len - i - 1; j++) {
if(arr[j] > arr[j+1]){
swap(arr, j, j+1);
}
}
}
return;
}
...
拥有自己的代码库真的很酷--如何开发一个SDK
拥有自己的代码库真的很酷–如何开发一个SDK日复一日编程,年复一年造轮
前言不知你是否和我一样,对编程解决问题有一种 ” 懒人执着 “ :已有代码能解决的,一律不重复造轮子
写过的重要代码就拷贝到自己的文本文件里整理起来,下次遇到相同问题直接cv,还记的我一个水仙花算法的代码应付了整个大学遇到的水仙花问题
即了解代码怎么实现,也节省了重复编写代码的时间,看上去真是一举两得
但当我存储的代码块越来越多,管理则成了一个问题:
试问:你希望看满满一大页的代码块来找你的目标代码,还是顺手就自己编写完那简单的轮子?
何况固定的代码并不能应对不同的场景,没准你还要理解和修改呢
于是在大二那年,我的项目用上了Maven,一个开源的依赖管理工具,你想要的功能大多都可以直接搜索下载依赖
几乎彻底解决了造轮子问题,但仍然有问题:
其一:尽管依赖有很多,但毕竟不是自己写的,对于功能实现和后续优化可能并没有那么有帮助
其二:下载的依赖是否匹配项目也是一个问题,名称相似而不相同的依赖也有不少,如何选择也会影响之后的开发
既然又希望理解原理,又不想后续重复造轮子
为什么不自己写常用的依赖呢?
通用的类,固定的常 ...
阿里巴巴开发手册 --编程规约
命名风格
命名使用全英文 / 纯拼音,不可以混合使用
长类名使用UpperCamelCase式驼峰命名,即每个单词的首字母都要大写(除去DO、BO、DTO、VO、AO等固定缩写)
方法名,参数名,变量名使用lowerCameCase式驼峰命名,即除去首个单词之外的其他单词都要首字母大写
常量每个单词全部大写,单词间使用下划线隔开
抽象类使用 Abstract/Base开头,异常类使用Exception结尾,测试类使用Test结尾
杜绝不规范,不明意义的缩写
Service的实现类使用Impl作为后缀来和接口做区分
常量定义
禁止任何魔法值
long和Long初始赋值时,必须使用大写的L(避免小写 l 和 1 混淆)
代码格式
大括号为空时,直接写{},不用换行;非空时做到:“ { ” 后换行,“ } ”前换行,如果“ } ”后有else等代码,则不用在换行,否则换行
“ ( “右边不要空格, “ ) ”左边不要空格
if,for,while,switch,do和括号之间加空格
二目,三目运算符左右各加一个空格
缩进使用四个空格(如果要使用Tab就要先将Tab设置 ...
Nginx-入门
NginxNginx 是一个高性能的HTTP和反向代理服务器
作用:反向代理, 负载均衡,动静分离
正向代理和反向代理:
正向代理:访问外部服务器时依据代理服务器进行代理请求(访问外网利用VPN进行代理),即 代理客户端(隐藏客户端)
反向代理:访问不同服务器的同一网址(大家访问的百度都是同一个域名,但是百度有很多服务器)即 代理服务器端(隐藏服务器端)
负载均衡:
负载均衡策略分为:内置策略 和 扩展策略 两种,前者有 轮询,加权轮询 和 lp hash,后者自定义
轮询:按顺序一个个分,分到了就排最后让下一个分
加权轮询:利用加权使性能更好的服务器能处理更多请求
ip hash:通过ip运算,使得固定ip只会打到固定服务器上,避免堕胎服务器上有相同的session信息(但是一旦挂了就会丢数据)
动静分离:
将项目中不需要经过后台处理的(如css,html,js等文件)静态文件与动态文件做拆分,将静态文件做缓存操作,提高响应速度
常用命令在Nginx的sbin目录下
./nginx 启动
./nginx -s stop 停止
./nginx -s quit 安全退出
./n ...
RabbitMQ-快速上手
RabbitMQ四大核心:生产者,消费者,队列,交换机
AMQP四个核心组件:消息,交换机,队列,绑定
消息队列-基础知识
关于消息队列消息队列(Message Queue):一种用于在应用程序间传递消息的通信方式,允许应用程序异步地发送和接收消息(不用直接连接对方)
消息(Message):在应用间传送的数据,消息可以非常简单(只包含文本字符串)也可以很复杂(包含嵌入对象)
队列(Queue):一个数据结构,可以存储数据,满足先进先出的顺序
消息队列的应用场景
应用解耦:在多个系统中,合理使用MQ可以使得系统兼容性更好,扩展性更高的同时,减少原代码修改
加快响应:异步处理请求,可以节省响应时间,优化体验
削峰填谷:增大系统可用性,保证系统稳定性
消息队列缺点
降低系统可用性:系统外部引入的依赖越多,越容易挂掉
系统复杂度提高:使用MQ后需要额外考虑例如:消息是否被重复消费,处理消息丢失,保证消息传递顺序等问题
一致性问题:在多个系统中,需要注意部分系统未能成功处理,导致数据不一致的问题
消息队列保证顺序性
生产者有序:单线程消费来保证消息的顺序性
生产者无序:对消息编号,消费者处理时根据编号进行判断。多个消费者时,可以考虑增加分布式锁
参考文章:如何保证消息队列的顺序性 (yuque.com)
消息 ...
Java锁相关的名词
Java锁相关名词
synchronized:可用于方法和代码块,实现对实例或类的同步访问,提供互斥访问。当一个线程进入被synchronized修饰的代码块时,自动获取对象锁(锁监视器),其他线程要等待锁的释放
volatile:用于修饰变量,确保多个线程之间对被修饰变量的可见性,不可以保证原子性,所以在多线程操作volatile对象时,需要额外的同步手段
Lock:<接口>定义了基本锁机制,有如下常见方法:
lock():获取锁,如果锁不可用则阻塞等待
unlock():释放锁,让其他线程获取锁
trylock():尝试获取锁,如果可用则获取锁,否则返回false
ReentrantLock:<Lock接口的实现类>提供了可重入的互斥锁(可重入性:同一个线程可以多次获取同一个锁,不被自己持有的锁阻塞,即适应嵌套锁)
具有公平性与非公平性:前者按线程申请顺序进行,后者可能存在线程插队
监视器锁: 用于实现同步机制,基于对象的内置锁(互斥锁)实现,
每个Java对象都有一个内置锁,当synchronized修饰方法时, ...
Java复盘知识点
System输出System.err.println() : 错误输出,输出的内容为红色
System.out.println() : 常规输出,输出的内容为白色
System.getProperty(“user.dir”); 获取当前项目目录地址
File.separator 获取系统的分隔符
默认属性接口中的变量默认:public static final
方法中的变量默认:public abstract
关于数组
数组初始化后所占空间是固定的
数组相等的判断需要使用Arrays.equals(),进行逐个对比
因为数组是对象,所以java是存储到堆中的
执行顺序父类静态 —— 子类金泰 —— 父类构造代码块 —— 父类构造方法 —— 子类构造代码块 —— 子类构造方法
关于private只有本类和反射可以访问到
注意:一个java文件不能有两个public,且子类作用域不可以访问父类私有变量
(如果父类有private属性,子类无法访问到该私有变量)
Integer对比小于127的Integer值可以相互间直接比较,会作为数值直接比较
大于127的Integer与in ...
快速排序
快速排序逻辑快速排序采用分治法的思想,每次找到一个数的正确位置,并将左右两侧调整为小于大于该数的两部分,递归两侧找到每一个数字的正确位置
在交换过程中,相同大小的元素可能会改变它们的相对顺序,所以快速排序不稳定
复杂度分析平均时间复杂度:O(nlogn)
空间复杂度:O(logn)
最差情况的时间复杂度,待排序数组已经是有序的或者逆序的,此时每次划分只能得到一个很小或很大的子数组,其时间复杂度为O(n^2);
递归调用栈的最大深度为n,因此最坏情况下的空间复杂度为O(n)
代码实现class Main {
public static void quickSort(int[] arr, int left, int right) {
// 保证数组存在值
if(left < right) {
int temp = arr[left];
int i = left + 1, j = right;
// 左右指针,找到左边第一个大于temp的和右边第 ...