Inplace quick sort - java

Write a java program to sort a list of integers using ‘in place’ Quicksort algorithm.
Generate the list randomly every time using the java.util.Random class.
Allow the user to choose the size of the array. The program should display the result of sorting the array of that size using different pivot choices. In particular, try these 4 choices –
 First element as pivot
 Randomly choosing the pivot element
 Choosing the median of 3 randomly chosen elements as the pivot
 Median of first center and last element (book technique).
PLEASE dont give me the implementation because I would like to try on my own. I want to know what is inplace quick sort? How is it different from the regular quiksort. Is it regular quicksort. I am really confused. I would like someone to provide the pusedocode or explanation in plain english will help too.

Inplace sorting - it's when you operate on the original array, given to you from outside, as opposed to creating some new arrays and using them in any way. Inplace sorting takes O(1) space, as opposed to O(n)+ when using additional data structres
Example of inplace sort:
public static void simpleBubbleSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 1; j < arr.length; j++) {
if (arr[j - 1] > arr[j]) {
swap(arr, j - 1, j);
}
}
}
}
As opposed to Merge sort that creates arrays along the way, and by the end combines them and returns NOT the original (given to us) array, but an array containing the result.
public static int[] mergeSort(int[] arr) {
if (arr.length < 2) return arr;
int mid = arr.length / 2;
int[] left = new int[mid];
int[] right = new int[mid + arr.length % 2];
int j = 0;
for (int i = 0; i < arr.length; i++) {
if (i < mid) {
left[i] = arr[i];
} else {
right[j++] = arr[i];
}
}
// keeps going until there's 1 element in each array[]
return mergeReturn(mergeSort(left), mergeSort(right));
}
private static int[] mergeReturn(int[] leftArr, int[] rightArr) {
int leftPointer = 0, rightPointer = 0, combinedSize = leftArr.length + rightArr.length;
int[] merged = new int[combinedSize];
for (int i = 0; i < combinedSize; i++) {
if (leftPointer < leftArr.length && rightPointer < rightArr.length) {
if (leftArr[leftPointer] < rightArr[rightPointer]) {
merged[i] = leftArr[leftPointer++];
} else {
merged[i] = rightArr[rightPointer++];
}
} else if (leftPointer < leftArr.length) { // adding the last element
merged[i] = leftArr[leftPointer++];
} else {
merged[i] = rightArr[rightPointer++];
}
}
return merged;
}

Related

How to write a selectionSort method going in Descending order?

Hello there! At the moment, I am just a tad bit confused with my code. I'd like to move my array in descending order. This sounds very simple but for some reason I cannot wrap my head around this method. Currently, this is a selectionSort method I wrote that goes directly in ascending order. I'm not sure where to start when it comes to descending order.. as to how to reverse the equations, I usually end up overflowing since it's supposed to be using the original ".length" of the array.
Thank you very much for any help!
int[] arr = {5, 3, 2, 44, 1, 75, 23, 15};
private static void descendingSort (int[] arr) {
for ( int i = 0; i < arr.length - 1; i++) {
int smallestIndex = i;
for ( int j = i + 1; j < arr.length; j++) {
//searching for smallest...
//if statement declaring if arr is smaller than the index[0]
if (arr[j] < arr[smallestIndex]) {
//now it has changed to pickle because it has swapped. thx u
smallestIndex = j;
}
}
}
}
If you want to solve the problem fast, here's how you approach it.
Notice we just change a few lines.
Specifically ...
We still find the smallest element
We put it in the back and not the front
The iteration order in both loops is back-to-front and not front-to-back
An easier way to implement this would be to just sort the elements in ascending order and then just reverse the array.
void selectionSortDescending(int arr[])
{
int n = arr.length;
// Start by finding the smallest element to put in the very back
// One by one move boundary of unsorted subarray
for (int i = n-1; i >= 0; i--)
{
// Find the minimum element in unsorted array
int min_idx = i;
for (int j = i-1; j >= 0; j--)
if (arr[j] < arr[min_idx])
min_idx = j;
// Swap the found minimum element with the last element
int temp = arr[min_idx];
arr[min_idx] = arr[i];
arr[i] = temp;
}
}

is there a difference in time/space complexity between recursive and non-recursive merge sort algorithm?

