牛客多校第三場補題
阿新 • • 發佈:2020-07-23
樹
1. 樹的定義
樹的特點:
- 每個結點有0個或者多個子結點
- 沒有父結點的結點為根節點
- 每一個非根結點只有一個父結點
- 每個結點及其後代結點整體上可以看做一棵樹,稱為當前結點的父結點的一個子樹
2. 樹的相關術語
- 結點的度:一個結點含有的子樹的個數稱為結點的度(也可以理解為子結點的個數)
- 葉結點:度為0的結點稱為葉結點
- 分支結點:與葉結點相反,度不為0的結點稱為分支結點
- 結點的層次:從根結點開始,根結點的層次為1,根的直接後繼層次為2,以此類推
- 樹的度:樹中所有結點的度的最大值
- 樹的深度:樹中結點的最大層次
3. 二叉樹的基本定義
二叉樹就是度不超過2的樹(每個結點多有兩個子結點)
-
滿二叉樹:一個二叉樹,每一層的結點都達到最大值,則這個二叉樹就是滿二叉樹
-
完全二叉樹:葉節點只能出現在下層和次下層,並且下面一層的結點都集中在該層左邊的若干位置的二叉樹
4. 二叉樹的API設計
5.二叉樹的程式碼實現
public class BinaryTree <Key extends Comparable<Key>,Value>{ //記錄根結點 private Node root; private int N; private class Node{ public Key key; public Value value; public Node left; public Node right; public Node(Key key, Value value, Node left, Node right) { this.key = key; this.value = value; this.left = left; this.right = right; } } //獲取樹中元素的個數 public int size(){ return N; } //向樹中新增元素key-value public void put(Key key,Value value){ root = put(root,key,value); } //向指定樹X中新增元素key-value public Node put(Node x,Key key,Value value){ //如果x子樹為空 if (x == null){ N++; return new Node(key,value,null,null); } //如果X子樹不為空 int cmp = key.compareTo(x.key); if (cmp>0){ x.right = put(x.right,key,value); }else if (cmp<0){ x.left = put(x.left,key,value); }else { x.value = value; } return x; } //查詢樹種指定key的對應的value public Value get(Key key){ return get(root,key); } //從指定樹中查詢key對應的值 public Value get(Node x ,Key key){ //x樹為null if (x == null){ return null; } //x樹不為null int cmp = key.compareTo(x.key); if (cmp>0){ return get(x.right,key); }else if (cmp<0){ return get(x.left,key); }else { return x.value; } } //刪除樹中key對應的value public void delete(Key key){ delete(root,key); } //刪除指定樹中key對應的value,並返回刪除後的新樹 public Node delete(Node x,Key key){ N--; //x樹為null if (x == null){ return null; } //x樹不為null int cmp = key.compareTo(x.key); if (cmp>0){ x.right = delete(x.right,key); }else if (cmp<0){ x.left = delete(x.left,key); }else { if (x.right==null){ return x.left; } if (x.left==null){ return x.right; } Node minNode = x.right; while (minNode.left!=null){ minNode = minNode.left; } Node n = x.right; while (n.left!=null){ if (n.left.left==null){ n.left = null; }else { n = n.left; } } minNode.left = x.left; minNode.right = x.right; x = minNode; } return null; } }
6.二叉樹的遍歷
1. 前序遍歷
先訪問根結點,然後再訪問左子樹,後訪問右子樹
2. 前序遍歷程式碼實現
//獲取整個樹中所有的鍵 public Queue<Key> preErgodic(){ Queue<Key> keys = new Queue<>(); preErgodic(root,keys); return keys; } //獲取指定樹x的所有鍵,並放到keys佇列中 private void preErgodic(Node x,Queue<Key> keys){ if (x==null){ return; } //把x結點的key放入到keys中 keys.enqueue(x.key); //遞迴遍歷x結點的左子樹 if (x.left!=null){ preErgodic(x.left,keys); } //遞迴遍歷x結點的右子樹 if (x.right!=null){ preErgodic(x.right,keys); } }
3. 中序遍歷
先訪問左子樹,中間訪問根節點,後訪問右子樹
4. 中序遍歷程式碼實現
public Queue<Key> midErgodic(){
Queue<Key> keys = new Queue<>();
midErgodic(root,keys);
return null;
}
public void midErgodic(Node x,Queue<Key> keys){
if (x==null){
return;
}
//先遞迴,把左子樹中的鍵放到keys中
if (x.left!=null){
midErgodic(x.left,keys);
}
//把當前結點的x的鍵放到keys中
keys.enqueue(x.key);
//再遞迴,把右子樹中的鍵放到keys中
if (x.right!=null){
midErgodic(x.right,keys);
}
}
5. 後序遍歷
先訪問左子樹,再訪問右子樹,後訪問根節點
6. 後序遍歷程式碼實現
public Queue<Key> afterErgodic(){
Queue<Key> keys = new Queue<>();
afterErgodic(root,keys);
return keys;
}
public void afterErgodic(Node x,Queue<Key> keys){
if (x==null){
return;
}
if (x.left!=null){
afterErgodic(x.left,keys);
}
if (x.right!=null){
afterErgodic(x.right,keys);
}
keys.enqueue(x.key);
}
7. 層序遍歷
所謂的層序遍歷,就是從根節點(第一層)開始,依次向下,獲取每一層所有結點的值
8. 層序遍歷程式碼實現
public Queue<Key> layerErgodic(){
Queue<Key> keys = new Queue<>();
Queue<Node> nodes = new Queue<>();
nodes.enqueue(root);
while (!nodes.isEmpty()){
Node n = nodes.dequeue();
keys.enqueue(n.key);
if (n.left!=null){
nodes.enqueue(n.left);
}
if (n.right!=null){
nodes.enqueue(n.right);
}
}
return keys;
}
7.二叉樹的最大深度程式碼實現
public int maxDepth(){
return maxDepth(root);
}
public int maxDepth(Node x){
if (x ==null){
return 0;
}
int max = 0;
int maxL = 0;
int maxR = 0;
//計算左子樹最大深度
if (x.left!=null){
maxL = maxDepth(x.left);
}
//計算右子樹最大深度
if (x.right!=null){
maxR = maxDepth(x.right);
}
//比較左子樹的最大深度和右子樹的最大深度,取較大值
max = maxL>maxR?maxL+1:maxR+1;
return max;
}