/* * Copyright 2016 Nathan Howard * * This file is part of OpenGrave * * OpenGrave is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenGrave is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenGrave. If not, see <http://www.gnu.org/licenses/>. */ package com.opengrave.common.pathing; import java.util.ArrayList; public class BinaryHeap<T extends Comparable<T>> { ArrayList<T> openList = new ArrayList<T>(); public BinaryHeap() { } public void add(T node) { openList.add(node); int position = openList.size(); swapWithParent(position); } public T takeBest() { if (openList.size() == 0) { throw (new RuntimeException("Taking element from empty Binary Heap")); } T ret = openList.get(0); T last = openList.remove(openList.size() - 1); // Take the last item if (openList.size() == 0) { return ret; } openList.set(0, last); // And place at start swapWithChildren(1); return ret; } public void integrityChanged(T value) { int idx = openList.indexOf(value); if (idx != -1) { idx = swapWithParent(idx + 1); idx = swapWithChildren(idx + 1); } } /** * * @param position * The position which needs to be checked and possibly pushed up * the heap (to a lower index) The lowest(first) index should be * 1. Not Zero */ private int swapWithParent(int position) { if (position < 1) { return position; } if (position == 1) { return position; } // Can not pass higher than first index. int parent = position / 2; T node = openList.get(position - 1); T parentNode = openList.get(parent - 1); if (parentNode.compareTo(node) > 0) { // Swap Locations of items; openList.set(parent - 1, node); openList.set(position - 1, parentNode); // Check to see if it needs to be passed up again return swapWithParent(parent); } return position; } /** * * @param position * The position which needs to be checked and possibly pushed * down the heap (to a higher index) The lowest(first) index * should be 1. Not Zero */ private int swapWithChildren(int position) { if (position < 1) { throw (new RuntimeException("swapWithChild position must be 1 or higher")); } int child1 = position * 2; int child2 = position * 2 + 1; if (child1 > openList.size()) { return position; } // it has no children - done if (child2 > openList.size()) { // It has only child1. T child1Node = openList.get(child1 - 1); T node = openList.get(position - 1); if (node.compareTo(child1Node) <= 0) { // Lower or equal to only child. No futher action needed return position; } else { return swapWithChild1(position); } } else { T child1Node = openList.get(child1 - 1); T child2Node = openList.get(child2 - 1); T node = openList.get(position - 1); if (node.compareTo(child1Node) <= 0 && node.compareTo(child2Node) <= 0) { // Both Nodes are higher or equal to current. No further action needed return position; } else if (child1Node.compareTo(node) < 0 && child2Node.compareTo(node) < 0) { // Both Nodes are lower than current if (child1Node.compareTo(child2Node) < 0) { return swapWithChild1(position); } else { return swapWithChild2(position); } } else if (child1Node.compareTo(node) < 0) { // Only Child 1 is lower. return swapWithChild1(position); } else { // Only Child 2 is lower. return swapWithChild2(position); } } } private int swapWithChild1(int position) { int child = position * 2; T node = openList.get(position - 1); T childNode = openList.get(child - 1); openList.set(child - 1, node); openList.set(position - 1, childNode); return swapWithChildren(child); } private int swapWithChild2(int position) { int child = position * 2 + 1; T node = openList.get(position - 1); T childNode = openList.get(child - 1); openList.set(child - 1, node); openList.set(position - 1, childNode); return swapWithChildren(child); } public int indexOf(T node) { return openList.indexOf(node); } public int size() { return openList.size(); } public T get(int idx) { return openList.get(idx); } }