数据结构之树(二叉树的存储方式之数组)

存储方式

一般使用数组、链表来存储树(节点)。链表的优点就是添加、删除。数组优点是访问(遍历)。

一维数组表示法

首先将二叉树当作一颗满二叉树(Full Binary Tree),因此第K层具有2k-1  个节点。按照规则存放在一维数组中。

原理

  • 对于一个具有n个节点的二叉树,可以使用一个长度为2n的数组来表示它。通常,数组的索引从0开始。
  • 对于数组中的任意索引 i,如果 i 处的元素表示二叉树的一个节点,那么:
    • 节点i的左子节点将位于索引 2i + 1的位置。
    • 节点i的右子节点将位于索引 2i + 2的位置。
    • 节点i的父节点将位于索引 (i - 1) / 2的位置(如果i不是根节点)。

最佳实践

  1. 在数组中表示二叉树时,确保数组的大小足够以容纳树中的所有节点。通常情况下,您需要知道树的大小(节点数)以便创建正确大小的数组。

  2. 当使用数组表示树时,树的结构通常是静态的,即不支持插入或删除节点。如果需要经常进行插入和删除操作,使用链表表示法可能更合适。

  3. 当数组表示的二叉树是满二叉树时(每个层级都是满的),效果最好。如果树是完全二叉树,效果也不错,但如果树的形状不规则,可能会浪费一些空间。

示例

Java语言

复制代码
public class ArrayBinaryTree {
    private int[] treeArray;

    public ArrayBinaryTree(int size) {
        treeArray = new int[size];
    }

    public int find(int value) {
        for (int i = 0; i < treeArray.length; i++) {
            if (treeArray[i] == value) {
                return i;
            }
        }
        return -1;
    }

    public void insert(int value) {
        for (int i = 0; i < treeArray.length; i++) {
            if (treeArray[i] == 0) {
                treeArray[i] = value;
                return;
            }
        }
    }

    public void preOrderTraversal(int index) {
        if (index >= treeArray.length || treeArray[index] == 0) {
            return;
        }
        System.out.print(treeArray[index] + " ");
        preOrderTraversal(2 * index + 1); // 左子节点
        preOrderTraversal(2 * index + 2); // 右子节点
    }

    public static void main(String[] args) {
        // 构建数组其实就是构建树(数组索引与树的左右子节点、父节点有关系)
        ArrayBinaryTree tree = new ArrayBinaryTree(10);
        tree.insert(1);
        tree.insert(2);
        tree.insert(3);
        tree.insert(4);
        tree.insert(5);
        // 打印树结构,元素为0的表示是空节点即不存在的节点(空间浪费哦)
        System.out.println("Tree structure:");
        for (int value : tree.treeArray) {
            System.out.print(value + " ");
        }
        // 查找元素
        System.out.println("\nFind value 3 at index: " + tree.find(3));
        // 前序排序
        System.out.println("Pre-order traversal:");
        tree.preOrderTraversal(0);
    }
}
复制代码

输出:

1
2
3
4
5
Tree structure:
1 2 3 4 5 0 0 0 0 0
Find value 3 at index: 2
Pre-order traversal:
1 2 4 5 3

  

 

 

 python语言实现

复制代码
 1 class BinaryTree:
 2     def __init__(self, size):
 3         self.tree = [None] * size
 4 
 5     '''
 6     1. 先根节点  0
 7     2. 左子节点  2 * 0 + 1
 8     3. 右子节点  2 * 0 + 2
 9     4. 把第2步的左子节点当作根节点,插入其左、右子节点
10     5. 其左子节点 2 * 1 + 1
11     6. 其右子节点 2 * 2 + 2
12     7. 然后继续按此规律处理即把第5步的左子节点当作根节点继续处理
13     '''
14 
15     def insert(self, value):
16         for i in range(len(self.tree)):
17             if self.tree[i] is None:
18                 self.tree[i] = value
19                 return
20 
21     # 前序遍历: 根节点在左右子树所有节点前面即第1个。然后左子树(当作独立的树)进行处理,左子树遍历完,右子树遍历
22     def pre_order(self, index):
23         if index >= len(self.tree) or self.tree[index] is None:
24             return
25         print(self.tree[index])
26         self.pre_order(2 * index + 1)
27         self.pre_order(2 * index + 2)
28 
29     # 中序遍历: 根节点在左右子树的中间(不停的分独立树,直到无法再分为止,然后访问左子树节点(只有1个节点)、其根节点、右子树节点(也是不停分))
30     def in_order(self, index):
31         if index >= len(self.tree) or self.tree[index] is None:
32             return
33         self.in_order(2 * index + 1)
34         print(self.tree[index])
35         self.in_order(2 * index + 2)
36 
37     # 后序遍历:道路一样,不停拆树,直到拆不了,就可以处理。处理:左子树节点-->右子树节点-->其根节点
38     def post_order(self, index):
39         if index >= len(self.tree) or self.tree[index] is None:
40             return
41         self.post_order(2 * index + 1)
42         self.post_order(2 * index + 2)
43         print(self.tree[index])
44 
45 
46 # 创建一个大小为10的二叉树对象
47 tree = BinaryTree(10)
48 # 插入节点
49 tree.insert(1)
50 tree.insert(2)
51 tree.insert(3)
52 tree.insert(4)
53 tree.insert(5)
54 # 先序遍历
55 print("Pre-order traversal:")
56 tree.pre_order(0)
57 # 中序遍历
58 print("In-order traversal:")
59 tree.in_order(0)
60 # 后序遍历
61 print("Post-order traversal:")
62 tree.post_order(0)
复制代码

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Pre-order traversal:
1
2
4
5
3
In-order traversal:
4
2
5
1
3
Post-order traversal:
4
5
2
3
1

  

posted @   Allen_Hao  阅读(192)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示