分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net
package chimomo.learning.java.datastructure;
/**
* Implements a pairing heap.
* Supports a decreaseKey operation.
* Note that all "matching" is based on the compareTo method.
*
* @author Created by Chimomo
*/
public class PairingHeap> {
private PairNode root;
private int size;
// The tree array for combine siblings.
private PairNode[] treeArray = new PairNode[5];
/**
* Construct the pairing heap.
*/
public PairingHeap() {
root = null;
size = 0;
}
// Test program.
public static void main(String[] args) throws Exception {
// Create pairing heap.
PairingHeap h = new PairingHeap<>();
int numItems = 10000;
int i;
int j;
// Insert.
System.out.println("Checking; no bad output is good.");
for (i = 37; i != 0; i = (i + 37) % numItems) {
h.insert(i);
}
// Delete min.
for (i = 1; i < numItems; i++) {
if (h.deleteMin() != i) {
System.out.println("Oops! " + i);
}
}
ArrayList> p = new ArrayList<>();
for (i = 0; i < numItems; i++) {
p.add(null);
}
for (i = 0, j = numItems / 2; i < numItems; i++, j = (j + 71) % numItems) {
p.set(j, h.insert(j + numItems));
}
// Decrease key.
for (i = 0, j = numItems / 2; i < numItems; i++, j = (j + 53) % numItems) {
h.decreaseKey(p.get(j), p.get(j).getValue() - numItems);
}
i = -1;
// Delete min.
while (!h.isEmpty()) {
if (h.deleteMin() != ++i) {
System.out.println("Oops! " + i + " ");
}
}
System.out.println("Check completed.");
}
/**
* Insert into the priority queue, and return a position that can be used by decreaseKey.
* Duplicates are allowed.
*
* @param x The item to insert.
* @return The node containing the newly inserted item.
*/
public Position insert(T x) {
PairNode newNode = new PairNode<>(x);
if (root == null) {
root = newNode;
} else {
root = compareAndLink(root, newNode);
}
size++;
return newNode;
}
/**
* Find the smallest item in the priority queue.
*
* @return The smallest item.
* @throws Exception If pairing heap is empty.
*/
public T findMin() throws Exception {
if (isEmpty()) {
throw new Exception("Pairing heap is empty!");
}
return root.element;
}
/**
* Remove the smallest item from the priority queue.
*
* @return The smallest item.
* @throws Exception If pairing heap is empty.
*/
public T deleteMin() throws Exception {
if (isEmpty()) {
throw new Exception("Pairing heap is empty!");
}
T x = findMin();
// Null it out in case used in decrease key.
root.element = null;
if (root.leftChild == null) {
root = null;
} else {
root = combineSiblings(root.leftChild);
}
size--;
return x;
}
/**
* Change the value of the item stored in the pairing heap.
*
* @param position Any position returned by insert.
* @param newValue The new value, which must be smaller than the currently stored value.
* @throws IllegalArgumentException If position is null.
* @throws IllegalArgumentException If new value is larger than old.
*/
public void decreaseKey(Position position, T newValue) {
if (position == null) {
throw new IllegalArgumentException("Null position passed to decrease key.");
}
PairNode p = (PairNode) position;
if (p.element == null) {
throw new IllegalArgumentException("Position already deleted.");
}
if (p.element.compareTo(newValue) < 0) {
throw new IllegalArgumentException("New value/Old value: " + newValue + "/" + p.element);
}
p.element = newValue;
if (p != root) {
if (p.nextSibling != null) {
p.nextSibling.prev = p.prev;
}
if (p.prev.leftChild == p) {
p.prev.leftChild = p.nextSibling;
} else {
p.prev.nextSibling = p.nextSibling;
}
p.nextSibling = null;
root = compareAndLink(root, p);
}
}
/**
* Test if the priority queue is logically empty.
*
* @return True if empty, false otherwise.
*/
public boolean isEmpty() {
return root == null;
}
/**
* Returns number of items stored in the priority queue.
*
* @return The size of the priority queue.
*/
public int size() {
return size;
}
/**
* Make the priority queue logically empty.
*/
public void makeEmpty() {
root = null;
size = 0;
}
/**
* Internal method that is the basic operation to maintain order.
* Links first and second together to satisfy heap order.
*
* @param first The root of tree 1, which may not be null. (first.nextSibling MUST be null on entry)
* @param second The root of tree 2, which may be null.
* @return The result of the tree merge.
*/
private PairNode compareAndLink(PairNode first, PairNode second) {
if (second == null) {
return first;
}
if (second.element.compareTo(first.element) < 0) {
// Attach first as leftmost child of second.
second.prev = first.prev;
first.prev = second;
first.nextSibling = second.leftChild;
if (first.nextSibling != null) {
first.nextSibling.prev = first;
}
second.leftChild = first;
return second;
} else {
// Attach second as leftmost child of first.
second.prev = first;
first.nextSibling = second.nextSibling;
if (first.nextSibling != null) {
first.nextSibling.prev = first;
}
second.nextSibling = first.leftChild;
if (second.nextSibling != null) {
second.nextSibling.prev = second;
}
first.leftChild = second;
return first;
}
}
/**
* Double the array length if full.
*
* @param array The array.
* @param index The array index.
* @return The doubled array.
*/
private PairNode[] doubleIfFull(PairNode[] array, int index) {
if (index == array.length) {
PairNode[] oldArray = array;
array = new PairNode[index * 2];
for (int i = 0; i < index; i++) {
array[i] = oldArray[i];
}
}
return array;
}
/**
* Internal method that implements two-pass merging.
*
* @param firstSibling The root of the conglomerate; assumed not null.
*/
private PairNode combineSiblings(PairNode firstSibling) {
if (firstSibling.nextSibling == null) {
return firstSibling;
}
// Store the subtrees in an array.
int numSiblings = 0;
for (; firstSibling != null; numSiblings++) {
treeArray = doubleIfFull(treeArray, numSiblings);
treeArray[numSiblings] = firstSibling;
// Break links.
firstSibling.prev.nextSibling = null;
firstSibling = firstSibling.nextSibling;
}
treeArray = doubleIfFull(treeArray, numSiblings);
treeArray[numSiblings] = null;
// Combine subtrees two at a time, going left to right.
int i = 0;
for (; i + 1 < numSiblings; i += 2) {
treeArray[i] = compareAndLink(treeArray[i], treeArray[i + 1]);
}
// j has the result of last compareAndLink.
// If an odd number of trees, get the last one.
int j = i - 2;
if (j == numSiblings - 3) {
treeArray[j] = compareAndLink(treeArray[j], treeArray[j + 2]);
}
// Now go right to left, merging last tree with next to last.
// The result becomes the new last.
for (; j >= 2; j -= 2) {
treeArray[j - 2] = compareAndLink(treeArray[j - 2], treeArray[j]);
}
return treeArray[0];
}
/**
* The position interface represents a type that can be used for the decrease key operation.
*/
public interface Position {
/**
* Returns the value stored at this position.
*
* @return the value stored at this position.
*/
AnyType getValue();
}
/**
* Pairing heap node class, for use with PairingHeap.
*/
private static class PairNode implements Position {
// Friendly data; accessible by other package routines.
public AnyType element;
public PairNode leftChild;
public PairNode nextSibling;
public PairNode prev;
/**
* Construct the PairNode.
*
* @param element The value stored in the node.
*/
public PairNode(AnyType element) {
this.element = element;
leftChild = null;
nextSibling = null;
prev = null;
}
/**
* Returns the value stored at this position.
*
* @return the value stored at this position.
*/
public AnyType getValue() {
return element;
}
}
}
/*
Output:
Checking; no bad output is good.
Check completed.
*/