「CS61B」Note(7) Lab12 Merge and Quick Sort
In this lab, the task is to implement two of the sorting algorithms including Merge and Quick Sort. The requirements are at this link.
Merge Sort
makeSingleItemQueues
(I didn’t use this method in mergeSort):
For example, if you called makeSingleItemQueues
on the Queue ("Alice" > "Vanessa" > "Ethan")
, it should return (("Alice") > ("Vanessa") > ("Ethan"))
.
/** Returns a queue of queues that each contain one item from items. */
private static <Item extends Comparable> Queue<Queue<Item>>
makeSingleItemQueues(Queue<Item> items) {
// Your code here!
Queue<Queue<Item>> singleItemQueues = new Queue<Queue<Item>>();
for (Item i : items) {
Queue<Item> thisSingleItemQueue = new Queue<Item>();
thisSingleItemQueue.enqueue(i);
singleItemQueues.enqueue(thisSingleItemQueue);
}
return singleItemQueues;
}
mergeSortedQueues
:
/**
* Returns a new queue that contains the items in q1 and q2 in sorted order.
*
* This method should take time linear in the total number of items in q1 and q2. After
* running this method, q1 and q2 will be empty, and all of their items will be in the
* returned queue.
*
* @param q1 A Queue in sorted order from least to greatest.
* @param q2 A Queue in sorted order from least to greatest.
* @return A Queue containing all of the q1 and q2 in sorted order, from least to
* greatest.
*
*/
private static <Item extends Comparable> Queue<Item> mergeSortedQueues(
Queue<Item> q1, Queue<Item> q2) {
// Your code here!
if (q1.isEmpty()) {
return q2;
}
if (q2.isEmpty()) {
return q1;
}
Queue<Item> result = new Queue<Item>();
while (true) {
if (q1.peek().compareTo(q2.peek()) < 0) {
result.enqueue(q1.dequeue());
} else {
result.enqueue(q2.dequeue());
}
if (q1.isEmpty()) {
for (Item i : q2) {
result.enqueue(i);
}
break;
}
if (q2.isEmpty()) {
for (Item j : q1) {
result.enqueue(j);
}
break;
}
}
return result;
}
mergeSort
:
public static <Item extends Comparable> Queue<Item> mergeSort(
Queue<Item> items) {
// Your code here!
// Create a deep copy of items Queue to avoid changing the original one
Queue<Item> itemsCopy = new Queue<Item>();
for (Item j : items) {
itemsCopy.enqueue(j);
}
if (itemsCopy.size() == 1 || itemsCopy.isEmpty()) { return itemsCopy; }
if (itemsCopy.size() == 2) {
Item item1 = itemsCopy.dequeue();
if (item1.compareTo(itemsCopy.peek()) < 0) {
Item item2 = itemsCopy.dequeue();
itemsCopy.enqueue(item1);
itemsCopy.enqueue(item2);
} else {
itemsCopy.enqueue(item1);
}
return itemsCopy;
}
Queue<Item> firstHalf = new Queue<Item>();
int itemsSize = itemsCopy.size();
for (int i = 0; i <= itemsSize / 2 - 1; i++) {
firstHalf.enqueue(itemsCopy.dequeue());
}
return mergeSortedQueues(mergeSort(firstHalf), mergeSort(itemsCopy));
}
Quick Sort
partition()
:
/**
* Partitions the given unsorted queue by pivoting on the given item.
*
* @param unsorted A Queue of unsorted items
* @param pivot The item to pivot on
* @param less An empty Queue. When the function completes, this queue will contain
* all of the items in unsorted that are less than the given pivot.
* @param equal An empty Queue. When the function completes, this queue will contain
* all of the items in unsorted that are equal to the given pivot.
* @param greater An empty Queue. When the function completes, this queue will contain
* all of the items in unsorted that are greater than the given pivot.
*/
private static <Item extends Comparable> void partition(
Queue<Item> unsorted, Item pivot,
Queue<Item> less, Queue<Item> equal, Queue<Item> greater) {
// Your code here!
Queue<Item> unsortedCopy = new Queue<Item>();
for (Item j : unsorted) {
unsortedCopy.enqueue(j);
}
while(!unsortedCopy.isEmpty()) {
if (unsortedCopy.peek().compareTo(pivot) == 0) {
equal.enqueue(unsortedCopy.dequeue());
} else if (unsortedCopy.peek().compareTo(pivot) < 0) {
less.enqueue(unsortedCopy.dequeue());
} else {
greater.enqueue(unsortedCopy.dequeue());
}
}
}
quickSort
:
/** Returns a Queue that contains the given items sorted from least to greatest. */
public static <Item extends Comparable> Queue<Item> quickSort(
Queue<Item> items) {
// Your code here!
if (items.size() == 1 || items.isEmpty()) { return items; }
if (items.size() == 2) {
// Create a deep copy of items Queue to avoid changing the original one
Queue<Item> itemsCopy = new Queue<Item>();
for (Item j : items) {
itemsCopy.enqueue(j);
}
Item item1 = itemsCopy.dequeue();
if (item1.compareTo(itemsCopy.peek()) < 0) {
Item item2 = itemsCopy.dequeue();
itemsCopy.enqueue(item1);
itemsCopy.enqueue(item2);
} else {
itemsCopy.enqueue(item1);
}
return itemsCopy;
}
Queue<Item> less = new Queue<>();
Queue<Item> equal = new Queue<>();
Queue<Item> greater = new Queue<>();
partition(items, getRandomItem(items), less, equal, greater);
return catenate(catenate(quickSort(less), equal), quickSort(greater));
}
Notice: In the mergeSort()
and quickSort()
, if you directly use the input Queue items
and do dequeue()
operations, the original Queue will be changed, which is somenthing we don’t want to happen. This was mentioned in a previous lab. So I made a deep copy of items
(copy every item to a new Queue called itemsCopy
) to avoid this. The influence of this is shown in the results below.
Queue<Item> itemsCopy = new Queue<Item>();
for (Item j : items) {
itemsCopy.enqueue(j);
}
Output directly using the input Queue items
: Output using a deep copy of the input Queue items
: