實驗內容過多,故參考做業:php
getRight
,contains
,toString
,preorder
,postorder
,這些分別是獲得右孩子,是否包含,輸出,前序遍歷,後續遍歷,關鍵代碼以下:public LinkedBinaryTree1<T> getRight() { if(root == null) { throw new EmptyCollectionException("BinaryTree"); } LinkedBinaryTree1<T> result = new LinkedBinaryTree1<>(); result.root = root.getRight(); return result; public boolean contains(T targetElement) { BinaryTreeNode node = root; BinaryTreeNode temp = root; boolean result = false; if (node == null){ result = false; } if (node.getElement().equals(targetElement)){ result = true; } while (node.right != null){ if (node.right.getElement().equals(targetElement)){ result = true; break; } else { node = node.right; } } while (temp.left.getElement().equals(targetElement)){ if (temp.left.getElement().equals(targetElement)){ result = true; break; } else { temp = temp.left; } } return result; } public String toString() { UnorderedListADT<BinaryTreeNode<String>> nodes = new ArrayUnorderedList<BinaryTreeNode<String>>(); UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>(); BinaryTreeNode<String> current; String result = ""; int printDepth = this.getHeight(); int possibleNodes = (int)Math.pow(2, printDepth + 1); int countNodes = 0; nodes.addToRear((BinaryTreeNode<String>) root); Integer currentLevel = 0; Integer previousLevel = -1; levelList.addToRear(currentLevel); while (countNodes < possibleNodes) { countNodes = countNodes + 1; current = nodes.removeFirst(); currentLevel = levelList.removeFirst(); if (currentLevel > previousLevel) { result = result + "\n\n"; previousLevel = currentLevel; for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) { result = result + " "; } } else { for (int i = 0; i < ((Math.pow(2, (printDepth - currentLevel + 1)) - 1)) ; i++) { result = result + " "; } } if (current != null) { result = result + (current.getElement()).toString(); nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1); } else { nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; } protected void preOrder(BinaryTreeNode<T> node, ArrayUnorderedList<T> tempList) { if (node != null){ tempList.addToRear(node.getElement()); preOrder(node.getLeft(),tempList); preOrder(node.getRight(),tempList); } } protected void postOrder(BinaryTreeNode<T> node, ArrayUnorderedList<T> tempList) { if (node != null){ postOrder(node.getLeft(),tempList); postOrder(node.getRight(),tempList); tempList.addToRear(node.getElement()); } } }
public BinaryTreeNode initTree(String[] preOrder, int start1, int end1, String[] inOrder, int start2, int end2) { if (start1 > end1 || start2 > end2) { return null; } String rootData = preOrder[start1]; BinaryTreeNode head = new BinaryTreeNode(rootData); //找到根節點所在位置 int rootIndex = findIndexInArray(inOrder, rootData, start2, end2); //構建左子樹 BinaryTreeNode left = initTree(preOrder, start1 + 1, start1 + rootIndex - start2, inOrder, start2, rootIndex - 1); //構建右子樹 BinaryTreeNode right = initTree(preOrder, start1 + rootIndex - start2 + 1, end1, inOrder, rootIndex + 1, end2); head.left = left; head.right = right; return head; } }
第三:對於書上的背部疼痛診斷器簡單修改,無需放上。html
第四:本次實驗惟一的難點,關鍵代碼:java
public static String toSuffix(String infix) { String result = ""; String[] array = infix.split("\\s+"); Stack<LinkedBinaryTree> num = new Stack(); Stack<LinkedBinaryTree> op = new Stack(); for (int a = 0; a < array.length; a++) { if (array[a].equals("+") || array[a].equals("-") || array[a].equals("*") || array[a].equals("/")) { if (op.empty()) { op.push(new LinkedBinaryTree<>(array[a])); } else { if ((op.peek().root.element).equals("+") || (op.peek().root.element).equals("-") && array[a].equals("*") || array[a].equals("/")) { op.push(new LinkedBinaryTree(array[a])); } else { LinkedBinaryTree right = num.pop(); LinkedBinaryTree left = num.pop(); LinkedBinaryTree temp = new LinkedBinaryTree(op.pop().root.element, left, right); num.push(temp); op.push(new LinkedBinaryTree(array[a])); } } } else { num.push(new LinkedBinaryTree<>(array[a])); } } while (!op.empty()) { LinkedBinaryTree right = num.pop(); LinkedBinaryTree left = num.pop(); LinkedBinaryTree temp = new LinkedBinaryTree(op.pop().root.element, left, right); num.push(temp); } Iterator itr=num.pop().iteratorPostOrder(); while (itr.hasNext()){ result+=itr.next()+" "; } return result; }
static final class Entry<K,V> implements Map.Entry<K,V> { K key; // 鍵 V value; // 值 Entry<K,V> left = null; // 左孩子 Entry<K,V> right = null; // 右孩子 Entry<K,V> parent; // 雙親節點 boolean color = BLACK; // 當前節點顏色 // 構造函數 Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } }
TreeMap
的構造方法進行分析,TreeMap
一共四個構造方法。1.無參數構造方法node
public TreeMap() { comparator = null; }
2.帶有比較器的構造方法web
public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; }
3.帶Map的構造方法數據結構
public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m); }
4.帶有SortedMap的構造方法app
public TreeMap(SortedMap<K, ? extends V> m) { comparator = m.comparator(); try { buildFromSorted(m.size(), m.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } }
// 將map中的所有節點添加到TreeMap中 public void putAll(Map<? extends K, ? extends V> map) { // 獲取map的大小 int mapSize = map.size(); // 若是TreeMap的大小是0,且map的大小不是0,且map是已排序的「key-value對」 if (size==0 && mapSize!=0 && map instanceof SortedMap) { Comparator c = ((SortedMap)map).comparator(); // 若是TreeMap和map的比較器相等; // 則將map的元素所有拷貝到TreeMap中,而後返回! 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; } } // 調用AbstractMap中的putAll(); // AbstractMap中的putAll()又會調用到TreeMap的put() super.putAll(map); }
顯然,若是Map裏的元素是排好序的,就調用buildFromSorted方法來拷貝Map中的元素,這在下一個構造方法中會重點說起,而若是Map中的元素不是排好序的,就調用AbstractMap的putAll(map)方法,該方法源碼以下:函數
public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); }
put
方法,一樣的,利用備註的形式在代碼中標出。public V put(K key, V value) { Entry<K,V> t = root; // 若紅黑樹爲空,則插入根節點 if (t == null) { // throw NullPointerException // compare(key, key); // type check root = new Entry<K,V>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // split comparator and comparable paths Comparator<? super K> cpr = comparator; // 找出(key, value)在二叉排序樹中的插入位置。 // 紅黑樹是以key來進行排序的,因此這裏以key來進行查找。 if (cpr != null) { do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } else { if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } // 爲(key-value)新建節點 Entry<K,V> e = new Entry<K,V>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; // 插入新的節點後,調用fixAfterInsertion調整紅黑樹。 fixAfterInsertion(e); size++; modCount++; return null; }
TreeMap
的deleteEntry
方法,deleteEntry
方法一樣也只需按照二叉排序樹的操做步驟實現便可,刪除指定節點後,再對樹進行調整便可。deleteEntry
方法的實現源碼以下:// 刪除「紅黑樹的節點p」 private void deleteEntry(Entry<K,V> p) { modCount++; size--; if (p.left != null && p.right != null) { Entry<K,V> s = successor (p); p.key = s.key; p.value = s.value; p = s; } Entry<K,V> replacement = (p.left != null ? p.left : p.right); if (replacement != null) { replacement.parent = p.parent; if (p.parent == null) root = replacement; else if (p == p.parent.left) p.parent.left = replacement; else p.parent.right = replacement; p.left = p.right = p.parent = null; if (p.color == BLACK) fixAfterDeletion(replacement); } else if (p.parent == null) { root = null; } else { if (p.color == BLACK) fixAfterDeletion(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; } } }
對於紅黑樹的源碼分析到此就告一段落,由於最近時間有限,若是後期有空閒時間會繼續對其源碼進行分析。源碼分析
1.
post
2.
3.
4.
5.
問題1解決方案:在寢室中跟王文彬同窗討論相應問題的時候他提醒我說「雖然對於一棵表達式樹來講中序遍歷獲得的就是中綴表達式,後序遍歷獲得的就是後續表達式,但書上是利用後綴表達式構建了一棵樹,而咱們的要求是利用中綴表達式構建一棵樹。」這讓我意識到了問題所在。好像問題沒有那麼簡單,事實也證實如此,的確沒有那麼簡單。
TreeMap
的源代碼,看到那3013行代碼時,腦袋都大了一圈。問題2解決方案:好在有於欣月同窗的提醒,網上有相似的分析,因此在網上搜了一下相應的問題,發現果真有相似的源碼分析,便去參考了一番。