第一章:算法概述

第二章:数据结构基础

基础定义

同量级函数: 存在函数f(n),使得f(n)/T(n)的极限值为不是0的常数。记作T(n) = O(f(n)),这里的O渐进时间复杂度,简称时间复杂度

if f(n) exist && f(n max)/T(n) !=0

其实就是把时间函数T(n),简化成一个数

随机读取:

比如有个数组,你array[3],就是拿下标为3的数据,这种根据下标读取元素的方式就叫随机读取

物理结构:内存中实实在在存在的就叫物理结构,比如list、array

逻辑结构:靠意淫想象出来的结构,比如redis的跳表

栈:线性的数据结构。先入后出(FILO),比如吧一个球放进只有一个孔的半密闭容器,只能从上往下拿球。最上面的叫栈顶,最下面的叫栈底。方法分别对应压栈/入栈 push和出栈pop

队列:线性的数据结构。先入先出。按照顺序一个一个的执行,不能跳过或者删除。队列的出口叫队头,入口叫队尾。方法分别对应入队enqueue和出队dequeue。需要注意的是出队只允许出对头的那个

循环队列:吧队列想成一个首尾相接的圆环,下次取队头的时候就根据 (队尾下标+1)%数组长度 来算。

栈的一些小应用举例

1.比如某些网页的返回上一次

2.比如递归找到上一层调用,从而找到整个的调用链

队列的一些小应用举例

1.按顺序争夺公平锁的等待队列

2.rabbitmq

优先级队列的小举例:

1.非公平锁里面可能是按照优先级来获取的

散列表/哈希表:其实就是键值对

哈希函数:将键和数据下班进行转换的方法,就叫哈希函数

哈希的写操作:

1.先对key做hash操作,返回值就是找到key的下标位置

具体的是

// 先对key做哈希运算 // 这个>>> 表示无符号右移,如果是正数 则和>>一样,表示除以2的n次方; 忽略符号位,空位都以0补齐 (h = key.hashCode()) ^ (h >>> 16)

2.putValue

如果长度不够就扩容(含负载因子)

如果对应的下标没有就吧这个entry放过去

如果已经存在了,则吧原来的key的值和当前的值做对比。如果是一样的,就覆盖;如果不是一样的,就先变成链表,数量到了8个以上就变成红黑树。这就是所谓的哈希冲突

发生哈希碰撞(就是出现了多个相同的哈希值),jdk7是将新的放到头部去,jdk8是放到数组最后面去。哈希碰撞主要是为了避免哈希碰撞拒绝服务攻击(因为在元素放置过程中,如果一个对象哈希冲突, 都被放置到同一个桶里,则会形成一个链表,我们知道链表查询是线性的,查的慢,会严重影响存取的性能。然后导致cpu大量占用)

至于解决哈希冲突的方法方法,有4个方法

  1. 开放地址
  2. 再哈希
  3. 链地址(这个是hashmap现在用的大value链表的,出现重复的就把它们串在同一个list里面。这个方法叫链地址法)
  4. 建立公共溢出区

其中开放地址又分为:

  • 线性探测再散列
  • 二次探测再散列
  • 伪随机探测再散列

开放地址寻址法可以理解为:比如我的key的下标是5,那么我继续往下看看下标为6的有没有数据,有的话,去看看7.如果7没有数据,则吧当前数据插进去。ThreadLoack就是用的开放寻址法

map的getValue

1.寻找下标等等和put一样。

2.明显是如果找到了就先比较下字面值,如果一样则返回走,如果不一样则继续往下查。现在知道为什么哈希冲突会增大查询速度吧?

我们知道链表查询是线性的,查的慢,会严重影响存取的性能。然后导致cpu大量占用

扩容

需要注意的是扩容的大小和重新哈希

大小是原来的2倍

重新哈希:遍历原来的数组,吧原来的key全部重新再hash放进新的数组。重哈希的原因是长度扩大后,hash的规则也会跟着改变。经过扩容,如果原来的数据不再哈希,那么所有的老数据都会挤在前面,后面空荡荡的

回到最开始,为什么哈希查询这么快呢?

因为hash是通过下标查询的,所以是O(1)

第三章:树

树的定义:

1.有且仅有一个特定的称为根

2.n>1时候,其余节点可分为m个互不相交的有限集,每一个集合本身又是一棵树

最外层的叫叶子节点。比如图中的3 、6 、18 、21

由同一个节点衍生出来的节点叫兄弟节点,比如4和6 5和10 18和21

