javascript/js實現 排序二叉樹數據結構 學習隨筆


二叉樹是一種數據結構。其特點是:

1.由一系列節點組成,具有層級結構。每個節點的特性包含有節點值、關系指針。節點之間存在對應關系。

2.樹中存在一個沒有父節點的節點,叫做根節點。樹的末尾存在一系列沒有子節點的節點,稱為葉子節點。其他可以叫做中間節點。

3.樹的根節點位於第一層,層級數越大,節點位置越深,層級數也叫做樹高。

排序二叉樹為二叉樹的一種類型,其特點是:

1.節點分為左右子樹。

2.在不為空的情況下,左子樹子節點的值都小於父節點的值。

3.在不為空的情況下,右子樹子節點的值都大於父節點的值。

4.每個節點的左右子樹都按照上述規則排序。

如圖:

(打錯字了..)

js代碼來實現上述數據結構:

1.節點用對象來描述,節點特性用對象屬性來描述。

1 class Node {
2   constructor(key) {
3     this.key = key;// 節點值
4     this.left = null;// 左指針
5     this.right = null;// 右指針
6   }
7 }

2.二叉樹結構用對象來描述。

 1 // 二叉樹
 2 class BinaryTree {
 3   constructor() {
 4     this.root = null;// 根節點
 5   }
 6   insert(key) {// api--插入
 7     const newNode = new Node(key);
 8     if (this.root === null) {// 設置根節點  9       this.root = newNode;
10     }
11     method.insertNode(this.root, newNode);
12   }
13 }

相關方法:

 1 // method
 2 method = {
 3   insertNode(root, newNode) {
 4     if (newNode.key < root.key) {// 進入左子樹
 5       if (root.left === null) {// 左子樹為空
 6         root.left = newNode;
 7       } else {// 左子樹已存在
 8         method.insertNode(root.left, newNode);
 9       }
10     } else if (newNode.key > root.key) {// 進入右子樹
11       if (root.right === null) {// 右子樹為空
12         root.right = newNode;
13       } else {// 右子樹已存在
14         method.insertNode(root.right, newNode);
15       }
16     }
17   }
18 };

具體用法:

1 // 實例化二叉樹
2 const binaryTree = new BinaryTree();
3 
4 // key值
5 const keys = [19, 8, 15, 24, 45, 12, 5];
6 
7 // 生成排序二叉樹
8 keys.forEach(key => binaryTree.insert(key));

結果:

 

排序二叉樹的遍歷:

 一、中序遍歷

(1)以上圖為例,中序遍歷順序為: 5 - 8 - 12 - 15 - 19 - 24 - 45。

(2)總是先遍歷左子樹,然后訪問根節點,接着遍歷右子樹。

代碼實現:

 1 class BinaryTree {
 2   ...
 3   // callback為訪問節點時執行的操作
 4   inorderTraversal(callback) {// api--中序遍歷
 5     method.inorderTraversalNode(this.root, callback);
 6   }
 7 }
 8 
 9 method = {
10   ...
11 
12   inorderTraversalNode(node, callback) {
13     if (node) {// 當前節點
14       method.inorderTraversalNode(node.left, callback);// 遍歷左子樹
15       callback(node);// 訪問節點
16       method.inorderTraversalNode(node.right, callback);// 遍歷右子樹
17     }
18   },
19 };
20 
21 // 中序遍歷
22 binaryTree.inorderTraversal(node => console.log(node.key));
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

輸入結果:5 - 8 - 12 - 15 - 19 - 24 - 45

二、前序遍歷

(1)以上圖為例,前序遍歷順序為: 19 - 8 - 5 - 15  - 12 - 24 - 45。

(2)總是先訪問根節點,然后遍歷左子樹,接着遍歷右子樹。

代碼實現:

 1 class BinaryTree {
 2   ...    
 3   preOrderTraversal(callback) {// api--前序遍歷
 4     method.preOrderTraversalNode(this.root, callback);
 5   }
 6 }
 7 
 8 method = {
 9   ... 
10   preOrderTraversalNode(node, callback) {
11     if (node) {// 當前節點
12       callback(node);// 訪問節點
13       method.preOrderTraversalNode(node.left, callback);// 遍歷左子樹
14       method.preOrderTraversalNode(node.right, callback);// 遍歷右子樹
15     }
16   }
17 };
18 
19 // 前序遍歷
20 binaryTree.preOrderTraversal(node => console.log(node.key));
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

輸入結果:19 - 8 - 5 - 15  - 12 - 24 - 45

三、后序遍歷

(1)以上圖為例,后序遍歷順序為: 5 - 12 - 15 - 8  - 45 - 24 - 19。

(2)先遍歷左子樹,接着遍歷右子樹,最后訪問根節點。

