[置頂] js代碼實現二叉查找樹的算法

分類:編程 時間:2017-02-24

js代碼實現二叉查找樹的算法

理論

二叉查找樹(Binary Search Tree),又稱二叉排序樹或二叉搜索樹,是屬於二叉樹的一種。它最大的特點是每個節點的左子節點永遠比該節點小,而每個節點的右子節點卻永遠比該節點大,即任意節點的左子樹上所有結點永遠比該節點的右子樹上所有結點的值小,它的任意左、右子樹也分別為二叉查找樹。

代碼

以下是使用js代碼來實現。

先定義二叉查找樹的節點:

/**
 * 樹的節點
 * @param  data  節點的數值
 * @param  left  該節點的左子節點
 * @param  right 該節點的右子節點
 */
function TreeNode(data, left, right) {
    this.data = http://www.ithao123.cn/data;
    this.left = left || null;
    this.right = right || null;
}

定義二叉樹:

/**
 * 二叉查找樹
 * @param  rootNode 根節點
 */
function BinarySearchTree(rootNode) {
    this.rootNode = rootNode || null;
}

BinarySearchTree.prototype = {
    // 後面講的查找,新增,刪除功能會放在本區域(即原型)
}

二叉查找樹的新增功能

插入工作必須按照二叉查找樹的特性來完成。

  1. 首先判斷該二叉樹是否有根節點,如果沒有則把新節點作為根節點,反之則繼續;
  2. 從根節點開始逐級比較,即如果新結點的值小於根節點的值,則將新結點與根節點的左子樹中的節點去比較,大於則與根節點的右子樹中的節點去比較;
  3. 逐級比較直到找到需要插入的空位為止,把新節點放入即可;

新增代碼如下:

/**
* 插入節點
* @param   data 需要插入節點的值
*/
function insert(data) {
   // 生成新的節點
   var newNode = new TreeNode(data);
   // 判斷根節點是否存在
   if (!this.rootNode) {
       this.rootNode = newNode;
       return;
   }
   var currentNode = this.rootNode;
   var parent = null;
   while (true) {
       parent = currentNode;
       if (data < currentNode.data) {
           currentNode = currentNode.left;
           if (!currentNode) {
               parent.left = newNode;
               return;
           }
       } else if (data > currentNode.data) {
           currentNode = currentNode.right;
           if (!currentNode) {
               parent.right = newNode;
               return;
           }
       } else {
           console.log("該節點已存在");
           return;
       }
   }
}

二叉查找樹的查找功能

查找功能其實與新增功能類似,首先要判斷根節點是否存在,然後需要把待查找的節點從根節點開始逐級比較查找,規則同樣是左子樹的節點永遠小於右子樹的節點,直到找到為止。

/**
* 查找節點
* @param   data 待查找節點的值
*/
function: find(data) {
    // 判斷根節點是否存在
    if (!this.rootNode) {
        return;
    }
    var currentNode = this.rootNode;
    while (true) {
        if (!currentNode) {
            console.log("該節點不存在");
            return;
        }
        if (data < currentNode.data) {
            currentNode = currentNode.left;
        } else if (data > currentNode.data) {
            currentNode = currentNode.right;
        } else {
            return currentNode;
        }
    }
}

二叉查找樹的節點刪除功能

刪除功能就比較復雜了,主要分三種情況:

  1. 待刪除節點無子節點時,直接刪除節點即可;
  2. 待刪除節點只有右子樹或只有左子樹時,直接把待刪除節點的父節點的指針指向待刪除節點的右子樹或右子樹即可,然後刪除節點;
  3. 這種情況相對較復雜,就是待刪除節點既有左節點又有右節點。通常有兩種方法來解決:
    1. 從待刪除節點的左子樹選出最大的節點即最靠近右邊的節點來頂替刪除後騰出的節點位置;
    2. 從待刪除節點的右子樹選出最小的節點即最靠近左邊的節點來頂替刪除後騰出的節點位置;

具體流程如下:
1. 查找到待刪除的結點和它的父節點;
2. 判斷該節點有無左右子樹,如果沒有,那麽直接刪除;
3. 如果只有左右子樹中的一個,那麽直接它的父節點指向它的左子樹或右子樹,然後刪除節點;
4. 如果左右子樹都有,本人按照從左子樹的取最大的節點方法列實行;