树的最大层级数,叫树的高度或者深度 上图的高度是4

二叉树:在普通树的限制上,再加上每个节点最多只有2个子节点,左边的叫左孩子,右边的叫右孩子。这左右的顺序是固定的

二叉树又分城 满二叉树和完全二叉树

满二叉树:要求叶子节点都在同一行,并且每个非叶子节点都存在左右孩子

完全二叉树:满二叉树的弱化版本。叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。上图是符合的

因为二叉树属于逻辑结构,所以还是要通过物理结构来表述的

二叉查找树:在二叉树的基础上新增:

1.如果左子树不为空,那么这下面的所有子节点的的值都小于这个节点的值

2.如果右子树不为空,那么这下面的所有子节点的值都大于这个节点的值

3.左右子树也是二叉查找树(相当于递归了)-

二叉查找树的好处:对于节点分布相对均衡的二叉树来说,搜索节点的时间复杂度是o(logn)

比如上图要查4 ,先查根节点,发现4比7小,所以继续查5,;发现4比5小 所以查左下角的4.找到了。二叉树分成两半,所以搜索节点的时间复杂度是o(logn)。是不是感觉很像redis的跳表?

因为二叉查找树会维持着左右平衡,所以又叫做二叉平衡树

二叉堆:也维持着相对的顺序,但是只要求父节点比左右孩子大

根据遍历节点的关系:

一棵树,总共由三个部分组成,分别为 根、左节点、右节点。英文简称D、L、R。

所以按照顺序 排列组合有六种:DLR、DRL、LDR、LRD、RLD、RDL

因为先遍历左节点和遍历右节点的顺序是没有本质的区别的,就是左撇子和右撇子的区别。所以真正的就3种组合 6/2=3

前序遍历DLR。顾名思义,从根节点开始,先查左节点,然后查右节点。按照上图就是:先查根节点G。G有左节点D,查D。 D有左节点A。A没有左节点,则回到上一层查D。那么查D的右节点;同理,查到完。。。。。。。。。等等等等。所以总体顺序是 G-->D-->A-->F-->E-->M-->H-->Z

中序LDR。L是左节点,所以先左一路走到底,发现走不下去了,回退一格(即父节点),然后走右节点找最左边的节点。按照图中的顺序是A-->D-->E-->F-->G-->H-->M-->Z

后序LRD。输出它的左孩子,然后输出它的右孩子,最后输出该结点。A-->E-->F-->D-->H-->Z-->M-->G 。需要注意的是查到D的时候,先看到D的右节点是M,但是不是马上查M,而是查最左边的H,因为要走到底嘛

大部分可以通过递归来遍历的,都可以用栈来表示

至于通过栈来遍历的话,可以理解为前序遍历++

比如上图,先放G入栈,找到G的左D入栈,继续找到D的左节点A入栈。A没有左右节点,所以A出栈(栈的特点就是先入先出)。重新回到了D,因为自己已经没什么利用价值了,所以D出栈(这里的出栈原因是,因为这是先一直往左,所以D实际上是没有用的),找到D的儿子F入栈,找到F的儿子E入栈,没用了,然后E出栈,然后F出栈。

整体的顺序是G入栈-->D入栈-->A入栈-->A出栈-->D出栈-->F入栈-->E入栈-->E出栈-->F出栈-->G出栈-->M入栈-->H入栈-->H出栈-->M出栈-->Z入栈-->Z出栈

深度优先遍历:直接走到无路可走再回头看继续走到死

广度优先遍历,大家一起放射性的走,一个深度走一步

拿队列来举例子,

比如上图是G入队-->G出队-->D、M入队-->D、M出队-->A、F、H、Z入队-->A、F、H、Z出队-->E入队-->E出队

二叉堆:二叉堆本质上是完全二叉树,只是多了个最大值的最大堆和最小值的最小堆的概念

最大堆的堆顶是整个堆的最大元素,最大堆任何一个父节点的值,都大于等于它左右孩子节点的值;

最小堆的堆顶是整个堆的最小元素,最小堆任何一个父节点的值,都小于等于它左右孩子节点的值。

Heap Visualization

二叉堆的插入、删除、构建,略

1.插入节点

二叉堆的节点插入,插入位置是完全二叉树的最后一个位置

比如这样图准备插入个1,则先放到7的右子节点去(当然,如果7的左右节点都满了,则跑到8的左节点去,以此类推;如果这一行没有了,则跑到最左边去,即9的左节点),发现1比7小,两者换个位置;发现1比3小,和3换个位置,发现比2小,和2换个位置