I have implemented a merge sort algorithm using divide and conquer approach where an array is split into two sub arrays.
In my code i re-used insertion sort algorithm to sort the sub arrays in merge sort. Is this right approach or i have to use different sorting approach to sort the sub arrays in merge sort ?
As far as concerned with the understanding of merge sort algorithm, everything is clear but when coming to the implementation of merge sort, how does it happen to divide an array into n-sub arrays without using recursive strategy.
is recursive or non-recursive efficient way to implement merge sort ?
Below is my code snippet in github:
https://github.com/vamsikankipati/algorithms-in-java/blob/master/src/com/algorithms/sort/MergeSort.java
I have understood from implementation perspective that my code is wrong as i divided the array into only two sub arrays instead of n-sub arrays.
Any help needed to clearly understand merge sort in terms of algorithm implementation perspective.
Here is the code:
package com.algorithms.sort;
public class MergeSort {
public static int[] increasing(int[] arr) {
int[] result = new int[arr.length];
int q = arr.length / 2;
System.out.println("q: " + q);
int[] left = new int[q];
int[] right = new int[q];
for (int i = 0; i < q; i++) {
left[i] = arr[i];
}
int k = 0;
for (int j = q; j < arr.length; j++) {
right[k] = arr[j];
k += 1;
}
left = InsertionSort.increasing(left);
right = InsertionSort.increasing(right);
// Printing
for (int e : left) {
System.out.print(e);
}
System.out.println("\n");
for (int e : right) {
System.out.print(e);
}
System.out.println("\n");
int i = 0;
int j = 0;
int s = 0;
while ((i < left.length) && (j < right.length)) {
if (left[i] <= right[j]) {
result[s] = left[i];
i++;
} else {
result[s] = right[j];
j++;
}
s++;
}
while (i < left.length) {
result[s] = left[i];
i++;
s++;
}
while (j < right.length) {
result[s] = right[j];
j++;
s++;
}
return result;
}
/**
* Main method to test an example integer array
*/
public static void main(String[] args) {
int[] ar = { 18, 12, 11, 6, 55, 100 };
int[] res = increasing(ar);
for (int a : res) {
System.out.print(a + " ");
}
}
}
More important than optimisation, you must first achieve correctness. There is a bug in the increasing static method: if the size of the array argument is not even, the right subarray is allocated with an incorrect size: int[] right = new int[q]; should be
int[] right = new int[arr.length - q];
Furthermore, you should not try to split the array if it is too small.
Regarding optimisation, you should only fallback to InsertionSort() when the subarray size is below a threshold, somewhere between 16 and 128 elements. Careful benchmarking with different thresholds and a variety of distributions will help determine a good threshold for your system.
As currently implemented, your function has a time complexity of O(N2) because it defers to InsertionSort for all but the last merge phase. To reduce the complexity to O(N.log(N)), you must recurse on the subarrays until their size is below a fixed threshold.
Here is a modified version:
package com.algorithms.sort;
public class MergeSort {
public static int threshold = 32;
public static int[] increasing(int[] arr) {
if (arr.length <= threshold)
return InsertionSort.increasing(arr);
int len1 = arr.length / 2;
int[] left = new int[len1];
for (int i = 0; i < len1; i++) {
left[i] = arr[i];
}
int len2 = arr.length - len1;
int[] right = new int[len2];
for (int i = 0; i < len2; i++) {
right[i] = arr[i + len1];
}
left = increasing(left);
right = increasing(right);
int[] result = new int[len1 + len2];
int i = 0;
int j = 0;
int s = 0;
while (i < len1 && j < len2) {
if (left[i] <= right[j]) {
result[s] = left[i];
i++;
} else {
result[s] = right[j];
j++;
}
s++;
}
while (i < len1) {
result[s] = left[i];
i++;
s++;
}
while (j < len2) {
result[s] = right[j];
j++;
s++;
}
return result;
}
/**
* Main method to test an example integer array
*/
public static void main(String[] args) {
int[] ar = { 18, 12, 11, 6, 55, 100 };
int[] res = increasing(ar);
for (int a : res) {
System.out.print(a + " ");
}
}
}
Both time complexity is O( n log n).
About space complexity, the implementation may vary on your data structure choice.
in recursive
if you choose array:
space complexity: N log N
if you choose linked-list:
space complexity is O(1)
in iterative:
if you choose array:
space complexity: N
( based on your implementation it is O ( N log N) because you create a new sub-array in every dividing state,
to reduce it to O(n) you should use one extra array as size of the original one, and indexes)
if you choose linked-list:
space complexity is O(1)
As you can see linked-list is best for sorting.
Beyond that recursive may consume more memory than expected based on programming language because of function frame creation.
Source

