Menu
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS R TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI GO KOTLIN SASS VUE DSA GEN AI SCIPY AWS CYBERSECURITY DATA SCIENCE
     ❯   

DSA 数组实现


二叉树的数组实现

为了避免使用数组时出现的内存移动成本,使用指针从一个元素指向下一个元素来实现二叉树是有用的,就像我们在之前实现二叉树的方式一样,特别是在二叉树经常被修改的情况下。

但如果我们从二叉树中读取数据的频率远大于修改它的频率,那么使用数组实现二叉树是有意义的,因为它需要的内存更少,更容易实现,并且由于缓存局部性,在某些操作中速度更快。

缓存局部性是指计算机中的高速缓存内存存储最近访问过的内存部分,或者缓存存储当前访问地址附近的内存部分。这是因为 CPU 很可能在下个周期需要之前周期使用过的内存部分附近的数据,无论是在时间上还是空间上。

由于数组元素在内存中是连续存储的,一个元素紧挨着另一个元素,所以计算机在从数组中读取数据时有时会更快,因为下一个元素已经被缓存,如果 CPU 在下个周期需要它,就可以快速访问。

数组如何在内存中存储,可以在 这里 找到更详细的解释。

考虑这棵二叉树

R A B C D E F G

这棵二叉树可以存储在一个数组中,从索引 0 开始存储根节点 R。树的其余部分可以通过取索引 \(i\) 上存储的节点,并在索引 \(2\cdot i+1\) 上存储它的左子节点,并在索引 \(2\cdot i+2\) 上存储它的右子节点来构建。

下面是一个二叉树的数组实现。

示例

Python

binary_tree_array = ['R', 'A', 'B', 'C', 'D', 'E', 'F', None, None, None, None, None, None, 'G']

def left_child_index(index):
    return 2 * index + 1

def right_child_index(index):
    return 2 * index + 2

def get_data(index):
    if 0 <= index < len(binary_tree_array):
        return binary_tree_array[index]
    return None

right_child = right_child_index(0)
left_child_of_right_child = left_child_index(right_child)
data = get_data(left_child_of_right_child)

print("root.right.left.data:", data)
运行示例 »

在这个数组实现中,由于二叉树节点被放置在一个数组中,所以大部分代码都是关于使用索引访问节点,以及如何找到正确的索引。

假设我们想要找到节点 B 的左右子节点。因为 B 在索引 2 上,所以 B 的左子节点在索引 \(2\cdot 2+1=5\) 上,即节点 E,对吧?并且 B 的右子节点在索引 \(2\cdot 2+2=6\) 上,即节点 F,这与上面的图也相符,对吧?

如你所见,第 1 行的实现需要在节点没有子节点的地方使用空的数组元素。因此,为了避免在空的数组元素上浪费空间,使用数组实现存储的二叉树应该是“完美”二叉树,或者接近完美的二叉树。

完美二叉树是指每个内部节点都有两个子节点,并且所有叶子节点都在同一层。

如果我们在上面的二叉树中删除节点 G,它看起来像这样

R A B C D E F

上面代码中的第一行可以改写为,不浪费空间在空的数组元素上

binary_tree_array = ['R', 'A', 'B', 'C', 'D', 'E', 'F']

这是在二叉树的数组实现中如何执行三种不同的 DFS 遍历。

示例

Python

binary_tree_array = ['R', 'A', 'B', 'C', 'D', 'E', 'F', None, None, None, None, None, None, 'G']

def left_child_index(index):
    return 2 * index + 1

def right_child_index(index):
    return 2 * index + 2

def pre_order(index):
    if index >= len(binary_tree_array) or binary_tree_array[index] is None:
        return []
    return [binary_tree_array[index]] + pre_order(left_child_index(index)) + pre_order(right_child_index(index))

def in_order(index):
    if index >= len(binary_tree_array) or binary_tree_array[index] is None:
        return []
    return in_order(left_child_index(index)) + [binary_tree_array[index]] + in_order(right_child_index(index))

def post_order(index):
    if index >= len(binary_tree_array) or binary_tree_array[index] is None:
        return []
    return post_order(left_child_index(index)) + post_order(right_child_index(index)) + [binary_tree_array[index]]

print("Pre-order Traversal:", pre_order(0))
print("In-order Traversal:", in_order(0))
print("Post-order Traversal:", post_order(0))
运行示例 »

通过比较这些遍历在数组实现中的执行方式与指针实现中的遍历方式,你可以看到前序中序后序遍历以相同的方式递归执行。



×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
[email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
[email protected]

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2024 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.