2.删除节点

二叉堆的节点删除过程和插入过程正好相反,所删除的是处于堆顶的节点。比如我们删除最小堆的堆顶节点1。目前我看到的好像只能删堆顶,知道为啥不?因为它这个是出栈,先从顶上来搞。

比如要删2,;吧最下面的11放到堆顶去(和增加一样,替换的是完全二叉树的最后一个位置),比较11和3、4的大小,发现3比11小,3、11互换位置;同理,比较11和6、7的大小,和6互换位置;比较11和9 、10的大小,和9互换位置,下面没有可以比的了,完事

本质上都是为了维持二叉堆的结构,即 让所有非叶子节点下沉。找到最大的/最小的,然后放到栈顶,然后所有连着的节点都往下走

因为删除和新增,每次都是对左右节点一半做判断,所以时间复杂度是O(logN)。但是堆的构建就是O(n)了,

解释:

自底向上建堆时: 1.最下层的元素n/2个元素不需要移动,剩下的n/2个元素在上面 2.倒数第二层的n/4个元素需要下沉1层,即n/4 *1 3.倒数第三层的n/8个元素需要下沉2层,即n/8*2 4.倒数第三层的n/16个元素需要下沉3层,即n/16*2 所以Sn=0*(n/2)+1*(n/4)+2*(n/8)+3*(n/16)+.............. 两边乘以2 2Sn=0*(n)+1*(n/2)+2*(n/4)+3*(n/8)+.............. 2Sn-Sn=n Sn=n... 所以时间复杂度为O(n) 熟悉不。。。。典型的高中错位相减

参考自为什么建立一个二叉堆的时间为O(N)而不是O(Nlog(N))? - 知乎

二叉堆是实现堆排序和优先队列的基础

优先队列又分成两种:最大优先队列和最小优先队列

顾名思义,就是不管入队顺序怎么样,出队的那个都是当前队列里面最大/最小的元素

是不是感觉和最大/最小二叉堆很像?入队就是放到堆的末尾,然后浮上去。出队就是把顶给拿走咯

因为二叉堆的上浮起和下沉的时间复杂度都是O(logN),所以优先队列入队的入队和出队也都是O(logN)

第三章:排序算法

可以把算法按照时间复杂度分成

O(n2):

  • 冒泡排序
  • 选择排序
  • 插入排序

O(n logn)

  • 快排
  • 规定排序
  • 堆排序

O(1)

  • 计数排序
  • 桶排序
  • 基数排序

一.冒泡

吧相邻的元素两两对比,然后交换顺序。最大的数放到最右边

冒泡是一种稳定排序,因为不会打乱元素相等时原来的顺序

复杂度分析下

1.两两对比,然后交换 花费O(n)

2.要遍历 n-1轮,所以总体是O(n2)

二.鸡尾酒排序

把相邻的元素两两对比,然后交换顺序。最大的数放到最右边,第二轮的时候吧最小的数放最左边,第三轮的时候第二大的放最右边-1的位置。。。以此类推。因为很像摇可乐,但是为了讲究虚伪的优雅,叫鸡尾酒排序更好听点

优势当然是大部分元素已经有序的情况

优点是特定条件下排序的回合数减少了,缺点当然是代码也差不多加了一倍,因为你往右摇和往左摇都要区分的

复杂度分析下

1.先往左遍历一遍 找到最小的,花费O(n)

2.再往右遍历一遍 找到最大的,花费O(n)

.....

因为总共有n个元素,所以总体花费O(n2)

三.快速排序

分而治之,和以前的砍树一样,每次砍一半,直到砍不下去为止.

平均时间复杂度是O(nLog n):假设有n个元素,每个元素都要被作为基准元素,平均情况下 每个元素需要logN轮才可以。所以是O(nLog n)

最坏的时间复杂度是O(n2),比如基准元素取得不好,每次都是当前未排序的元素里面最大/最小的,这样就达不到分而治之的程度了,只能一边倒

因为快拍每次选完基准元素之后,还要进行再排序,即把大的放到右边,小的放到左边。所以又分成两种元素交换的方法,即双边排序和单边排序

双边排序,

搞2个指针,最左边一个,最右边一个。如果右指针比左边的小,则两者交换位置,如果大,则右指针往左移一位,然后继续比较大小。比到左指针没有比较更小的时候,左指针右移,继续比,直到没有的比为止

单边排序,只要一个左指针,然后依次和右边的来比较,同理,比到左指针没有比较更小的时候,左指针右移,继续比,知道没有的比为止

