二叉樹的遍歷
關於二叉樹的遍歷,總共有四種方式:
- 先序遍歷
- 中序遍歷
- 後序遍歷
- 層序遍歷
其中前三種都屬於深度優先遍歷,最後一種屬於廣度優先遍歷,下面逐一講解。
先序遍歷
先序遍歷是先訪問二叉樹的根節點,再訪問二叉樹根結點的左子樹,最後訪問其右子樹。圖示如下:
代碼實現如下:
//先序遍歷,將遍歷的結點上的value保存在List中
public List<V> preOrder() {
List<Node> nodeList = new LinkedList<>();
List<V> valueList = new LinkedList<>();
preOrder(root,nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void preOrder(Node node, List<Node> nodeList) {
if(node == null) {
return;
}
nodeList.add(node);
preOrder(node.left, nodeList);
preOrder(node.right, nodeList);
}
先序遍歷非遞歸實現
另外,除了遞歸的方式,還可以借用棧這種數據結構進行先序遍歷。它的思路是怎樣的呢?它每訪問一個結點都將其入棧,然後訪問該結點的左子樹,當該結點的左子樹爲空時,利用棧回到剛纔訪問的結點,然後去訪問其右子樹。圖示如下:
代碼實現如下:
//借用棧實現非遞歸先序遍歷
private void preOrder2(Node node, List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
while(node != null || !stack.isEmpty()) {
if(node != null) {
//訪問該結點併入棧
nodeList.add(node);
stack.push(node);
//訪問其左子樹
node = node.left;
}else{
//左子樹爲null或右子樹爲null,將棧頂元素出棧
node = stack.pop();
//訪問棧頂元素右子樹
node = node.right;
}
}
}
中序遍歷
中序遍歷的順序是先訪問左子樹,再訪問根結點,最後訪問其右子樹。
遞歸實現代碼如下:
//中序遍歷,將遍歷的結點保存在List中
public List<V> inOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
inOrder(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void inOrder(Node node, List<Node> nodeList) {
if(node == null) {
return;
}
inOrder(node.left, nodeList);
nodeList.add(node);
inOrder(node.right, nodeList);
}
注意這裏保存的value的值,而比較的是key值,所以不是順序的,這個根據實際需要調整。
下面也來實現一下非遞歸方式實現中序遍歷:
思路和前面一樣,也是利用棧這種數據結構。只不過這裏當遍歷到結點時直接把它入棧記錄訪問的順序,知道左子樹爲null時才通過出棧的方式來訪問它。
代碼實現如下:
//非遞歸方式實現中序遍歷
private void inOrder2(Node node,List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
while(node != null || stack.size()!=0) {
if(node != null) {
stack.push(node);
node = node.left;
}else {
node = stack.pop();
nodeList.add(node);
node = node.right;
}
}
}
後序遍歷
後序遍歷訪問二叉樹結點的順序是先訪問樹的左子樹,再訪問樹的右子樹,最後才訪問樹的根結點。它也有遞歸方式和非遞歸方式實現。和前面兩種區別不大,只是順序不一樣。就不羅嗦了,直接上代碼:
//後序遍歷,將遍歷的結點保存在List中
public List<V> postOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
postOrder2(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void postOrder(Node node, List<Node> nodeList) {
if(node == null){
return;
}
postOrder(node.left, nodeList);
postOrder(node.right, nodeList);
nodeList.add(node);
}
//後序遍歷的非遞歸實現
public void postOrder2(Node node, List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
Node prev = root; //記錄前面訪問過的一個結點
while(node != null || stack.size()!=0) {
if(node != null) {
stack.push(node);
node = node.left;
}else {
node = stack.peek().right;
//沒有右子樹或之前訪問過
if(node == null || node == prev) {
node = stack.pop();
nodeList.add(node);
prev = node;
node = null;
}
}
}
}
層序遍歷
層序遍歷的順序是這樣的,從樹的根結點開始,從上至下、再從左至右一次訪問樹上的結點。舉個例子:
代碼實現如下:
//層序遍歷,,將遍歷的結點保存在List中
public List<V> levelOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
levelOrder(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void levelOrder(Node node, List<Node> nodeList) {
Queue<Node> nodes = new ArrayDeque<>();
while(node != null) {
nodeList.add(node);
if(node.left != null){
nodes.add(node.left);
}
if(node.right != null){
nodes.add(node.right);
}
//隊列的頭部元素出隊
if(nodes.size() > 0){
node = nodes.remove();
}else{
node = null;
}
}
}
最後貼上二叉樹的完整代碼。
import java.util.*;
public class BinaryTree<K extends Comparable<K>,V> {
private class Node {
K key;
V value;
Node left;
Node right;
int height;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
//結點默認添加爲葉子結點,故高度爲1
this.height = 1;
}
}
private Node root;
private int size;
public BinaryTree() {
root = null;
size = 0;
}
//獲取二叉樹樹中結點個數
public int getSize() {
return size;
}
//判空
public boolean isEmpty() {
return size == 0;
}
//獲得結點的高度
public int getHeight(Node node) {
if(node == null){
return 0;
}
return node.height;
}
// //判斷以node爲根的樹是否平衡
// //平衡因子爲-1、0、1代表該樹平衡
// public boolean isBalance(Node node) {
// int balanceFactor = getBalanceFactor(node);
// if(Math.abs(balanceFactor) > 1){
// return false;
// }
// return isBalance(node.left) && isBalance(node.right);
// }
// //獲取node爲根的樹的平衡因子
// private int getBalanceFactor(Node node) {
// int l = getHeight(node.left);
// int r = getHeight(node.right);
// return l - r;
// }
//先序遍歷,將遍歷的結點上的value保存在List中
public List<V> preOrder() {
List<Node> nodeList = new LinkedList<>();
List<V> valueList = new LinkedList<>();
preOrder2(root,nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void preOrder(Node node, List<Node> nodeList) {
if(node == null) {
return;
}
nodeList.add(node);
preOrder(node.left, nodeList);
preOrder(node.right, nodeList);
}
//借用棧實現非遞歸先序遍歷
private void preOrder2(Node node, List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
while(node != null || !stack.isEmpty()) {
if(node != null) {
//訪問該結點併入棧
nodeList.add(node);
stack.push(node);
//訪問其左子樹
node = node.left;
}else{
//左子樹爲null或右子樹爲null,將棧頂元素出棧
node = stack.pop();
//訪問棧頂元素右子樹
node = node.right;
}
}
}
//中序遍歷,將遍歷的結點保存在List中
public List<V> inOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
inOrder2(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void inOrder(Node node, List<Node> nodeList) {
if(node == null) {
return;
}
inOrder(node.left, nodeList);
nodeList.add(node);
inOrder(node.right, nodeList);
}
//非遞歸方式實現中序遍歷
private void inOrder2(Node node,List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
while(node != null || stack.size()!=0) {
if(node != null) {
stack.push(node);
node = node.left;
}else {
node = stack.pop();
nodeList.add(node);
node = node.right;
}
}
}
//後序遍歷,將遍歷的結點保存在List中
public List<V> postOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
postOrder2(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void postOrder(Node node, List<Node> nodeList) {
if(node == null){
return;
}
postOrder(node.left, nodeList);
postOrder(node.right, nodeList);
nodeList.add(node);
}
//後序遍歷的非遞歸實現
public void postOrder2(Node node, List<Node> nodeList) {
Stack<Node> stack = new Stack<>();
Node prev = root; //記錄前面訪問過的一個結點
while(node != null || stack.size()!=0) {
if(node != null) {
stack.push(node);
node = node.left;
}else {
node = stack.peek().right;
//沒有右子樹或之前訪問過
if(node == null || node == prev) {
node = stack.pop();
nodeList.add(node);
prev = node;
node = null;
}
}
}
}
//層序遍歷,,將遍歷的結點保存在List中
public List<V> levelOrder() {
List<V> valueList = new LinkedList<>();
List<Node> nodeList = new LinkedList<>();
levelOrder(root, nodeList);
for(Node node : nodeList) {
valueList.add(node.value);
}
return valueList;
}
private void levelOrder(Node node, List<Node> nodeList) {
Queue<Node> nodes = new ArrayDeque<>();
while(node != null) {
nodeList.add(node);
if(node.left != null){
nodes.add(node.left);
}
if(node.right != null){
nodes.add(node.right);
}
//隊列的頭部元素出隊
if(nodes.size() > 0){
node = nodes.remove();
}else{
node = null;
}
}
}
//在以node爲根的樹上尋找key的結點
private Node findNode(Node node, K key) {
if(node == null){
return null;
}
if(node.key.compareTo(key) == 0) {
return node;
}else if(node.key.compareTo(key) > 0) {
return findNode(node.left, key);
}else{
return findNode(node.right, key);
}
}
//是否包含某個鍵值
public boolean contains(K key) {
return findNode(root, key) != null;
}
//獲取key的結點的value
public V get(K key) {
Node node = findNode(root, key);
if(node != null){
return node.value;
}
return null;
}
//是否包含某個V
public boolean containsValue(V value) {
List<V> valueList = inOrder();
for(V v : valueList) {
if(v.equals(value)) {
return true;
}
}
return false;
}
//獲取以node爲根,key爲鍵的樹上的結點
private Node getNode(Node node, K key) {
return findNode(node, key);
}
//設置key的結點的值
public void set(K key, V value) {
Node node = findNode(root, key);
if(node != null) {
node.value = value;
}else{
throw new IllegalStateException("Node doesn't exist.");
}
}
//找到以node爲根結點的樹上的最大結點
private Node findMax(Node node) {
if(node == null) {
return null;
}
while(node.right != null) {
node = node.right;
}
return node;
}
//找到以node爲根結點的樹上的最小結點
private Node findMin(Node node) {
if(node == null){
return null;
}
while(node.left != null){
node = node.left;
}
return node;
}
//刪除以node爲根的樹上的最小結點,返回該樹的根結點
public Node removeMin(Node node){
if(node.left == null) {
//此時node爲最小結點
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
//添加結點
public void add(K key, V value) {
root = add(root, key, value);
}
private Node add(Node node, K key, V value) {
if(node == null) { //找到了合適的位置,直接添加
node = new Node(key,value);
size ++;
//維護結點的高度
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
}
if(node.key.compareTo(key) > 0) {
//比當前根結點小,遞歸添加到其左子樹上
node.left = add(node.left, key, value);
}else if(node.key.compareTo(key) < 0){
//比當前結點大,遞歸添加到其右子樹上
node.right = add(node.right, key, value);
}else {
node.value = value;
}
return node;
}
//刪除指定的結點
public V remove(K key) {
Node node = getNode(root, key);
if(node != null) {
return node.value;
}
return null;
}
private Node remove(Node node, K key) {
if(node == null) {
return null;
}
if(node.key.compareTo(key) > 0) {
node.left = remove(node.left, key);
return node;
}else if(node.key.compareTo(key) < 0) {
node.right = remove(node.right, key);
return node;
}else { //找到了要刪除的結點
if(node.left == null) { //沒有左孩子或者沒有孩子結點
Node rightNode = node.right;
size --;
node.right = null;
return rightNode;
}else if(node.right == null) { //沒有右孩子
Node leftNode = node.left;
size --;
node.left = null;
return leftNode;
}else {
Node successor = findMin(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
return successor;
}
}
}
public static void main(String[] args) {
BinaryTree<Integer,Integer> binaryTree = new BinaryTree<>();
Random random = new Random();
Integer[] keys = new Integer[10];
for(int i=0;i<10;i++){
keys[i] = random.nextInt(25);
binaryTree.add(keys[i],random.nextInt(100));
}
List<Integer> list = binaryTree.levelOrder();
for(Integer i : list) {
System.out.print(i+" ");
}
}
}