JS實現(xiàn)二叉排序樹

二叉樹的特點:

  • 二叉樹是一種數(shù)據(jù)結(jié)構(gòu)。
  • 由一系列節(jié)點組成助泽,具有層級結(jié)構(gòu)。每個節(jié)點的特性包含有節(jié)點值嚎京,關(guān)系指針嗡贺。節(jié)點之間存在對應(yīng)關(guān)系。
  • 樹中存在一個沒有父節(jié)點的節(jié)點鞍帝,叫做根節(jié)點诫睬。樹的末尾存在一系列沒有子節(jié)點的節(jié)點,成為葉子節(jié)點帕涌。其他可以叫做中間節(jié)點摄凡。
  • 樹的根節(jié)點位于第一層,層級數(shù)越大蚓曼,節(jié)點位置越深亲澡,層基數(shù)也叫做樹高。

二叉樹排序是二叉樹的一種類型纫版,特點是:

  • 節(jié)點分為左右子樹床绪。
  • 在不為空的情況下,左子樹子節(jié)點的值都小于父節(jié)點的值。
  • 在不為空的情況下癞己,右子樹子節(jié)點的值都大于父節(jié)點得值膀斋。


    二叉排序樹.png

代碼實現(xiàn)

節(jié)點用對象來描述,節(jié)點特性用對象屬性來描述末秃。

//創(chuàng)建節(jié)點類
class Node {
    constructor(key) {
        this.key = key;//節(jié)點值
        this.left = null;//左指針
        this.right = null;//右指針
    }
}

二叉樹結(jié)構(gòu)用對象來描述概页。

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

插入值

//插入
insert(key) {
    const newNode = new Node(key);
    if (this.root === null) {//設(shè)置根節(jié)點
        this.root = newNode;
    }
    this.insertNode(this.root, newNode);
}
insertNode(node, newNode) {
    if (newNode.key < node.key) {//插值小于節(jié)點值進入左子樹
        if (node.left === null) {//直到左子樹為空
            node.left = newNode
        } else {//左子樹已存在
            this.insertNode(node.left, newNode)
        }
    } else if (newNode.key > node.key){//插入值大于節(jié)點值進入右子樹
        if (node.right === null) {//直到右子樹為空
            node.right = newNode
        } else {//右子樹已存在
            this.insertNode(node.right, newNode)
        }
    }
}
使用方法
// 實例化二叉樹
const binaryTree = new BinaryTree();
// key值
const keys = [19, 8, 15, 24, 45, 12, 5];
// 生成二叉排序樹
keys.forEach(key => binaryTree.insert(key));

二叉排序樹的遍歷

中序遍歷
  • 總是先遍歷左子樹,然后訪問根節(jié)點练慕,接著遍歷右子樹
//中序遍歷
inorderTraversal() {
    let info = [];
    this.inorderTraversalNode(this.root, ({key}) => {
        info.push(key)
    });
    return info;
}
inorderTraversalNode(node, callback) {
    if (node) {//當(dāng)前節(jié)點
        this.inorderTraversalNode(node.left, callback);//遍歷左子樹
        callback(node);//訪問節(jié)點
        this.inorderTraversalNode(node.right, callback);//遍歷右子樹
    }
}
//遍歷結(jié)果:[5, 8, 12, 15, 19, 24, 45]
前序遍歷
  • 總是先訪問根節(jié)點惰匙,然后遍歷左子樹,接著遍歷右子樹铃将。
//前序遍歷
preOrderTraversal() {
    let info = [];
    this.preOrderTraversalNode(this.root, ({key}) => {
        info.push(key)
    });
    return info;
}
preOrderTraversalNode(node, callback) {
    if (node) {//當(dāng)前節(jié)點
        callback(node);//訪問節(jié)點
        this.preOrderTraversalNode(node.left, callback);//遍歷左子樹
        this.preOrderTraversalNode(node.right, callback);//遍歷右子樹
    }
}
//遍歷結(jié)果:[19,  8,  5, 15, 12, 24, 45]
后序遍歷
  • 總是先遍歷左子樹项鬼,接著遍歷右子樹,最后訪問根節(jié)點劲阎。
//后序遍歷
postOrderTraversal() {
    let info = [];
    this.postOrderTraversalNode(this.root, ({key}) => {
        info.push(key)
    });
    return info;
}
postOrderTraversalNode(node, callback){
    if (node) {//當(dāng)前節(jié)點
        this.postOrderTraversalNode(node.left, callback);//遍歷左子樹
        this.postOrderTraversalNode(node.right, callback);//遍歷右子樹
        callback(node);//訪問節(jié)點
    }
}
//遍歷結(jié)果:[5, 12, 15, 8, 45, 24, 19]

二叉排序樹的查找

查找最大值
  • 根據(jù)二叉排序樹的特點绘盟,右子樹的值都大于父節(jié)點得值。只需要進入節(jié)點的右子樹查找悯仙,當(dāng)某個節(jié)點的右子樹為空時龄毡,該節(jié)點就是最大值。
