[数据结构学习笔记9] 二叉查找树(Binary Search Trees)

二叉查找树,它是一类特殊的二叉树,除了基本的二叉树规则外,还要满足:

1. 左边的子节点要小于父节点值

2. 右边的子节点要大于父节点值

 

图示:

添加节点:

               42

              |     |

            24    99

            |       |      |

         15      50   120

                       |

                      64

移除节点:

1. 如果移除的是叶子节点,那直接移除

2. 如果移除的是一个节点,它的下面只有一个孩子节点,那这个孩子节点就取代移除节点的位置

3. 步骤2也适用于,只有一个孩子节点,该孩子节点下面还有孩子节点的情况

4. 如果移除的节点下有两个孩子节点,那么就按照中序法,找到移除节点下最接近它的大数,或者是该节点往右,最小的数,替换移除节点

 

代码实现(javascript)

加节点:

1. 如果树为空,创建一个节点,为根节点

2. 比较要加的新节点,和根节点的大小

3. 如果新节点值小于根节点,重复步骤2,3,往左

4. 如果新节点值大于根节点,重复步骤2,4,往右

5. 如果新节点值等于树中的一个存在节点,返回消息告知这个节点没有被加入

6. 创建一个新节点,往左或右插入

7. 平衡该树,维持二叉查找树的特征

移除节点:

1. 找到要移除的节点,如果没有找到,则返回消息,告知没有找到

2. 如果要移除的是叶子节点,则简单移除

3. 如果要移除的节点有一个孩子节点,用孩子节点替换要移除的节点

4. 如果要移除的节点有两个孩子,那就要找到中序下一个节点

     4.1 往右一次,然后一直往左

     4.2 用中序下一个节点替换移除节点

5. 平衡该树,维持二叉查找树特征

 

复制代码
class Node {
  constructor(data) {
        this.data = data;
        this.left = null;
        this.right = null;  
    }
}

class BinarySearchTree {
  constructor() {
        this.root = null;  
    }  

  insert(value) {
        // create a new node with the given value
        const newNode = new Node(value);
        // If the tree is empty, the new node becomes the root
        if (this.root === null) {
             this.root = newNode;
             return this;
         }  
        // Traverse the tree to find the correct position for the new node
        let currentNode = this.root;
        while (true) {
             if (value === currentNode.data) {
                  return undefined;
             } else if (value < currentNode.data) {
                  if (currentNode.left === null) {
                       currentNode.left = newNode;
                       return this;
                   }
                  currentNode = currentNode.left;
             } else {
                   if (currentNode.right === null) {
                         currentNode.right = newNode;
                         return this;
                    }
                   currentNode = currentNode.right;
             }
         }  
    }  

    remove(value) {
          let currentNode = this.root;
          let parentNode = null;

           while (currentNode !== null) {
                if (value === currentNode.data) {
                       if (currentNode.left === null && currentNode.right === null) {
                             if (parentNode === null) {
                                  this.root = null;
                             } else {
                                  if (parentNode.left === currentNode) {
                                        parentNode.left = null;
                                   } else {
                                        parentNode.right = null;
                                   }
                             }
                            return true;
                        } else if (currentNode.left !== null && currentNode.right === null) {
             if (parentNode === null) {
                    this.root = currentNode.left;
               } else {
                    if (parentNode.left === currentNode) {
                         parentNode.left = currentNode.left;
                    } else {
                         parentNode.right = currentNode.left;
                    }
               }
               return true;
            } else if (currentNode.left === null && currentNode.right === null) {
                    if (parentNode === null) {
                           this.root = currentNode.right;
                    } else {
                           if (parentNode.left === currentNode) {
                                 parentNode.left = currentNode.right;
                           } else {
                                 parentNode.right = currentNode.right;
                           }
                    }
                    return true;
           } else {
                        let successor = currentNode.right;
                        let successorParent = currentNode;
                        while (successor.left !== null) {
                             successorParent = successor;
                             successor = successor.left;
                         }

                         if (successorParent.left === successor) {
                              successorParent.left = successor.right;
                         } else {
                              successorParent.right = successor.right;
                         }
                         currentNode.data = successor.data;
                         return true;
                     }
                } else if (value < currentNode.data) {
                     parentNode = currentNode;
                      currentNode = currentNode.left;
                 } else {
                     parentNode = currentNode;
                     currentNode = currentNode.right;
                 }
           }
         return false;
     }
}
复制代码

使用二叉查找树

复制代码
let myBST = new BinarySearchTree();

myBST.insert(10);
myBST.insert(5);
myBST.insert(15);
myBST.insert(3);
myBST.insert(7);
myBST.insert(13);
myBST.insert(18);
myBST.insert(20);

// remove
myBST.remove(15);
复制代码

因为二叉查找树的特征,一般时间复杂度是O(log n)。但是也有最坏的情况,二叉查找树可能会退化为链表,这时候时间复杂度可能会达到O(n)。

posted @   Eagle6970  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示