20162320劉先潤大二 實驗二

1-實現二叉樹

實驗目標:完成鏈樹LinkedBinaryTree的實現(getRight,contains,toString,preorder,postorder)

實驗步驟:html

public LinkedBinaryTree<T> getRight() {
        if (root == null)
            throw new EmptyCollectionException("Get right operation " + "failed. The tree is empty.");
        LinkedBinaryTree<T> result = new LinkedBinaryTree<T>();
        result.root = root.getRight();
        return result;
    }

     public boolean contains (T target) {

         if (root.find(target) != null)
             return true;
         else
             return false;

     }
public String toString() {
      ArrayIterator<T> lxr=new ArrayIterator();
      lxr= (ArrayIterator<T>) levelorder();//強制轉化
      String content="";
      for (T i: lxr){//臨時引用lxr的每個元素
          content += i +" ";
      }
      return content;

}

 public Iterator<T> preorder() {
     ArrayIterator<T> iter = new ArrayIterator <>();
     if (root != null)
         root.preorder(iter);
     return iter;
 }
 public Iterator<T> postorder() { 
   ArrayIterator<T> iter = new ArrayIterator<T>();
        if(root!=null){
            root.postorder (iter);
        }
        return iter;}

    public boolean isEmpty() {
        if (root.count() != 0)
            return false;
        else
            return true;
    }
  • 1.根據已經提供的getLeft()套用補全getRight()
  • 2.對於包含方法,可使用LinkedBinaryTree類前面的查找find方法,該方法最後會返回查找的元素,則使用find查找target目標元素,根據查找結果返回true或false
  • 3.對於比較樹中是否爲空能夠經過查看根結點是否爲空,因此直接比較根的count是否爲0來比較。
  • 4.對於後序遍歷,參照樹中給出的先序遍歷補全。
  • 5.toString方法有些複雜,由於最後打印的結果要一目瞭然,知道樹的輪廓,因此我選擇使用levelorder()層序遍從來打印。將樹中的元素進行層序遍歷,建立T創建for循環臨時引用樹中的每個元素並將其加入一個String的變量上,最後返回它。最後測試,創建一個樹如圖,獲得打印結果1 2 3 4 5
  • 6.編寫BTNode中先序和後序遍歷的方法,根據它已經給出的中序遍歷方法,能夠變換得知,三者的區別在於加入元素的位置,先序在最前邊添加,後序在最後面添加,附上BTNode
  • 7.編寫測試類LinkedBinargTreeTest

2-中序先序序列構造二叉樹

實驗目標:基於LinkedBinaryTree,實現基於(中序,先序)序列構造惟一一棵二㕚樹的功能

代碼連接
參考連接:我參考了這位博主的博客根據先序和中序遍歷重建二叉樹java實現,依葫蘆畫瓢完成實驗
實驗步驟:java

  • 1.題目要求根據先序後中序實現樹,問題在於如何將其打印出來,打印出一個具備枝葉聯繫的二叉樹很難實現,可是能夠把經過已知的遍歷獲得它的後序遍歷,再進行比較,即實現目標。已知中序和先序分別爲給出HDIBEMJNAFCKGL和ABDHIEJMNCFGKL的樹,經過圖可知它的後序爲HIDMNJEFKLGCA 。
  • 2.因爲中序的特殊性能夠獲得根結點A的左右子樹分別有哪些元素,我能夠將左子樹和右子樹分別做爲新的二叉樹,找到子結點,左子樹和右子樹。
  • 3.代碼實現,首先創建一個簡單的二叉樹的類TNode,規定其左右子樹。而後實現二叉樹的重建過程PreAndInToPost,使用遞歸的算法進行掃描,再將元素進行不一樣的遍歷獲得後序遍歷結果。
  • 4.編寫測試類,截圖以下,符合預期測試成功

3-決策樹

實驗目標:「20問」模型,猜一我的,經過問問題方式獲得結果

代碼連接
實驗步驟:git

  • 1.創建一個20問的模型,個人樹以下圖所示
  • 2.根據書上代碼肯定並創建問題結點,但因爲最後要返回答案值因此還須要建立保存答案的結點以獲得返回值。
  • 3.建立以下所示的Asking()提問方法,創建while循環以獲得每次須要的問題,並輸出答案是或否,當不爲否時則取樹結點的左子樹。