大部分的递归 都可以用堆来代替,比如上面的单边排序--->只要一个左指针,然后依次和右边的来比较,比到左指针没有比较更小的时候,最左边的出栈,然后最左边下一个数据作为左指针,继续比,直到栈空了为止。

四.堆排序

最大/最小二叉堆本质上可以理解为一个有序的数组,那么也可以通过二叉堆来进行排序

步骤

1.先把无需数组构建成二叉堆,时间复杂度O(n)-----》可以理解为插入到空的二叉堆,n个元素就是O(n)

2.构建最大/最小二叉树。需要n-1次(去掉自己那层)调用二叉堆叶子下移的方法,因为二叉每次遍历一半,所以时间复杂度是(n-1)*logN 即时间复杂度为O(nLog n)

堆排序和快拍的对比:

相同点

1.平均时间复杂度都是O(n log n)

2.都是不稳定排序,打乱了原有相同元素的顺序

不同点

1.快排的最坏时间复杂度是O(n2),即基准数每次选的最小边或者最大的;堆排序最坏的时间复杂度在O(nLog n)

2.快排和递归的平均空间复杂度是O(logn),堆排序是O(1)------------------>以前我误认为快排空间复杂度是O(1)。和时间复杂度相关,每次递归需要的空间是固定的,总体空间复杂度即为递归层数,因此平均/最好空间复杂度为O(logn),最坏空间复杂度为O(n)。         因为堆排序是就地排序,空间复杂度为常数:O(1)

五.计数排序

找出最大数m和最小数n,然后建立m-n+1个有序的格子,统计这些数出现的次数

比如 有数据 5,8,7,10,2,5,6,则建立格子2,3,4,5,6,7,8,9,10 ,统计各个数字出现的次数即最终2*1,3*0,4*0,5*2,6*1,7*1,8*1,9*0,10*1

去掉次数为0的 ,即2,5*2,6,7,8,10,把乘号去掉即 2,5,6,7,8,10

适用于取值范围差别不是很大的情况,性能甚至能超过那些时间复杂度为O(logN)的排序。并且排序不适用于整数

但是如果取值范围差别很大,就很浪费了,比如由数据1,10000 排这2个数,就要建10000个格子。而且无法保持数组原有的顺序,比如2个5的顺序你就没法区分哪个在前面

六.桶排序:

先建立n个桶,这个桶里面装一个区间范围。先把所有数据按区间放入不同的桶。然后再对每个桶内部的元素进行排序,有点类似于分而治之。

区间跨度=(最大值-最小值)/(桶的数量-1)

桶排序可以看做是计数排序缺点的改良版本

桶排序的时间复杂度分析:

1.找到数列最大和最小值,花费O(n)

2.创建n个空桶,花费的也是O(n)

3.把原来的数组都放到桶里面,也是O(n)

4.每个桶做排序, 如果元素分布均匀还是 O(n);如果极不均匀,则是O(nLogN)

5.输出新的排序序列,也是O(n)

因为时间复杂度前面的常数是可以省略的,所以总体的 常规情况分布均匀还是O(n),极端最坏的条件是O(nLogN)

排序算法

平均时间复杂度

最坏时间复杂度

最坏情况

空间复杂度

是否稳定排序(保持顺序)

冒泡

O(n2)

O(n2)

已经有序了还会继续O(n2)

O(1)

稳定

鸡尾酒

O(n2)

O(n2)

已经有序了还会继续O(n2)

O(1)

稳定

快排

O(nLogN)

O(n2)

1.已经有序了,无论是正序还是倒序,还会继续O(n2),就和普通冒泡没区别了

2.所有的元素都相同

O(logN)

不稳定

堆排序

O(nLogN)

O(nLogN)

O(1)-->数组内构建的

不稳定

计数排序

O(n+m)

O(n+m)

最大值m和最小值m的差距过大

o(m)

稳定

桶排序

O(n)

O(nLogN)

第一个桶n-1个元素,第二个桶1个元素

O(n)

稳定

LRU:最近最少使用

redis里面经常有

最初的代码如下:key都没有优化,感觉和限流一样

