mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-10 14:36:06 +00:00
Update ru translation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Представление двоичного дерева с помощью массивом
|
||||
# Представление двоичного дерева с помощью массива
|
||||
|
||||
При представлении в виде списка единицей хранения двоичного дерева является узел `TreeNode`, а узлы соединяются между собой указателями. В предыдущем разделе были рассмотрены основные операции с двоичным деревом, представленным в виде списка.
|
||||
|
||||
@@ -8,61 +8,153 @@
|
||||
|
||||
Сначала рассмотрим простой пример. Если дано идеальное двоичное дерево и все его узлы хранятся в массиве в порядке обхода по уровням, то каждому узлу соответствует уникальный индекс массива.
|
||||
|
||||
На основе свойств обхода по уровням можно вывести формулу отображения между индексом родительского узла и индексами дочерних узлов: **если индекс узла равен $i$, то индекс его левого дочернего узла равен $2i + 1$, а индекс правого дочернего узла равен $2i + 2$**. На рисунке ниже показаны отношения отображения между индексами различных узлов.
|
||||
На основе свойств обхода по уровням можно вывести формулу соответствия между индексами родительского и дочерних узлов: **если индекс узла равен $i$, то индекс его левого дочернего узла равен $2i + 1$, а правого -- $2i + 2$**. На рис. 7.12 показаны отношения соответствия между индексами узлов.
|
||||
|
||||
<!-- 🔴 俄文版缺失图片 -->
|
||||
<!-- 中文原文: -->
|
||||

|
||||
|
||||
**Роль формулы отображения эквивалентна ссылкам на узлы (указателям) в списке**. Для любого узла в массиве мы можем получить доступ к его левому (правому) дочернему узлу с помощью формулы отображения.
|
||||
**Формула соответствия играет роль, аналогичную ссылкам (указателям) в списке**. Имея любой узел в массиве, можно с помощью формулы получить доступ к его левому и правому дочерним узлам.
|
||||
|
||||
## Представление произвольного двоичного дерева
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:完美二叉树是一个特例,在二叉树的中间层通常存在许多 `None` 。由于层序遍历序列并不包含这些 `None` ,因此我们无法仅凭该序列来推测 `None` 的数量和分布位置。**这意味着存在多种二叉树结构都符合该层序遍历序列**。 -->
|
||||
Идеальное двоичное дерево является частным случаем. Обычно на средних уровнях двоичного дерева присутствует много пустых значений `None`. Но последовательность обхода по уровням не содержит этих `None`, поэтому невозможно по этой последовательности определить количество и расположение пустых значений. **Это означает, что существует множество структур двоичных деревьев, соответствующих данной последовательности обхода по уровням**.
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:如下图所示,给定一棵非完美二叉树,上述数组表示方法已经失效。 -->
|
||||
Для такого неидеального двоичного дерева вышеописанный метод представления с помощью массива уже не работает, см. рис. 7.13.
|
||||
|
||||
<!-- 🔴 俄文版缺失图片 -->
|
||||
<!-- 中文原文: -->
|
||||

