getRight
方法、contains
方法、toString
方法、preorder
方法、postorder
方法,此五个方法。getRight
方法public LinkedBinaryTree1<T> getRight() { LinkedBinaryTree1 node = new LinkedBinaryTree1(); node.root = root.getRight(); return node; }
这个基本上是以前好久就实现的一个简单的方法,先进行一个树的初始化,能够获得一个新树,而后经过下面一行的代码获得新的根,使咱们获得合适的右子树。html
contains
方法@Override public boolean contains(T targetElement) { if (find(targetElement) == targetElement) { return true; } else { return false; } } @Override public T find(T targetElement) throws ElementNotFoundException { BinaryTreeNode<T> current = findNode(targetElement, root); if (current == null) throw new ElementNotFoundException("LinkedBinaryTree"); return (current.getElement()); }
这个方法其实自己没有什么东西,可是里面须要用到
find
方法,首先用find
方法查找这个结点,假如找到了这个结点就返回true,假如没有找到就返回false。java
toString
方法public String toString() { UnorderedListADT<BinaryTreeNode<T>> nodes = new week7.jiumingdaima.ArrayUnorderedList<BinaryTreeNode<T>>(); UnorderedListADT<Integer> levelList = new week7.jiumingdaima.ArrayUnorderedList<Integer>(); BinaryTreeNode<T> current; String result = ""; int printDepth = this.getHeight(); int possibleNodes = (int) Math.pow(2, printDepth + 1); int countNodes = 0; nodes.addToRear(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; }
这个代码直接使用的书上
ExpressionTree
类的代码node
preorder
方法public Iterator<T> iteratorPreOrder() { ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>(); preOrder(root, tempList); return new TreeIterator(tempList.iterator()); } public ArrayUnorderedList preorder() { ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>(); preOrder(root, tempList); return tempList; } protected void preOrder(BinaryTreeNode<T> node, ArrayUnorderedList<T> tempList) { if (node != null) { // System.out.print(node.getElement()+" "); tempList.addToRear(node.getElement()); preOrder(node.getLeft(), tempList); preOrder(node.getRight(), tempList); } }
这个方法要用到的迭代器方法和自己都是已经给出了的,我加了一段方便方法直接使用express
postorder
方法public ArrayUnorderedList postorder() { ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>(); postOrder(root, tempList); return tempList; }
和前序遍历同样都是现成的方法,只是加了一段数组
//根据前序和中序序列,创建二叉树 public int findroot(String[] S, String s, int begin, int end) { for (int i = begin; i <= end; i++) { if (S[i] == s) { return i; } } return -1; } public BinaryTreeNode getAtree(String[] preSort, int prestart, int preend, String[] inSort, int instart, int inend) { if (prestart > preend || instart > inend) { return null; } if (preSort.length != inSort.length) { try { throw new Exception("不知足条件的非法输入!"); } catch (Exception e) { e.printStackTrace(); } } BinaryTreeNode treeroot; String rootData = preSort[prestart]; treeroot = new BinaryTreeNode(rootData); int rwhere = findroot(inSort, rootData, instart, inend);//找根节点的位置 treeroot.left = getAtree(preSort, prestart + 1, prestart + rwhere - instart, inSort, instart, rwhere - 1);//左子树 treeroot.right = getAtree(preSort, prestart + rwhere - instart + 1, preend, inSort, rwhere + 1, inend);//右子树 return treeroot; } public void getAtree(String[] preOrder, String[] inOrder) { this.root = getAtree(preOrder, 0, preOrder.length - 1, inOrder, 0, inOrder.length - 1); }
getAtree
方法,结合前序和中序序列,找到根结点和左右子树,而后对左右子树分别递归使用加getAtree
方法,逐步往下创建树。已知先序遍历和中序遍历获得二叉树有三个步骤:数据结构
找到根结点。由于先序遍历按照先访问根结点再访问左右孩子的顺序进行的,因此先序遍历的第一个结点就是二叉树的根。框架
区分左右子树。在肯定了根结点以后,在中序遍历结果中,根结点以前的就是左子树,根结点以后的就是右子树。若是跟结点前边或后边为空,那么该方向子树为空;若是根节点前边和后边都为空,那么根节点已经为叶子节点。ide
分别对左右子树再重复第1、二步直至彻底构造出该树。函数
input.txt
每一个选项改一下就行了,我改了一下二叉树的形状,结果下面那堆数字就要所有改一下了5 9 10 7 11 12 8 13 14 3 5 6 4 7 8 2 3 4 0 1 2
public int evaluate(String expression) throws EmptyCollectionException { ExpressionTree operand1, operand2; char operator; String tempToken; Scanner parser = new Scanner(expression); while (parser.hasNext()) { tempToken = parser.next(); operator = tempToken.charAt(0); if ((operator == '+') || (operator == '-') || (operator == '*') || (operator == '/')) { operand1 = getOperand(treeStack); operand2 = getOperand(treeStack); treeStack.push(new ExpressionTree(new ExpressionTreeOp(1, operator, 0), operand2, operand1)); } else { treeStack.push(new ExpressionTree(new ExpressionTreeOp(2, ' ', Integer.parseInt(tempToken)), null, null)); } } return (treeStack.peek()).evaluateTree(); }
public void posorder() { System.out.println("后缀表达式为: "); posOrder(root); System.out.println(""); } public void posOrder(BinaryNode node) { if (node != null) { posOrder(node.getLeft()); posOrder(node.getRight()); System.out.print(node.getData() + " "); } }
removeMax
方法public T removeMax() throws EmptyCollectionException { // To be completed as a Programming Project T result = null; if (isEmpty()) throw new EmptyCollectionException("LinkedBinarySearchTree"); else { if (root.right == null) { result = root.element; root = root.left; } else { BinaryTreeNode<T> parent = root; BinaryTreeNode<T> current = root.right; while (current.right != null) { parent = current; current = current.right; } result = current.element; parent.right = current.left; } modCount--; } return result; }
findMin
方法public T findMin() throws EmptyCollectionException { // To be completed as a Programming Project T result = null; if (isEmpty()) throw new EmptyCollectionException("LinkedBinarySearchTree"); else { if (root.left == null) { result = root.element; } else { BinaryTreeNode<T> parent = root; BinaryTreeNode<T> current = root.left; while (current.left != null) { parent = current; current = current.left; } result = current.element; } } return result; }
- HashMap能够说是Java中最经常使用的集合类框架之一,是Java语言中很是典型的数据结构,咱们总会在不经意间用到它,很大程度上方便了咱们平常开发。 - HashMap 是基于哈希表的 Map 接口的实现。此实现提供全部可选的映射操做,并容许使用 null 值和 null 键。(除了非同步和容许使用 null 以外,HashMap 类与 Hashtable 大体相同。)此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
- HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在建立时的容量。加载因子 是哈希表在其容量自动增长以前能够达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操做(即重建内部数据结构),从而哈希表将具备大约两倍的桶数。
// 默认构造函数。 public HashMap() { // 设置“加载因子” this.loadFactor = DEFAULT_LOAD_FACTOR; // 设置“HashMap阈值”,当HashMap中存储数据的数量达到threshold时,就须要将HashMap的容量加倍。 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); // 建立Entry数组,用来保存数据 table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); } // 指定“容量大小”和“加载因子”的构造函数 public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); // HashMap的最大容量只能是MAXIMUM_CAPACITY if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; // 设置“加载因子” this.loadFactor = loadFactor; // 设置“HashMap阈值”,当HashMap中存储数据的数量达到threshold时,就须要将HashMap的容量加倍。 threshold = (int)(capacity * loadFactor); // 建立Entry数组,用来保存数据 table = new Entry[capacity]; init(); } // 指定“容量大小”的构造函数 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } // 包含“子Map”的构造函数 public HashMap(Map<? extends K, ? extends V> m) { this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); // 将m中的所有元素逐个添加到HashMap中 putAllForCreate(m); }
public boolean containsKey(Object key) { return getEntry(key) != null; }
containsKey() 首先经过getEntry(key)获取key对应的Entry,而后判断该Entry是否为null。
getEntry()的源码以下:源码分析
final Entry<K,V> getEntry(Object key) { // 获取哈希值 // HashMap将“key为null”的元素存储在table[0]位置,“key不为null”的则调用hash()计算哈希值 int hash = (key == null) ? 0 : hash(key.hashCode()); // 在“该hash值对应的链表”上查找“键值等于key”的元素 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 != null && key.equals(k)))) return e; } return null; }
getEntry() 的做用就是返回“键为key”的键值对,它的实现源码中已经进行了说明。
这里须要强调的是:HashMap将“key为null”的元素都放在table的位置0处,即table[0]中;“key不为null”的放在table的其他位置!
public V put(K key, V value) { // 若“key为null”,则将该键值对添加到table[0]中。 if (key == null) return putForNullKey(value); // 若“key不为null”,则计算该key的哈希值,而后将其添加到该哈希值对应的链表中。 int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // 若“该key”对应的键值对已经存在,则用新的value取代旧的value。而后退出! if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 若“该key”对应的键值对不存在,则将“key-value”添加到table中 modCount++; addEntry(hash, key, value, i); return null; }
说到addEntry(),就不得不说另外一个函数createEntry()。
addEntry()通常用在 新增Entry可能致使“HashMap的实际容量”超过“阈值”的状况下。例如,咱们新建一个HashMap,而后不断经过put()向HashMap中添加元素;put()是经过addEntry()新增Entry的。在这种状况下,咱们不知道什么时候“HashMap的实际容量”会超过“阈值”;所以,须要调用addEntry()
createEntry() 通常用在 新增Entry不会致使“HashMap的实际容量”超过“阈值”的状况下。例如,咱们调用HashMap“带有Map”的构造函数,它绘将Map的所有元素添加到HashMap中;但在添加以前,咱们已经计算好“HashMap的容量和阈值”。也就是,能够肯定“即便将Map中的所有元素添加到HashMap中,都不会超过HashMap的阈值”。此时,调用createEntry()便可。
public V get(Object key) { if (key == null) return getForNullKey(); // 获取key的hash值 int hash = hash(key.hashCode()); // 在“该hash值对应的链表”上查找“键值等于key”的元素 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; }
public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } // 删除“键为key”的元素 final Entry<K,V> removeEntryForKey(Object key) { // 获取哈希值。若key为null,则哈希值为0;不然调用hash()进行计算 int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); Entry<K,V> prev = table[i]; Entry<K,V> e = prev; // 删除链表中“键为key”的元素 // 本质是“删除单向链表中的节点” while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
由于这一大堆英语并非很直观,我在他们前面进行了编号。而后在我本身试着写的时候发现0 1 2必须在最下面一排,1是左孩子,2是右孩子,再上面一排数字必须是先安排右孩子和他的孩子们,就是说必须是
2 5 6 1 3 4
而不是
1 3 4 2 5 6
除非没有右孩子