本文是关于数据结构和算法之美的研究笔记
树的数据结构与现实中的树非常相似. 其中的每个元素称为节点. 相邻节点通过线连接. 相邻节点之间的关系称为父子关系.
例如,在下图中,节点A是B的父节点,B是A的子节点,B,C和D是兄弟节点,E没有父节点,称为根节点,没有子节点是叶节点,G,H,I,H,K,L是叶节点.
通常可以用高度,深度,层三个概念来描述树木
高度: 从节点到叶节点的最长路径(边数)
深度: 从根节点到该节点的边数
层数: 将节点的深度加1
树的高度: 根节点的高度

高度是从底部到顶部进行测量的,就像对楼层进行计数一样. 深度是从上到下测量的,就像在水下一样,层数与深度相似数据结构 二叉树,但以1为起点.
顾名思义,每个节点最多具有两个分支,即两个叶子节点,一个左子节点和一个右子节点,只要只有一个左右子节点即可.
如果除叶节点之外的每个节点都有左右两个子节点,则这种二叉树称为“全二叉树”
如果叶节点在最下面的两层中,则最后一层的叶节点都排列在左侧,并且除最后一层外,其他节点的数量必须达到最大值. 这种二叉树称为“完整二叉树”“
如何存储二叉树?
您可以使用基于指针或引用的二进制链存储方法,或基于数组的顺序存储方法.
链存储方法:
每个节点都有三个字段,其中一个缓存数据数据结构 二叉树,其余两个是指向左子节点和右子节点的指针. 只要找到根节点,就可以通过左右指针找到所有数据.
顺序存储方法:
将根节点存储在下标位置i = 1,将左子节点存储在下标位置2 i = 2,将右子节点存储在2 i + 1 = 3,等等.

对于顺序存储方法,完整的二叉树可以节省内存.
有三种经典方法: 前遍历,中遍历和后遍历. 前面,中间和后面指示节点本身的打印顺序.
实际上,遍历二叉树是一个递归过程. 例如,预遍历是先打印节点,然后递归打印左子树,然后递归打印右子树.
穿刺方法:
void preOrder(Node* root) {
if (root == null) return;
System.out.print(root.data);
preOrder(root->left);
preOrder(root->right);
}
void inOrder(Node* root) {
if (root == null) return;
inOrder(root->left);
System.out.print(root.data);
inOrder(root->right);
}
void postOrder(Node* root) {
if (root == null) return;
postOrder(root->left);
postOrder(root->right);
System.out.print(root.data);
}
还有一层遍历,需要一个队列
public void levelOrder(BinaryTree tree) {
// 利用队列先入先出的特点来实现按层遍历
LinkedList<BinaryTree> linkedList = new LinkedList<>();
// 记录当前遍历到哪个结点
BinaryTree currentNode = tree;
// 根节点入队
linkedList.add(currentNode);
// 从队列中弹出各结点数据,直到队列为空,遍历完毕
while (linkedList.size()>0){
// 弹出队首元素(当前结点),打印其数据,并依次将其左右子节点入队
currentNode = linkedList.poll();
System.out.print(currentNode.data+" -> ");
if (currentNode.left!=null) {
linkedList.add(currentNode.left);
}
if (currentNode.right!=null) {
linkedList.add(currentNode.right);
}
}
}
二叉树的最大特点是支持动态数据集的快速插入,删除和搜索操作.
二进制搜索树也称为二进制搜索树,其诞生是为了实现快速搜索,但它不仅支持快速搜索,而且还支持快速插入和删除.
二分查找树提供了对于树中的任何节点,左子树的每个值都小于该节点的值,而右子树的每个值都大于该节点的值.

1. 二叉搜索树搜索
首先获取根节点,如果它等于我们要查找的数据,则返回,如果要找到的数据小于根节点的值,则返回左侧子树,否则返回正确的子树.
代码:
public class BinarySearchTree {
private Node tree;
public Node find(int data) {
Node p = tree;
while (p != null) {
if (data < p.data) p = p.left;
else if (data > p.data) p = p.right;
else return p;
}
return null;
}
public static class Node {
private int data;
private Node left;
private Node right;
public Node(int data) {
this.data = data;
}
}
}
2. 插入二叉搜索树
新插入的数据通常在叶节点中. 我们需要从根节点开始依次比较要插入的数据和该节点的大小. 如果要插入的数据大于节点的数据,并且该节点的右子树为空,则将数据插入到右子节点的位置. 如果不为空,则递归遍历右边的子树,直到找到插入位置. 如果要插入的数据小于该节点的值,并且该节点的左子树为空,则插入该数据,而不是为空,然后递归遍历该左子树,直到找到插入位置为止.
代码:
public void insert(int data) {
if (tree == null) {
tree = new Node(data);
return;
}
Node p = tree;
while (p != null) {
if (data > p.data) {
if (p.right == null) {
p.right = new Node(data);
return;
}
p = p.right;
} else { // data < p.data
if (p.left == null) {
p.left = new Node(data);
return;
}
p = p.left;
}
}
}
3. 删除二叉搜索树
删除操作比插入和搜索操作麻烦一些

(1)如果要删除的节点是叶节点,则只需将父节点的指针更新为已删除节点为空
(2)如果要删除的节点只有一个子节点,我们只需要在其父节点中更新指向要删除的节点的指针,以便它指向要删除的节点的子节点.
(3)如果要删除的节点有两个子节点,则需要在该节点的右子树中找到最小的节点,或者在该节点的左子树中找到最大的节点,并将其替换为该节点被删除. 因为父节点的指针必须大于所有左子树的节点值和右子树的节点值
代码:
public void delete(int data) {
Node p = tree; // p 指向要删除的节点,初始化指向根节点
Node pp = null; // pp 记录的是 p 的父节点
while (p != null && p.data != data) {
pp = p;
if (data > p.data) p = p.right;
else p = p.left;
}
if (p == null) return; // 没有找到
// 要删除的节点有两个子节点
if (p.left != null && p.right != null) { // 查找右子树中最小节点
Node minP = p.right;
Node minPP = p; // minPP 表示 minP 的父节点
while (minP.left != null) {
minPP = minP;
minP = minP.left;
}
p.data = minP.data; // 将 minP 的数据替换到 p 中
p = minP; // 下面就变成了删除 minP 了
pp = minPP;
}
// 删除节点是叶子节点或者仅有一个子节点
Node child; // p 的子节点
if (p.left != null) child = p.left;
else if (p.right != null) child = p.right;
else child = null;
if (pp == null) tree = child; // 删除的是根节点
else if (pp.left == p) pp.left = child;
else pp.right = child;
}
传统的二叉树遍历可以输出有序数据序列,并且非常有效. 因此,二叉搜索树也称为二叉排序树.
如果数据中有重复数据怎么办?
(1)二进制搜索树中不仅会存储一个数据,而且还可以通过支持动态扩展的链接列表和数组将相同的值存储在同一节点上.
(2)插入数据时,如果节点的值与要插入的数据的值相同,则将要插入的数据放置在该节点的右子树中,即认为大于此值. 将处理该节点的值.
寻找数据时,遇到具有相同值的节点时,不要停止搜索操作,而要继续在右侧子树中搜索,直到叶节点停止为止.
删除数据时,首先找到要删除的每个节点,然后根据以前的删除方法将其逐个删除.
以上是编辑器向您介绍的“数据结构的二叉树”. 希望对大家有帮助. 如果您有任何疑问,请给我留言,编辑会及时给您答复. 我也非常感谢大家对Code Agriculture Network的支持!
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-222716-1.html
我们就应该是没有敌对情绪亲密同胞