在这里我不得不感叹《算法导论》绝对是算法数据结构经典中的经典!作为一个学习入门的人,对此书实在是敬佩不已。语言凝练,表达清楚,字字珠玑。
———Paul Zhang. 2015.11.26
1.堆
1.1堆的定义
堆就是具有两个附加属性的二叉树。
【1】它是一棵完全树;
【2】对每一结点,它小于和等于其左孩子和右孩子。
上述定义描述的是最小堆。一个堆也可以是最大堆,其中结点大于或者小于它的左右孩子。
1.2堆ADT定义
堆UML设计
Java源码
package ds.java.ch12.heapImpl;
import java.util.Iterator;
/**
* @author LbZhang
* @version 创建时间:2015年11月22日 上午10:51:51
* @description 二叉树的ADT
*/
public interface BinaryTreeADT<T> {
/**
* 获取根部元素
*
* @return
*/
public T getRootElement();
/**
* 判断是否是空树
*
* @return true if this binary tree is empty, false otherwise
*/
public boolean isEmpty();
/**
* 返回树中元素的个数
*
* @return the number of elements in the tree
*/
public int size();
/**
*判定二叉树中是否存在当前的元素
*
* @param targetElement
* the element being sought in the tree
* @return true if the tree contains the target element
*/
public boolean contains(T targetElement);
/**
*在二叉树中查找响应的元素
*
* @param targetElement
* the element being sought in the tree
* @return a reference to the specified element
*/
public T find(T targetElement);
/**
*输出二叉树
*
* @return a string representation of the binary tree
*/
public String toString();
/**
*返回二叉树的迭代器
*
* @return an iterator over the elements of this binary tree
*/
public Iterator<T> iterator();
/**
* Returns an iterator that represents an inorder traversal on this binary
* tree.
*
* @return an iterator over the elements of this binary tree
*/
public Iterator<T> iteratorInOrder();
/**
* Returns an iterator that represents a preorder traversal on this binary
* tree.
*
* @return an iterator over the elements of this binary tree
*/
public Iterator<T> iteratorPreOrder();
/**
* Returns an iterator that represents a postorder traversal on this binary
* tree.
*
* @return an iterator over the elements of this binary tree
*/
public Iterator<T> iteratorPostOrder();
/**
* Returns an iterator that represents a levelorder traversal on the binary
* tree.
*
* @return an iterator over the elements of this binary tree
*/
public Iterator<T> iteratorLevelOrder();
}
package ds.java.ch12.heapImpl;
/**
* @author LbZhang
* @version 创建时间:2015年11月29日 下午7:26:38
* @description 堆ADT
* 有序 完全二叉树
*/
public interface HeapADT<T> extends BinaryTreeADT<T> {
/**
* 添加元素操作,将给定的元素添加到堆的恰当位置处,且维持该堆的完全性属性和有序属性。
* 如果该元素Comparable的,该方法将抛出一个ClassCastException异常。
* @param obj
* 关键概念:
* addElement方法将给定的Comparable元素添加到堆的恰当位置处,且维持该堆的完全属性和有序属性。
* 因为一个堆是完全树,所以对插入新的结点而言 ,只存在一个正确的位置,且它要么是h层左边的下一个空位置,
* 要么实在h+1层左边的第一个位置(如果h层是满层的话)。
* 一旦将新结点定位到正确位置,就必须考虑排序属性。为此我们只需将该值与双亲值进行比较,如果新结点小于
* 其双亲则将他们互换。我们沿着树向上继续这一过程,直至该新值要么是大于其双亲要么是位于该堆的根处。
*
*/
public void addElement(T obj);
/**
* removeMin方法将删除最小堆中的最小元素并返回它。由于最小元素是存储在最小堆的根处的,所以我们需要返回存储
* 在根处的元素并用堆中的另一元素替换它,与addElement操作一样,要维持该树的完全性那么只有一个能替换根的合法
* 元素,且它是存储在最末一片叶子上的元素。
*
* 一旦存储在最末一片叶子中的元素被移动到了根处,则必须对该堆进行重排序以维持该堆的排序属性。这一目标实现的方式,
* 将该根元素与其较小的孩子进行比较,且如果孩子更小则将它们互换。 沿着树向下继续这一过程,直至该元素要么位于某一
* 叶子中,要么比它的两个孩子都小。 显示了删除最小元素然后重新对树排序的过程。
* @return
*/
public T removeMin();
/**
* 返回一个指向该最小堆中的最小元素的引用。由于该元素总是存储在该树的根处,
* 所以实现这一方法只需要通过返回存储根处的元素即可。
* @return
*/
public T findMin();
}
2.堆的数组实现
package ds.java.ch12.heapImpl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import ds.java.ch12.exceptions.ElementNotFoundException;
import ds.java.ch12.exceptions.EmptyCollectionException;
/**
* @author LbZhang
* @version 创建时间:2015年11月30日 上午10:44:08
* @description 类说明
*/
public class ArrayBinaryTree<T> implements BinaryTreeADT<T>, Iterable<T> {
private static final int DEFAULT_CAPACITY = 50;
protected int count;
protected T[] tree;//持有数组用于实现堆
protected int modCount;
public ArrayBinaryTree(){
count = 0;
tree = (T[])new Object[DEFAULT_CAPACITY];
}
public ArrayBinaryTree(T element){
count = 1;
tree = (T[])new Object[DEFAULT_CAPACITY];
tree[0] = element;
}
protected void expandCapacity(){
tree=Arrays.copyOf(tree, tree.length*2);
}
@Override
public T getRootElement() throws EmptyCollectionException{
if(isEmpty()){
throw new EmptyCollectionException("ArrayBinaryTree");
}
return tree[0];
}
@Override
public boolean isEmpty() {
return count==0;
}
@Override
public int size() {
return count;
}
@Override
public boolean contains(T targetElement) {
T temp;
boolean found = false;
try{
temp = find(targetElement);
found = true;
}catch(Exception ElementNotFoundException){
found = false;
}
return found;
}
@Override
public T find(T targetElement) throws ElementNotFoundException{
T temp = null;
boolean found = false;
for(int i=0;i<tree.length;i++){
if(tree[i]!=null){
if(targetElement.equals(tree[i])){
found = true;
temp=tree[i];
}
}
}
if(!found){
throw new ElementNotFoundException("ArrayBinaryTree");
}
return temp;
}
@Override
public String toString() {
ArrayList<T> tempList = new ArrayList<T>();
///用于临时存储连理获取的对象的引用的队列
inOrder(0,tempList);
return tempList.toString();
}
@Override
public Iterator<T> iterator() {
return this.iteratorInOrder();
}
@Override
public Iterator<T> iteratorInOrder() {
ArrayList<T> tempList = new ArrayList<>();
inOrder(0, tempList);
return new TreeIterator(tempList.iterator());
}
protected void inOrder(int root,ArrayList<T> tempList){
if(root<tree.length){
if(tree[root]!=null){
inOrder(root*2+1, tempList);
tempList.add(tree[root]);
inOrder(root*2+2, tempList);
}
}
}
@Override
public Iterator<T> iteratorPreOrder() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterator<T> iteratorPostOrder() {
// TODO Auto-generated method stub
return null;
}
@Override
public Iterator<T> iteratorLevelOrder() {
// TODO Auto-generated method stub
return null;
}
/**
* 自定义一个TreeIterator类
* @author MrLBZ
*
*/
private class TreeIterator implements Iterator<T>
{
private int expectedModCount;
private Iterator<T> iter;
public TreeIterator(Iterator<T> iter)
{
this.iter = iter;
expectedModCount = modCount;
}
/**
* Returns true if this iterator has at least one more element
* to deliver in the iteration.
*
* @return true if this iterator has at least one more element to deliver
* in the iteration
* @throws ConcurrentModificationException if the collection has changed
* while the iterator is in use
*/
public boolean hasNext() throws ConcurrentModificationException
{
if (!(modCount == expectedModCount))
throw new ConcurrentModificationException();
return (iter.hasNext());
}
/**
* Returns the next element in the iteration. If there are no
* more elements in this iteration, a NoSuchElementException is
* thrown.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iterator is empty
*/
public T next() throws NoSuchElementException
{
if (hasNext())
return (iter.next());
else
throw new NoSuchElementException();
}
/**
* The remove operation is not supported.
*
* @throws UnsupportedOperationException if the remove operation is called
*/
public void remove()
{
throw new UnsupportedOperationException();
}
}
}
package ds.java.ch12.heapImpl;
import ds.java.ch11.exceptions.EmptyCollectionException;
/**
* @author LbZhang
* @version 创建时间:2015年11月30日 下午3:00:26
* @description 类说明
*/
public class ArrayHeap<T> extends ArrayBinaryTree<T> implements HeapADT<T> {
public ArrayHeap() {
super();
}
@Override
public void addElement(T obj) {
if (count == tree.length) {
expandCapacity();
}
tree[count] = obj;
count++;
modCount++;
if (count > 1) {
// 检查当前的插入
heapModifyAdd();
}
}
private void heapModifyAdd() {
T temp;
int next = count - 1;
temp = tree[next];
while (next != 0
&& (((Comparable) temp).compareTo(tree[(next - 1) / 2]) < 0)) {
tree[next] = tree[(next - 1) / 2];
next = (next - 1) / 2;
}
tree[next] = temp;
}
@Override
public T removeMin() throws EmptyCollectionException {
if (isEmpty()) {
throw new EmptyCollectionException("ArrayHeap");
}
T minElement = tree[0];
tree[0] = tree[count - 1];
heapModifyRemove();
count--;//当前的空白位置--
modCount--;
return minElement;
}
/**
* //删除修改堆结构
*/
private void heapModifyRemove() {
T temp;
// 开始的三个结点
int node = 0;
int left = 1;
int right = 2;
int next;
if ((tree[left] == null) && (tree[right] == null))
next = count;
else if (tree[right] == null)
next = left;//右边为null
else if (((Comparable) tree[left]).compareTo(tree[right]) < 0)
next = left;
else
next = right;
temp = tree[node];//临时存储 一个需要迁移的位置
while ((next < count)
&& (((Comparable) tree[next]).compareTo(temp) < 0)) {
tree[node] = tree[next];
node = next;
left = 2 * node + 1;
right = 2 * (node + 1);
if ((tree[left] == null) && (tree[right] == null))
next = count;
else if (tree[right] == null)
next = left;
else if (((Comparable) tree[left]).compareTo(tree[right]) < 0)
next = left;
else
next = right;
}
//最后放在node
tree[node] = temp;
}
@Override
public T findMin() {
if (isEmpty())
throw new EmptyCollectionException("ArrayHeap");
return tree[0];
}
}
3.堆的无序链表实现
package ds.java.ch12.heapImpl;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import ds.java.ch05.queueImpl.EmptyCollectionException;
import ds.java.ch06.listImpl.ArrayUnorderedList;
import ds.java.ch06.listImpl.ElementNotFoundException;
/**
* @author LbZhang
* @version 创建时间:2015年11月22日 上午11:04:36
* @description 二叉树的构建
*/
public class LinkedBinaryTree<T> implements Iterable<T>, BinaryTreeADT<T> {
// 根结点的设置
protected BinaryTreeNode<T> root;//gen结点
protected int modCount;// 修改标记 用于Iterator中使用
// protected int sizeOfLTree;
/**
* 无参构造方法
*/
public LinkedBinaryTree() {
root = null;
}
public LinkedBinaryTree(T element) {
root = new BinaryTreeNode<T>(element);
}
public LinkedBinaryTree(BinaryTreeNode<T> ltn) {
this.root = ltn;
}
public LinkedBinaryTree(T element, LinkedBinaryTree<T> left,
LinkedBinaryTree<T> right) {
root = new BinaryTreeNode<T>(element);
root.setLeft(left.root);
root.setRight(right.root);
}
/**
* 获取根节点
*
* @return
*/
public BinaryTreeNode<T> getRootNode() throws EmptyCollectionException {
if (isEmpty()) {
throw new EmptyCollectionException("BinaryTreeNode ");
}
return root;
}
/**
* Returns the left subtree of the root of this tree.
*
* @return a link to the right subtree of the tree
*/
public LinkedBinaryTree<T> getLeft() {
return new LinkedBinaryTree(this.root.getLeft());
// To be completed as a Programming Project
}
/**
* Returns the right subtree of the root of this tree.
*
* @return a link to the right subtree of the tree
*/
public LinkedBinaryTree<T> getRight() {
return new LinkedBinaryTree(this.root.getRight());
}
/**
* Returns the height of this tree.
*
* @return the height of the tree
*/
public int getHeight() {
return 0;
// To be completed as a Programming Project
}
/**
* Returns the height of the specified node.
*
* @param node
* the node from which to calculate the height
* @return the height of the tree
*/
private int height(BinaryTreeNode<T> node) {
return 0;
// To be completed as a Programming Project
}
@Override
public T getRootElement() throws EmptyCollectionException {
if (root.getElement().equals(null)) {
throw new EmptyCollectionException("BinaryTreeNode ");
}
return root.getElement();
}
@Override
public boolean isEmpty() {
return (root == null);
}
/**
* 返回的是当前结点孩子结点的个数
*/
@Override
public int size() {
int size = 0;
if(root.getLeft()!=null){
size+=1;
}
if(root.getRight()!=null){
size+=1;
}
return size;
}
@Override
public boolean contains(T targetElement) {
return false;
}
@Override
public T find(T targetElement) {
// 获取当前元素
BinaryTreeNode<T> current = findNode(targetElement, root);
if (current == null)
throw new ElementNotFoundException("LinkedBinaryTree");
return (current.getElement());
}
private BinaryTreeNode<T> findNode(T targetElement, BinaryTreeNode<T> next) {
if (next == null)
return null;
if (next.getElement().equals(targetElement))
return next;
// 递归调用
BinaryTreeNode<T> temp = findNode(targetElement, next.getLeft());
if (temp == null)
temp = findNode(targetElement, next.getRight());
return temp;
}
@Override
public Iterator<T> iteratorInOrder() {
ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
inOrder(root, tempList);
return new TreeIterator(tempList.iterator());
}
/**
* Performs a recursive inorder traversal. 中根遍历
*
* @param node
* the node to be used as the root for this traversal
* @param tempList
* the temporary list for use in this traversal
*/
protected void inOrder(BinaryTreeNode<T> node,
ArrayUnorderedList<T> tempList) {
if (node != null) {
inOrder(node.getLeft(), tempList);
tempList.addToRear(node.getElement());
inOrder(node.getRight(), tempList);
}
}
/**
* Performs an preorder traversal on this binary tree by calling an
* overloaded, recursive preorder method that starts with the root.
*
* @return a pre order iterator over this tree
*/
@Override
public Iterator<T> iteratorPreOrder() {
ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
preOrder(root, tempList);
return new TreeIterator(tempList.iterator());
}
/**
* Performs a recursive preorder traversal.
*
* @param node
* the node to be used as the root for this traversal
* @param tempList
* the temporary list for use in this traversal
*/
private void preOrder(BinaryTreeNode<T> node, ArrayUnorderedList<T> tempList) {
if (node != null) {
tempList.addToRear(node.getElement());
inOrder(node.getLeft(), tempList);
inOrder(node.getRight(), tempList);
}
}
/**
* Performs an postorder traversal on this binary tree by calling an
* overloaded, recursive postorder method that starts with the root.
*
* @return a post order iterator over this tree
*/
@Override
public Iterator<T> iteratorPostOrder() {
ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
postOrder(root, tempList);
return new TreeIterator(tempList.iterator());
}
/**
* Performs a recursive postorder traversal.
*
* @param node
* the node to be used as the root for this traversal
* @param tempList
* the temporary list for use in this traversal
*/
private void postOrder(BinaryTreeNode<T> node,
ArrayUnorderedList<T> tempList) {
if (node != null) {
tempList.addToRear(node.getElement());
inOrder(node.getLeft(), tempList);
inOrder(node.getRight(), tempList);
}
}
@Override
public Iterator<T> iteratorLevelOrder() {
ArrayUnorderedList<BinaryTreeNode<T>> nodes = new ArrayUnorderedList<BinaryTreeNode<T>>();
ArrayUnorderedList<T> tempList = new ArrayUnorderedList<T>();
BinaryTreeNode<T> current;
nodes.addToRear(root);
while (!nodes.isEmpty()) {
current = nodes.removeFirst();
if (current != null) {
tempList.addToRear(current.getElement());
if (current.getLeft() != null)
nodes.addToRear(current.getLeft());
if (current.getRight() != null)
nodes.addToRear(current.getRight());
} else
tempList.addToRear(null);
}
return new TreeIterator(tempList.iterator());
}
@Override
public Iterator<T> iterator() {
return iteratorInOrder();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
/**
* Inner class to represent an iterator over the elements of this tree
*/
private class TreeIterator implements Iterator<T> {
private int expectedModCount;
private Iterator<T> iter;
/**
* Sets up this iterator using the specified iterator.
*
* @param iter
* the list iterator created by a tree traversal
*/
public TreeIterator(Iterator<T> iter) {
this.iter = iter;
expectedModCount = modCount;
}
/**
* Returns true if this iterator has at least one more element to
* deliver in the iteration.
*
* @return true if this iterator has at least one more element to
* deliver in the iteration
* @throws ConcurrentModificationException
* if the collection has changed while the iterator is in
* use
*/
public boolean hasNext() throws ConcurrentModificationException {
if (!(modCount == expectedModCount))
throw new ConcurrentModificationException();
return (iter.hasNext());
}
/**
* Returns the next element in the iteration. If there are no more
* elements in this iteration, a NoSuchElementException is thrown.
*
* @return the next element in the iteration
* @throws NoSuchElementException
* if the iterator is empty
*/
public T next() throws NoSuchElementException {
if (hasNext())
return (iter.next());
else
throw new NoSuchElementException();
}
/**
* The remove operation is not supported.
*
* @throws UnsupportedOperationException
* if the remove operation is called
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
}
package ds.java.ch12.heapImpl;
import ds.java.ch12.exceptions.EmptyCollectionException;
/**
* @author LbZhang
* @version 创建时间:2015年11月30日 下午8:56:51
* @description 类说明
*/
public class LinkedHeap<T> extends LinkedBinaryTree<T> implements HeapADT<T> {
public HeapNode<T> lastNode;
public LinkedHeap() {
super();
}
@Override
public void addElement(T obj) {
// 一个堆结点
HeapNode<T> node = new HeapNode<T>(obj);
if (root == null)
root = node;// 如果为空 就把root指向当前的结点
else {
// 获取父结点 把需要添加的父结点返回
HeapNode<T> nextParent = getNextParentAdd();
if (nextParent.getLeft() == null)
nextParent.setLeft(node);
else
nextParent.setRight(node);
node.setParent(nextParent);
}
lastNode = node;// 最后的结点的引用
modCount++;
if (size() > 1)
heapifyAdd();
}
/**
* 添加修改当前堆
*/
private void heapifyAdd() {
T temp;
// 获取最后一个结点
HeapNode<T> next = lastNode;
// 临时保存
temp = next.getElement();
// 如果不是root结点而且小于当前的结点的父结点就进行循环
while ((next != root)
&& (((Comparable) temp)
.compareTo(next.getParent().getElement()) < 0)) {
next.setElement(next.getParent().getElement());
next = next.parent;
}
next.setElement(temp);// 放置到最后的结点
}
/**
* 获取当前需要添加位置的结点的父结点
*
* @return
*/
private HeapNode<T> getNextParentAdd() {
HeapNode<T> result = lastNode;// 当前的空白结点
while ((result != root) && (result.getParent().getLeft() != result))
result = result.getParent();
if (result != root) {
// /不是一个满堆
if (result.getParent().getRight() == null)
result = result.getParent();
else {
result = (HeapNode<T>) result.getParent().getRight();
// 不断的向下寻找最后的父结点
while (result.getLeft() != null)
result = (HeapNode<T>) result.getLeft();
}
} else {// 当前堆是一个满堆
while (result.getLeft() != null)
result = (HeapNode<T>) result.getLeft();
}
return result;
}
@Override
public T removeMin() throws EmptyCollectionException {
if (isEmpty())
throw new EmptyCollectionException("LinkedHeap");
T minElement = root.getElement();
if (size() == 1) {
root = null;
lastNode = null;
} else {
// 获取一个新的尾结点
HeapNode<T> nextLast = getNewLastNode();
if (lastNode.getParent().getLeft() == lastNode)
lastNode.getParent().setLeft(null);
else
lastNode.getParent().setRight(null);
((HeapNode<T>) root).setElement(lastNode.getElement());
lastNode = nextLast;
heapifyRemove();
}
modCount++;
return minElement;
}
/**
* 这里面的规则其实比较简单 就是在描述的时候比较麻烦: 【1】首先我们需要在程序中找到当前的最后一个结点,
* 【2】然后判断如果当前结点不是根节点,并且是父结点的左孩子,就不断的迭代向上查找;反之终止迭代
* 【3】然后判断当前结点不是是根节点,就寻找当前结点父结点的左孩子 【4】获取当前结点的右孩子是不是空 如果不为空
* 迭代一直到result的右孩子为空为止
*
* @return
*
* 返回最新的最末结点
*/
private HeapNode<T> getNewLastNode() {
HeapNode<T> result = lastNode;
// 非根的右边结点
while ((result != root) && (result.getParent().getLeft() == result))
result = result.getParent();
if (result != root)
result = (HeapNode<T>) result.getParent().getLeft();
while (result.getRight() != null)
result = (HeapNode<T>) result.getRight();
return result;
}
private void heapifyRemove() {
T temp;
HeapNode<T> node = (HeapNode<T>) root;//用户遍历的根结点
HeapNode<T> left = (HeapNode<T>) node.getLeft();
HeapNode<T> right = (HeapNode<T>) node.getRight();
HeapNode<T> next;
if ((left == null) && (right == null))
next = null;
else if (right == null)
next = left;
else if (((Comparable) left.getElement()).compareTo(right.getElement()) < 0)
next = left;
else
next = right;
temp = node.getElement();
while ((next != null)
&& (((Comparable) next.getElement()).compareTo(temp) < 0)) {
node.setElement(next.getElement());
node = next;
left = (HeapNode<T>) node.getLeft();
right = (HeapNode<T>) node.getRight();
if ((left == null) && (right == null))
next = null;
else if (right == null)
next = left;
else if (((Comparable) left.getElement()).compareTo(right
.getElement()) < 0)
next = left;
else
next = right;
}
node.setElement(temp);
}
@Override
public T findMin() {
if (isEmpty())
throw new EmptyCollectionException("LinkedHeap");
return root.getElement();
}
}