auto commit

This commit is contained in:
CyC2018 2018-07-26 23:12:25 +08:00
parent 8a77f76a2c
commit 41176bb717
7 changed files with 103 additions and 61 deletions

View File

@ -8,6 +8,7 @@
* [三、源码分析](#三源码分析)
* [ArrayList](#arraylist)
* [Vector](#vector)
* [CopyOnWriteArrayList](#copyonwritearraylist)
* [LinkedList](#linkedlist)
* [HashMap](#hashmap)
* [ConcurrentHashMap](#concurrenthashmap)
@ -25,23 +26,23 @@
### 1. Set
- HashSet基于哈希实现支持快速查找但不支持有序性操作例如根据一个范围查找元素的操作。并且失去了元素的插入顺序信息也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的
- HashSet基于哈希实现支持快速查找但不支持有序性操作例如根据一个范围查找元素的操作。并且失去了元素的插入顺序信息也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的
- TreeSet基于红黑树实现支持有序性操作但是查找效率不如 HashSetHashSet 查找时间复杂度为 O(1)TreeSet 则为 O(logN)
- TreeSet基于红黑树实现支持有序性操作但是查找效率不如 HashSetHashSet 查找时间复杂度为 O(1)TreeSet 则为 O(logN)
- LinkedHashSet具有 HashSet 的查找效率,且内部使用链表维护元素的插入顺序。
### 2. List
- ArrayList基于动态数组实现支持随机访问
- ArrayList基于动态数组实现支持随机访问
- Vector和 ArrayList 类似,但它是线程安全的
- Vector和 ArrayList 类似,但它是线程安全的
- LinkedList基于双向链表实现只能顺序访问但是可以快速地在链表中间插入和删除元素。不仅如此LinkedList 还可以用作栈、队列和双向队列。
### 3. Queue
- LinkedList可以用它来支持双向队列;
- LinkedList可以用它来实现双向队列。
- PriorityQueue基于堆结构实现可以用它来实现优先队列。
@ -85,14 +86,14 @@ java.util.Arrays#asList() 可以把数组类型转换为 List 类型。
public static <T> List<T> asList(T... a)
```
如果要将数组类型转换为 List 类型,应该注意的是 asList() 的参数为泛型的变长参数,因此不能使用基本类型数组作为参数,只能使用相应的包装类型数组。
应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的包装类型数组。
```java
Integer[] arr = {1, 2, 3};
List list = Arrays.asList(arr);
```
也可以使用以下方式生成 List。
也可以使用以下方式使用 asList()
```java
List list = Arrays.asList(1,2,3);
@ -235,12 +236,12 @@ public synchronized E get(int index) {
}
```
### 2. ArrayList 与 Vector
### 2. 与 ArrayList 的区别
- Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。最好使用 ArrayList 而不是 Vector因为同步操作完全可以由程序员自己来控制
- Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。
### 3. Vector 替代方案
### 3. 替代方案
为了获得线程安全的 ArrayList可以使用 `Collections.synchronizedList();` 得到一个线程安全的 ArrayList。
@ -255,7 +256,15 @@ List<String> synList = Collections.synchronizedList(list);
List<String> list = new CopyOnWriteArrayList<>();
```
CopyOnWriteArrayList 是一种 CopyOnWrite 容器,从以下源码看出:读取元素是从原数组读取;添加元素是在复制的新数组上。读写分离,因而可以在并发条件下进行不加锁的读取,读取效率高,适用于读操作远大于写操作的场景。
## CopyOnWriteArrayList
### 读写分离
写操作在一个复制的数组上进行,读操作还是在原始数组中进行,读写分离,互不影响。
写操作需要加锁,防止同时并发写入时导致的写入数据丢失。
写操作结束之后需要把原始数组指向新的复制数组。
```java
public boolean add(E e) {
@ -264,7 +273,7 @@ public boolean add(E e) {
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
@ -276,13 +285,26 @@ public boolean add(E e) {
final void setArray(Object[] a) {
array = a;
}
```
```java
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
```
### 适用场景
CopyOnWriteArrayList 在写操作的同时允许读操作,大大提高了读操作的性能,因此很适合读多写少的应用场景。
但是 CopyOnWriteArrayList 有其缺陷:
- 内存占用:在写操作时需要复制一个新的数组,使得内存占用为原来的两倍左右;
- 数据不一致:读操作不能读取实时性的数据,因为部分写操作的数据还未同步到读数组中。
所以 CopyOnWriteArrayList 不适合内存敏感以及对实时性要求很高的场景。
## LinkedList
### 1. 概览

View File

@ -871,7 +871,9 @@ $ ls -al /etc | less
## 提取指令
cut 对数据进行切分,取出想要的部分。切分过程一行一行地进行。
cut 对数据进行切分,取出想要的部分。
切分过程一行一行地进行。
```html
$ cut
@ -891,7 +893,7 @@ root pts/1 192.168.201.254 Thu Feb 5 22:37 - 23:53 (01:16)
$ last | cut -d ' ' -f 1
```
示例 2将 export 输出的息,取出第 12 字符以后的所有字符串。
示例 2将 export 输出的息,取出第 12 字符以后的所有字符串。
```html
$ export
@ -906,7 +908,7 @@ $ export | cut -c 12
## 排序指令
**sort** 进行排序。
**sort** 用于排序。
```html
$ sort [-fbMnrtuk] [file or stdin]
@ -1204,7 +1206,7 @@ pid_t wait(int *status)
如果成功,返回被收集的子进程的进程 ID如果调用进程没有子进程调用就会失败此时返回 -1同时 errno 被置为 ECHILD。
参数 status 用来保存被收集的子进程退出时的一些状态,如果我们对这个子进程是如何死掉的毫不在意,只想把这个子进程消灭掉,可以设置这个参数为 NULL
参数 status 用来保存被收集的子进程退出时的一些状态,如果对这个子进程是如何死掉的毫不在意,只想把这个子进程消灭掉,可以设置这个参数为 NULL
```c
pid = wait(NULL);
@ -1218,7 +1220,7 @@ pid_t waitpid(pid_t pid, int *status, int options)
作用和 wait() 完全相同,但是多了两个可由用户控制的参数 pid 和 options。
pid 参数指示一个子进程的 ID表示只关心这个子进程退出 SIGCHLD 信号。如果 pid=-1 时,那么和 wait() 作用相同,都是关心所有子进程退出的 SIGCHLD 信号。
pid 参数指示一个子进程的 ID表示只关心这个子进程退出 SIGCHLD 信号。如果 pid=-1 时,那么和 wait() 作用相同,都是关心所有子进程退出的 SIGCHLD 信号。
options 参数主要有 WNOHANG 和 WUNTRACED 两个选项WNOHANG 可以使 waitpid() 调用变成非阻塞的,也就是说它会立即返回,父进程可以继续执行其它任务。
@ -1238,7 +1240,7 @@ options 参数主要有 WNOHANG 和 WUNTRACED 两个选项WNOHANG 可以使 w
系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。
要消灭系统中大量的僵尸进程,只需要将其父进程杀死,此时所有的僵尸进程就会变成孤儿进程,从而被 init 所收养,这样 init 就会释放所有的僵死进程所占有的资源,从而结束僵尸进程。
要消灭系统中大量的僵尸进程,只需要将其父进程杀死,此时僵尸进程就会变成孤儿进程,从而被 init 所收养,这样 init 就会释放所有的僵死进程所占有的资源,从而结束僵尸进程。
# 参考资料

View File

@ -91,7 +91,7 @@ ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE
主要用于实现分布式事务,分布式事务指的是事务操作跨越多个节点,并且要求满足事务的 ACID 特性。
通过引入协调者Coordinator来调度参与者的行为并最终决定这些参与者是否要真正执行事务。
通过引入协调者Coordinator来调度参与者的行为并最终决定这些参与者是否要真正执行事务。
## 运行过程

View File

@ -216,7 +216,9 @@ HTTP 重定向负载均衡服务器收到 HTTP 请求之后会返回服务器的
### 2. DNS 重定向
使用 DNS 作为负载均衡器,根据负载情况返回不同服务器的 IP 地址。大型网站基本使用了这种方式做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。
使用 DNS 作为负载均衡器,根据负载情况返回不同服务器的 IP 地址。
大型网站基本使用了这种方式做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。
缺点:

View File

@ -90,12 +90,20 @@
## 题目描述
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组 {2, 3, 1, 0, 2, 5},那么对应的输出是第一个重复的数字 2。
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
```html
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
```
## 解题思路
要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
这种数组元素在 [0, n-1] 范围内的问题,可以将值为 i 的元素放到第 i 个位置上。
以 (2, 3, 1, 0, 2, 5) 为例:
@ -158,7 +166,11 @@ Given target = 20, return false.
## 解题思路
从右上角开始查找。因为矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
从右上角开始查找。矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
当前元素的查找区间为左下角的所有元素,例如元素 12 的查找区间如下:
<div align="center"> <img src="../pics//026d3cb4-67f7-4a83-884d-8032f57ec446.png" width="250"/> </div><br>
复杂度O(M + N) + O(1)
@ -261,25 +273,14 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
}
```
### 使用 Collections.reverse()
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> ret = new ArrayList<>();
while (listNode != null) {
ret.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(ret);
return ret;
}
```
### 使用头插法
利用链表头插法为逆序的特点。
头结点和第一个节点的区别:头结点是在头插法中使用的一个额外节点,这个节点不存储值;第一个节点就是链表的第一个真正存储值的节点。
头结点和第一个节点的区别:
- 头结点是在头插法中使用的一个额外节点,这个节点不存储值;
- 第一个节点就是链表的第一个真正存储值的节点。
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -302,6 +303,20 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
}
```
### 使用 Collections.reverse()
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> ret = new ArrayList<>();
while (listNode != null) {
ret.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(ret);
return ret;
}
```
# 7. 重建二叉树
[NowCoder](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
@ -322,22 +337,23 @@ inorder = [9,3,15,20,7]
前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。
```java
private Map<Integer, Integer> inOrderNumsIndexs = new HashMap<>(); // 缓存中序遍历数组的每个值对应的索引
// 缓存中序遍历数组的每个值对应的索引
private Map<Integer, Integer> inOrderNumsIndexs = new HashMap<>();
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
for (int i = 0; i < in.length; i++)
inOrderNumsIndexs.put(in[i], i);
return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return reConstructBinaryTree(pre, 0, pre.length - 1, 0, in.length - 1);
}
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in, int inL, int inR) {
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL, int inR) {
if (preL > preR)
return null;
TreeNode root = new TreeNode(pre[preL]);
int inIndex = inOrderNumsIndexs.get(root.val);
int leftTreeSize = inIndex - inL;
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, in, inL, inL + leftTreeSize - 1);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, in, inL + leftTreeSize + 1, inR);
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL, inL + leftTreeSize - 1);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1, inR);
return root;
}
```
@ -350,16 +366,6 @@ private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in,
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
## 解题思路
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
<div align="center"> <img src="../pics//cb0ed469-27ab-471b-a830-648b279103c8.png" width="250"/> </div><br>
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
<div align="center"> <img src="../pics//e143f6da-d114-4ba4-8712-f65299047fa2.png" width="250"/> </div><br>
```java
public class TreeLinkNode {
int val;
@ -373,6 +379,16 @@ public class TreeLinkNode {
}
```
## 解题思路
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
<div align="center"> <img src="../pics//cb0ed469-27ab-471b-a830-648b279103c8.png" width="250"/> </div><br>
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
<div align="center"> <img src="../pics//e143f6da-d114-4ba4-8712-f65299047fa2.png" width="250"/> </div><br>
```java
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode.right != null) {
@ -398,7 +414,7 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) {
## 题目描述
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。队列中的元素为 int 类型。
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。
## 解题思路
@ -442,7 +458,7 @@ public int pop() throws Exception {
<div align="center"> <img src="../pics//a0df8edc-581b-4977-95c2-d7025795b899.png" width="300"/> </div><br>
递归方法是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,避免重复求解子问题。
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
```java
public int Fibonacci(int n) {
@ -521,11 +537,11 @@ public int JumpFloor(int n) {
```java
public int JumpFloor(int n) {
if (n <= 1)
if (n <= 2)
return n;
int pre2 = 0, pre1 = 1;
int result = 0;
for (int i = 1; i <= n; i++) {
int pre2 = 1, pre1 = 2;
int result = 1;
for (int i = 2; i < n; i++) {
result = pre2 + pre1;
pre2 = pre1;
pre1 = result;

View File

@ -70,7 +70,7 @@
一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
可以通过数据库备份和恢复来实现,在系统发生溃时,使用备份的数据库进行数据恢复。
可以通过数据库备份和恢复来实现,在系统发生溃时,使用备份的数据库进行数据恢复。
----
@ -79,9 +79,9 @@
- 只有满足一致性,事务的执行结果才是正确的。
- 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时要只要能满足原子性,就一定能满足一致性。
- 在并发的情况下,多个事务并发执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
- 事务满足持久化是为了能应对数据库溃的情况。
- 事务满足持久化是为了能应对数据库溃的情况。
<div align="center"> <img src="../pics//35650b4b-efa1-49ba-9680-19837027cfc9.png" width="500"/> </div><br>
<div align="center"> <img src="../pics//a58e294a-615d-4ea0-9fbf-064a6daec4b2.png" width="400"/> </div><br>
## AUTOCOMMIT

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB