Java尋找演算法(四): 二叉排序樹,java二叉

來源:互聯網
上載者:User

Java尋找演算法(四): 二叉排序樹,java二叉

[ 為什麼使用二叉排序樹 ] 

如果尋找的資料集是有序線性表,並且是順序儲存的,尋找可以用折半、插值等尋找演算法來實現,但是因為有序,在插入和刪除操作上,需要耗費大量的時間。

因為二叉排序樹使用連結的方式儲存,在執行插入或刪除操作時不用移動元素,所以插入刪除的時間效能比較好


[ 二叉排序樹的特點 ] 

二叉排序樹又稱為二叉尋找樹,它或者是一顆空樹,或者是具有下列性質的二叉樹:

1. 若它的左子樹不空,則左子樹上所有結點的值均小於它的根節點的值。

2. 若它的右子樹不空,則右子樹上所有結點的值均大於它的根節點的值。

3. 它的左、右子樹也分別為二叉排序樹


[ 二叉排序樹的實現 ] 

import java.util.Iterator;import java.util.NoSuchElementException;/** * 二叉排序樹,也可以稱為二叉尋找樹,它的性質如下: * 1.若它的左子樹不為空白,則左子樹上所有的節點均小於其根節點 * 2.若它的右子樹不為空白,則右子樹上所有的節點的值均大於根節點  * 3.它的左右子樹也分別為二叉排序樹 * 簡單起見,假設樹中元素都實現了Comparable介面或者他們可以按自然順序比較 */public class BinarySortTree<E> {// 根節點private Entry<E> root = null;// 樹中元素個數private int size = 0;public BinarySortTree() {}public int size() {return size;}public E getRoot() {return root == null ? null : root.element;}/** * 遞迴實現: 尋找指定元素element是否在樹中存在,如果尋找失敗確認其添加的位置,尋找成功直接返回 * @param t 表示從此節點開始往下尋找 * @param f 儲存t的父節點 * @param p 若尋找成功p指向此資料元素節點,否則返回尋找路徑上的最後一個節點 */private boolean searchBST(Entry<E> t, Object element, Entry<E> f, Entry<E> p) {if (t == null) {p = f;return false;}Comparable<? super E> e = (Comparable<? super E>) element;int cmp = e.compareTo(t.element);if (cmp < 0) {return searchBST(t.left, element, t, p);} else if (cmp > 0) {return searchBST(t.right, element, t, p);} else {p = t;return true;}}/** * 非遞迴實現 */private boolean searchBST(Object element, Entry[] p) {Comparable<? super E> e = (Comparable<? super E>) element;Entry<E> parent = root;Entry<E> pp = null;// 儲存parent父節點while (parent != null) {int cmp = e.compareTo(parent.element);pp = parent;if (cmp < 0) {parent = parent.left;} else if (cmp > 0) {parent = parent.right;} else {p[0] = parent;return true;}}p[0] = pp;return false;}/** * 首先尋找二叉排序樹,如果找不到指定元素 則插入到二叉樹中 */public boolean add(E element) {Entry<E> t = root;if (t == null) {// 如果根節點為空白root = new Entry<E>(element, null);size = 1;return false;}Comparable<? super E> e = (Comparable<? super E>) element;Entry[] p = new Entry[1];if (!searchBST(element, p)) {// 尋找失敗,插入元素Entry<E> s = new Entry<E>(element, p[0]);int cmp = e.compareTo((E) p[0].element);if (cmp < 0) {p[0].left = s;}if (cmp > 0) {p[0].right = s;}size++;return true;}return false;}/** * 移除節點,同時調整二叉樹使之為二叉排序樹 實現原理:  * 假設要刪除的節點為p,其父節點為f,而p是f的左節點 分三種情況討論: * 1.若p為葉子節點,直接刪除  * 2.若p有只有一個左孩子或者一個右孩子,則刪除p,使PL或者PR為f的左子樹 * 3.若p的左右子樹均不為空白,由二叉排序樹的特點可知在刪除p前,中序遍曆此二叉樹 * 可以得到一個有序序列,在刪去p後為了保持其他元素的相對位置不變,可以這樣做: * 令p的直接前驅(或直接後繼)替代p,然後刪除其直接前驅或直接後繼。其直接前驅可由 中序遍曆的特點獲得 */public boolean remove(Object o) {Entry[] p = new Entry[1];if (searchBST(o, p)) {deleteEntry(p[0]); // 尋找成功,刪除元素return true;}return false;}private void deleteEntry(Entry<E> p) {size--;if (p.left != null && p.right != null) { // 如果p左右子樹都不為空白,找到其直接後繼,替換pEntry<E> s = successor(p);p.element = s.element;p = s;}Entry<E> replacement = (p.left != null ? p.left : p.right);if (replacement != null) { // 如果其左右子樹有其一不為空白replacement.parent = p.parent;if (p.parent == null) // 如果p為root節點root = replacement;else if (p == p.parent.left) // 如果p是左孩子p.parent.left = replacement;elsep.parent.right = replacement; // 如果p是右孩子p.left = p.right = p.parent = null; // p的指標清空} else if (p.parent == null) { // 如果全樹只有一個節點root = null;} else { // 左右子樹都為空白,p為葉子節點if (p.parent != null) {if (p == p.parent.left)p.parent.left = null;else if (p == p.parent.right)p.parent.right = null;p.parent = null;}}}/** * 返回以中序遍曆方式遍曆樹時,t的直接後繼 */static <E> Entry<E> successor(Entry<E> t) {if (t == null)return null;else if (t.right != null) {Entry<E> p = t.right; // 往右,然後向左直到盡頭while (p.left != null)p = p.left;return p;} else { // right為空白,如果t是p的左子樹,則p為t的直接後繼Entry<E> p = t.parent;Entry<E> ch = t;while (p != null && ch == p.right) {ch = p; // 如果t是p的右子樹,則繼續向上搜尋其直接後繼p = p.parent;}return p;}}public Iterator<E> itrator() {return new BinarySortIterator();}/** * 返回中序遍曆此樹的迭代器 */private class BinarySortIterator implements Iterator<E> {Entry<E> next;Entry<E> lastReturned;public BinarySortIterator() {Entry<E> s = root;if (s != null) {while (s.left != null) {s = s.left; // 找到中序遍曆的第一個元素}}next = s; // 賦給next}@Overridepublic boolean hasNext() {return next != null;}@Overridepublic E next() {Entry<E> e = next;if (e == null)throw new NoSuchElementException();next = successor(e);lastReturned = e;return e.element;}@Overridepublic void remove() {if (lastReturned == null)throw new IllegalStateException();// deleted entries are replaced by their successorsif (lastReturned.left != null && lastReturned.right != null)next = lastReturned;deleteEntry(lastReturned);lastReturned = null;}}/** * 樹節點,為方便起見不寫get,set方法 */static class Entry<E> {E element;Entry<E> parent;Entry<E> left;Entry<E> right;public Entry(E element, Entry<E> parent) {this.element = element;this.parent = parent;}public Entry() {}}// just for testpublic static void main(String[] args) {BinarySortTree<Integer> tree = new BinarySortTree<Integer>();tree.add(45);tree.add(24);tree.add(53);tree.add(45);tree.add(12);tree.add(90);System.out.println(tree.remove(400));System.out.println(tree.remove(45));System.out.println("root=" + tree.getRoot());Iterator<Integer> it = tree.itrator();while (it.hasNext()) {System.out.println(it.next());}System.out.println(tree.size());}}



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.