在二进制搜索树的数组实现上实现插入函数
Implementing an insert function onto array implementation of Binary Search Tree
我试图在不实际创建节点 objects 并为它们提供 left/right children 的情况下使用二叉搜索树的功能,而是使用二叉搜索树的基本思想在三个并行数组中:左、数据和右。在这些数组中的特定索引处,left 保存当前数据左侧 child 所在数据的索引,而 right 保存当前数据右侧 child 所在数据的索引。这个 table 给出了一个更好的例子来说明我在说什么:
-1 值表示节点没有左或右 child。在插入任何节点之前,所有数组的值都是0,每次插入一个节点时,其左右children索引值都设置为-1(表示我们刚刚插入的是叶子).我正在努力弄清楚的是如何递归地执行此操作而不会意外访问 -1 的索引。我目前在下面看到的尝试是 运行 进入这个问题:
public void insert(int d) {
//PRE: the tree is not full
//if d is not in the tree insert d otherwise the tree does not change
if(root == -1) {
root = d;
}
insert(d, 0);
}
private void insert(int d, int index) {
if(data[index] == d) {
return;
}
if(data[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
}
if(data[index] > d) {
if(left[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, left[index]);
}
}
if(data[index] < d) {
if(right[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, right[index]);
}
}
return;
}
我很好奇如何防止访问索引值为 -1 的数组,同时仍然能够指示节点在特定一侧没有 child。
我理解的概念是每次插入一个节点时,我都是在插入一个叶子,所以当一个节点被放置在一个特定的索引处时,它的左右可以自动设置为-1,但是我当前的递归调用最终在某一时刻传入 -1。即使我将此值更改为 0 或其他值,也不一定能帮助我在递归中取得任何进展。
对您的代码的一些评论:
root
变量不应该赋值d
,而是index会存储d
的地方,只有这样,用等于 -1 的 root
编码空树才有意义(意识到 d
可能是 -1)。
您的代码没有逻辑来确定在哪个索引处存储新节点。这真的是你的问题。一个简单的解决方案是维护一个 size
变量。这就是存储下一个节点的索引,之后 size
成员应该递增。
没有理由将 0 视为某种特殊指示符,您的代码应该只检查 -1 引用,而不是 0。
你有一些代码重复,你可以通过创建一个将“创建”节点的方法来避免:它将使用 size
作为它的索引,并将一个值作为参数.
这是建议的代码:
class BinaryTree {
public static final int MAXSIZE = 100;
int left[] = new int[BinaryTree.MAXSIZE];
int right[] = new int[BinaryTree.MAXSIZE];
int data[] = new int[BinaryTree.MAXSIZE];
int root = -1;
int size = 0;
private int createNode(int value) {
data[size] = value;
left[size] = -1;
right[size] = -1;
return size++;
}
public void insert(int value) {
if (root == -1) {
root = createNode(value);
} else {
insert(value, 0);
}
}
private void insert(int value, int index) {
if (data[index] == value) {
return;
}
if (data[index] > value) {
if (left[index] == -1) {
left[index] = createNode(value);
} else {
insert(value, left[index]);
}
} else {
if (right[index] == -1) {
right[index] = createNode(value);
} else {
insert(value, right[index]);
}
}
return;
}
}
此代码可以进一步扩展:
- 验证树已达到最大大小,
- 节点删除
- 重用已删除节点索引的“内存管理”(通过维护“空闲列表”)
- 自平衡(如 AVL 或红黑树)
自己进行“内存管理”(数组槽管理)真的会模仿 Java 在使用 class 实例时开箱即用的强大堆内存管理。出于这个原因,我建议以 OOP 方式实现树。
我试图在不实际创建节点 objects 并为它们提供 left/right children 的情况下使用二叉搜索树的功能,而是使用二叉搜索树的基本思想在三个并行数组中:左、数据和右。在这些数组中的特定索引处,left 保存当前数据左侧 child 所在数据的索引,而 right 保存当前数据右侧 child 所在数据的索引。这个 table 给出了一个更好的例子来说明我在说什么:
-1 值表示节点没有左或右 child。在插入任何节点之前,所有数组的值都是0,每次插入一个节点时,其左右children索引值都设置为-1(表示我们刚刚插入的是叶子).我正在努力弄清楚的是如何递归地执行此操作而不会意外访问 -1 的索引。我目前在下面看到的尝试是 运行 进入这个问题:
public void insert(int d) {
//PRE: the tree is not full
//if d is not in the tree insert d otherwise the tree does not change
if(root == -1) {
root = d;
}
insert(d, 0);
}
private void insert(int d, int index) {
if(data[index] == d) {
return;
}
if(data[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
}
if(data[index] > d) {
if(left[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, left[index]);
}
}
if(data[index] < d) {
if(right[index] == 0) {
data[index] = d;
right[index] = -1;
left[index] = -1;
} else {
insert(d, right[index]);
}
}
return;
}
我很好奇如何防止访问索引值为 -1 的数组,同时仍然能够指示节点在特定一侧没有 child。
我理解的概念是每次插入一个节点时,我都是在插入一个叶子,所以当一个节点被放置在一个特定的索引处时,它的左右可以自动设置为-1,但是我当前的递归调用最终在某一时刻传入 -1。即使我将此值更改为 0 或其他值,也不一定能帮助我在递归中取得任何进展。
对您的代码的一些评论:
root
变量不应该赋值d
,而是index会存储d
的地方,只有这样,用等于 -1 的root
编码空树才有意义(意识到d
可能是 -1)。您的代码没有逻辑来确定在哪个索引处存储新节点。这真的是你的问题。一个简单的解决方案是维护一个
size
变量。这就是存储下一个节点的索引,之后size
成员应该递增。没有理由将 0 视为某种特殊指示符,您的代码应该只检查 -1 引用,而不是 0。
你有一些代码重复,你可以通过创建一个将“创建”节点的方法来避免:它将使用
size
作为它的索引,并将一个值作为参数.
这是建议的代码:
class BinaryTree {
public static final int MAXSIZE = 100;
int left[] = new int[BinaryTree.MAXSIZE];
int right[] = new int[BinaryTree.MAXSIZE];
int data[] = new int[BinaryTree.MAXSIZE];
int root = -1;
int size = 0;
private int createNode(int value) {
data[size] = value;
left[size] = -1;
right[size] = -1;
return size++;
}
public void insert(int value) {
if (root == -1) {
root = createNode(value);
} else {
insert(value, 0);
}
}
private void insert(int value, int index) {
if (data[index] == value) {
return;
}
if (data[index] > value) {
if (left[index] == -1) {
left[index] = createNode(value);
} else {
insert(value, left[index]);
}
} else {
if (right[index] == -1) {
right[index] = createNode(value);
} else {
insert(value, right[index]);
}
}
return;
}
}
此代码可以进一步扩展:
- 验证树已达到最大大小,
- 节点删除
- 重用已删除节点索引的“内存管理”(通过维护“空闲列表”)
- 自平衡(如 AVL 或红黑树)
自己进行“内存管理”(数组槽管理)真的会模仿 Java 在使用 class 实例时开箱即用的强大堆内存管理。出于这个原因,我建议以 OOP 方式实现树。