1. 程式人生 > >用一個圖書庫例項搞懂二分搜尋樹的底層原理

用一個圖書庫例項搞懂二分搜尋樹的底層原理

[toc] #### 一、背景 二叉樹是一種常用的資料結構,更是實現眾多演算法的一把利器。本文將通過建立一個圖書庫的例項對二叉樹中的常用型別:二分搜尋樹(Binary Search Tree)進行底層原理的深入理解。 #### 二、概念 ##### 1、定義 > **1 二分搜尋樹是一顆二叉樹 2 二分搜尋樹每個節點的左子樹的值都小於該節點的值,每個節點右子樹的值都大於該節點的值 3 任意一個節點的每棵子樹都滿足二分搜尋樹的定義** ##### 2、 動畫示例 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200623140545408.gif) #### 三、圖書庫例項 ##### 3.1、專案需求 - 建立一個圖書類:圖書類中需包含ISBN號,書名,作者,定價,出版社、出版日期等 - 用二分搜尋樹的資料結構建立一個圖書庫,每種圖書需有當前數量 - 圖書庫需實現新增圖書,遍歷整個圖書庫,及可根據ISBN號進行快速查詢 ##### 3.2、程式碼結構 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200623140817144.png) ##### 3.3、圖書類 - 在圖書類的定義中,重寫compareTo方法:通過比較ISBN(國際標準書號)的大小表示圖書在二叉樹的結點順序。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200623141326685.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pwZ3podQ==,size_16,color_FFFFFF,t_70) ```java /** - 用二分搜尋樹實現圖書庫--圖書類 - - @author zhuhuix - @date 2020-06-23 */ public class Books implements Serializable, Comparable { // ISBN private Long bookId; // 作者 private String author; // 分類 private String category; // 書名 private String bookName; // 定價 private BigDecimal bookPrice; // 出版社 private String bookPublisher; // 出版時間 private LocalDate bookDate; // 當前數量 private Integer bookCount; public Books(Long bookId, String bookName, String category, String author, BigDecimal bookPrice, String bookPublisher, LocalDate bookDate, Integer bookCount) { this.bookId = bookId; this.author = author; this.category = category; this.bookName = bookName; this.bookPrice = bookPrice; this.bookPublisher = bookPublisher; this.bookDate = bookDate; this.bookCount = bookCount; } public Books(Long bookId){ this.bookId= bookId; } // 通過ISBN號進行比較大小 @Override public int compareTo(Object o) { if (o instanceof Books) { return this.getBookId().compareTo(((Books) o).getBookId()); } else { return -1; } } public Long getBookId() { return bookId; } public Integer getBookCount() { return bookCount; } public void setBookCount(Integer bookCount) { this.bookCount += bookCount; } @Override public String toString() { return "{" + "ISBN=" + bookId + ", 書名='" + bookName + '\'' + ", 作者='" + author + '\'' + ", 分類='" + category + '\'' + ", 價格=" + bookPrice + ", 出版社='" + bookPublisher + '\'' + ", 出版時間=" + bookDate + ", 當前數量=" + bookCount + '}'; } } ``` ##### 3.4、二分搜尋樹的底層實現 - 底層建立內部結點類(class Node):元素,左子樹,右子樹 - add方法:使用遞迴方法增加結點: -- 如果圖書種類不存在,則建立新結點。 -- 如果圖書種類存在,則對數量進行累加。 - traverse方法:使用遞迴方法對所有結點進行遍歷 - search方法:根據ISBN碼查詢結點 ```java /** * 用二分搜尋樹實現圖書庫--二分搜尋樹 * * @author zhuhuix * @date 2020-06-23 */ public class BinarySearchTree { // 結點 private Node root; // 書的種類 private int bookSize; // 書的總數量 private int bookCount; public BinarySearchTree() { this.root = null; this.bookSize = 0; this.bookCount = 0; } // 增加元素 public void add(Books data) { this.root = addNode(this.root, data); } // 用遞迴方法實現結點的新增 private Node addNode(Node node, Books data) { // 遞迴退出條件 書不存在拉加結點,並將結點數量加1 if (node == null) { this.bookSize++; this.bookCount += data.getBookCount(); return new Node(data); } if (node.data.compareTo(data) < 0) { node.right = addNode(node.right, data); } else if (node.data.compareTo(data) > 0) { node.left = addNode(node.left, data); } else if (node.data.compareTo(data) == 0) { // 如果結點已存在,則將書的數量累加 this.bookCount += data.getBookCount(); node.getData().setBookCount(data.getBookCount()); } return node; } // 用遞迴方法實現結點前序遍歷 public void traverse(Node node) { if (node == null) { return; } System.out.println(node.getData().toString()); traverse(node.left); traverse(node.right); } // 用遞迴方法實現通過isbn查詢圖書 public Books search(Long isbn) { Node node = nodeSearch(this.root, new Books(isbn)); if (node != null) { return node.getData(); } else { return null; } } private Node nodeSearch(Node node, Books books) { if (node == null) { return null; } if (books.compareTo(node.getData()) == 0) { return node; } else if (books.compareTo(node.getData()) < 0) { return nodeSearch(node.left, books); } else { return nodeSearch(node.right, books); } } public Node getRoot() { return root; } // 返回書的種類數 public int getBookSize() { return bookSize; } // 返回書的總數量 public int getBookCount() { return bookCount; } // 私有內部類-樹結點 private class Node { Books data; Node left, right; Node(Books data) { this.data = data; this.left = null; this.right = null; } Books getData() { return data; } } } ``` ##### 3.5、圖書庫的構建 1. 構建一棵二分搜尋樹; 2. 將京東十大暢銷圖書加入二分搜尋樹; 3. 統計圖書種類及數量,並遍歷輸出; 4. 加入3種已經進入圖書庫的圖書; 5. 再次統計圖書種類及數量,並遍歷輸出; 6. 根據某個ISBN號查詢圖書。 ```java /** * 用二分搜尋樹實現圖書庫 * * @author zhuhuix * @date 2020-06-23 */ public class BookStore { public static void main(String[] args) { // 構建一棵二分搜尋樹 BinarySearchTree bst = new BinarySearchTree(); // 將十大暢銷圖書加入二分搜尋樹 bst.add(new Books(9787115428028L,"Python程式設計 從入門到實踐", "程式語言與程式設計","埃裡克·馬瑟斯", BigDecimal.valueOf(61.40),"人民郵電出版社", LocalDate.of(2017,07,01),1)); bst.add(new Books(9787115525963L,"說服力 工作型PPT該這樣做", "辦公軟體","秦陽", BigDecimal.valueOf(66.30),"人民郵電出版社", LocalDate.of(2020,05,01),1)); bst.add(new Books(9787569222258L,"零基礎學Python(全綵版)", "程式語言與程式設計","明日科技", BigDecimal.valueOf(67.00),"吉林大學出版社", LocalDate.of(2018,04,01),1)); bst.add(new Books(9787121388361L,"PS之光:一看就懂的Photoshop攻略(全綵)", "圖形影象/多媒體","馮注龍", BigDecimal.valueOf(60.70),"電子工業出版社", LocalDate.of(2020,06,01),1)); bst.add(new Books(9787302423287L,"機器學習", "人工智慧","周志華", BigDecimal.valueOf(64.80),"清華大學出版社", LocalDate.of(2016,01,01),1)); bst.add(new Books(9787111641247L,"深入理解Java虛擬機器:JVM高階特性與最佳實踐(第3版)", "程式語言與程式設計","周志明", BigDecimal.valueOf(106.40),"機械工業出版社", LocalDate.of(2019,12,01),1)); bst.add(new Books(9787115472588L,"鳥哥的Linux私房菜 基礎學習篇 第四版", "作業系統","鳥哥", BigDecimal.valueOf(93.00),"人民郵電出版社", LocalDate.of(2018,10,01),1)); bst.add(new Books(9787115293800L,"演算法(第4版)", "程式語言與程式設計","Robert Sedgewick,Kevin Wayne", BigDecimal.valueOf(66.30),"人民郵電出版社", LocalDate.of(2012,10,01),1)); bst.add(new Books(9787115537973L,"數學之美 第三版", "計算機理論、基礎知識","吳軍", BigDecimal.valueOf(54.40),"人民郵電出版社", LocalDate.of(2020,05,01),1)); bst.add(new Books(9787302255659L,"大話資料結構", "程式語言與程式設計","程傑", BigDecimal.valueOf(47.20),"清華大學出版社", LocalDate.of(2011,06,01),1)); // 遍歷圖書庫 System.out.println("圖書庫新建:"); System.out.println("書的種類數:"+bst.getBookSize()); System.out.println("書的總數量:"+bst.getBookCount()); bst.traverse(bst.getRoot()); // 再次增加相同的書 bst.add(new Books(9787302255659L,"大話資料結構", "程式語言與程式設計","程傑", BigDecimal.valueOf(47.20),"清華大學出版社", LocalDate.of(2011,06,01),1)); bst.add(new Books(9787115472588L,"鳥哥的Linux私房菜 基礎學習篇 第四版", "作業系統","鳥哥", BigDecimal.valueOf(93.00),"人民郵電出版社", LocalDate.of(2018,10,01),1)); bst.add(new Books(9787115293800L,"演算法(第4版)", "程式語言與程式設計","Robert Sedgewick,Kevin Wayne", BigDecimal.valueOf(66.30),"人民郵電出版社", LocalDate.of(2012,10,01),1)); // 再次遍歷圖書庫 System.out.println("圖書庫同種圖書加入:"); System.out.println("書的種類數:"+bst.getBookSize()); System.out.println("書的總數量:"+bst.getBookCount()); bst.traverse(bst.getRoot()); // 根據ISBN號查詢圖書 Books books =bst.search(9787115472588L); if (books!=null) { System.out.println("已找到該圖書:"); System.out.println(books.toString()); } } } ``` 程式輸出如下: ```clike 圖書庫新建: 書的種類數:10 書的總數量:10 {ISBN=9787115428028, 書名='Python程式設計 從入門到實踐', 作者='埃裡克·馬瑟斯', 分類='程式語言與程式設計', 價格=61.4, 出版社='人民郵電出版社', 出版時間=2017-07-01, 當前數量=1} {ISBN=9787111641247, 書名='深入理解Java虛擬機器:JVM高階特性與最佳實踐(第3版)', 作者='周志明', 分類='程式語言與程式設計', 價格=106.4, 出版社='機械工業出版社', 出版時間=2019-12-01, 當前數量=1} {ISBN=9787115293800, 書名='演算法(第4版)', 作者='Robert Sedgewick,Kevin Wayne', 分類='程式語言與程式設計', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2012-10-01, 當前數量=1} {ISBN=9787115525963, 書名='說服力 工作型PPT該這樣做', 作者='秦陽', 分類='辦公軟體', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1} {ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='作業系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=1} {ISBN=9787569222258, 書名='零基礎學Python(全綵版)', 作者='明日科技', 分類='程式語言與程式設計', 價格=67.0, 出版社='吉林大學出版社', 出版時間=2018-04-01, 當前數量=1} {ISBN=9787121388361, 書名='PS之光:一看就懂的Photoshop攻略(全綵)', 作者='馮注龍', 分類='圖形影象/多媒體', 價格=60.7, 出版社='電子工業出版社', 出版時間=2020-06-01, 當前數量=1} {ISBN=9787115537973, 書名='數學之美 第三版', 作者='吳軍', 分類='計算機理論、基礎知識', 價格=54.4, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1} {ISBN=9787302423287, 書名='機器學習', 作者='周志華', 分類='人工智慧', 價格=64.8, 出版社='清華大學出版社', 出版時間=2016-01-01, 當前數量=1} {ISBN=9787302255659, 書名='大話資料結構', 作者='程傑', 分類='程式語言與程式設計', 價格=47.2, 出版社='清華大學出版社', 出版時間=2011-06-01, 當前數量=1} 圖書庫同種圖書加入: 書的種類數:10 書的總數量:13 {ISBN=9787115428028, 書名='Python程式設計 從入門到實踐', 作者='埃裡克·馬瑟斯', 分類='程式語言與程式設計', 價格=61.4, 出版社='人民郵電出版社', 出版時間=2017-07-01, 當前數量=1} {ISBN=9787111641247, 書名='深入理解Java虛擬機器:JVM高階特性與最佳實踐(第3版)', 作者='周志明', 分類='程式語言與程式設計', 價格=106.4, 出版社='機械工業出版社', 出版時間=2019-12-01, 當前數量=1} {ISBN=9787115293800, 書名='演算法(第4版)', 作者='Robert Sedgewick,Kevin Wayne', 分類='程式語言與程式設計', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2012-10-01, 當前數量=2} {ISBN=9787115525963, 書名='說服力 工作型PPT該這樣做', 作者='秦陽', 分類='辦公軟體', 價格=66.3, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1} {ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='作業系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=2} {ISBN=9787569222258, 書名='零基礎學Python(全綵版)', 作者='明日科技', 分類='程式語言與程式設計', 價格=67.0, 出版社='吉林大學出版社', 出版時間=2018-04-01, 當前數量=1} {ISBN=9787121388361, 書名='PS之光:一看就懂的Photoshop攻略(全綵)', 作者='馮注龍', 分類='圖形影象/多媒體', 價格=60.7, 出版社='電子工業出版社', 出版時間=2020-06-01, 當前數量=1} {ISBN=9787115537973, 書名='數學之美 第三版', 作者='吳軍', 分類='計算機理論、基礎知識', 價格=54.4, 出版社='人民郵電出版社', 出版時間=2020-05-01, 當前數量=1} {ISBN=9787302423287, 書名='機器學習', 作者='周志華', 分類='人工智慧', 價格=64.8, 出版社='清華大學出版社', 出版時間=2016-01-01, 當前數量=1} {ISBN=9787302255659, 書名='大話資料結構', 作者='程傑', 分類='程式語言與程式設計', 價格=47.2, 出版社='清華大學出版社', 出版時間=2011-06-01, 當前數量=2} 已找到該圖書: {ISBN=9787115472588, 書名='鳥哥的Linux私房菜 基礎學習篇 第四版', 作者='鳥哥', 分類='作業系統', 價格=93.0, 出版社='人民郵電出版社', 出版時間=2018-10-01, 當前數量=2} ``` #### 四、深入理解 1. 二分搜尋樹的底層是一個鏈點,可以實現高效地插入,刪除以及動態維護。 2. 二分搜尋樹的結點是有序的,可以很快地求出最大,最小之類的關係值。 3. 也正是因為二分搜尋樹的結點是有序的,在極端情況下,二分搜尋樹會褪化成一個