1. 程式人生 > 其它 >二叉樹相關概念及前中後層序遍歷

二叉樹相關概念及前中後層序遍歷

技術標籤:演算法與資料結構

二叉樹

二叉樹:二叉樹是每個節點最多有兩個子樹的樹結構;是n(n>=0)個結點的有限集合,它或者是空樹(n=0),或者是由一個根結點及兩顆互不相交的、分別稱為左子樹和右子樹的二叉樹所組成。

img

完全二叉樹

完全二叉樹:除最後一層外,每一層上的結點數均達到最大值;在最後一層上只缺少右邊的若干結點;

img

滿二叉樹

滿二叉樹:除最後一層外,每一層上的所有結點都有兩個子結點;滿二叉樹是一種特殊的完全二叉樹;

img

二叉排序樹(二叉搜尋樹)

二叉搜尋樹是二叉樹的一種,是應用非常廣泛的一種二叉樹,英文簡稱為 BST 又被稱為:二叉查詢樹、二叉排序樹

  • 任意一個節點的值都大於其左子樹所有節點的值
  • 任意一個節點的值都小於其右子樹所有節點的值
  • 它的左右子樹也是一棵二叉搜尋樹

二叉排序(搜尋)樹:二叉樹中,每個節點都不比它左子樹的任意元素小,而且不比它的右子樹的任意元素大。又叫二叉搜尋樹。

img

平衡二叉樹

平衡二叉樹(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; } } }