二叉樹相關概念及前中後層序遍歷
阿新 • • 發佈:2021-02-18
技術標籤:演算法與資料結構
二叉樹
二叉樹:二叉樹是每個節點最多有兩個子樹的樹結構;是n(n>=0)個結點的有限集合,它或者是空樹(n=0),或者是由一個根結點及兩顆互不相交的、分別稱為左子樹和右子樹的二叉樹所組成。
完全二叉樹
完全二叉樹:除最後一層外,每一層上的結點數均達到最大值;在最後一層上只缺少右邊的若干結點;
滿二叉樹
滿二叉樹:除最後一層外,每一層上的所有結點都有兩個子結點;滿二叉樹是一種特殊的完全二叉樹;
二叉排序樹(二叉搜尋樹)
二叉搜尋樹是二叉樹的一種,是應用非常廣泛的一種二叉樹,英文簡稱為 BST 又被稱為:二叉查詢樹、二叉排序樹
- 任意一個節點的值都大於其左子樹所有節點的值
- 任意一個節點的值都小於其右子樹所有節點的值
- 它的左右子樹也是一棵二叉搜尋樹
二叉排序(搜尋)樹:二叉樹中,每個節點都不比它左子樹的任意元素小,而且不比它的右子樹的任意元素大。又叫二叉搜尋樹。
平衡二叉樹
平衡二叉樹(Balanced Binary Tree)是二叉查詢樹的一個進化體,也是第一個引入平衡概念的二叉樹。1962年,G.M. Adelson-Velsky 和 E.M. Landis發明了這棵樹,所以它又叫AVL樹。
平衡二叉樹要求對於每一個節點來說,它的左右子樹的高度之差不能超過1,如果插入或者刪除一個節點使得高度之差大於1,就要進行節點之間的旋轉,將二叉樹重新維持在一個平衡狀態。
這個方案很好的解決了二叉查詢樹退化成連結串列的問題,把插入,查詢,刪除的時間複雜度最好情況和最壞情況都維持在O(logN)。但是頻繁旋轉會使插入和刪除犧牲掉O(logN)左右的時間,不過相對二叉查詢樹來說,時間上穩定了很多。
二叉樹遍歷
package com.michealkz.tree;
import com.michealkz.printer.BinaryTreeInfo;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
/**
* 二叉搜尋樹繼承自BinaryTreeInfo 實現其中的方法以便進行列印
*
* @param <E>
*/
public class BinarySearchTree<E> implements BinaryTreeInfo {
private int size;
private Node<E> root;
private Comparator<E> comparator;
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void clear() {
root = null;
size = 0;
}
public void add(E element) {
elementNotNullCheck(element);
// 新增第一個節點
if (root == null) {
root = new Node<E>(element, null);
size++;
return;
}
// 新增的不是第一個節點 則找到父節點
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
do {
/*
* 根據compare的返回值正負或者相等來判斷是左子樹還是右子樹還是相等
*/
cmp = compare(element, node.element);
// 將節點儲存下來作為查詢下一個的父節點
parent = node;
if (cmp > 0) {
node = node.right;
} else if (cmp < 0) {
node = node.left;
} else { // 相等
node.element = element;
return;
}
} while (node != null);
// 看看插入到父節點的哪個位置
Node<E> newNode = new Node<E>(element, parent);
if (cmp > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
}
/*
* @return 返回值等於0,代表e1和e2相等;返回值大於0,代表e1大於e2;返回值小於於0,代表e1小於e2
*/
private int compare(E e1, E e2) {
if (comparator != null) {
return comparator.compare(e1, e2);
}
return ((Comparable<E>) e1).compareTo(e2);
}
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
// 二叉樹的前序遍歷操作
public void preorderTraversal() {
preorderTraversal(root);
}
// 二叉樹的前序遍歷傳入根節點進行遍歷操作
private void preorderTraversal(Node<E> node) {
if (node == null) return;
System.out.print(node.element + "\t");
preorderTraversal(node.left);
preorderTraversal(node.right);
}
// 二叉樹中序遍歷
public void middleOrderTraversal() {
middleOrderTraversal(root);
}
// 二叉樹中序遍歷實現邏輯
private void middleOrderTraversal(Node<E> node) {
if (node == null) return;
middleOrderTraversal(node.left);
System.out.print(node.element + "\t");
middleOrderTraversal(node.right);
}
// 二叉樹後序遍歷
public void postOrderTraversal() {
postOrderTraversal(root);
}
// 二叉樹後序遍歷實現
private void postOrderTraversal(Node<E> node) {
if (node == null) return;
postOrderTraversal(node.left);
postOrderTraversal(node.right);
System.out.print(node.element + "\t");
}
// 二叉樹層序遍歷
public void levelOrderTraversal() {
levelOrderTraversal(root);
}
// 二叉樹層序遍歷實現邏輯
/**
* 二叉樹層序遍歷很重要
* 遍歷思路:
* - 1.定義佇列存放節點
* - 2.首先將根節點入佇列
* - 3.如果佇列不為空,那麼將佇列頂部元素出隊
* - 4.輸出根節點的值
* - 5.判斷根節點左右節點是否為空,如果不為空,那麼將左右節點入佇列,只要佇列不為空就一直執行while迴圈
* @param root
*/
private void levelOrderTraversal(Node<E> root) {
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> node = queue.poll();
System.out.print(node.element + "\t");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
/**
* 下面是列印需要重寫的四個方法
* 根節點
*/
@Override
public Object root() {
return root;
}
// 左樹的尋找方式
@Override
public Object left(Object node) {
return ((Node<E>) node).left;
}
// 右樹的尋找方式
@Override
public Object right(Object node) {
return ((Node<E>) node).right;
}
// 列印方式
@Override
public Object string(Object node) {
Node<E> myNode = (Node<E>) node;
// 獲取父節點儲存下來並列印
String parentString = "null";
if (myNode.parent != null) {
parentString = myNode.parent.element.toString();
}
return myNode.element;
}
public BinarySearchTree() {
this(null);
}
public BinarySearchTree(Comparator<E> comparator) {
this.comparator = comparator;
}
/**
* 二叉樹的 Node節點 物件
*/
public static class Node<E> {
E element;
Node<E> left;
Node<E> right;
Node<E> parent;
public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
public boolean isLeaf() {
return left == null && right == null;
}
public boolean hasTwoChildren() {
return left != null && right != null;
}
}
}