提交 37eda90b 编写于 作者: W wizardforcel

2019-11-28 00:19:00

上级 620bf7b4
...@@ -2,21 +2,21 @@ ...@@ -2,21 +2,21 @@
> 原文: [https://javatutorial.net/difference-between-hashmap-and-treemap-in-java](https://javatutorial.net/difference-between-hashmap-and-treemap-in-java) > 原文: [https://javatutorial.net/difference-between-hashmap-and-treemap-in-java](https://javatutorial.net/difference-between-hashmap-and-treemap-in-java)
在本文中,我将解释 java [HashMap](https://javatutorial.net/java-hashmap-example) 和 java [TreeMap](https://javatutorial.net/java-treemap-example) 之间的区别 在本文中,我将解释 java [`HashMap`](https://javatutorial.net/java-hashmap-example)和 java [`TreeMap`](https://javatutorial.net/java-treemap-example)之间的区别
尽管两者都实现了 Map 接口并提供了大多数相同的功能,但是 HashMap 和 TreeMap 具有不同的实现。 最重要的区别是通过条目进行[迭代的顺序。](https://javatutorial.net/java-iterate-hashmap-example) 尽管两者都实现了`Map`接口并提供了大多数相同的功能,但是`HashMap``TreeMap`具有不同的实现。 最重要的区别是通过条目进行[迭代的顺序](https://javatutorial.net/java-iterate-hashmap-example)
查看下表,直观了解 HashMap 和 TreeMap 之间的区别 查看下表,直观了解`HashMap``TreeMap`之间的区别
![Differences between HashMap and TreeMap in Java](img/efc320eb579294e6d9ab67535f116599.jpg) ![Differences between HashMap and TreeMap in Java](img/efc320eb579294e6d9ab67535f116599.jpg)
Java 中 HashMap 和 TreeMap 之间的区别 Java 中`HashMap``TreeMap`之间的区别
## `HashMap`和`TreeMap`之间的主要区别 ## `HashMap`和`TreeMap`之间的主要区别
**TreeMap**[SortedMap](https://javatutorial.net/java-sortedmap-example) 的示例,由 Red-Black 树实现,这意味着对键的顺序进行了排序。 遍历键时,您可以依靠它们会井然有序的事实。 键的顺序由元素的`compareTo()`方法或外部提供的[比较器](https://javatutorial.net/java-comparator-example)确定。 `TreeMap`[`SortedMap`](https://javatutorial.net/java-sortedmap-example)的示例,由红黑树实现,这意味着对键的顺序进行了排序。 遍历键时,您可以依靠它们会井然有序的事实。 键的顺序由元素的`compareTo()`方法或外部提供的[比较器](https://javatutorial.net/java-comparator-example)确定。
**HashMap** 则不做任何保证。 它由哈希表实现。 因此,当迭代 HashMap 的键时,您不能确定它们将以什么顺序排列。 `HashMap`则不做任何保证。 它由哈希表实现。 因此,当迭代`HashMap`的键时,您不能确定它们将以什么顺序排列。
看下面的例子: 看下面的例子:
...@@ -84,16 +84,16 @@ TreeMap iteration order ======= ...@@ -84,16 +84,16 @@ TreeMap iteration order =======
77 = Y 77 = Y
``` ```
如您所见,在 HashMap 上进行迭代时,我们以“随机”顺序获得条目。 另一方面,TreeMap 迭代以其自然顺序返回条目。 如您所见,在`HashMap`上进行迭代时,我们以“随机”顺序获得条目。 另一方面,`TreeMap `迭代以其自然顺序返回条目。
## 实现复杂度差异 ## 实现复杂度差异
由于 HashMap 实现的复杂度为 O(1),因此通常可以认为 HashMap 效率更高,因此无论您何时在乎键的顺序,都可以使用它。 另一方面,TreeMap 中获取,放置和删除操作的复杂度为 O(log(n)) 由于`HashMap`实现的复杂度为`O(1)`,因此通常可以认为`HashMap`效率更高,因此无论您何时在乎键的顺序,都可以使用它。 另一方面,`TreeMap`中获取,放置和删除操作的复杂度为 `O(log n)`
## 允许的键和值的差异 ## 允许的键和值的差异
另一个重要的区别是,键和值允许使用 HashMap null 值,而 TreeMap 仅允许将 null 用作其值。 另一个重要的区别是,`HashMap`允许使用`null`键和值,而`TreeMap`仅允许将`null`用作其值。
## 同步(无差异) ## 同步(无差异)
请注意,两个实现都不同步,这意味着在这些映射上进行操作不是线程安全的。 如果需要线程安全的 Map,则可能要从 java.util.concurrent 包中选择 ConcurrentHashMap 类。 这是 Map 的线程安全实现,比`Collections.synchronizedMap(Map&lt;K,V&gt; m)`提供更好的并发性 请注意,两个实现都不同步,这意味着在这些映射上进行操作不是线程安全的。 如果需要线程安全的`Map`,则可能要从`java.util.concurrent`包中选择`ConcurrentHashMap`类。 这是`Map`的线程安全实现,比`Collections.synchronizedMap(Map<K,V> m)`提供更好的并发性
\ No newline at end of file \ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
> 原文: [https://javatutorial.net/graphs-java-example](https://javatutorial.net/graphs-java-example) > 原文: [https://javatutorial.net/graphs-java-example](https://javatutorial.net/graphs-java-example)
通常由顶点和弧线组成。 有时,它们也称为节点(而不是顶点)和边(而不是弧)。 为了本教程的缘故,我将使用节点和边作为参考。 图通常由顶点和弧线组成。 有时,它们也称为节点(而不是顶点)和边(而不是弧)。 为了本教程的缘故,我将使用节点和边作为参考。
![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg) ![java-featured-image](img/e0db051dedc1179e7424b6d998a6a772.jpg)
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
![Graphs](img/e7be6f3fc7788ad7d4de72f0db9ff8e5.jpg) ![Graphs](img/e7be6f3fc7788ad7d4de72f0db9ff8e5.jpg)
可视化 图可视化
在许多情况下,节点和边被分配了值。 一个非常有用的图的著名示例是,当节点代表城市并且边沿代表这两个节点(或与此有关的城市)之间的距离时。 这样的例子可以在下面看到: 在许多情况下,节点和边被分配了值。 一个非常有用的图的著名示例是,当节点代表城市并且边沿代表这两个节点(或与此有关的城市)之间的距离时。 这样的例子可以在下面看到:
...@@ -18,13 +18,13 @@ ...@@ -18,13 +18,13 @@
从上图判断,很容易理解它代表什么,也很容易阅读。 芝加哥到纽约的距离是 791.5 英里,纽约和华盛顿特区的距离是 227.1 英里。 从上图判断,很容易理解它代表什么,也很容易阅读。 芝加哥到纽约的距离是 791.5 英里,纽约和华盛顿特区的距离是 227.1 英里。
这只是一个简单的示例,说明如何使用图很有用,但是还有更多示例。 这只是一个简单的示例,说明如何使用图很有用,但是还有更多示例。
图的其他有用示例可能是表示家谱,facebook 联系人,甚至是旅行路线。 图的其他有用示例可能是表示家谱,facebook 联系人,甚至是旅行路线。
## 无向图 ## 无向图
当图无向时,这意味着可以在两个方向上遍历边。 当图无向时,这意味着可以在两个方向上遍历边。
![Undirected graph](img/13fc61c8f8cc7127a460a61277978a9e.jpg) ![Undirected graph](img/13fc61c8f8cc7127a460a61277978a9e.jpg)
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
## 有向图 ## 有向图
定向图时,这意味着只能沿其“指向”的方向遍历这些边。 定向图时,这意味着只能沿其“指向”的方向遍历这些边。
![Directed graph](img/d925c10d009f3ac8a8168d9036caa201.jpg) ![Directed graph](img/d925c10d009f3ac8a8168d9036caa201.jpg)
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
## Java 中的图实现 ## Java 中的图实现
**Node.java** `Node.java`
```java ```java
import java.util.*; import java.util.*;
...@@ -79,17 +79,17 @@ public class Node { ...@@ -79,17 +79,17 @@ public class Node {
} }
``` ```
Node.java 有 3 个方法和 1 个构造函数。 `Node.java`有 3 个方法和 1 个构造函数。
**getNodeId()**仅返回每个节点的 ID。 `getNodeId()`仅返回每个节点的 ID。
**addNeighbour(Edge e)**通过边创建连接,该边作为参数传递到另一个节点。 这是通过将指定的边添加到 Node 类的边列表中来完成的。 **注意**,存在一个 if 条件,用于检查此节点的当前边中是否已经存在指定的边 **e** `addNeighbour(Edge e)`通过边创建连接,该边作为参数传递到另一个节点。 这是通过将指定的边添加到`Node`类的边列表中来完成的。 **注意**,存在一个`if`条件,用于检查此节点的当前边中是否已经存在指定的边`e`
**getNeighbours()**仅用于显示目的。 查看**输出**,以查看此方法显示信息的精确程度。 `getNeighbours()`仅用于显示目的。 查看**输出**,以查看此方法显示信息的精确程度。
构造函数将 **id** 作为参数。 构造函数将`id`作为参数。
**Edge.java** `Edge.java`
```java ```java
public class Edge { public class Edge {
...@@ -132,23 +132,23 @@ public class Edge { ...@@ -132,23 +132,23 @@ public class Edge {
``` ```
Edge.java 有 6 个方法和 1 个构造函数。 `Edge.java`有 6 个方法和 1 个构造函数。
**getId()**仅返回当前边的 ID。 `getId()`仅返回当前边的 ID。
**getStart()**返回边从其开始的 Node 对象。 `getStart()`返回边从其开始的`Node`对象。
**getIdOfStartNode()**返回边从其开始的 Node 对象的 ID。 `getIdOfStartNode()`返回边从其开始的`Node`对象的 ID。
**getEnd()**返回边“停止”在的 Node 对象。 `getEnd()`返回边“停止”在的`Node`对象。
**getIdOfEndNode()**返回边“停止”在的 Node 对象的 ID。 `getIdOfEndNode()`返回边“停止”在的`Node`对象的 ID。
**getWeight()**获取当前 Node 对象的权重。 `getWeight()`获取当前`Node`对象的权重。
**Edge** 构造函数采用 4 个参数,并使用它们初始化构造函数。 `Edge`构造函数采用 4 个参数,并使用它们初始化构造函数。
**Graph.java** `Graph.java`
```java ```java
import java.util.*; import java.util.*;
...@@ -172,15 +172,15 @@ public class Graph { ...@@ -172,15 +172,15 @@ public class Graph {
} }
``` ```
Graph.java 只有 3 个方法,没有构造函数。 `Graph.java`只有 3 个方法,没有构造函数。
**checkForAvailability()**检查是否有多个节点。 如果节点数不超过 1 个,则无法建立连接,因为节点本身不能具有优势。 它**必须**与另一个节点建立连接。 `checkForAvailability()`检查是否有多个节点。 如果节点数不超过 1 个,则无法建立连接,因为节点本身不能具有优势。 它**必须**与另一个节点建立连接。
**createNode(Node node)**接受类型为 Node 的参数,并将该节点添加到节点 List 中。 添加节点后,当前图形会将节点数增加 1。这样,我们就可以在某个时候将 **checkForAvailability()**方法评估为 true `createNode(Node node)`接受类型为`Node`的参数,并将该节点添加到节点`List`中。 添加节点后,当前图会将节点数增加 1。这样,我们就可以在某个时候将`checkForAvailability()`方法评估为`true`
**getNumberOfNodes()**返回节点数。 `getNumberOfNodes()`返回节点数。
**Main.java** `Main.java`
```java ```java
public class Main { public class Main {
...@@ -211,11 +211,11 @@ public class Main { ...@@ -211,11 +211,11 @@ public class Main {
``` ```
Main.java 只有一个 main 方法。 `Main.java`只有一个`main`方法。
main 方法中创建一个图形。 之后,将创建 3 个 Node 实例。 然后,使用 **createNode(Node 节点)**方法将这些 Node 实例添加到图形中。 之后,将创建 2 个 Edge 实例。 第一个将节点 1 连接到节点 2。第二个将节点 1 连接到节点 3。 `main`方法中创建一个图。 之后,将创建 3 个`Node`实例。 然后,使用`createNode(Node node)`方法将这些`Node`实例添加到图中。 之后,将创建 2 个`Edge`实例。 第一个将节点 1 连接到节点 2。第二个将节点 1 连接到节点 3。
此后,存在一个 if 条件,该条件检查节点数是否大于 1,如果超过,则将“ Neighbour”添加​​到 node1。 (e12 是连接 node1 和 node2 的边。)(e13 是连接 node1 和 node3 的边)。 此后,存在一个`if`条件,该条件检查节点数是否大于 1,如果超过,则将`Neighbour`添加​​到`node1`。 (`e12`是连接`node1``node2`的边。)(`e13`是连接`node1``node3`的边)。
**输出** **输出**
...@@ -240,6 +240,6 @@ ID of the second node: 3 ...@@ -240,6 +240,6 @@ ID of the second node: 3
![Visualisation of a graph](img/32c470f049af89a27d47c45d733e4f59.jpg) ![Visualisation of a graph](img/32c470f049af89a27d47c45d733e4f59.jpg)
**问题:**是上述程序生成的**无向**还是**有向**图? 如果它生成未定义的**图**,您可以修改 API 来生成**定向的**图吗? 如果生成**有向**形,您是否可以修改 API 以生成**无向**一个 **问题:**是上述程序生成的**无向**还是**有向**图? 如果它生成未定义的**图**,您可以修改 API 来生成**定向的**图吗? 如果生成**有向**,您是否可以修改 API 以生成**无向**
**答案:**上面的图产生一个**定向的**图,因为顾名思义,弧线“指向”某个位置。 要使其成为**无向**,您只需删除圆弧的“箭头”,然后将其作为一条简单的线即可。 就像下面的图片代表**无向**图一样。 **答案:**上面的图产生一个**定向的**图,因为顾名思义,弧线“指向”某个位置。 要使其成为**无向**,您只需删除圆弧的“箭头”,然后将其作为一条简单的线即可。 就像下面的图片代表**无向**图一样。
\ No newline at end of file
...@@ -16,11 +16,11 @@ ...@@ -16,11 +16,11 @@
### 使用栈数据结构实现 DFS ### 使用栈数据结构实现 DFS
Node.java 代表上图中的每个“球”或“圆”。 它有一个 **值** ,它代表每个球的“值”。 它也有一个名为 **Visited** 的布尔变量,顾名思义,它表示遍历是否访问了 Node。 第三个实例变量 Node 类具有一个 ArrayList,它表示当前节点 **_ 与 _** 的所有相邻节点(或相邻节点)。 (如果您想了解有关 ArrayList 的更多信息,可以查看[本教程](https://javatutorial.net/java-arraylist-example)。) `Node.java`代表上图中的每个“球”或“圆”。 它有一个**值** ,它代表每个球的“值”。 它也有一个名为`Visited`的布尔变量,顾名思义,它表示遍历是否访问了`Node`。 第三个实例变量`Node`类具有一个`ArrayList`,它表示当前节点与的所有相邻节点(或相邻节点)。 (如果您想了解有关`ArrayList`的更多信息,可以查看[本教程](https://javatutorial.net/java-arraylist-example)。)
就此类中的方法而言,有一个简单的构造函数(该函数接受一个值并创建一个空的 ArrayList),Setter 和 Getter 方法以及允许添加相邻 Node 的方法。 就此类中的方法而言,有一个简单的构造函数(该函数接受一个值并创建一个空的`ArrayList`),Setter 和 Getter 方法以及允许添加相邻`Node`的方法。
**Node.java** `Node.java`
```java ```java
import java.util.*; import java.util.*;
...@@ -61,11 +61,11 @@ public class Node{ ...@@ -61,11 +61,11 @@ public class Node{
} }
``` ```
**DFS.java** `DFS.java`
此类只有一种方法:解决方案。 此类只有一种方法:解决方案。
它使用栈数据结构,并以节点为元素。 它将指定的元素添加到节点,然后将其标记为已访问。 在那之后,有一个 while 循环,不断检查栈是否为空。 如果不是,则从栈中删除一个元素,获取要删除的元素的邻居。 然后,存在另一个循环,其目的是将每个邻居节点标记为已访问,并将该邻居节点添加到栈中。 它使用栈数据结构,并以节点为元素。 它将指定的元素添加到节点,然后将其标记为已访问。 在那之后,有一个`while`循环,不断检查栈是否为空。 如果不是,则从栈中删除一个元素,获取要删除的元素的邻居。 然后,存在另一个循环,其目的是将每个邻居节点标记为已访问,并将该邻居节点添加到栈中。
```java ```java
import java.util.*; import java.util.*;
...@@ -92,9 +92,9 @@ public class DFS { ...@@ -92,9 +92,9 @@ public class DFS {
} }
``` ```
**Main.java** `Main.java`
在此类中,主要方法是创建 Node 类的 8 个实例并传递一些值。 (请记住,下面的示例使用上图(图像)。我们将不同的节点作为邻居添加到不同的节点。此后,我们从 node5 开始并遍历它)。 在此类中,主要方法是创建`Node`类的 8 个实例并传递一些值。 (请记住,下面的示例使用上图(图像)。我们将不同的节点作为邻居添加到不同的节点。此后,我们从`node5`开始并遍历它)。
```java ```java
import java.util.*; import java.util.*;
......
...@@ -29,45 +29,45 @@ ...@@ -29,45 +29,45 @@
## 不同类型的算法复杂度 ## 不同类型的算法复杂度
* ### 恒定时间:O(1) * ### 恒定时间:`O(1)`
如果时间量不取决于输入大小,则可以说算法大小以恒定时间运行。 如果时间量不取决于输入大小,则可以说算法大小以恒定时间运行。
一个例子是从数组访问元素。 您只需“调用”数组的索引即可访问数组的元素。 一个例子是从数组访问元素。 您只需“调用”数组的索引即可访问数组的元素。
* ### 线性时间:O(n) * ### 线性时间:`O(n)`
线性时间是指算法取决于的输入大小。 如果输入大小为 n ,则复杂度也将为 n。 线性时间是指算法取决于的输入大小。 如果输入大小为 n ,则复杂度也将为 n。
具有这种时间复杂度的算法的一个著名示例是线性搜索。 具有这种时间复杂度的算法的一个著名示例是线性搜索。
* ### 对数时间:O(log n) * ### 对数时间:`O(log n)`
如果执行时间与输入大小的对数成正比,则可以说该算法以对数时间运行。 如果执行时间与输入大小的对数成正比,则可以说该算法以对数时间运行。
这种时间复杂度的算法的一个著名示例是 Binary Search 这种时间复杂度的算法的一个著名示例是二分搜索
* ### 二次时间:O(n &lt;sup&gt;2&lt;/sup&gt; * ### 二次时间:`O(n^2)`
二次时间是指执行时间为输入大小的平方。 二次时间是指执行时间为输入大小的平方。
例如冒泡排序,选择排序,插入排序。 例如冒泡排序,选择排序,插入排序。
* ### “大欧米茄”的定义 * ### “大 Ω”的定义
大欧米茄,也称为下界,用Ω符号表示。 大欧米茄,也称为下界,用`Ω`符号表示。
## 大 O ## 大 O
如果执行时间与输入大小的对数成正比,则可以说该算法以对数时间运行。 例如,如果 Java 中有一个数组,其中包含 5 个苹果,并且您需要打印每个苹果,则该数组将为 O(5)或换句话说,为 O(数组的长度)或 O(n) 如果执行时间与输入大小的对数成正比,则可以说该算法以对数时间运行。 例如,如果 Java 中有一个数组,其中包含 5 个苹果,并且您需要打印每个苹果,则该数组将为`O(5)`或换句话说,为`O(数组长度)``O(n)`
这种时间复杂度的算法的一个著名示例是 Binary Search 这种时间复杂度的算法的一个著名示例是二分搜索
## 大 Θ ## 大 Θ
如果 T(n)是Θ(f(n)),则意味着 T(n)增长(精确)与 f(n)一样快。 n + n 仍然是 n。 是不是有点满嘴? 让我们尝试一个更简单的解释。 如果`T(n)``Θ(f(n))`,则意味着`T(n)`增长(精确)与`f(n)`一样快。`n + n`仍然是 n。 是不是有点满嘴? 让我们尝试一个更简单的解释。
您可以将 Big Theta 视为: 您可以将大 Θ 视为:
“花费的时间不会超过且不短于” “花费的时间不会超过且不短于”
...@@ -83,9 +83,9 @@ int sumArray(int[] aiNumbers) ...@@ -83,9 +83,9 @@ int sumArray(int[] aiNumbers)
} }
``` ```
该程序的复杂度只是 aiNumbers.length。 因此,如果此数组的长度为 4,则复杂度为 4。如果 aiNumbers.length 为 6,则复杂度为 6。 该程序的复杂度只是`aiNumbers.length`。 因此,如果此数组的长度为 4,则复杂度为 4。如果`aiNumbers.length`为 6,则复杂度为 6。
复杂度是 aiNumbers.length 的原因是因为它会循环 aiNumbers.length 次。 因此,复杂度为 O(N) 复杂度是`aiNumbers.length`的原因是因为它会循环`aiNumbers.length`次。 因此,复杂度为`O(N)`
```java ```java
N = in.length; N = in.length;
...@@ -97,7 +97,7 @@ while (i < N) { ...@@ -97,7 +97,7 @@ while (i < N) {
} }
``` ```
上面程序的复杂度为 N * N,即 N 乘以 2 的幂。这是因为 for 循环每次将运行 N 次,而整个循环将运行 N 次。 因此,N *N。因此,该算法的复杂度是二次(O(n &lt;sup&gt;2&lt;/sup&gt; 上面程序的复杂度为`N * N`,即 N 乘以 2 的幂。这是因为`for`循环每次将运行 N 次,而整个循环将运行 N 次。 因此,`N *N`。因此,该算法的复杂度是二次(`O(n^2)`
```java ```java
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
...@@ -109,13 +109,13 @@ for (int i = 0; i < n; i++) { ...@@ -109,13 +109,13 @@ for (int i = 0; i < n; i++) {
} }
``` ```
在上面的示例中,算法的时间复杂度为 n 。 这样做的原因是因为有 2 个循环 n 次循环– n + n。 简而言之,n + n 就是 n 。 在上面的示例中,算法的时间复杂度为 n 。 这样做的原因是因为有 2 个循环 n 次循环`n + n`。 简而言之,`n + n`就是 n 。
## 每种算法的可视化表示 ## 每种算法的可视化表示
![Visual Represantion](img/75d78d34a85f1639c3ccd6bff1bb4759.jpg) ![Visual Represantion](img/75d78d34a85f1639c3ccd6bff1bb4759.jpg)
视觉修复 视觉表示
图片来源: [https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/](https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/) 图片来源: [https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/](https://adrianmejia.com/most-popular-algorithms-time-complexity-every-programmer-should-know-free-online-tutorial-course/)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册