package edu.lmu.cs.sorting;
import java.util.Random;
/**
* A little utility class with a bozosort method for integer arrays.
* A main method is also thrown in that prints a little table showing
* the average number of swaps required to sort arrays of various
* sizes.
*/
public class Bozosorter {
/**
* Returns whether the given array is sorted.
*/
private static boolean isSorted(int[] a) {
for (int i = 1; i < a.length; i++) {
if (a[i-1] > a[i]) {
return false;
}
}
return true;
}
/**
* Does a bozosort, returning the number of swaps required to sort.
*/
public static int sort(int[] a, Random random) {
int swaps = 0;
while (!isSorted(a)) {
int i = random.nextInt(a.length);
int j = random.nextInt(a.length);
if (i != j) {
int x = a[i];
int y = a[j];
a[i] = y;
a[j] = x;
swaps++;
}
}
return swaps;
}
/**
* Returns a randomly filled in integer array for a given size.
*/
private static int[] randomArray(int size, Random random) {
int[] a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = random.nextInt();
}
return a;
}
public static void main(String[] args) {
Random random = new Random();
// Try 50 sorts at each size, recording average # of swaps
int iterations = 50;
System.out.println("Size Avg # of swaps");
System.out.println("----------------------");
for (int trialSize = 1; trialSize < 15; trialSize++) {
int totalSwaps = 0;
for (int k = 0; k < iterations; k++) {
totalSwaps += sort(randomArray(trialSize, random), random);
}
System.out.printf("%2d%20.2f\n", trialSize,
totalSwaps / (double)iterations);
}
}
}
Here is one particular output:
Size Avg # of swaps ---------------------- 1 0.00 2 0.48 3 4.20 4 21.90 5 126.86 6 828.60 7 5532.56 8 49353.32 9 473626.84 10 3389858.32
Another run gave these averages
Size Avg # of swaps ---------------------- 1 0.00 2 0.58 3 5.06 4 24.10 5 107.74 6 818.54 7 5133.62 8 39475.00 9 292153.18 10 4204461.32
package edu.lmu.cs.collections;
import java.util.ArrayList;
import java.util.NoSuchElementException;
/**
* A heap-based priority queue implementation.
*/
public class PriorityQueue<E extends Comparable<E>> {
private ArrayList<E> heap = new ArrayList<E>();
/**
* Adds an item to the queue.
*/
public void add(E item) {
heap.add(item);
siftUp(size() - 1);
}
/**
* Remove the highest priority item from the queue.
*
* @throws NoSuchElementException if the queue is empty
*/
public E remove() {
if (isEmpty()) {
throw new NoSuchElementException();
}
E item = heap.get(0);
if (size() == 1) {
heap.remove(0);
} else {
heap.set(0, heap.remove(size() - 1));
siftDown(0);
}
return item;
}
/**
* Returns the highest priority element without removing it.
*
* @throws NoSuchElementException if the queue is empty
*/
public E peek() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return heap.get(0);
}
/**
* Returns the number of items in the queue.
*/
public int size() {
return heap.size();
}
/**
* Returns whether the queue is empty.
*/
public boolean isEmpty() {
return heap.isEmpty();
}
// Sifts the item at position j up as far as it can go.
private void siftUp(int j) {
int i = (j - 1) / 2;
if (i < 0) return;
E parent = heap.get(i);
E child = heap.get(j);
if (parent.compareTo(child) <= 0) return;
heap.set(i, child);
heap.set(j, parent);
siftUp(i);
}
// Sifts the item at position i down as far as it can go.
private void siftDown(int i) {
int j = i * 2 + 1;
if (j >= size()) return;
E parent = heap.get(i);
E child = heap.get(j);
if (j + 1 < size()) {
E rightChild = heap.get(j + 1);
if (rightChild.compareTo(child) < 0) {
child = rightChild;
j++;
}
}
if (parent.compareTo(child) <= 0) return;
heap.set(i, child);
heap.set(j, parent);
siftDown(j);
}
}
And a test
package edu.lmu.cs.collections;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import org.junit.Test;
/**
* PriorityQueue unit tests.
*/
public class PriorityQueueTest {
@Test
public void testConstructor() {
assertTrue(new PriorityQueue<Integer>().isEmpty());
assertEquals(new PriorityQueue<String>().size(), 0);
}
@Test
public void testSizeOne() {
PriorityQueue<Integer> q = new PriorityQueue<Integer>();
assertTrue(q.isEmpty());
q.add(1000);
assertTrue(q.size() == 1);
assertTrue(!q.isEmpty());
assertTrue(q.peek() == 1000);
q.remove();
assertTrue(q.isEmpty());
}
@Test
public void testBiggerQueues() {
PriorityQueue<Integer> q = new PriorityQueue<Integer>();
// Add 0..99, scrambled
List<Integer> a = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) a.add(i);
Collections.shuffle(a);
for (int x: a) q.add(x);
assertFalse(q.isEmpty());
assertEquals(q.size(), 100);
assertEquals((int)q.peek(), 0);
// Insert 100
q.add(100);
assertFalse(q.peek() == 100);
assertEquals(q.size(), 101);
// Insert and remove a highest priority element
q.add(-1);
assertEquals((int)q.peek(), -1);
assertEquals((int)q.remove(), -1);
// Remove 0..99
for (int i = 0; i < 100; i++) {
assertEquals((int)q.remove(), i);
}
// Remove 100
assertFalse(q.isEmpty());
assertTrue(q.remove() == 100);
assertTrue(q.isEmpty());
assertTrue(q.size() == 0);
}
/*
* Cannot peek into an empty queue.
*/
@Test(expected=NoSuchElementException.class)
public void testPeekException() {
new PriorityQueue<String>().peek();
}
/*
* Cannot remove from an empty queue.
*/
@Test(expected=NoSuchElementException.class)
public void testRemoveException() {
new PriorityQueue<String>().remove();
}
}
And a unit test for it:
package edu.lmu.cs.crypto;
/**
* An auto-key Vigenere cipher. During encryption, the input text is
* used for the key stream after the initial key is used up. During
* decryption, we get the key characters from the plaintext we are
* recovering.
*/
public class AutoKeyVigenere {
/**
* Encrypt the given plaintext with the given key.
*/
public static String encipher(String plaintext, String key) {
return encipher(plaintext, key, 1);
}
/**
* Decrypt the given ciphertext with the given key.
*/
public static String decipher(String ciphertext, String key) {
return encipher(ciphertext, key, -1);
}
private static String encipher(String text, String key, int multiplier) {
if ("".equals(key)) {
throw new IllegalArgumentException("Key cannot be empty");
}
StringBuilder builder = new StringBuilder();
int keyLength = key.length();
for (int i = 0, n = text.length(); i < n; i++) {
char k = i < keyLength ? key.charAt(i) :
multiplier == 1 ? text.charAt(i - keyLength) :
builder.charAt(i - keyLength);
builder.append((char)(k * multiplier + text.charAt(i)));
}
return builder.toString();
}
}
And a unit test for it:
package edu.lmu.cs.crypto;
import org.junit.Assert;
import org.junit.Test;
public class AutoKeyVigenereTest {
@Test
public void testRoundTrip() {
String[] messages = {
"Attack @T DaWN!",
"",
"fjh94h8\u3032\u412b2r98h923h",
"%"
};
String[] keys = {
"......11111111111111111111111111111..",
"\uffff,\uff73"
};
for (String message: messages) {
for (String key: keys) {
String cipherText = AutoKeyVigenere.encipher(message, key);
String recoveredText = AutoKeyVigenere.decipher(cipherText, key);
Assert.assertEquals(message, recoveredText);
}
}
}
@Test(expected=IllegalArgumentException.class)
public void testEmptyKey() {
AutoKeyVigenere.encipher("hello", "");
}
}