//最大值
max() {
    return this.maxNode(this.root)
}
maxNode(node) {
    if (node) {
        while (node.right !== null) {//右子樹不為空時
            node = node.right;
        }
        return node.key
    }
    return null
}
查找最小值
  • 根據(jù)二叉排序樹的特點锡垄,左子樹的值都小于父節(jié)點的值沦零。只需要進入節(jié)點的左子樹查找,當(dāng)某個節(jié)點的左子樹為空時货岭,該節(jié)點就是最小值
//最小值
min() {
    return this.minNode(this.root)
}
minNode(node) {
    if (node) {
        while (node.left !== null) {//左子樹不為空時
            node = node.left;
        }
        return node.key
    }
    return null
}
查找指定值路操。
  • 在二叉排序樹中查找有沒有節(jié)點對應(yīng)的值與給定值相同。
  • 根據(jù)排序二叉樹的特點千贯,比較給定值與節(jié)點值屯仗,小于時進入節(jié)點左子樹。大于時進入節(jié)點右子樹搔谴。等于時返回真魁袜。層層對比,最后如果子樹為空己沛,則表示沒找到慌核。
//查找
search(key) {
    return this.searchNode(this.root, key)
}
searchNode(node, key) {
    if (node === null) {
        return false
    }
    if (key < node.key) {//進入左子樹
        return this.searchNode(node.left, key)
    } else if (key > node.key) {//進入右子樹
        return this.searchNode(node.right, key)
    } else {//相等
        return true
    }
}

二叉排序樹的刪除

  • 當(dāng)刪除的節(jié)點為葉子節(jié)點,關(guān)系指針為空申尼,直接把葉子節(jié)點設(shè)置成空。
  • 當(dāng)刪除的節(jié)點存在左子樹垫桂,把父節(jié)點的關(guān)系指針直接指向左子樹师幕。存在右子樹同理。
  • 當(dāng)刪除的節(jié)點存在左右子樹時,先去右子樹找最小值霹粥,然后用最小值替換節(jié)點值灭将,最后進入右子樹刪除最小值對應(yīng)的節(jié)點。
//刪除
remove(key) {
    this.root = this.removeNode(this.root, key)
}
removeNode(node, key) {
    if (node === null) {//沒有找到值對應(yīng)節(jié)點
        return null
    }
    if (key < node.key) {//給定值小于當(dāng)前節(jié)點值
        node.left = this.removeNode(node.left, key);
        return node
    } else if (key > node.key) {//給定值大于當(dāng)前節(jié)點值
        node.right = this.removeNode(node.right, key);
        return node
    } else {//找到對應(yīng)的節(jié)點
        if (node.left === null && node.right === null) {//節(jié)點為葉子節(jié)點
            node = null;
            return node
        }
        if (node.right === null) {//節(jié)點存在左子樹
            node = node.left;
            return node
        } else if (node.left === null) {//節(jié)點存在右子樹
            node = node.right;
            return node
        }
        //節(jié)點存在左右子樹時后控,先去右子樹找最小值
        const minKey = this.minNode(node.right);
        //用最小值替換節(jié)點值
        node.key = minKey;
        //進入右子樹刪除最小值對應(yīng)的節(jié)點庙曙。
        this.removeNode(node.right, minKey);
        return node;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浩淘,隨后出現(xiàn)的幾起案子捌朴,更是在濱河造成了極大的恐慌,老刑警劉巖张抄,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砂蔽,死亡現(xiàn)場離奇詭異,居然都是意外死亡署惯,警方通過查閱死者的電腦和手機左驾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來极谊,“玉大人诡右,你說我怎么就攤上這事∏岵” “怎么了帆吻?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蜕依。 經(jīng)常有香客問我桅锄,道長,這世上最難降的妖魔是什么样眠? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任友瘤,我火速辦了婚禮,結(jié)果婚禮上檐束,老公的妹妹穿的比我還像新娘辫秧。我一直安慰自己,他們只是感情好被丧,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布盟戏。 她就那樣靜靜地躺著,像睡著了一般甥桂。 火紅的嫁衣襯著肌膚如雪柿究。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天黄选,我揣著相機與錄音蝇摸,去河邊找鬼婶肩。 笑死,一個胖子當(dāng)著我的面吹牛貌夕,可吹牛的內(nèi)容都是我干的律歼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼啡专,長吁一口氣:“原來是場噩夢啊……” “哼险毁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起们童,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畔况,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后病附,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體问窃,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年完沪,在試婚紗的時候發(fā)現(xiàn)自己被綠了域庇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡覆积,死狀恐怖听皿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宽档,我是刑警寧澤尉姨,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站吗冤,受9級特大地震影響又厉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜椎瘟,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一覆致、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肺蔚,春花似錦煌妈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至仇冯,卻和暖如春之宿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苛坚。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工澈缺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坪创,地道東北人炕婶。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓姐赡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親柠掂。 傳聞我的和親對象是個殘疾皇子项滑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容