/**
* 刪除目標節點
* @param   data 待刪除目標節點的值
*/
function removeNode(data) {
    // 判斷根節點是否存在
    if (!this.rootNode) {
        return;
    }
    // 目標節點的父節點
    var parent = null;
    // 目標節點
    var currentNode = this.rootNode;
    // 目標節點位於父節點的位置
    var place = null;
    while (true) {
        if (!currentNode) {
            console.log("該節點不存在");
            return;
        }
        if (data < currentNode.data) {
            parent = currentNode;
            currentNode = currentNode.left;
            place = "left";
        } else if (data > currentNode.data) {
            parent = currentNode;
            currentNode = currentNode.right;
            place = "right";
        } else {
            // 找到對應節點跳出循環
            break;
        }
    }

    if (!currentNode.left) {
        // 刪除的節點沒有左孩子的情況
        parent[place] = currentNode.right || null;
    } else if (!currentNode.right) {
        // 刪除的節點沒有右孩子的情況
        parent[place] = currentNode.left || null;
    } else {
        // 用於代替的節點
        var replaceNode = currentNode.left;
        // 代替節點的父節點
        var replaceNodeParent = null;
        // 循環找出左子樹中最大的節點(即用於代替的節點)
        while(replaceNode.right) {
            replaceNodeParent = replaceNode;
            replaceNode = replaceNode.right;
        }
        // 代替原位置
        parent[place] = replaceNode;
        // 當代替節點就是刪除的節點的左子節點時無需賦左子樹
        if (replaceNodeParent) {
            replaceNodeParent.right = replaceNode.left || null;
            parent[place].left = currentNode.left;
        }
        // 獲取刪除的節點的右子樹
        parent[place].right = currentNode.right;
    }
    return;
}

以上即是具體講解,整套代碼如下:

/**
 * 樹的節點
 * @param  data  節點的數值
 * @param  left  該節點的左子節點
 * @param  right 該節點的右子節點
 */
function TreeNode(data, left, right) {
    this.data = http://www.ithao123.cn/data;
    this.left = left || null;
    this.right = right || null;
}

/**
 * 二叉查找樹
 * @param  rootNode 根節點
 */
function BinarySearchTree(rootNode) {
    this.rootNode = rootNode || null;
}

BinarySearchTree.prototype = {
    // 插入子節點
    insert: function(data) {
        // 生成新的節點
        var newNode = new TreeNode(data);
        // 判斷根節點是否存在
        if (!this.rootNode) {
            this.rootNode = newNode;
            return;
        }
        var currentNode = this.rootNode;
        var parent = null;
        while (true) {
            parent = currentNode;
            if (data < currentNode.data) {
                currentNode = currentNode.left;
                if (!currentNode) {
                    parent.left = newNode;
                    return;
                }
            } else if (data > currentNode.data) {
                currentNode = currentNode.right;
                if (!currentNode) {
                    parent.right = newNode;
                    return;
                }
            } else {
                console.log("該節點已存在");
                return;
            }
        }
    },
    // 查找節點
    find: function(data) {
        // 判斷根節點是否存在
        if (!this.rootNode) {
            return;
        }
        var currentNode = this.rootNode;
        while (true) {
            if (!currentNode) {
                console.log("該節點不存在");
                return;
            }
            if (data < currentNode.data) {
                currentNode = currentNode.left;
            } else if (data > currentNode.data) {
                currentNode = currentNode.right;
            } else {
                return currentNode;
            }
        }
    },
    // 刪除目標節點
    removeNode: function (data) {
        // 判斷根節點是否存在
        if (!this.rootNode) {
            return;
        }
        // 目標節點的父節點
        var parent = null;
        // 目標節點
        var currentNode = this.rootNode;
        // 目標節點位於父節點的位置
        var place = null;
        while (true) {
            if (!currentNode) {
                console.log("該節點不存在");
                return;
            }
            if (data < currentNode.data) {
                parent = currentNode;
                currentNode = currentNode.left;
                place = "left";
            } else if (data > currentNode.data) {
                parent = currentNode;
                currentNode = currentNode.right;
                place = "right";
            } else {
                // 找到對應節點跳出循環
                break;
            }
        }

        if (!currentNode.left) {
            // 刪除的節點沒有左孩子的情況
            parent[place] = currentNode.right || null;
        } else if (!currentNode.right) {
            // 刪除的節點沒有右孩子的情況
            parent[place] = currentNode.left || null;
        } else {
            // 用於代替的節點
            var replaceNode = currentNode.left;
            // 代替節點的父節點
            var replaceNodeParent = null;
            // 循環找出左子樹中最大的節點(即用於代替的節點)
            while(replaceNode.right) {
                replaceNodeParent = replaceNode;
                replaceNode = replaceNode.right;
            }
            // 代替原位置
            parent[place] = replaceNode;
            // 當代替節點就是刪除的節點的左子節點時無需賦左子樹
            if (replaceNodeParent) {
                replaceNodeParent.right = replaceNode.left || null;
                parent[place].left = currentNode.left;
            }
            // 獲取刪除的節點的右子樹
            parent[place].right = currentNode.right;
        }
        return;
    }
}

Tags: function js代碼 二叉樹 最大的 null

文章來源:


ads
ads

相關文章
ads

相關文章

ad