二叉搜索树:针对任何一颗子树来说都要满足,父节点>左子树,父节点<右子树。(父节点是中间大小的元素。

堆:父节点和子节点中间的关系,堆顶元素一定是最大值或者最小值
二叉搜索树中序遍历的结果是一个有序的序列
具体实现
主要有三个核心操作(增删查),对于二叉搜索树,修改操作不能针对key进行修改
package package1123;
public class BinarySearchTree {
public static class Node{
int key;
int value; //TreeSet,TreeMap
Node left;
Node right;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"key=" + key +
", value=" + value +
'}';
}
}
//创建一根树根节点,初始情况下是空树,根节点指向null
private Node root = null;
//查找
public Node search(int key){
//从根节点出发,根据这个关系,决定在左子树中找还是右子树中找
Node cur = root;
while (cur != null){
if (key == cur.key){
return cur;
}else if (key < cur.key){
//去左子树找
cur = cur.left;
}else {
//去右子树找
cur = cur.right;
}
}
return null;
}
//插入
//1.找到合适位置,新的节点放到合适位置
//2.啥时候会插入失败,约定如果当前的key在树中已经存在了,就认为插入失败,TreeSet
//还可以这样约定,如果当前的key存在,直接修改value TreeMap //武松的故事
public boolean insert(int key,int value){
//1.当前要插入的树是空树的话
if (root == null){
root = new Node(key,value);
}
//2.对于一个不是空的树,就需要先找到合适的位置
//查找的过程中,随时记录当前节点的父亲
Node cur = root;
Node parent = null;
while (cur != null){
if (key == cur.key){
//当前的key已经存在
return false; //TreeSet
}else if (key < cur.key){
parent = cur;//parent 一直指向cur的父节点
cur = cur.left;
}else {
//parent 是cur的父节点,所以得更新parent
parent = cur;
cur = cur.right;
}
}
//cur 一定是空,这点很重要
Node newNode = new Node(key,value);
if (key < parent.key){
parent.left = newNode;
}else {
parent.right = newNode;
}
return true;
}
public boolean remove(int key){
//记录当前位置的父节点
Node cur = root;
Node parent = null;
//查找要删除元素的位置
while (cur != null){
if (cur.key == key){
//找到了
removeNode(parent,cur);
return true;
}else if(key < cur.key){
parent = cur;
cur = cur.left;
}else {
parent = cur;
cur = cur.right;
}
}
return false;
}
public void removeNode(Node parent,Node cur){
//很多考虑的细节从这里删掉
if (cur.left == null){
//1.1cur就是根节点
if (cur == root){
root = cur.right;
}else if(parent.left == cur){
//cur是父节点的左子树
parent.left = cur.right;
}else {
parent.right = cur.right;
}
}else if(cur.right == null){
//2.1cur是根节点
if(cur == root){
root = cur.left;
}else if (parent.left == cur){
//2.1 cur 是父节点的左子树
parent.left = cur.left;
}else {
//2.3 cur 是父节点的右子树
parent.right = cur.left;
}
}else {
//3.同时有左右子树的情况
//找到替罪羊(cur右子树的最左侧元素)
//把替罪羊的key value 赋值到待删除结点之中
//在删除替罪羊节点
Node scapeGoat = cur.right;
Node scapeGoatParent = cur;
while (scapeGoat.left != null){
scapeGoatParent = scapeGoat;
scapeGoat = scapeGoat.left;
}
cur.key = scapeGoat.key;
cur.value = scapeGoat.value;
//删除替罪羊节点
if (scapeGoat == scapeGoatParent.left){
scapeGoatParent.left = scapeGoat.right;
}else {
//就是cur.right 就已经是最左边的情况了。
scapeGoatParent.right = scapeGoat.right;
}
}
}
public static void inOrder(Node root){
//验证
if (root == null){
return;
}
inOrder(root.left);
System.out.print(root.key + " ");
inOrder(root.right);
}
public static void main(String[] args) {
//建立一个二叉搜索树
BinarySearchTree tree = new BinarySearchTree();
int[] arr = {9,5,2,7,3,6,8};
for (int x : arr){
tree.insert(x,0);
}
tree.remove(6);
inOrder(tree.root);
}
}
性能分析
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
1.查找复杂度:
最优情况下,二叉搜索树为完全二叉树,平均比较次数为log2(N)
最坏情况下,二叉搜索树为极端的单枝树,平均比较次数 N/2
平衡二叉树的具体实现形式
2.红黑树:特点有六条规则,红黑树是一种不太严格的平衡二叉树,不能让左右子树差太多
TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树

二叉搜索树是一种特殊树形结构,其中每个节点的值大于其左子树所有节点,小于其右子树所有节点。这确保了中序遍历结果为有序序列。堆与之不同,它要求父节点的值大于或小于子节点。二叉搜索树常用于增删查操作,但不支持直接修改key。插入和删除操作依赖查找效率,性能分析关键在于树的平衡。平衡二叉树如红黑树,通过特定规则保持平衡,避免性能退化。Java中的TreeMap和TreeSet即使用红黑树实现。
1547

被折叠的 条评论
为什么被折叠?



