好幾天沒把筆記整理上來了,一個是這幾天在忙着一些投標以及項目論文的事情,哈哈,還有麼 就是畫圖也是比較耗費我時間的,若是有好的畫圖建議或者工具,麻煩推薦一下,謝謝。廢話很少說,直接進入今天的兩個主題:二叉搜索樹,平衡二叉樹。 java
1.二叉搜索樹(BST) node
二叉搜索樹的定義很簡單:是二叉樹,且知足兩個條件:若是有左孩子,則左孩子的關鍵字必定不大於父節點的關鍵字,若是有右孩子,則右孩子的關鍵字不小於父節點的關鍵字。同時,左右子樹都是二叉搜索樹。 工具
BST_1 學習
中序遍歷獲得的結果是:一、二、三、四、五、六、七、八、九、10 this
BST_2 code
中序遍歷獲得的結果是:一、二、三、四、五、六、七、八、九、10 遞歸
如今有一個場景,加入我要在這顆樹中查找一個關鍵字11,若是沒有的話,則加入到這顆樹中,查詢步驟是: rem
1.針對BST_1,根節點是6,由於11大於6,則查找根節點的右孩子(由於二叉搜索樹的右孩子的關鍵字不小於父節點); get
2.右孩子的值是9,小於11,繼續查他的右孩子; it
3.右孩子的值是10,小於11,繼續查他的右孩子;
4.由於沒有右孩子了,因此,須要將其添加爲右孩子。
針對BST_2,咱們只須要一直找右孩子就能夠了。咱們再看一個二叉搜索樹:
BST3
中序遍歷獲得的結果是:一、二、三、四、五、六、七、九、10
如今我要查找一個節點,其中的關鍵字是8的一個節點,若是不在這顆樹中,則把它加到樹中做爲一個節點:
1.根節點是6,小於8,找右孩子;
2.右孩子的值是9大於8,找他的左孩子;
3.左孩子的值7小於8,找他的右孩子;
4.由於沒有右孩子了,因此,將其添加爲7的右孩子。
從上面幾個過程當中咱們發現一個規律:動態查找過程當中,咱們不須要重構這個結構,只是在葉子節點上進行操做,很是方便。
那若是要刪除一個節點呢?
刪除節點的時候,有幾種狀況須要考慮:
1.該節點是葉子節點,所以,不用重構;
2.該節點只有左子樹或者右子樹,則把左子樹或者右子樹的根,接到刪除節點的父節點上就能夠了;
3.若是該節點二者都有呢?
咱們一個一個的來看:
1.該節點是葉子節點。
咱們要刪除BST3中的節點7,則先按照查詢步驟找到這個節點,發現他沒有左子樹,也沒有右子樹,則直接刪除,並把該節點的父節點的左孩子或者右孩子(取決於該節點是左孩子仍是右孩子)清空便可。
2.該節點只有左子樹。
咱們要刪除BST3中的節點4,則先按照查詢步驟找到這個節點,發現他只有左子樹,所以,只要刪除該節點,並把該節點的左孩子放在改節點的位置便可。
3.該節點只有右子樹:
咱們要刪除BST2中的節點5,則先按照查詢步驟找到這個節點,發現他只有由子樹,所以,只要刪除該節點,並把該節點的右孩子放在該節點的位置便可。
4.該節點有左子樹,也有右子樹。
咱們如今要刪除BST1中的根節點,則中序遍歷這個節點的左子樹,獲得的此節點前的那個節點,就是要刪除節點的前驅。
好比上述根節點的左子樹的中序遍歷是:一、二、三、5,則,我是要刪除節點6的前驅,將該前驅替代要刪除的節點的位置,並設置左指向和右指向便可。
,咱們如今再來看一BST。
如今我要刪除節點9,按照上面的步驟,9有左右孩子,所以,先作9的左子樹的中序遍歷,找到9的前驅是8.5,而後來替換。最終獲得結果是:
,說了那麼多,仍是上上代碼吧,此次用java代碼:
package com.tang.bst; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class BST<Key extends Comparable<Key>> { BSTNode<Key> root; public BST() { } /** * 插入一個節點 * * @param data * 節點的數據 * @return */ public boolean insert(Key data) { if (null == data) return false; if (null == this.root) { this.root = new BSTNode<Key>(data); this.root.parent = null; this.root.leftChild = null; this.root.rightChild = null; return true; } else { return insertBST(this.root, data); } } private boolean insertBST(BSTNode<Key> node, Key data) { // 左分支,右分支的判斷 int lOrR = node.data.compareTo(data); if (lOrR == 0) { return false; } else if (lOrR < 0) { // 右子樹 if (null == node.rightChild) { BSTNode<Key> rChild = new BSTNode<Key>(data); rChild.parent = node; node.rightChild = rChild; return true; } else { return insertBST(node.rightChild, data); } } else { // 左子樹 if (null == node.leftChild) { BSTNode<Key> lChild = new BSTNode<Key>(data); lChild.parent = node; node.leftChild = lChild; return true; } else { return insertBST(node.leftChild, data); } } } /** * 在這棵樹中,指定一個節點,而後開始非遞歸方式中序遍歷以這個節點爲根節點的二叉樹 * * @param node * 指定爲根節點的節點 * @return */ public List<BSTNode<Key>> noRecurseInOrderTraverse(Key data) { if (null == this.root) return null; BSTNode<Key> beginRoot = null; if (null == data) { beginRoot = this.root;// 若是沒有指定節點爲根節點,那麼就從這棵樹的根節點開始 } else { BSTNode<Key> sNode = searchBST(this.root, data); beginRoot = sNode; } List<BSTNode<Key>> stack = new ArrayList<BSTNode<Key>>(); List<BSTNode<Key>> retStack = new ArrayList<BSTNode<Key>>(); if (null != beginRoot) { stack.add(beginRoot); } while (!stack.isEmpty()) { while (beginRoot != null && null != beginRoot.leftChild) { beginRoot = beginRoot.leftChild; stack.add(beginRoot); } if (!stack.isEmpty()) { BSTNode<Key> tmpNode = stack.get(stack.size() - 1); stack.remove(stack.size() - 1); retStack.add(tmpNode); if (tmpNode != null && null != tmpNode.rightChild) { beginRoot = tmpNode.rightChild; stack.add(beginRoot); } } } return retStack; } /** * 查找指定的節點,若是沒有,則將他加入到這顆樹上 * * @param data * @return 0:表示在原樹上就有,1:表示添加進去的新節點,-1:表示查詢中出錯 */ public boolean search(Key data) { if (null == data) { return false; } if (null == this.root) { return false; } return searchBST(this.root, data) == null ? false : true; } private BSTNode<Key> searchBST(BSTNode<Key> searhNode, Key data) { if (null == data) { return null; } if (null == searhNode) { return null; } int lOrR = searhNode.data.compareTo(data); if (lOrR > 0) { // 要往左子樹去找 return searchBST(searhNode.leftChild, data); } else if (lOrR == 0) { // 已經找到了,直接返回去 return searhNode; } else { // 要往右子樹去找 return searchBST(searhNode.rightChild, data); } } /** * 查找指定的節點,若是沒有的話,插入節點 * * @param data * @return */ public boolean searchOrInsert(Key data) { return search(data) == false ? insert(data) : true; } /** * 刪除指定的節點 * * @param data * @return */ public boolean delete(Key data) { if (null == this.root || null == data) { return false; } BSTNode<Key> node = searchBST(this.root, data); if (null == node) { return false; } BSTNode<Key> parent = node.parent; BSTNode<Key> leftChild = node.leftChild; if (null == node.rightChild) { // 由於沒有右孩子,所以,只要從新接上她的左孩子就能夠了 if (null == parent) { // 說明他是根節點 if (null != leftChild) { node.leftChild.parent = null; } else { this.root = null; } } else { node.parent.leftChild = leftChild; } } else if (null == node.leftChild) { // 由於沒有左孩子,只要從新接上她的右孩子就能夠了 if (parent == null) { // 說明他就是根節點 if (null != node.rightChild) { node.rightChild.parent = null; } else { this.root = null; } } else { node.parent.rightChild = node.rightChild; } } else { // 既有左子樹,又有右子樹 // 中序遍歷此節點的左子樹,找到此節點的前驅 // 此前驅的特色是,要麼是葉子節點,要麼是隻有左節點 System.out.println(node.rightChild==null); List<BSTNode<Key>> stack=noRecurseInOrderTraverse(node.leftChild.data); BSTNode<Key> preNode=stack.get(stack.size()-1); BSTNode<Key> rightNode=node.rightChild; node.data=preNode.data; if(preNode.leftChild!=null){ node.leftChild=preNode.leftChild; } if(preNode.parent!=null){ if(preNode.parent.leftChild.data.compareTo(preNode.data)==0){ preNode.parent.leftChild=null; }else{ preNode.parent.rightChild=null;//這裏有問題 } } node.rightChild=rightNode; System.out.println(node.rightChild==null); } return true; } public static void main(String[] args) { BST<Integer> bst = new BST<Integer>(); bst.insert(new Integer(6)); bst.insert(new Integer(5)); bst.insert(new Integer(9)); bst.insert(new Integer(2)); bst.insert(new Integer(8)); bst.insert(new Integer(10)); bst.insert(new Integer(1)); bst.insert(new Integer(4)); bst.insert(new Integer(3)); List<BSTNode<Integer>> stack = bst.noRecurseInOrderTraverse(null); for (Iterator<BSTNode<Integer>> iterator = stack.iterator(); iterator .hasNext();) { BSTNode<Integer> bstNode = (BSTNode<Integer>) iterator.next(); System.out.print(bstNode.data + "---"); } bst.delete(new Integer(5)); System.out.println("刪除以後"); stack = bst.noRecurseInOrderTraverse(null); for (Iterator<BSTNode<Integer>> iterator = stack.iterator(); iterator .hasNext();) { BSTNode<Integer> bstNode = (BSTNode<Integer>) iterator.next(); System.out.print(bstNode.data + "---"); } } }
經過上面的學習,咱們能夠看到,二叉搜索樹受輸入順序影響很大,有可能就是造成了一個線性表,效率很是低。咋整呢?收看下一節,歡迎加qq:359311095討論