日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构与算法--二叉查找树实现原理

發布時間:2023/12/4 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构与算法--二叉查找树实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

二叉查找樹

  • 二叉樹的一個重要應用就是他在查詢中的使用,假設書中每個節點存儲一項數據。在我們的案例中,任意復雜的項在java中都容易處理,但為了簡單還是假設都是整數。還假設他們都是不重復的整數,使二叉樹稱為二叉查找樹的性質是:
    • 對于樹中每個節點X,左子樹中所有項小于X中的項
    • 而右子樹中的所有元素都大于X中的項目
  • 依據以上規則,意味著改樹中所有元素都可以用某種一致的方式排序。

  • 如上圖中圖一中的樹是二叉查找樹,但是圖二中的樹不是,圖二中樹在其項是3 的節點的右子樹 上 有一個節點項是1 ,1< 3,右子節點中數據有小于該節點數據的項目,違反的二叉樹的兩個規則之一。

二叉查找樹的實現

  • 二叉查找樹要求所有項都能夠排序,那么必定在樹中任意兩個節點之間都可以進行比較,所以我們必須對樹節點實現Comparable接口。節點定義如下,和上篇中定義有一點不同:
/*** 二叉樹節點對象定義** @author liaojiamin* @Date:Created in 15:24 2020/12/11*/ public class BinaryNode implements Comparable {private Object element;private BinaryNode left;private BinaryNode right;private int count;public BinaryNode(Object element, BinaryNode left, BinaryNode right) {this.element = element;this.left = left;this.right = right;this.count = 1;}public Object getElement() {return element;}public void setElement(Object element) {this.element = element;}public BinaryNode getLeft() {return left;}public void setLeft(BinaryNode left) {this.left = left;}public BinaryNode getRight() {return right;}public void setRight(BinaryNode right) {this.right = right;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic int compareTo(Object o) {if(o == null){return 1;}int flag = this.element.toString().compareTo(o.toString());if(flag == 0){return 0;}else if (flag > 0){return 1;}else {return -1;}} }
  • 二叉查找樹對應相關方法實現:
/*** 二叉查找樹實現** @author liaojiamin* @Date:Created in 15:42 2020/12/15*/ public class BinarySearchTree {public void makeEmpty(BinaryNode root) {root = null;}public boolean isEmpty(BinaryNode root) {return root == null;}/*** 節點元素是否存在** @author: liaojiamin* @date: 15:48 2020/12/15*/private boolean contains(Object x, BinaryNode t) {if (x == null) {return false;}if (t == null) {return false;}int flag = t.compareTo(x);if (flag > 0) {return contains(x, t.getLeft());} else if (flag < 0) {return contains(x, t.getRight());} else {return true;}}/*** 查找最小元素節點** @author: liaojiamin* @date: 15:48 2020/12/15*/private BinaryNode findMin(BinaryNode t) {if (t == null) {return null;}if (t.getLeft() != null) {return findMin(t.getLeft());}return t;}/*** 查找最大元素節點** @author: liaojiamin* @date: 15:48 2020/12/15*/private BinaryNode findMax(BinaryNode t) {if (t == null) {return null;}if (t.getRight() != null) {return findMax(t.getRight());}return t;}/*** 插入節點** @author: liaojiamin* @date: 15:48 2020/12/15*/private BinaryNode insert(Object x, BinaryNode t) {if (x == null) {return t;}if (t == null || t.getElement() == null) {t = new BinaryNode(x, null, null);return t;}int flag = t.compareTo(x);if (flag > 0) {t.setLeft(insert(x, t.getLeft()));} else if (flag < 0) {t.setRight(insert(x, t.getRight()));} else {t.setCount(t.getCount() + 1);}return t;}/*** 刪除節點** @author: liaojiamin* @date: 15:48 2020/12/15*/private BinaryNode remove(Object x, BinaryNode t) {if (x == null) {return t;}int flag = t.compareTo(x);if (flag > 0) {return remove(x, t.getLeft());} else if (flag < 0) {return remove(x, t.getRight());} else if (t.getLeft() != null && t.getRight() != null) {//找到對應節點,將節點右子樹下面最小的值替換當前值BinaryNode min = findMin(t.getRight());t.setElement(min.getElement());//遞歸刪除右子樹下最小值remove(min.getElement(), t.getRight());} else {//找到對應節點,但是當前節點只有一個子節點// 遞歸思想:只考慮最簡單情況,當只有當前節點與其左子節點,刪除當前節點返回當節點左子節點,右節點同理t = t.getLeft() != null ? t.getLeft() : t.getRight();}return t;}/*** 按順序打印節點信息:左中右** @author: liaojiamin* @date: 15:48 2020/12/15*/public void printTree(BinaryNode t) {if (t == null || t.getElement() == null) {return;}printTree(t.getLeft());for (int i = 0; i < t.getCount(); i++) {System.out.print(t.getElement() + " ");}printTree(t.getRight());}public static void main(String[] args) {BinaryNode node = new BinaryNode(null, null, null);BinarySearchTree searchTree = new BinarySearchTree();Random random = new Random();for (int i = 0; i < 20; i++) {node = searchTree.insert(random.nextInt(1000), node);}System.out.println(searchTree.findMax(node).getElement());System.out.println(searchTree.findMin(node).getElement());searchTree.printTree(node);if(!searchTree.contains(13, node)){node = searchTree.insert(13, node);}System.out.println(searchTree.contains(13, node));node = searchTree.remove(13, node);System.out.println(searchTree.contains(13, node));} }
方法解析:
containes方法
  • 如果在樹T中包含有項目X的節點,你們這個需要返回True,否則放回false。我們用兩個遞歸調用來實現這個方法,其實也可以用while循環來替代遞歸調用。但是這里用遞歸也是合理的,因為算法表達式的簡單性是以降低速度為代價的,而這里所使用的棧空間的量也不過是O(logN)而已
findMin,findMax方法
  • 同樣遞歸,依據二叉查找樹的規則左子樹永遠小于本節點,所以一直向左節點遞歸 可以得到最小值,同樣,一直向右節點遞歸可以得到最大值
insert方法
  • 插入操作概念是簡單的。為了將X插入到樹T中,可以用contains方法那樣沿著樹查找。如果找到X,則更新數量。否則將X插入到變量的路徑上的最后一個點上。如下圖顯示,為了插入4, 我們遍歷改樹就好像在運行contains。在具有關鍵字的1節點處我們需要向右邊行進,但是右邊不存在子樹,因此4不在這棵樹上,從而這個位置就是我們要插入的位置,將4節點的引用交給 1 節點的right
  • 重復插入可以在節點距離中保留一個附加字段頻率來處理,就想我們定義的count

remove方法
  • 在集合相關API中醫院,最困難的是remove刪除操作。因為我們發現要刪除的對應節點,需要考慮多種情況

    • 如果節點是葉子節點,那么可以立刻刪除,
    • 如果節點有一個兒子節點,則該節點卡伊在其父節點調整自己的鏈,從而繞過改節點后邏輯上被刪除
    • 最復雜情況,處理具有兩個兒子節點,一般的刪除策略是用其右子樹的最小數據代替該節點的數據,并遞歸的刪除那個最小的數據(相當于將右子樹最小數據和需要刪除數據做替換),因為右子樹的最小節點不可能有左節點,所以第二次remove要容易。
    • 下面分別圖示一個子節點和兩個子節點的情況
  • 一個節點情況

  • 兩個子節點情況,刪除5 節點,將右子樹中最小節點6 和 5 替換,再刪除 右子樹最小節點6:

平均時間復雜度分析

  • 二叉樹我們期望的平均時間復雜度是O(logN)時間,但是一顆二叉查找樹在不斷的insert和remove的過程中,由于上面我們所采用的的刪除策略有助于使得左子樹的深度比右子樹更深,因為我們總是用右子樹中最小的節點去替換需要刪除的節點。這種方案的準確性是已經在業界證明可行,就避免不了最終不平衡的可能。
  • 我們在刪除過程中可以通過隨機選取右子樹的最小元素 和 左子樹的最大元素來代替刪除元素的策略來消除這種不平衡問題,但是這種做法還沒有人能證明可行性。
  • 好像不能完全解決平衡問題,出發我們增加一個平衡(balance)的附加條件:任何節點深度不得過深那就是AVL樹。

上一篇:數據結構與算法–重建二叉樹
下一篇:數據結構與算法–AVL樹原理及實現

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的数据结构与算法--二叉查找树实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。