private static final int ARRAYS_MAX_LENGTH = 4; public static void main(String[] args) { List<Integer> array = new ArrayList<>(); add(1, array); add(2, array); add(3, array); add(4, array); add(5, array); add(6, array); add(7, array); add(8, array); System.out.println(array); } public static void add(int addNum, List<Integer> array) { if (array.size() < ARRAYS_MAX_LENGTH) { array.add(array.size(), addNum); return; } // 如果超过了数组最大的长度,移除最左边的 for (int i = 0; i < array.size(); i++) { if (i < array.size() - 1) { array.set(i, array.get(i + 1)); } else { array.set(i, addNum); } } }

// 如果是用map的话,当然 能被优化空间还有很大

/** * @author PrinceCharimgDong * @description: * @date 2021/12/28 18:55 */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Node { //双向链表 private Node pre; private Node next; private String key; private String value; // 因为属性引用子属性,导致toString方法会不断调用子节点的属性。最终栈溢出。 所以pre和next不能toString出来 @Override public String toString() { return "Node{" + ", key='" + key + '\'' + ", value='" + value + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Node node = (Node) o; return Objects.equals(pre, node.pre) && Objects.equals(next, node.next) && Objects.equals(key, node.key) && Objects.equals(value, node.value); } @Override public int hashCode() { return Objects.hash(pre, next, key, value); } } class LruDemo { private static final int ARRAYS_MAX_LENGTH = 4; private Node head; private Node end; private Map<String, Node> saveDate; public void add(String key, String value) { Node lruDemo = saveDate.get(key); if (null != lruDemo) { return; } lruDemo = Node.builder().key(key).value(value).build(); if (saveDate.size() == 0) { head = lruDemo; end = null; } //如果超过了长度,则去掉第一个 if (saveDate.size() >= ARRAYS_MAX_LENGTH) { String oldFirstKey = head.getKey(); Node node2 = head.getNext(); saveDate.remove(oldFirstKey); // 修改新的第一个数据 head = node2; } // init上一个的next if (saveDate.size() > 1) { String lastKey2 = end.getKey(); Node lastNode2 = saveDate.get(lastKey2); lastNode2.setNext(lruDemo); saveDate.put(lastKey2, lastNode2); lruDemo.setPre(lastNode2); lruDemo.setNext(null); } saveDate.put(key, lruDemo); end = lruDemo; } } public static void main(String[] args) { LruDemo lruDemo = new LruDemo(); lruDemo.add("1", "a"); lruDemo.add("2", "b"); lruDemo.add("3", "c"); lruDemo.add("2", "b"); lruDemo.add("4", "d"); lruDemo.add("5", "e"); lruDemo.add("6", "f"); lruDemo.add("7", "g"); lruDemo.add("7", "g"); lruDemo.add("8", "h"); System.out.println(); }

A星算法==> A*

我们从起点开始,检查其相邻的方格,然后向四周扩展,直至找到目标。

1.拆成二维坐标系,确定起点和重点

2.忽略障碍物!引入常量,E即当前点和终点的最短直线距离。S即当前点和起点的步数。F即起点到终点的距离

3.从起点开始走,走一步计算下下一个

3.每一步找出最小的F

拆红包的比较公平的小技巧:线段切割法和二倍均值法

n倍均值法:把每个人的预期金额*n,最后一次的取余。

比如 100块钱的红包10个人抢

那么第一个人的概率是 100/10*2,范围在0-20,中位数是10

第2个人的概率是 100/10*2,范围在0-20,中位数是10

第n个人的概率是 100/10*2,范围在0-20,中位数是10

最后一个人的范围是 0-(100-前面所有个人金额加起来的值)

缺点:除了最后一次取余抢,任何一次抢到的金额都不会超过人均金额的n倍,且并不是绝对的任意的随机

线段切割法

将金额看成一条线段,线段的长度放大一百倍,即范围是0到M*100,首先需要生成1-(M*100-1) 中间的(N-1)个随机的且不重复的数,可以使用这(N-1)个数去切割线段,切割后的每一份就是红包的金额数。

2022年1月11日15:13:02

《漫画算法:小灰的算法之旅》读后相关推荐

  1. 【总结】Java核心技术36讲知识点大纲(转载)

    Java核心技术36讲知识点总结大纲 1 Java平台的理解 Java的特性,解释运行和编译运行 2 Exception 和 Error 有什么区别 理解Java的异常体系的设计,Throwable ...

  2. 【总结】Java核心技术36讲知识点大纲

    前段时间在极客时间上购买了杨晓峰老师的<Java核心技术36讲>,趁着这段时间有空,对相关知识点做了一个整体的大纲,也对自己所掌握的Java基础进行了一个复习和梳理,若想深入学习,可以购买 ...

  3. 杨晓峰-java核心技术36讲(学习笔记)- 第1讲 | 谈谈你对Java平台的理解?

    杨晓峰-java核心技术36讲(学习笔记) 接下来我会分享杨晓峰-java核心技术36讲的学习笔记,内容较多,补充了其中一些牛人评论,相对详细(仅供个人学习记录整理,希望大家支持正版:https:// ...

  4. 读Java核心技术36讲有感——谈谈对Java的理解,谈谈Exception和Error

    读过杨晓峰老师的36讲之后,想总结下自己的感想,写下来也有助于记忆,方便以后面试查阅和复习.题目所提到的话题本来是两讲,但是由于感想篇幅较短,所以合成一篇来写. 一.谈谈对Java平台的理解: 1.J ...

  5. 《java核心技术36讲》学习笔记-------杨晓峰(极客时间)

    非常荣幸作为晓峰哥的同事,之前就看过这篇文章,重写读一遍,再学习学习.同时也推荐给大家 一.开篇词 初级.中级:java和计算机科学基础.开源框架的使用:高级.专家:java io/nio.并发.虚拟 ...

  6. Java核心技术36讲

    java平台的理解 谈谈你对 Java 平台的理解?"Java 是解释执行",这句话正确么? Java本身是一种面向对象的语音,最显著的特性有两个方面,一个是所谓的"书写 ...

  7. Java核心技术36讲(个人整理)

    今天我要问你的问题是,谈谈你对 Java 平台的理解? "Java 是解释执行",这句话正确吗? Java特性: 面向对象(封装,继承,多态) 平台无关性(JVM运行.class文 ...

  8. Java核心技术36讲 第一讲:Java平台的理解

    java语言 一次编译,到处运行 GC.Garbage Collection JRE: Java Runtime Environment 包含JVM和Java类库等 JDK: Java Develop ...

  9. 杨晓峰Java核心36讲学习笔记

    最近在极客时间上订阅了Oracle首席工程师杨晓峰的Java核心技术36讲, 接下来会对每一课的学习: 记下学习笔记 有不懂的地方继续深入 一些思考或者总结. 下面从第一课开始,Exception和E ...

  10. java核心技术精讲-李兴华-专题视频课程

    java核心技术精讲-101993人已学习 课程介绍         本课程主要读者全面细致的讲解Java编程的所有核心知识,从基础语法.到面向对象以及Java的实际应用进行完整讲解.官方QQ群:61 ...

最新文章

  1. php request payload怎么接收,[问题] PHP接收Request payload传递过来的参数
  2. hexo部署在Github-Page流程
  3. 深入理解Java虚拟机知乎_深入理解Java虚拟机(类文件结构)
  4. 第二轮冲次会议第三次
  5. 你了解京东云区块链吗?点开有详情!
  6. 模糊综合评价的 matlab,模糊综合评价法代码matlab
  7. 计算机操作系统第四版课后习题答案(完整版)
  8. 整理:周鸿祎谈如何写商业计划书
  9. 免费又好用怎么把文字转换成语音呢?分享我常用的3个配音神器
  10. 表格标签-表格基本结构
  11. 360度全景标定方法_一种车辆行驶360度全景行车标定板的制作方法
  12. 【QT】实现贪吃蛇小游戏(附源码)
  13. XSSFWorkbook 设置单元格样式_6.6 使用单元格样式
  14. Docer可视化管理工具Portainer部署
  15. SpringBoot写一个聊天工具
  16. 转移神经网络_神经体系结构转移
  17. Excel 中自定义函数的限制
  18. DevOps ACA 阿里云效持续交付流水线(十)
  19. psm进销存管理系统、供应商管理、进货管理、销售管理、仓库管理、采购记录
  20. 企业组织架构.1___VIE模式

热门文章

  1. Apaceh的访问控制 日志分割 分析
  2. HC-SR04超声波传感器使用
  3. npm ERR! cb() never called! 解决办法
  4. 爱奇艺2020春季校园招聘全面开启!
  5. django mysql 时间_Python Django MySQL,时区、日期、时间戳(USE_TZ=True时的时间存储问题)...
  6. 前后端分离项目token怎么验证_微信端前后端分离开发中token验证和数据的获取...
  7. 巨人征途的成功 依赖于不处不在的海报
  8. matlab使用矩形窗设计一个具有线性相位的低通数字滤波器,用矩形窗设计一个FIR线性相位低通数字滤波器...
  9. 沉浸式状态栏和虚拟键盘冲突
  10. 图书馆管理系统(C++实现)(含自定义数据库操作)