Current I have a home work question which says,
It is possible to make the heap sort algorithm more efficient by
writing a method that will order the entire list at once instead of
adding the elements one at a time.
However I can't figure out what exactly it means by "instead of adding elements one at a time", surely one has to building a heap first (which involves adding element from a unsorted list one by one), then remove the largest from the heap one at a time.
Here is my heap array:
import exceptions.exceptions.*;
public class ArrayHeap<T> extends ArrayBinaryTree<T> implements HeapADT<T> {
public ArrayHeap(){
super();
}
public void addElement (T element){
if (count==size())
expandCapacity();
tree[count] = element;
count++;
if (count > 1)
heapifyAdd();
}
private void heapifyAdd(){
int index = count - 1;
while ((index != 0) && (((Comparable)tree[index]).compareTo(tree[(index-1)/2]) < 0))
{
T temp = tree[index];
tree[index] = tree[(index-1)/2];
tree[(index-1)/2] = temp;
index = (index-1)/2;
}
}
public T removeMin(){
if (isEmpty())
throw new EmptyCollectionException ("Empty Heap");
T minElement = findMin();
tree[0] = tree[count-1];
heapifyRemove();
count--;
return minElement;
}
private void heapifyRemove()
{
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[left] == null)
next = right;
else if (tree[right] == null)
next = left;
else if (((Comparable)tree[left]).compareTo(tree[right]) < 0)
next = left;
else
next = right;
while ((next < count) && (((Comparable)tree[next]).compareTo(tree[node]) < 0)){
temp = tree[node];
tree[node] = tree[next];
tree[next] = temp;
node = next;
left = 2*node + 1;
right = 2*(node+1);
if ((tree[left] == null) && (tree[right] == null))
next = count;
else if (tree[left] == null)
next = right;
else if (tree[right] == null)
next = left;
else if (((Comparable)tree[left]).compareTo(tree[right]) < 0)
next = left;
else
next = right;
}
}
public T findMin() {
if (isEmpty())
throw new EmptyCollectionException ("Empty Heap");
return tree[0];
}
}
Here is more HeapSort algorithm:
import ArrayHeap;
public class HeapSort<T>{
public T[] heapsort(T[] data, int min, int max){
ArrayHeap<T> temp = new ArrayHeap<T>();
for (int c = min; c <= max; c++){
temp.addElement(data[c]);
}
int count = min;
while(!(temp.isEmpty())){
T jj = temp.removeMin();
data[count] = jj;
count ++;
}
return data;
}
The most straight-forward way to perform heapsort is to use a separate heap and add all the elements to it, then the elements will be in order when we pop them out one by one. This is what "adding the elements one at a time" refers to in the statement, and this is what your implementation is doing: create a heap of type ArrayHeap and insert the elements of data to it, in the end pop the elements back to data.
A more efficient way (in terms of both space and time) is to perform in-place sorting, where we use the array to be sorted as the heap, rather than using additional memory for the heap, this is what "order the entire list at once" refers to. The steps of this implementation is as follow, we will order the elements in non-decreasing order:
We max-heapify the input array (i.e. we re-arrange the elements in the array so that it follows the max-heap property.
For i = n - 1 to 1:
Swap the 0-th element in the array with the i-th element.
Decrease the size of the heap by 1 (i.e. the heap should be of size i).
Perform the sift-down operation on the heap to restore the max-heap property.
Note that whenever the max-heap property holds, the top-most element in the heap is the largest element, so at the start of the k-th iteration (k = n - i here) the 0-th element is the k-largest element, and we place is in the correct position in the array by swapping.
Note that step 1 can be done in O(n), and in step 2 there are O(n) iterations and each sift-down operation takes time O(log(n)), so the overall time complexity is O(n log(n)).
Below is an implementation in Java for your reference:
import java.util.Random;
public class HeapSort {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
System.out.println(String.format("Iteration number %d%n", i));
Integer[] array = randomIntArray(10, 0, 100);
System.out.println(String.format("Array before sorting: [%s]", toStr(array)));
heapSort(array);
System.out.println(String.format("Array after sorting: [%s]", toStr(array)));
System.out.println("================================================================");
}
}
private static <T extends Comparable<T>> T[] heapSort(T[] array) {
maxHeapify(array, array.length);
for (int i = array.length - 1; i > 0; i--) {
swap(array, 0, i);
siftDown(array, i, 0);
}
return array;
}
private static <T extends Comparable<T>> void maxHeapify(T[] array, int heapSize) {
for (int i = getParentIdx(heapSize - 1); i >= 0; i--) {
siftDown(array, heapSize, i);
}
}
private static <T extends Comparable<T>> void siftDown(T[] array, int heapSize, int idx) {
final int length = Math.min(array.length, heapSize) - 1;
if (idx > length || idx < 0) throw new IllegalArgumentException("Index out of range");
while (true) {
int maxIdx = idx;
int leftChildIdx = getLeftChildIdx(idx);
int rightChildIdx = getRightChildIdx(idx);
if (leftChildIdx <= length && array[maxIdx].compareTo(array[leftChildIdx]) < 0) maxIdx = leftChildIdx;
if (rightChildIdx <= length && array[maxIdx].compareTo(array[rightChildIdx]) < 0) maxIdx = rightChildIdx;
if (idx != maxIdx) {
swap(array, idx, maxIdx);
idx = maxIdx;
} else {
return;
}
}
}
private static int getParentIdx(int idx) {
return (idx - 1) / 2;
}
private static int getLeftChildIdx(int idx) {
return idx * 2 + 1;
}
private static int getRightChildIdx(int idx) {
return idx * 2 + 2;
}
private static <T> void swap(T[] array, int i, int j) {
T tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
private static <T> String toStr(T[] array) {
StringBuilder sb = new StringBuilder();
for (T element : array) {
sb.append(element + ", ");
}
return sb.substring(0, sb.length() - 2);
}
private static Integer[] randomIntArray(int size, int lowerBound, int upperBound) {
Integer[] result = new Integer[size];
Random random = new Random();
int diff = upperBound - lowerBound + 1;
for (int i = 0; i < size; i++) result[i] = lowerBound + random.nextInt(diff);
return result;
}
}
Related
Sorry for the wordy title but it explains my question pretty well.
I am working on an assignment in Java where I need to create my own Hash Table.
The specifications are such that I must use an Array, as well as open-addressing for collision handling (with both double hashing and quadratic hashing implementations).
My implementation works quite well, and using over 200,000 randomly generated Strings I end up with only ~1400 Collisions with both types of collision handling mentioned about (keeping my load factor at 0.6 and increasing my Array by 2.1 when it goes over).
Here is where I'm stumped, however... My assignment calls for 2 specifications that I cannot figure out.
1) Have an option which, when removing a value form the table, instead of using "AVAILABLE" (replacing the index in the array with a junk value that indicates it is empty), I must find another value that previously hashed to this index and resulted in a collision. For example, if value A hashed to index 2 and value B also hashed to index 2 (and was later re-hashed to index 5 using my collision handling hash function), then removing value A will actually replace it with Value B.
2) Keep track of the maximum number of collisions in a single array index. I currently keep track of all the collisions, but there's no way for me to keep track of the collisions at an individual cell.
I was able to solve this problem using Separate Chaining by having each Array Index hold a linked list of all values that have hashed to this index, so that only the first one is retrieved when I call my get(value) method, but upon removal I can easily replace it with the next value that hashed to this index. It's also an easy way to get the max number of collisions per index.
But we were specifically told not to use separate chaining... I'm actually wondering if this is even possible without completely ruining the complexity of the hash table.
Any advice would be appreciated.
edit:
Here are some examples to give you an idea of my class structure:
public class daveHash {
//Attributes
public String[] dTable;
private double loadFactor, rehashFactor;
private int size = 0;
private String emptyMarkerScheme;
private String collisionHandlingType;
private int collisionsTotal = 0;
private int collisionsCurrent = 0;
//Constructors
public daveHash()
{
dTable = new String[17];
rehashFactor = 2.1;
loadFactor = 0.6;
emptyMarkerScheme = "A";
collisionHandlingType = "D";
}
public daveHash(int size)
{
dTable = new String[size];
rehashFactor = 2.1;
loadFactor = 0.6;
emptyMarkerScheme = "A";
collisionHandlingType = "D";
}
My hashing functions:
public long getHashCode(String s, int index)
{
if (index > s.length() - 1)
return 0;
if (index == s.length()-1)
return (long)s.charAt(index);
if (s.length() >= 20)
return ((long)s.charAt(index) + 37 * getHashCode(s, index+3));
return ((long)s.charAt(index) + 37 * getHashCode(s, index+1));
}
public int compressHashCode(long hash, int arraySize)
{
int b = nextPrime(arraySize);
int index = ((int)((7*hash) % b) % arraySize);
if (index < 0)
return index*-1;
else
return index;
}
Collision handling:
private int collisionDoubleHash(int index, long hashCode, String value, String[] table)
{
int newIndex = 0;
int q = previousPrime(table.length);
int secondFunction = (q - (int)hashCode) % q;
if (secondFunction < 0)
secondFunction = secondFunction*-1;
for (int i = 0; i < table.length; i++)
{
newIndex = (index + i*secondFunction) % table.length;
//System.out.println(newIndex);
if (isAvailable(newIndex, table))
{
table[newIndex] = value;
return newIndex;
}
}
return -1;
}
private int collisionQuadraticHash(int index, long hashCode, String value, String[] table)
{
int newIndex = 0;
for (int i = 0; i < table.length; i ++)
{
newIndex = (index + i*i) % table.length;
if (isAvailable(newIndex, table))
{
table[newIndex] = value;
return newIndex;
}
}
return -1;
}
public int collisionHandling(int index, long hashCode, String value, String[] table)
{
collisionsTotal++;
collisionsCurrent++;
if (this.collisionHandlingType.equals("D"))
return collisionDoubleHash(index, hashCode, value, table);
else if (this.collisionHandlingType.equals("Q"))
return collisionQuadraticHash(index, hashCode, value, table);
else
return -1;
}
Get, Put and Remove:
private int getIndex(String k)
{
long hashCode = getHashCode(k, 0);
int index = compressHashCode(hashCode, dTable.length);
if (dTable[index] != null && dTable[index].equals(k))
return index;
else
{
if (this.collisionHandlingType.equals("D"))
{
int newIndex = 0;
int q = previousPrime(dTable.length);
int secondFunction = (q - (int)hashCode) % q;
if (secondFunction < 0)
secondFunction = secondFunction*-1;
for (int i = 0; i < dTable.length; i++)
{
newIndex = (index + i*secondFunction) % dTable.length;
if (dTable[index] != null && dTable[newIndex].equals(k))
{
return newIndex;
}
}
}
else if (this.collisionHandlingType.equals("Q"))
{
int newIndex = 0;
for (int i = 0; i < dTable.length; i ++)
{
newIndex = (index + i*i) % dTable.length;
if (dTable[index] != null && dTable[newIndex].equals(k))
{
return newIndex;
}
}
}
return -1;
}
}
public String get(String k)
{
long hashCode = getHashCode(k, 0);
int index = compressHashCode(hashCode, dTable.length);
if (dTable[index] != null && dTable[index].equals(k))
return dTable[index];
else
{
if (this.collisionHandlingType.equals("D"))
{
int newIndex = 0;
int q = previousPrime(dTable.length);
int secondFunction = (q - (int)hashCode) % q;
if (secondFunction < 0)
secondFunction = secondFunction*-1;
for (int i = 0; i < dTable.length; i++)
{
newIndex = (index + i*secondFunction) % dTable.length;
if (dTable[index] != null && dTable[newIndex].equals(k))
{
return dTable[newIndex];
}
}
}
else if (this.collisionHandlingType.equals("Q"))
{
int newIndex = 0;
for (int i = 0; i < dTable.length; i ++)
{
newIndex = (index + i*i) % dTable.length;
if (dTable[index] != null && dTable[newIndex].equals(k))
{
return dTable[newIndex];
}
}
}
return null;
}
}
public void put(String k, String v)
{
double fullFactor = (double)this.size / (double)dTable.length;
if (fullFactor >= loadFactor)
resizeTable();
long hashCode = getHashCode(k, 0);
int index = compressHashCode(hashCode, dTable.length);
if (isAvailable(index, dTable))
{
dTable[index] = v;
size++;
}
else
{
collisionHandling(index, hashCode, v, dTable);
size++;
}
}
public String remove(String k)
{
int index = getIndex(k);
if (dTable[index] == null || dTable[index].equals("AVAILABLE") || dTable[index].charAt(0) == '-')
return null;
else
{
if (this.emptyMarkerScheme.equals("A"))
{
String val = dTable[index];
dTable[index] = "AVAILABLE";
size--;
return val;
}
else if (this.emptyMarkerScheme.equals("N"))
{
String val = dTable[index];
dTable[index] = "-" + val;
size--;
return val;
}
}
return null;
}
Hopefully this can give you an idea of my approach. This does not include the Separate Chaining implementation I mentioned above. For this, I had the following inner classes:
private class hashList
{
private class hashNode
{
private String element;
private hashNode next;
public hashNode(String element, hashNode n)
{
this.element = element;
this.next = n;
}
}
private hashNode head;
private int length = 0;
public hashList()
{
head = null;
}
public void addToStart(String s)
{
head = new hashNode(s, head);
length++;
}
public int getLength()
{
return length;
}
}
And my methods were modified appropriate to access the element in the head node vs the element in the Array. I took this out, however, since we are not supposed to use Separate Chaining to solve the problem.
Thanks!!
I tried to build a minHeap using java, this is my code:
public class MyMinHeap {
private ArrayList<Node> heap;
public MyMinHeap() {
heap = new ArrayList<Node>();
}
public MyMinHeap(ArrayList<Node> nodeList) {
heap = nodeList;
buildHeap();
}
public void buildHeap() {
int i = heap.size() / 2;
while (i >= 0) {
minHeapify(i);
i--;
}
}
public Node extractMin() {
if (heap.size() <= 0) return null;
Node minValue = heap.get(0);
heap.set(0, heap.get(heap.size() - 1));
heap.remove(heap.size() - 1);
minHeapify(0);
return minValue;
}
public String toString() {
String s = "";
for (Node n : heap) {
s += n + ",";
}
return s;
}
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
if (smallest != i) {
swap(smallest, i);
minHeapify(smallest);
}
}
private void swap(int i, int j) {
Node t = heap.get(i);
heap.set(i, heap.get(j));
heap.set(j, t);
}
public boolean lessThan(int i, int j) {
return heap.get(i)
.compareTo(heap.get(j)) < 0;
}
public static void main(String[] args) {
char[] chars = {'a', 'b', 'c', 'd', 'e', 'f'};
int[] freqs = {45, 13, 12, 16, 9, 5};
ArrayList<Node> data = new ArrayList<Node>();
for (int i = 0; i < chars.length; i++) {
data.add(new Node(chars[i], freqs[i]));
}
MyMinHeap heap = new MyMinHeap(data);
System.out.println("print the heap : " + heap);
for (int i = 0; i < chars.length; i++) {
System.out.println("Smallest is :" + heap.extractMin());
}
}
}
The output should be:5,9,12,13,16,45,
but what I got is : 9,13,12,16,45
I have debugged this but still can't figure out, anybody help? thanks a lot.
Insert :
When we insert into a min-heap, we always start by inserting the element at the bottom. We insert at the
rightmost spot so as to maintain the complete tree property.
Then, we "fix" the tree by swapping the new element with its parent, until we find an appropriate spot for
the element. We essentially bubble up the minimum element.
This takes 0 (log n) time, where n is the number of nodes in the heap.
Extract Minimum Element :
Finding the minimum element of a min-heap is easy: it's always at the top. The trickier part is how to remove
it. (I n fact, this isn't that tricky.)
First, we remove the minimum element and swap it with the last element in the heap (the bottommost,
rightmost element). Then, we bubble down this element, swapping it with one of its children until the minheap
property is restored.
Do we swap it with the left child or the right child? That depends on their values. There's no inherent
ordering between the left and right element, but you'll need to take the smaller one in order to maintain
the min-heap ordering.
public class MinHeap {
private int[] heap;
private int size;
private static final int FRONT = 1;
public MinHeap(int maxSize) {
heap = new int[maxSize + 1];
size = 0;
}
private int getParent(int position) {
return position / 2;
}
private int getLeftChild(int position) {
return position * 2;
}
private int getRightChild(int position) {
return position * 2 + 1;
}
private void swap(int position1, int position2) {
int temp = heap[position1];
heap[position1] = heap[position2];
heap[position2] = temp;
}
private boolean isLeaf(int position) {
if (position > size / 2) {
return true;
}
return false;
}
public void insert(int data) {
heap[++size] = data;
int currentItemIndex = size;
while (heap[currentItemIndex] < heap[getParent(currentItemIndex)]) {
swap(currentItemIndex, getParent(currentItemIndex));
currentItemIndex = getParent(currentItemIndex);
}
}
public int delete() {
int item = heap[FRONT];
swap(FRONT, size--); // heap[FRONT] = heap[size--];
heapify(FRONT);
return item;
}
private void heapify(int position) {
if (isLeaf(position)) {
return;
}
if (heap[position] > heap[getLeftChild(position)]
|| heap[position] > heap[getRightChild(position)]) {
// if left is smaller than right
if (heap[getLeftChild(position)] < heap[getRightChild(position)]) {
// swap with left
swap(heap[position], heap[getLeftChild(position)]);
heapify(getLeftChild(position));
} else {
// swap with right
swap(heap[position], heap[getRightChild(position)]);
heapify(getRightChild(position));
}
}
}
#Override
public String toString() {
StringBuilder output = new StringBuilder();
for (int i = 1; i <= size / 2; i++) {
output.append("Parent :" + heap[i]);
output
.append("LeftChild : " + heap[getLeftChild(i)] + " RightChild :" + heap[getRightChild(i)])
.append("\n");
}
return output.toString();
}
public static void main(String... arg) {
System.out.println("The Min Heap is ");
MinHeap minHeap = new MinHeap(15);
minHeap.insert(5);
minHeap.insert(3);
minHeap.insert(17);
minHeap.insert(10);
minHeap.insert(84);
minHeap.insert(19);
minHeap.insert(6);
minHeap.insert(22);
minHeap.insert(9);
System.out.println(minHeap.toString());
System.out.println("The Min val is " + minHeap.delete());
}
}
The problem is in your minHeapify function. You have:
public void minHeapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int smallest = i;
if (left < heap.size() - 1 && lessThan(left, smallest))
smallest = left;
if (right < heap.size() - 1 && lessThan(right, smallest))
smallest = right;
Now, let's say that your initial array list is {3,2}, and you call minHeapify(0).
left = 2 * i + 1; // = 1
right = 2 * i + 2; // = 2
smallest = i; // 0
Your next statement:
if (left < heap.size() - 1 && lessThan(left, smallest))
At this point, left = 1, and heap.size() returns 2. So left isn't smaller than heap.size() - 1. So your function exits without swapping the two items.
Remove the - 1 from your conditionals, giving:
if (left < heap.size() && lessThan(left, smallest))
smallest = left;
if (right < heap.size() && lessThan(right, smallest))
smallest = right;
import java.util.Comparator;
public class SortedList implements Container{
private int size;
private int front = 0;
private int rear = 0;
private WorkOrder[] buffer;
Comparator comparator;
public SortedList(){
buffer = new WorkOrder[10];
}
/**
* The comparator that the container will use to arrange the container
*
* #param comp
*/
public void setComparator(Comparator comp){
if (comp == null){
throw new IllegalArgumentException();
}
comparator = comp;
}
/**
* Add a workorder to the container
*/
public void add(WorkOrder wo){
if(wo == null){
throw new IllegalArgumentException();
}
if (size == capacity()){
WorkOrder[] regrowArray = new WorkOrder[2*capacity()];
for (int i = 0; i<size;i++){
regrowArray[i] = buffer[i];
}
buffer = regrowArray;
rear = size;
}
buffer[rear] = wo;
rear++;
size++;
}
/**
* Gets a workorder (removes it also) from the container
*/
public WorkOrder getNext(){
if (isEmpty()){
return null;
}
WorkOrder itemRemoved = buffer[front];
buffer[front] = null;
front++;
size--;
return itemRemoved;
}
/**
* Arranges the workorders in the required order
* Uses the comparator if necessary
* Some data structures may not need this method (like Queue)
* Just make it a no-op for those structures.
*/
public void arrange(){
if (buffer == null || size == 0){
return;
}
partition(0,size-1);
//sort(0,size-1);
}
private void partition(int left, int right){
int pivotIndex = (right + left) / 2;
int i = left;
int j = right;
if ((right-left) <= 10){
insertionSort(left,right);
return;
}
while (i <= j){
while (comparator.compare(buffer[i],buffer[pivotIndex]) < 0){
i++;
}
while (comparator.compare(buffer[j],buffer[pivotIndex]) > 0){
j--;
}
if (i <= j){
swap(i,j);
i++;
j--;
}
}
if (left < j){
partition(left,j);
}
if (i<right){
partition(i, right);
}
}
private void insertionSort(int left, int right){
for (int i = 1; i < right; i++){
WorkOrder val = buffer[i];
int j = i - 1;
while (j>=0 && comparator.compare(buffer[j], val) > 0){
buffer[j+1] = buffer[j];
j = j - 1;
}
buffer[j+1] = val;
}
}
private void swap(int x, int y){
WorkOrder temp = buffer[x];
buffer[x] = buffer[y];
buffer[y] = temp;
}
}
the output I see is:
0123567894
The comparator being passed in is dependent on the junits being run on it so that is why I am using comparator. compare for everything. I'm almost positive the sorting algos are correct, I could be manipulating the backing array incorrectly.
The problem seems its the insertion sort part:
for (int i = 1; i < right; i++){ //going from 1 to one previous to the last (right - 1)
WorkOrder val = buffer[i];
int j = i - 1;
while (j>=0 && comparator.compare(buffer[j], val) > 0){
buffer[j+1] = buffer[j];
j = j - 1;
}
buffer[j+1] = val;
}
you need to take into account that it needs to loop until the last one, since you know that the right variable is the last index of that partition.
for (int i = 1; i <= right; i++) //replace < for <=
since right is the last index (and it needs to be taken into account) of the array when its 10 or less elements.
edit:
The only thing else i see (in the quick sort code) is this part:
if (left < j){
partition(left,j); //trying to partition from left to j (since 'j' and 'i' may overlap)
}
it should be
if (left < (i - 1)){
partition(left,i - 1); //so the partition doesnt overlap with the 'i' to 'right' partition by an element (since i and j may overlap at the end).
}
That way you ensure that you are splitting the partition in half at all times.
How can i implement a recursive binary search in an int array using only 1 parameter in java ?
it tried but my code doesn't work. I implemented a class which its instances are objects having arrays and a count variable to detect how many elements are their in the array. any idea how can i implement the recursive binary search using only 1 parameter ?
public class LinearSortedArray {
int count;
int[] a;
public LinearSortedArray() {
count = 0;
}
public LinearSortedArray(int size) {
count = 0;
a = new int[size];
}
public static int[] copyingMethod(int startPoint, int endPoint,
LinearSortedArray arrayObj) {
int[] copyingArray = new int[endPoint - startPoint];
int j = startPoint;
for (int i = 0; i < copyingArray.length; i++) {
copyingArray[i] = arrayObj.a[j];
j++;
}
return copyingArray;
}
public int binarySearchRec(int x) {
if (count == 0) {
return -1;
}
int pivot = count / 2;
LinearSortedArray newArrayObj;
if (x > a[pivot]) {
newArrayObj = new LinearSortedArray(count - pivot);
newArrayObj.count = newArrayObj.a.length;
newArrayObj.a = copyingMethod(pivot, count, this);
for (int i = 0; i < newArrayObj.a.length; i++) {
System.out.print(newArrayObj.a[i]);
System.out.print(" ");
}
System.out.println();
return pivot + newArrayObj.binarySearchRec(x);
} else if (x < a[pivot]) {
newArrayObj = new LinearSortedArray(pivot);
newArrayObj.count = newArrayObj.a.length;
newArrayObj.a = copyingMethod(0, pivot, this);
for (int i = 0; i < newArrayObj.a.length; i++) {
System.out.print(newArrayObj.a[i]);
System.out.print(" ");
}
System.out.println();
return newArrayObj.binarySearchRec(x);
} else {
return pivot;
}
}
}
P.S.: The arrays are already sorted
Binary search really requires a range and a target value -- so if you're only passing one parameter, this has to be the target and this must encapsulate the array & range.
public class ArraySegment {
protected int[] array;
protected int boundLo;
protected int boundHi;
public class ArraySegment (int[] array) {
// entire array.
this( array, 0, array.length);
}
public class ArraySegment (int[] array, int lo, int hi) {
this.array = array;
this.boundLo = lo;
this.boundHi = hi;
}
public int binarySearch (int target) {
if (boundHi <= boundLo) {
return -1; // Empty; not found.
}
int pivot = (boundLo + boundHi) / 2;
int pivotEl = array[ pivot];
if (target == pivotEl) {
return pivot; // Found!
}
if (target < pivotEl) {
// recurse Left of pivot.
ArraySegment sub = new ArraySegment( array, boundLo, pivot);
return sub.binarySearch( target);
} else {
// recurse Right of pivot.
ArraySegment sub = new ArraySegment( array, pivot, boundHi);
return sub.binarySearch( target);
}
}
}
It's a little bit questionable what kind of result you should return -- there isn't a good answer with the question posed like this, as an "integer index" kinda defeats the purpose of the ArraySegment/ range wrapper, and returning an ArraySegment containing only the found value is also fairly useless.
PS: You really shouldn't be copying the array or it's contents, just passing round references to ranges on that array. Like java.lang.String is a range on a character array.
You could contrive a single-parameter by using the Value Object Pattern, where you pass one "wrapper" object, but the object has many fields.
For example:
class SearchParams {
int target;
int start;
int end;
SearchParams(t, s, e) {
target = t;
start = s;
end = e'
}
}
int search(SearchParams params) {
// some impl
return search(new SearchParams(params.target, a, b));
}
Technically, this is one parameter. Although it may not be in the spirit of the rules.
I'm having trouble combining these two algorithms together. I've been asked to modify Binary Search to return the index that an element should be inserted into an array. I've been then asked to implement a Binary Insertion Sort that uses my Binary Search to sort an array of randomly generated ints.
My Binary Search works the way it's supposed to, returning the correct index whenever I test it alone. I wrote out Binary Insertion Sort to get a feel for how it works, and got that to work as well. As soon as I combine the two together, it breaks. I know I'm implementing them incorrectly together, but I'm not sure where my problem lays.
Here's what I've got:
public class Assignment3
{
public static void main(String[] args)
{
int[] binary = { 1, 7, 4, 9, 10, 2, 6, 12, 3, 8, 5 };
ModifiedBinaryInsertionSort(binary);
}
static int ModifiedBinarySearch(int[] theArray, int theElement)
{
int leftIndex = 0;
int rightIndex = theArray.length - 1;
int middleIndex = 0;
while(leftIndex <= rightIndex)
{
middleIndex = (leftIndex + rightIndex) / 2;
if (theElement == theArray[middleIndex])
return middleIndex;
else if (theElement < theArray[middleIndex])
rightIndex = middleIndex - 1;
else
leftIndex = middleIndex + 1;
}
return middleIndex - 1;
}
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int i = 0;
int[] returnArray = new int[theArray.length + 1];
for(i = 0; i < theArray.length; i++)
{
returnArray[ModifiedBinarySearch(theArray, theArray[i])] = theArray[i];
}
for(i = 0; i < theArray.length; i++)
{
System.out.print(returnArray[i] + " ");
}
}
}
The return value I get for this when I run it is 1 0 0 0 0 2 0 0 3 5 12. Any suggestions?
UPDATE: updated ModifiedBinaryInsertionSort
static void ModifiedBinaryInsertionSort(int[] theArray)
{
int index = 0;
int element = 0;
int[] returnArray = new int[theArray.length];
for (int i = 1; i < theArray.lenght - 1; i++)
{
element = theArray[i];
index = ModifiedBinarySearch(theArray, 0, i, element);
returnArray[i] = element;
while (index >= 0 && theArray[index] > element)
{
theArray[index + 1] = theArray[index];
index = index - 1;
}
returnArray[index + 1] = element;
}
}
Here is my method to sort an array of integers using binary search.
It modifies the array that is passed as argument.
public static void binaryInsertionSort(int[] a) {
if (a.length < 2)
return;
for (int i = 1; i < a.length; i++) {
int lowIndex = 0;
int highIndex = i;
int b = a[i];
//while loop for binary search
while(lowIndex < highIndex) {
int middle = lowIndex + (highIndex - lowIndex)/2; //avoid int overflow
if (b >= a[middle]) {
lowIndex = middle+1;
}
else {
highIndex = middle;
}
}
//replace elements of array
System.arraycopy(a, lowIndex, a, lowIndex+1, i-lowIndex);
a[lowIndex] = b;
}
}
How an insertion sort works is, it creates a new empty array B and, for each element in the unsorted array A, it binary searches into the section of B that has been built so far (From left to right), shifts all elements to the right of the location in B it choose one right and inserts the element in. So you are building up an at-all-times sorted array in B until it is the full size of B and contains everything in A.
Two things:
One, the binary search should be able to take an int startOfArray and an int endOfArray, and it will only binary search between those two points. This allows you to make it consider only the part of array B that is actually the sorted array.
Two, before inserting, you must move all elements one to the right before inserting into the gap you've made.
I realize this is old, but the answer to the question is that, perhaps a little unintuitively, "Middleindex - 1" will not be your insertion index in all cases.
If you run through a few cases on paper the problem should become apparent.
I have an extension method that solves this problem. To apply it to your situation, you would iterate through the existing list, inserting into an empty starting list.
public static void BinaryInsert<TItem, TKey>(this IList<TItem> list, TItem item, Func<TItem, TKey> sortfFunc)
where TKey : IComparable
{
if (list == null)
throw new ArgumentNullException("list");
int min = 0;
int max = list.Count - 1;
int index = 0;
TKey insertKey = sortfFunc(item);
while (min <= max)
{
index = (max + min) >> 1;
TItem value = list[index];
TKey compKey = sortfFunc(value);
int result = compKey.CompareTo(insertKey);
if (result == 0)
break;
if (result > 0)
max = index - 1;
else
min = index + 1;
}
if (index <= 0)
index = 0;
else if (index >= list.Count)
index = list.Count;
else
if (sortfFunc(list[index]).CompareTo(insertKey) < 0)
++index;
list.Insert(index, item);
}
Dude, I think you have some serious problem with your code. Unfortunately, you are missing the fruit (logic) of this algorithm. Your divine goal here is to get the index first, insertion is a cake walk, but index needs some sweat. Please don't see this algorithm unless you gave your best and desperate for it. Never give up, you already know the logic, your goal is to find it in you. Please let me know for any mistakes, discrepancies etc. Happy coding!!
public class Insertion {
private int[] a;
int n;
int c;
public Insertion()
{
a = new int[10];
n=0;
}
int find(int key)
{
int lowerbound = 0;
int upperbound = n-1;
while(true)
{
c = (lowerbound + upperbound)/2;
if(n==0)
return 0;
if(lowerbound>=upperbound)
{
if(a[c]<key)
return c++;
else
return c;
}
if(a[c]>key && a[c-1]<key)
return c;
else if (a[c]<key && a[c+1]>key)
return c++;
else
{
if(a[c]>key)
upperbound = c-1;
else
lowerbound = c+1;
}
}
}
void insert(int key)
{
find(key);
for(int k=n;k>c;k--)
{
a[k]=a[k-1];
}
a[c]=key;
n++;
}
void display()
{
for(int i=0;i<10;i++)
{
System.out.println(a[i]);
}
}
public static void main(String[] args)
{
Insertion i=new Insertion();
i.insert(56);
i.insert(1);
i.insert(78);
i.insert(3);
i.insert(4);
i.insert(200);
i.insert(6);
i.insert(7);
i.insert(1000);
i.insert(9);
i.display();
}
}