kruti-working-branch #14

Closed
kruti wants to merge 15 commits from kruti/Princeton1:kruti-working-branch into main
11 changed files with 275 additions and 322 deletions

View File

@ -6,23 +6,11 @@ import javax.annotation.Nonnull;
public class ArrayQueue<E> extends Queue<E>{
// insertion from tail, removal from head
public static final int DEFAULT_CAPACITY = 10;
private int capacity;
private int tail;
private int head;
private E[] queueArray = (E[]) new Object[5];
private int startPtr;
private int endPtr;
private int size;
private E[] arr;
public ArrayQueue(){
this(DEFAULT_CAPACITY);
}
public ArrayQueue(int capacity){
this.capacity = capacity;
arr = (E[]) new Object[this.capacity];
size = 0;
}
private int queueArrayLength = queueArray.length;
@Override
public boolean isEmpty() {
@ -31,49 +19,25 @@ public class ArrayQueue<E> extends Queue<E>{
@Override
public E dequeue() {
if(isEmpty())
if(isEmpty()){
return null;
else{
E element = arr[head];
// Garbage collection
arr[head] = null;
head = (head+1)%capacity;
size = size - 1;
if(capacity >= 40 && size < capacity/4){
capacity = capacity/2;
resize(capacity, capacity*2);
}
return element;
}
E currentValue = queueArray[startPtr % queueArrayLength];
queueArray[startPtr++ % queueArrayLength] = null;
size--;
if(size() < queueArrayLength/4){
changeArraySize(queueArrayLength/2);
}
return currentValue;
}
@Override
public void enqueue(E element) {
// We plan capacity expansion if needed
if (size == capacity){
capacity = capacity * 2;
resize(capacity, capacity/2);
queueArray[endPtr++ % queueArrayLength] = element;
size++;
if(size == queueArrayLength){
changeArraySize(queueArrayLength*2);
}
arr[tail] = element;
tail = (tail + 1) % capacity;
++size;
}
// When resize takes place always the original array is full, so copy the complete array as is
private void resize(int capacity, int oldCapacity) {
E[] resizedArr = (E[]) new Object[capacity];
for(int i = 0; i < size; i++) {
resizedArr[i] = arr[head];
// halving because capacity has now doubled
arr[head] = null;
head = (head + 1) % oldCapacity;
}
arr = resizedArr;
// When resizing takes place, we bring the head to 0 and the tail to size
// tail is where new inserts will be made and head will be where elements will be removed
tail = size;
head = 0;
}
@Override
@ -81,24 +45,37 @@ public class ArrayQueue<E> extends Queue<E>{
return size;
}
@Override
@Nonnull
public Iterator<E> iterator() {
return new Iterator<E>() {
int counter = size;
int pointer = head;
@Override
public boolean hasNext() {
return counter != 0;
}
private void changeArraySize(int targetSize){
E[] tempArray = queueArray;
int oldArraySize = tempArray.length;
queueArray = (E[]) new Object[targetSize];
int j = 0;
@Override
public E next() {
E element = arr[pointer];
pointer = (pointer + 1)% capacity;
--counter;
return element;
}
};
for(int i=0; i<size; i++)
hitanshu marked this conversation as resolved Outdated

If the old queue is wrapped, then endPtr will be less than startPtr

If the old queue is wrapped, then endPtr will be less than startPtr
queueArray[j++]=tempArray[(startPtr+i)%oldArraySize];
endPtr = size();
startPtr = 0;
queueArrayLength = queueArray.length;
}
@Nonnull
@Override
public Iterator<E> iterator() {
return new QueueArrayIterator();
}
private class QueueArrayIterator implements Iterator<E>{
private int iteratorIndex = startPtr;
@Override
public boolean hasNext() {
return iteratorIndex % queueArrayLength < endPtr % queueArrayLength;
}
@Override
public E next() {
hitanshu marked this conversation as resolved
Review

Iterator does not account for wrapping

Iterator does not account for wrapping
return queueArray[iteratorIndex++ % queueArrayLength];
}
}
}

View File

@ -6,93 +6,68 @@ import javax.annotation.Nonnull;
// Creating a generic stack of type E
public class ArrayStack<E> extends Stack<E> {
// Capacity and size are two variables, capacity determines total capacity of array, capacity defaults at 10
// every time size == capacity, capacity = 2 * capacity
private static final int DEFAULT_CAPACITY = 10;
private int capacity;
private int size;
private E[] arr;
public ArrayStack(int capacity){
this.capacity = capacity;
arr = (E[]) new Object[this.capacity];
}
// Constructor chaining, default constructor will call parametrized constructor with default initial capacity 10
public ArrayStack(){
this(DEFAULT_CAPACITY);
}
E[] stackArray = (E[]) new Object[1];
private int index = 0;
private int arrayLength = stackArray.length;
@Override
public boolean isEmpty() {
return size == 0;
return index == 0;
}
private void changeCapacity(int newCapacity){
E[] resizedArr = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++)
resizedArr[i] = arr[i];
arr = resizedArr;
}
private void incrementSize(){
if (size == capacity){
capacity = 2 * capacity;
changeCapacity(capacity);
}
}
// Push always happens at the end of the stack
// Say the size of the stack is 1, new element gets inserted at 1
@Override
public void push(E element) {
// Lazy approach, we assume size to always be lesser than capacity
incrementSize();
arr[size++] = element;
if(index == arrayLength){
changeArraySize(arrayLength*2);
}
stackArray[index] = element;
index++;
}
@Override
public E pop() {
if (isEmpty())
if(index == 0){
return null;
else{
E e = arr[--size];
arr[size] = null;
checkResize();
return e;
}
}
private void checkResize() {
if (size < capacity / 4 && capacity >= 20){
capacity = capacity / 2;
changeCapacity(capacity);
index--;
if(index < arrayLength/4){
changeArraySize(arrayLength/2);
}
E temp = stackArray[index];
stackArray[index] = null;
return temp;
}
@Override
public int size() {
return size;
return index;
}
@Override
@Nonnull
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
return new StackIterator();
}
int current = 0;
private void changeArraySize(int intendedSize){
E[] tempArray = stackArray;
int oldArraySize = stackArray.length;
stackArray = (E[]) new Object[intendedSize];
arrayLength = stackArray.length;
System.arraycopy(tempArray, 0, stackArray, 0, Math.min(oldArraySize, arrayLength));
}
@Override
public boolean hasNext() {
return current != size;
}
private class StackIterator implements Iterator<E>{
private int iteratorIndex = 0;
@Override
public E next() {
E element = arr[current];
current = current + 1;
return element;
}
};
@Override
public boolean hasNext() {
return stackArray[iteratorIndex] != null;
}
@Override
public E next() {
return stackArray[iteratorIndex++];
}
}
}

View File

@ -5,70 +5,76 @@ import java.util.Iterator;
public class LinkedQueue<E> extends Queue<E>{
Node head;
Node tail;
int size;
Node<E> start = null;
Node<E> end = null;
private class Node{
E value;
Node next;
static private class Node<E>{
E data;
Node<E> next;
Node(E value){
this.value = value;
private Node(E element){
data=element;
next=null;
}
}
@Override
public boolean isEmpty() {
return size==0;
return start == null;
}
@Override
public E dequeue() {
if(isEmpty())
return null;
E element = head.value;
// Only a single element is present
if (head == tail){
tail = null;
}
head = head.next;
--size;
return element;
E currentValue = start.data;
start = start.next;
if(isEmpty())
end = null;
hitanshu marked this conversation as resolved Outdated

Case where only 1 element in queue, end pointer is dangling.

Case where only 1 element in queue, end pointer is dangling.
return currentValue;
}
@Override
public void enqueue(E element) {
Node newNode = new Node(element);
Node<E> new_node = new Node<E>(element);
if(isEmpty())
head = newNode;
start = new_node;
else
tail.next = newNode;
tail = newNode;
++size;
end.next = new_node;
end = new_node;
}
@Override
public int size() {
int size = 0;
Node<E> sizePtr = start;
while (sizePtr != null) {
sizePtr = sizePtr.next;
size++;
}
return size;
}
@Override
@Nonnull
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node current = head;
@Override
public boolean hasNext() {
return current != null;
}
return new LinkedQueueIterator();
}
@Override
public E next() {
E element = current.value;
current = current.next;
return element;
}
};
private class LinkedQueueIterator implements Iterator<E>{
Node<E> traversePtr = start;
@Override
public boolean hasNext() {
return traversePtr != null;
}
@Override
public E next() {
E currentValue = traversePtr.data;
traversePtr = traversePtr.next;
return currentValue;
}
}
}

View File

@ -1,72 +1,71 @@
package com.hithomelabs.princeton1.module4;
import javax.annotation.Nonnull;
import java.util.Iterator;
// Creating a concrete linked Implementation of Stack
public class LinkedStack<E> extends Stack<E>{
// No need for an explicit constructor as size will be initialized to 0 and root to null
private int size;
private Node first;
static class Node<E>{
E data;
Node<E> next;
// By default instance variables are package private
private class Node{
E value;
Node next;
Node(E data) {
this.data = data;
this.next = null;
}
}
// Will return true if size is 0
Node<E> head = null;
hitanshu marked this conversation as resolved
Review

Why do you need two pointers, both insertion and deletion happen at head

Why do you need two pointers, both insertion and deletion happen at head
int stackLength = 0;
@Override
public boolean isEmpty() {
return (this.size == 0);
return head == null;
}
// Adds an element to the start of a linked list
@Override
public void push(E element) {
Node newNode = new Node();
newNode.value = element;
newNode.next = first;
first = newNode;
this.size = this.size + 1;
Node<E> new_node = new Node<E>(element);
new_node.next = head;
head = new_node;
stackLength++;
}
@Override
public E pop() {
if (this.isEmpty())
if(stackLength == 0)
return null;
else{
Node toBePopped = first;
first = first.next;
this.size = this.size - 1;
return toBePopped.value;
}
E currentValue = head.data;
head = head.next;
return currentValue;
}
@Override
public int size() {
return this.size;
return stackLength;
}
@Nonnull
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
// Internal classes can access outer objects
Node current = first;
@Override
public boolean hasNext() {
return current != null;
}
@Override
public E next() {
E element = current.value;
current = current.next;
return element;
}
};
return new LinkedlistIterator();
}
private class LinkedlistIterator implements Iterator<E>{
Node<E> iteratorPtr = head;
@Override
public boolean hasNext() {
return iteratorPtr.next != null;
}
@Override
public E next() {
E currentValue = iteratorPtr.data;
iteratorPtr = iteratorPtr.next;
return currentValue;
}
}
}

View File

@ -4,12 +4,14 @@ public abstract class AbstractCustomSorts<E> {
public abstract void sort(E[] arr);
// TODO: Implement this method
public void exch(E[] arr, int j, int i) {
E temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// TODO: Implement this method
public boolean less(Comparable<E> e1, E e2) {
return e1.compareTo(e2) < 0;
}

View File

@ -1,23 +1,15 @@
package com.hithomelabs.princeton1.module5;
public class Insertion<E> extends AbstractCustomSorts<E> {
public void sort(E[] arr){
if (arr == null) return;
else{
int N = arr.length;
// * * swap arr[i] with each element greater to it's left
for (int i = 1; i < N; i++){
int j = i;
while(j >= 1 && less((Comparable<E>)arr[j], arr[j-1])){
exch(arr, j, j-1);
j = j-1;
}
@Override
public void sort(E[] arr) {
for(int i=1; i<arr.length; i++){
int k = i;
for(int j=i-1; j>=0 && less((Comparable<E>) arr[k], arr[j]); j--){
exch(arr, k, j);
k = j;
}
}
}
}
}

View File

@ -1,23 +1,20 @@
package com.hithomelabs.princeton1.module5;
/*
* * Selection sort "selects" the smallest element and swaps it with arr[0] of the array
* * Then proceeds to do the same swapping arr[i] with arr[i:arr.length-1]
*/
public class Selection<E> extends AbstractCustomSorts<E>{
/*
* * Selection sort "selects" the smallest element and swaps it with arr[0] of the array
* * Then proceeds to do the same swapping arr[i] with arr[i:arr.length-1]
*/
public void sort(E[] arr){
if (arr == null) return;
Comparable<E>[] arr1 = (Comparable<E>[]) arr;
for(int i = 0; i < arr1.length - 1; i++){
@Override
public void sort(E[] arr) {
for (int i = 0; i < arr.length; i++) {
int minIndex = i;
for(int j = i+1; j < arr.length; j ++){
if (less((Comparable<E>) arr[j], arr[minIndex])) minIndex = j;
for(int j = i+1; j < arr.length; j++){
if(less((Comparable<E>) arr[j], arr[minIndex]))
minIndex = j;
}
exch(arr, i, minIndex);
}
}
}

View File

@ -25,32 +25,37 @@ public class Shell<E> extends AbstractCustomSorts<E> {
@Override
public void sort(E[] arr) {
MetaData metaData = new MetaData();
int N = arr.length;
int h = 1;
// * * Calculates the largest value of h greater than n
while (3 * h + 1 < N) {
h = 3 * h + 1;
while(3*h + 1 < arr.length){
h = 3*h + 1;
}
while (h >= 1) {
h = hsort(arr, h, metaData);
h = h / 3;
while(h>=1){
hsort(arr, h, metaData);
h= h/3;
}
// for(int i=arr.length/10; i>=0; i--){
// hsort(arr, 3*i+1, metaData);
// }
System.out.println("Array sorted (shell sort) with " + metaData.compares + " compares and " + metaData.swaps + " swaps");
}
private int hsort(E[] arr, int h, MetaData metadata) {
int N = arr.length;
for(int i = h; i < N; i++){
int j = i;
++metadata.compares;
while(j >= h && less((Comparable<E>) arr[j], arr[j-h])){
++metadata.swaps;
exch(arr, j, j-h);
j = j - h;
++metadata.compares;
private void hsort(E[] arr, int h, MetaData metadata) {
for(int i=h; i<arr.length; i=i+1){
int k = i;
for(int j=i-h; j>=0; j=j-h){
metadata.compares++;
if(less((Comparable<E>) arr[k], arr[j])){
exch(arr, k, j);
k = j;
metadata.swaps++;
}
else{
break;
}
}
}
return h;
}
/*
* Sample implementation of insertion sort as h-sort of h = 1
@ -59,7 +64,7 @@ public class Shell<E> extends AbstractCustomSorts<E> {
public void insertionSort(E[] arr){
MetaData metaData = new MetaData();
int h = 1;
h = hsort(arr, h, metaData);
hsort(arr, h, metaData);
System.out.println("Array sorted (insertion sort) with " + metaData.compares + " compares and " + metaData.swaps + " swaps");
}

View File

@ -5,40 +5,40 @@ import com.hithomelabs.princeton1.module5.AbstractCustomSorts;
import java.util.Arrays;
public class Merge<E> extends AbstractCustomSorts<E> {
private E[] auxArr;
@Override
public void sort(E[] arr) {
int N = arr.length;
// * * aux is a helper array required for merge
E[] aux = Arrays.copyOf(arr, N);
mergesort(arr, aux, 0, N-1);
auxArr = (E[]) new Object[arr.length];
merge_sort(arr, 0, arr.length-1);
}
private void mergesort(E[] arr, E[] aux, int lo, int hi) {
private void merge_sort(E[] arr, int low_index, int high_index){
if(high_index - low_index > 0) {
int mid_index = low_index + (high_index - low_index)/2;
merge_sort(arr, low_index, mid_index);
merge_sort(arr, mid_index + 1, high_index);
hitanshu marked this conversation as resolved Outdated

Making a new aux arry with each recursive call is expensive

Making a new aux arry with each recursive call is expensive
if (hi <= lo) return;
int mid = lo + (hi - lo)/2;
mergesort(arr, aux, lo, mid);
mergesort(arr, aux, mid+1, hi);
merge(arr, aux, lo, mid, hi);
// Copy array
for(int i=low_index; i<= high_index; i++)
auxArr[i] = arr[i];
}
private void merge(E[] arr, E[] aux, int lo, int mid, int hi) {
// * * creating backup of original array
for (int i = lo; i <= hi; i++)
aux[i] = arr[i];
int i = lo;
int j = mid+1;
for (int k = lo; k <= hi; k++){
// * If i has already reached mid, no need to compare we insert at pointer k
if(i > mid) arr[k] = aux[j++];
else if(j > hi) arr[k] = aux[i++];
else if(less((Comparable<E>) aux[i], aux[j])) arr[k] = aux[i++];
else arr[k] = aux[j++];
// Sort
int low_index_ptr = low_index;
int mid_index_ptr = low_index + (high_index - low_index)/2;
int high_index_ptr = mid_index_ptr + 1;
if(!less((Comparable<E>) auxArr[mid_index_ptr], auxArr[high_index_ptr])) {
for (int i = low_index; i <= high_index; i++) {
if (low_index_ptr > mid_index_ptr) {
arr[i] = auxArr[high_index_ptr++];
} else if (high_index_ptr > high_index)
arr[i] = auxArr[low_index_ptr++];
else if (less((Comparable<E>) auxArr[low_index_ptr], auxArr[high_index_ptr]))
arr[i] = auxArr[low_index_ptr++];
else
arr[i] = auxArr[high_index_ptr++];
}
}
}
}
}

View File

@ -6,49 +6,45 @@ import com.hithomelabs.princeton1.module5.AbstractCustomSorts;
public class Quick<E> extends AbstractCustomSorts<E> {
@Override
public void sort(E[] arr) {
int N = arr.length;
quickSort(arr, 0, N - 1);
randomShuffle(arr);
partition(arr, 0, arr.length-1);
}
public void altSort(E[] arr) {
int N = arr.length;
altQuickSort(arr, 0, N-1);
private void randomShuffle(E[] arr){
int array_len = arr.length;
for(int i=0; i< array_len; i++){
int random_index = (int)(Math.random()*array_len);
exch(arr, i, random_index);
}
}
private void altQuickSort(E[] arr, int lo, int hi) {
if (lo >= hi) return;
int i = lo + 1;
int j = i;
while(j <= hi){
if(less((Comparable<E>) arr[j], arr[lo])){
exch(arr, i, j);
private void partition(E[] arr, int low, int high){
if(low >= high)
return;
int mid = sort(arr, low, high);
partition(arr, low, mid-1);
partition(arr, mid + 1, high);
}
private int sort(E[] arr, int low, int high){
int i = low+1;
int j = high;
while (true){
// Find the i index greater than 1st element
while (i<=high && !less((Comparable<E>) arr[low], arr[i]))
i++;
}
j++;
// Find the j index less than 1st element
while (less((Comparable<E>) arr[low], arr[j]) && j > low)
j--;
// Break if indexes are crossed
if(j < i)
break;
// Swap index values of i & j
if(less((Comparable<E>) arr[j], arr[i]))
exch(arr, i, j);
}
exch(arr, i-1, lo);
altQuickSort(arr, lo, i-2);
altQuickSort(arr, i, hi);
}
private void quickSort(E[] arr, int lo, int hi) {
if (lo >= hi) return;
int i = lo;
int j = hi+1;
while(true){
while(less((Comparable<E>) arr[++i], arr[lo])){
if(i == hi) break;
}
while(!less((Comparable<E>) arr[--j], arr[lo])){
if (j == lo ) break;
}
if(j<=i) break;
exch(arr, i , j);
}
exch(arr, j, lo);
quickSort(arr, lo, j-1);
quickSort(arr, j+1, hi);
// Swap 1st element to it's correct position
exch(arr, low, j);
return j;
}
}

View File

@ -33,6 +33,8 @@ class QuickTest {
Assertions.assertArrayEquals(sorted, arr);
}
// * * Optional test for alternate sort implmentation
/*
@Test
@DisplayName("testing Quick sort default implementation")
public void testAltSort(){
@ -45,6 +47,8 @@ class QuickTest {
Apple[] sorted = apples.toArray(new Apple[apples.size()]);
Assertions.assertArrayEquals(sorted, arr);
}
*/
@AfterEach