public void Asking() {
        Scanner scan = new Scanner(System.in);
        System.out.println("猜人遊戲,你只能回答「是」或「否」,這裏有若干我的可供你選擇:劉先潤,李一桐,張靚穎,楊冪,艾瑪沃特森,盧本偉,馬軍,劉偉康");
        while(NewTree.size()>0){
            System.out.println(NewTree.getRootElement());
           String a=scan.nextLine();
            if (a.equalsIgnoreCase("否")){
                if(NewTree.getRight()!=null) {
                    NewTree = NewTree.getRight();
                }else {
                    break;
                }
            }
            else {
                if(NewTree.getLeft()!=null) {
                    NewTree = NewTree.getLeft();
                }else {
                    break;
                }
            }
  • 4.創建測試類,測試答案全爲是的結果,以下圖,測試成功。

4-表達式樹

實驗目標:設計並實現程序,使用二叉樹來表示表達式樹,提供方法對數進行計算,獲得表達式的結果。

代碼連接
實驗步驟:算法

  • 1.創建一個建立二叉樹的類ExpressionTree,該類能夠創建標準的二叉樹或表達式樹。題目要經過一個表達式創建樹,我設的表達式爲1 + 6 * 9 -8 / 2,將其構建進這個樹中,可知創建的形狀以下圖所示
  • 2.在該類中添加後序遍歷的方法,由於表達式的後序遍歷即次表達式的後綴形式,並且後序遍歷以前也寫過,很少闡述。可是樹中的元素是由list保存的,因此在主函數中須要經過經過循環將後綴表達式打印出來,如圖所示
  • 3.在該類中添加計算後綴表達式的方法,求得該後綴表達式結果將其輸出。
  • 4.測試,以下圖所示,測試成功,附上測試代碼連接ExpressionTreeTest

5-二叉查找樹

實驗目標:完成17章LinkedBinarySearchTree類的實現,特別是findMin和findMax兩個操做

代碼連接
實驗步驟:數組

  • 1.查看二叉查找樹代碼,與通常二叉樹的實現方法相似,LinkedBInarySearchTree操做了一組表示樹中結點的獨立對象。
  • 2.因爲二叉查找樹的特殊性質,小的數在左子樹,大的樹在右子樹,因此在寫findMin()的時候考慮三種狀況(正常,邊界,異常)
  • 3.首先當根爲空,返回一個空子集;當樹中只有一個根結點時,返回根結點;當根有左孩子時讓根等於他的左孩子,創建循環,直到結點沒有左孩子,返回當前結點元素。依葫蘆畫瓢編寫findMax()方法。
public T findMin() {
        if (root == null) {
            return null;
        }
         if (root!=null && root.getLeft()==null) {
             return root.getElement();
         }

            while (root.getLeft() != null) {
                root = root.getLeft();
                if (root.getLeft()==null) {
                    break;
                }
            }return root.getElement();
    }
  • 4.測試結果截圖以下,測試成功。

6-紅黑樹分析

實驗目標:對Java中的紅黑樹(TreeMap,HashMap)進行源碼分析

分析結果:

  首先我須要瞭解紅黑樹的概念,何爲紅黑樹?它是一種特殊的二叉查找樹。紅黑樹的每一個節點上都有存儲位表示節點的顏色。根結點是黑色,結點顏色與子結點顏色不一樣。主要是用它來存儲有序的數據,它的時間複雜度是O(lgn),效率很是之高。附上參考資料連接:紅黑樹(一)之 原理和算法詳細介紹HashMap詳細介紹
  而後分析TreeMap,它是基於紅黑樹的 NavigableMap 實現。該映射根據其鍵的天然順序進行排序,或者根據建立映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。 TreeMap存儲的是key-value鍵值對,TreeMap的排序是基於對key的排序,它本質上就是一個紅黑樹。它內部有 Comparator用來給TreeMap排序,帶有Map和SortMap的構造函數會成爲TreeMap的子集。
  分析具體的方法get,獲取鍵key對應的值value,首先要獲取key鍵的節點p,若節點p不爲null,返回節點對應的值。app

public V get(Object key) {
           Entry<K,V> p = getEntry(key);
           return (p==null ? null : p.value);
       }

  分析putAll方法,它的做用是將map中的所有節點添加到TreeMap中。首先獲取map的大小,若是TreeMap的大小是0,且map的大小不是0,且map是已排序的「key-value對」,若是TreeMap和Map的comparator相等,則將map的元素所有拷貝到TreeNap中,而後返回。最後調用AbstractMap中的putAll(),而putAll()又會調用TreeMap的put()。函數

public void putAll(Map<? extends K, ? extends V> map) {
           int mapSize = map.size();
           if (size==0 && mapSize!=0 && map instanceof SortedMap) {
               Comparator c = ((SortedMap)map).comparator();
               if (c == comparator || (c != null && c.equals(comparator))) {
                   ++modCount;
                   try {
                       buildFromSorted(mapSize, map.entrySet().iterator(),
                                  null, null);
                  } catch (java.io.IOException cannotHappen) {
                  } catch (ClassNotFoundException cannotHappen) {
                  }
                  return;
              }
          }
            super.putAll(map);
      }

  對TreeMap有一個初步瞭解後再分析HashMap,經過查閱JDK文件得知,HashMap是基於哈希表的 Map 接口的實現。此實現提供全部可選的映射操做,並容許使用 null 值和 null 鍵。HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。HashMap有兩個重要參數,它存在一個容量(哈希表中桶的數量)和一個加載因子(容量自動增長以前能夠達到多滿的一種尺度)
  接着分析源碼,HashMap中的key-value都是存儲在Entry數組中的。它有4個構造函數,例以下列代碼,這是一個默認的構造函數,它首先設置加載因子,而後設置「HashMap閾值」,當HashMap中存儲的量達到threshold時,就將HashMap的容量加倍。最後建立Entry數組保存數據。源碼分析

public HashMap() {
      this.loadFactor = DEFAULT_LOAD_FACTOR;
      threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
      table = new Entry[DEFAULT_INITIAL_CAPACITY];
      init();
 }

  再分析一個方法get(),返回指定鍵所映射的值;若是對於該鍵來講,此映射不包含任何映射關係,則返回 null。它首先會獲取key的hash值,在該hash值對應的鏈表上查找鍵值爲key的元素。post

public V get(Object key) {
      if (key == null)
          return getForNullKey();
          int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
              e != null;
              e = e.next) {
              Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
               return e.value;
     }
     return null;
 }

  經過本次源碼分析對TreeMap和HashMap有了更深的瞭解,它的方法實現思路很是值得像我這樣的新手學習借鑑。學習

相關文章
相關標籤/搜索