代碼實現:

 1 class BinaryTree {
 2   ...   
 3   postOrderTraversal(callback) {// api--后序遍歷
 4     method.postOrderTraversalNode(this.root, callback);
 5   }
 6 }
 7 
 8 method = {
 9   ...
10   postOrderTraversalNode(node, callback) {
11     if (node) {// 當前節點
12       method.postOrderTraversalNode(node.left, callback);// 遍歷左子樹
13       method.postOrderTraversalNode(node.right, callback);// 遍歷右子樹
14       callback(node);// 訪問節點
15     }
16   }
17 };
18 
19 // 后序遍歷
20 binaryTree.postOrderTraversal(node => console.log(node.key));
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

輸入結果:5 - 12 - 15 - 8  - 45 - 24 - 19

排序二叉樹的查找:

(1)查找最大值。根據排序二叉樹的特點,右子樹的值都大於父節點的值。只需要進入節點的右子樹查找,當某個節點的右子樹為空時,該節點就是最大值節點。

代碼實現:

 1 class BinaryTree {
 2   ...
 3   max() {
 4     return method.maxNode(this.root);
 5   }
 6 }
 7 
 8 method = {
 9   ...
10   maxNode(node) {
11     if (node) {
12       while(node.right !== null) {// 右子樹不為空時 13         node = node.right;
14       }
15       return node.key;
16     }
17     return null;
18   }
19 };
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

結果:

(2)查找最小值。根據排序二叉樹的特點,左子樹的值都小於父節點的值。只需要進入節點的左子樹查找,當某個節點的左子樹為空時,該節點就是最小值節點。

代碼實現:

 1 class BinaryTree {
 2   ...
 3   min() {
 4     return method.minNode(this.root);
 5   }
 6 }
 7 
 8 method = {
 9   ...
10   minNode(node) {
11     if (node) {
12       while(node.left!== null) {// 左子樹不為空時
13         node = node.left;
14       }
15       return node.key;
16     }
17     return null;
18   }
19 };
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

結果:

(3)查找給定值。在排序二叉樹中查找有沒有節點對應的值與給定值相同。

根據排序二叉樹的特點,比較給定值與節點值,小於時進入節點左子樹。大於時進入節點右子樹。等於時返回真。層層對比,最后如果子樹為空,則表示沒有找到。

代碼實現:

 1 class BinaryTree {
 2   ...
 3   search(key) {
 4     return method.searchNode(this.root, key);
 5   }
 6 }
 7 
 8 method = {
 9   ...
10   searchNode(node, key) {
11     if (node === null) {// 沒有找到 12       return false;
13     }
14     if (key < node.key) {// 進入左子樹 15       return method.searchNode(node.left, key);
16     } else if (key > node.key) {// 進入右子樹 17       return method.searchNode(node.right, key);
18     } else {// 找到了 19       return true;
20     }
21   }
22 };
1 // key值
2 const keys = [19, 8, 15, 24, 45, 12, 5];

結果:

排序二叉樹的刪除:

當刪除的節點為葉子節點時,直接把葉子節點設置成空。如圖:刪除值為5的節點。

原:                                                                                                                                     

          

 現:

當刪除的節點存在左子樹時,把父節點的關系指針直接指向左子樹。如圖:刪除值為15的節點。存在右子樹時同理。

原:                                                                                                                                      

        

現:

  

當節點存在左右子樹時,先去右子樹里找到最小值,然后用最小值替換節點值,最后進入右子樹刪除最小值對應的節點。如圖:刪除值為8的節點。

原:                                                                                                                                      

     

現:

   

代碼實現:

 1 class BinaryTree {
 2   ...
 3   remove(key) {
 4     this.root = method.removeNode(this.root, key);
 5   }
 6 }
 7 
 8 method = {
 9   ...   
10   removeNode(node, key) {
11     if(node === null) {// 沒有找到值對應的節點
12       return null;
13     }
14     if (key < node.key) {// 給定值小於當前節點值
15       node.left = method.removeNode(node.left, key);
16       return node;
17     } else if (key > node.key) {// 給定值大於當前節點值
18       node.right = method.removeNode(node.right, key);
19       return node;
20     } else {// 找到給定值對應的節點
21       if (node.left === null && node.right === null) {// 節點為葉子節點
22         node = null;
23         return node;
24       }
25 
26       if (node.left === null) {// 節點存在右子樹
27         node = node.right;
28         return node;
29       } else if (node.right === null) {// 節點存在左子樹
30         node = node.left;
31         return node;
32       }
33 
34       // 節點存在左右子樹時,先去右子樹里找到最小值,然后用最小值替換節點值,最后進入右子樹刪除最小值對應的節點。
35       const minKey = method.minNode(node.right);
36       node.key = minKey;
37       method.removeNode(node.right, minKey);
38       return node;
39     }
40   }
41 };

結果:

累死我了。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM