1. 程式人生 > >js實現二叉查詢樹的建立、插入、刪除、遍歷操作

js實現二叉查詢樹的建立、插入、刪除、遍歷操作

1 概念

二叉排序樹(二叉查詢樹),它或者是一顆空樹,或者是具有以下性質的二叉樹:

  • 任意一個結點左子樹上的所有結點值均小於該結點值
  • 任意一個結點右子樹上的所有結點值均大於該結點值

例如下圖:
這裡寫圖片描述

2 插入和建立二叉排序樹

結點的資料結構

function newNode(value){
    this.value = value;
    this.left = null;
    this.right = null;
}

插入操作
插入操作很簡單,即用遞迴依次比較插入值與結點值的大小,找到插入的位置

function InsertNode(root, key){
    if
(!root.value){ //如果根結點不存在,則建立根結點 root.value = key; return true; } if (root.value > key){ //當前結點值比插入值大,說明插入位置在當前結點值的左子樹中 if (root.left){ //如果有左孩子結點,繼續比較 InsertNode(root.left, key); }else{ //插入操作 root.left = new newNode(key); } }else
if (root.value < key){ //當前結點值比插入值小,說明插入位置在當前結點值的右子樹中 if (root.right){ //如果有右孩子結點,繼續比較 InsertNode(root.right, key); }else{ //插入操作 root.right = new newNode(key); } }else{ //樹中已存在插入值的結點 return false; } return true; }

建立操作
二叉排序樹的建立就是多次執行插入操作

function create(array){
    var tree = new newNode(null);  //建立根節點
    for (let i=0; i < array.length; i++){
        InsertNode(tree, array[i]);
    }
    return tree;
}

3 遍歷

二叉排序樹中序遍歷的輸出結果就是結點值從小到大排序的結果

function InOrderTraverse(root){
    if (!root) return;
    InOrderTraverse(root.left);
    console.log(root.value);
    InOrderTraverse(root.right);
}

4 刪除操作

刪除操作稍微複雜一些。思路在於首先找到刪除值的結點,若該結點是葉子結點,則直接將其置為null,若其具有左子樹或右子樹,則將左孩子結點或右孩子結點賦值給當前結點。若當前結點既有左子樹,又有右子樹,則在其左子樹中,尋找一個和當前結點值最接近的孩子結點(即中序遍歷結果中當前結點的前驅),將當前結點的值替換為該孩子結點的值,替換後,樹中此時就有兩個重複的值,因此,再利用遞迴刪除重複的孩子結點,依次類推。。。

function deleteNode(root, key){
    if (!root){
        console.log("刪除失敗");
        return root;
    }

    if (root.value > key){  //若當前結點值大於刪除值,則繼續在左子樹中尋找刪除值
        root.left = deleteNode(root.left, key);
    }else if (root.value < key){  //若當前結點值小於刪除值,則繼續在右子樹中尋找刪除值
        root.right = deleteNode(root.right, key);
    }else{  //找到與刪除中相等的結點
        if (root.left === null & root.right === null){  //葉子結點
            root = null;
        }else if (root.left === null){  //只有右子樹
            root = root.right;
        }else if (root.right === null){  //只有左子樹
            root = root.left;
        }else{  //同時具有左右子樹
            let prevNode = root.left;
            while(prevNode.right){  //尋找不大於當前結點值的最大結點值
                prevNode = prevNode.right;
            }
            root.value = prevNode.value;  //替換值
            root.left = deleteNode(root.left, prevNode.value);  //遞迴左子樹,刪除重複值的結點
        }
    } 
    return root;
}