|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:为了解决此问题,**我们可以考虑在层序遍历序列中显式地写出所有 `None`** 。如下图所示,这样处理后,层序遍历序列就可以唯一表示二叉树了。示例代码如下: -->
|
||||
Для решения этой проблемы **можно явно записать все значения `None` в последовательности обхода по уровням**. После такой обработки последовательность обхода по уровням уже может однозначно представлять двоичное дерево, как показано на рис. 7.14. Ниже приведен пример кода.
|
||||
|
||||
<!-- 🔴 俄文版缺失代码示例 -->
|
||||
<!-- 中文原文:=== "Python" ... [多语言代码示例] -->
|
||||
=== "Python"
|
||||
|
||||
<!-- 🔴 俄文版缺失图片 -->
|
||||
<!-- 中文原文: -->
|
||||
```python title=""
|
||||
# Представление двоичного дерева с помощью массива
|
||||
# Использование None для обозначения пустых мест
|
||||
tree = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15]
|
||||
```
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:值得说明的是,**完全二叉树非常适合使用数组来表示**。回顾完全二叉树的定义,`None` 只出现在最底层且靠右的位置,**因此所有 `None` 一定出现在层序遍历序列的末尾**。 -->
|
||||
=== "C++"
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:这意味着使用数组表示完全二叉树时,可以省略存储所有 `None` ,非常方便。下图给出了一个例子。 -->
|
||||
```cpp title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование INT_MAX для обозначения пустых мест
|
||||
vector<int> tree = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
|
||||
```
|
||||
|
||||
<!-- 🔴 俄文版缺失图片 -->
|
||||
<!-- 中文原文: -->
|
||||
=== "Java"
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:以下代码实现了一棵基于数组表示的二叉树,包括以下几种操作。 -->
|
||||
```java title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование обертки Integer для типа int, чтобы можно было использовать null для обозначения пустых мест
|
||||
Integer[] tree = { 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 };
|
||||
```
|
||||
|
||||
<!-- 🔴 俄文版缺失列表 -->
|
||||
<!-- 中文原文:- 给定某节点,获取它的值、左(右)子节点、父节点。- 获取前序遍历、中序遍历、后序遍历、层序遍历序列。 -->
|
||||
=== "C#"
|
||||
|
||||
<!-- 🔴 俄文版缺失代码引用 -->
|
||||
<!-- 中文原文:```src [file]{array_binary_tree}-[class]{array_binary_tree}-[func]{} ``` -->
|
||||
```csharp title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование nullable типа int?, чтобы можно было использовать null для обозначения пустых мест
|
||||
int?[] tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
|
||||
```go title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование типа any для среза, чтобы можно было использовать nil для обозначения пустых мест
|
||||
tree := []any{1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование nullable типа Int?, чтобы можно было использовать nil для обозначения пустых мест
|
||||
let tree: [Int?] = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15]
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование null для обозначения пустых мест
|
||||
let tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
=== "TS"
|
||||
|
||||
```typescript title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование null для обозначения пустых мест
|
||||
let tree: (number | null)[] = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование nullable типа int?, чтобы можно было использовать null для обозначения пустых мест
|
||||
List<int?> tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование None для обозначения пустых мест
|
||||
let tree = [Some(1), Some(2), Some(3), Some(4), None, Some(6), Some(7), Some(8), Some(9), None, None, Some(12), None, None, Some(15)];
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование максимального значения int для обозначения пустых мест, поэтому значения узлов не могут быть равны INT_MAX
|
||||
int tree[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
|
||||
```
|
||||
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title=""
|
||||
/* Представление двоичного дерева с помощью массива */
|
||||
// Использование null для обозначения пустых мест
|
||||
val tree = arrayOf( 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 )
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
### Представление двоичного дерева с помощью массива ###
|
||||
# Использование nil для обозначения пустых мест
|
||||
tree = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15]
|
||||
```
|
||||
|
||||

|
||||
|
||||
Стоит отметить, что **совершенное двоичное дерево очень удобно представлять с помощью массива**. Вспоминая определение совершенного двоичного дерева, `None` появляются только на самом нижнем уровне и в правой части, поэтому **все значения `None` обязательно находятся в конце последовательности обхода по уровням**.
|
||||
|
||||
Это означает, что при использовании массива для представления совершенного двоичного дерева можно опустить хранение всех `None`, что очень удобно. На рис. 7.15 приведен пример такого представления.
|
||||
|
||||

|
||||
|
||||
В коде ниже реализуется двоичное дерево, основанное на представлении с помощью массива, включая следующие операции.
|
||||
|
||||
- Для заданного узла получение его значения, левого и правого дочернего узла, родительского узла.
|
||||
- Получение последовательностей обхода в прямом, симметричном, обратном порядке и в порядке обхода по уровням.
|
||||
|
||||
```src
|
||||
[file]{array_binary_tree}-[class]{array_binary_tree}-[func]{}
|
||||
```
|
||||
|
||||
## Преимущества и ограничения
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:二叉树的数组表示主要有以下优点。 -->
|
||||
Представление двоичного дерева с помощью массива имеет следующие преимущества:
|
||||
|
||||
<!-- 🔴 俄文版缺失列表 -->
|
||||
<!-- 中文原文:- 数组存储在连续的内存空间中,对缓存友好,访问与遍历速度较快。- 不需要存储指针,比较节省空间。- 允许随机访问节点。 -->
|
||||
- Массив хранится в непрерывной области памяти, что хорошо для кеширования. Скорость доступа и обхода достаточно высока.
|
||||
- Не требуется хранение указателей, что экономит пространство.
|
||||
- Позволяет выполнять произвольный доступ к узлам.
|
||||
|
||||
<!-- 🔴 俄文版缺失此段落 -->
|
||||
<!-- 中文原文:然而,数组表示也存在一些局限性。 -->
|
||||
Однако представление с помощью массива имеет и некоторые ограничения:
|
||||
|
||||
<!-- 🔴 俄文版缺失列表 -->
|
||||
<!-- 中文原文:- 数组存储需要连续内存空间,因此不适合存储数据量过大的树。- 增删节点需要通过数组插入与删除操作实现,效率较低。- 当二叉树中存在大量 `None` 时,数组中包含的节点数据比重较低,空间利用率较低。 -->
|
||||
- Хранение в массиве требует непрерывной области памяти, поэтому не подходит для хранения деревьев с очень большим объемом данных.
|
||||
- Добавление и удаление узлов требует выполнения операций вставки и удаления в массиве, которые менее эффективны.
|
||||
- Когда в двоичном дереве содержится много значений `None`, доля данных узлов в массиве низка, что приводит к низкой эффективности использования пространства.
|
||||
|
||||
Reference in New Issue
Block a user