How do I remove the item with the highest value in an unsorted array?

So right now I am trying to code a function that will remove the highest value in an unsorted array.
Currently the code looks like this:
#Override
public void remove() throws QueueUnderflowException {
if (isEmpty()) {
throw new QueueUnderflowException();
} else {
int priority = 0;
for (int i = 1; i < tailIndex; i++) {
while (i > 0 && ((PriorityItem<T>) storage[i - 1]).getPriority() < priority)
storage[i] = storage[i + 1];
i = i - 1;
}
/*int max = array.get(0);
for (int i = 1; i < array.length; i++) {
if (array.get(i) > max) {
max = array.get(i);
}*/
}
tailIndex = tailIndex - 1;
}
Here I have my attempt at this:
int priority = 0;
for (int i = 1; i < tailIndex; i++) {
while (i > 0 && ((PriorityItem<T>) storage[i - 1]).getPriority() < priority)
storage[i] = storage[i + 1];
i = i - 1;
The program runs no bother but still deletes the first item in the array instead of the highest number. This code was given my my college lecturer for a different solution but unfortunately it doesn't work here.
Would this solution work with enough altercations? Or is there another solution I should try?
Thanks.
The code snippet in the question can be updated to below code, while keeping the same data structure i.e. queue and this updated code has 3 steps - finding the index of largest element, shifting the elements to overwrite the largest element and finally set the tailIndex to one less i.e. decrease the size of the queue.
#Override
public void remove() throws QueueUnderflowException {
if (isEmpty()) {
throw new QueueUnderflowException();
} else {
int priority = 0;
int largeIndex = 0;
for (int i = 0; i < tailIndex; i++) {
if (((PriorityItem<T>) storage[i]).getPriority() > priority) {
priority = ((PriorityItem<T>) storage[i]).getPriority();
largeIndex = i ;
}
}
for(int i = largeIndex; i < (tailIndex - 1) ; i++)
storage[i] = storage[i + 1];
}
tailIndex = tailIndex - 1;
}
Hope it helps.
Step 1
Find the highest index.
int[] array;
int highIndex = 0;
for (int i = 1; i < highIndex.size(); i++)
if (array[highIndex] < array[highIndex])
highIndex = i;
Step 2
Create new array with new int[array.size() - 1]
Step 3
Move all values of array into new array (except the highest one).
My hint: When its possible, then use a List. It reduces your complexity.
You can find the largest Number and it's index then copy each number to its preceding number. After that, you have two options:
Either add Length - 1 each time you iterate the array.
Or copy the previous array and don't include removed number in it.
Working Code:
import java.util.Arrays;
public class stackLargest
{
public static void main(String[] args)
{
int[] unsortedArray = {1,54,21,63,85,0,14,78,65,21,47,96,54,52};
int largestNumber = unsortedArray[0];
int removeIndex = 0;
// getting the largest number and its index
for(int i =0; i<unsortedArray.length;i++)
{
if(unsortedArray[i] > largestNumber)
{
largestNumber = unsortedArray[i];
removeIndex = i;
}
}
//removing the largest number
for(int i = removeIndex; i < unsortedArray.length -1; i++)
unsortedArray[i] = unsortedArray[i + 1];
// now you have two options either you can iterate one less than the array's size
// as we have deleted one element
// or you can copy the array to a new array and dont have to add " length - 1" when iterating through the array
// I am doing both at once, what you lke you can do
int[] removedArray = new int[unsortedArray.length-1];
for(int i =0; i<unsortedArray.length-1;i++)
{
System.out.printf(unsortedArray[i] + " ");
removedArray[i] = unsortedArray[i];
}
}
}
Note: Use List whenever possible, it will not only reduce complexity, but, comes with a very rich methods that will help you a big deal.

Why is my selection sort algorithm not working?

I'm trying to make a selection sort algorithm in java that finds the smallest element of an unsorted array and puts it on the end of a new array. But my program only copies the first element twice, gets the next one, and then the rest is all zeroes:
public static int find_min(int[] a){
int m = a[0];
for (int i = 0; i < a.length; i++){
if (m > a[i])
m = a[i];
}
return m;
}
public static int[] selectionSort(int[] unsorted){
int[] c = new int[unsorted.length];
for(int i = 0; i < unsorted.length; i++){
int smallest = find_min(unsorted);
c[i] = smallest;
unsorted = Arrays.copyOfRange(unsorted, i+1, unsorted.length );
}
return c;
}
When I put in something like:
public static void main(String[] args){
int a[] = {1,-24,4,-4,6,3};
System.out.println(Arrays.toString(selectionSort(a)));
}
I get:
[-24, -24, -4, 0, 0, 0]
where is this going wrong? Is this a bad algorithm?
Ok, let's revisit the selection sort algorithm.
public static void selectionSort(int[] a) {
final int n = a.length; // to save some typing.
for (int i = 0; i < n - 1; i++) {
// i is the position where the next smallest element should go.
// Everything before i is sorted, and smaller than any element in a[i:n).
// Now you find the smallest element in subarray a[i:n).
// Actually, you need the index
// of that element, because you will swap it with a[i] later.
// Otherwise we lose a[i], which is bad.
int m = i;
for (int j = m + 1; j < n; j++) {
if (a[j] < a[m]) m = j;
}
if (m != i) {
// Only swap if a[i] is not already the smallest.
int t = a[i];
a[i] = a[m];
a[m] = t;
}
}
}
In conclusion
You don't need extra space to do selection sort
Swap elements, otherwise you lose them
Remembering the loop invariant is helpful

Given two sorted lists (or arrays) and a number k, create an algorithm to fetch the least k numbers of the two lists

Need to find the first 3 smallest number in given two sorted array. I supposed that two array should merge into one first and sort it in order to fetch the first 3 smallest number. Can anyone help me with the merge and sort part or provide some advice, any help will appreciate.
This is where i reached now, I only can get the smallest number ( not first 3, just one).
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int smallest = set1[0];
int smallests = set2[0];
for(int i=0; i < set1.length; i++){
if(set1[i] < smallest)
smallest = set1[i];
}
for(int k=0; k < set2.length; k++){
if(set2[k] < smallests)
smallests = set2[k];
}
System.out.println("Smallest Number in Set 1 is : " + smallest);
System.out.println("Smallest Number in Set 2 is : " + smallests);
}
}
The arrays are already sorted, so you don't have to iterate over the entire arrays to find the 3 smallest numbers.
You just have to start iterating over both arrays at the same time (i.e. in the same loop).
In each iteration you compare the current two elements of the two arrays (starting at the 2 elements at the 0 index) and take the smaller of them
Then you advance the index of the array from which you took the smallest number.
Once you reach 3 elements (after 3 iterations), you break out of the loop.
Here's some pseudo code to get you started:
int i = 0;
int j = 0;
int c = 0;
int[] lowest3 = new int[3];
while (true) {
find the smaller of set1[i] and set2[j] and put it in lowest3[c]
if set1[i] is smaller, increment i
otherwise increment j
increment c
if (c==3) // you are done
break;
}
the lowest3 array now contains the 3 lowest numbers of both arrays
Of course you can swap 3 with any k. You just have to make sure that i is always smaller than set1.length and j is always smaller than set2.length.
If the arrays are already sorted, just implement the merging technique of merge sort with the limitation in while condition that it should run only k times (in this case 3), but dont forget to check that size of sets are less than k or not!
int k = 0,i = 0,j = 0;
while (k<3 && k<set1.length && k<set2.length )
{
if (set1[i] <= set2[j])
{
final_set[k] = set1[i];
i++;
}
else
{
final_set[k] = set2[j];
j++;
}
k++;
}
while (k<3 && k<set1.length) {
final_set[k]=set1[i];
k++;
i++;
}
while (k<3 && k<set2.length) {
final_set[k]=set1[j];
k++;
j++;
}
public class MergeandSort {
public static void main(String[] args) {
int[] set1 = {1,2,6,9,18};
int[] set2 = {2,3,7,10,21,30};
int[] sorted = new int[k];
int smallest = set1[0];
int smallests = set2[0];
int i = 0, j = 0, c = 0;
while(i < set1.length && j < set2.length && c < k){
if (set1[i] < set2[j])
sorted[c++] = arr1[i++];
else
sorted[c++] = arr2[j++];
while (i < set1.length && c < k)
sorted[c++] = arr1[i++];
while (j < set2.length && c < k)
sorted[c++] = arr2[j++];
System.out.println(sorted);
}
}
where k is the count of sorted numbers you want
That would not work as:
Array1 = {1,3,5}
Array2 = {2,3,4}
Correct solution: {1,2,3}
Output of your solution: {1,3,4}

Categories