How can I fix my java quick sort? - java

The problem is, it's a neverending recursion. I don't know, how can I finish the recursion. The funny is, it works, if I print the arraylist (mergedArray), it will be sorted after some iteration, but the function never stops.
The error message is:
"at javaapplication9.QuickSort.simple_quick_sort(QuickSort.java:40)"
The code below:
public ArrayList<Integer> simple_quick_sort(ArrayList<Integer> arr) {
ArrayList<Integer> mergedArray = new ArrayList<Integer>();
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
if (arr.size() <= 1) {
return arr;
}
else {
int pivot = arr.get(0);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) < pivot) {
left.add(arr.get(i));
}
else {
right.add(arr.get(i));
}
}
}
mergedArray.addAll(left);
mergedArray.addAll(right);
simple_quick_sort(mergedArray);
return mergedArray;
}

public ArrayList<Integer> simple_quick_sort(ArrayList<Integer> arr) {
if (arr.size() <= 1) {
return arr;
}
else {
ArrayList<Integer> mergedArray = new ArrayList<Integer>();
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
int pivot = arr.get(0);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) < pivot) {
left.add(arr.get(i));
left = simple_quick_sort(left);
}
else {
right.add(arr.get(i));
right = simple_quick_sort(right);
}
}
}
mergedArray.addAll(left);
mergedArray.addAll(right);
}
Of course, copying is contrary to the basic idea of quicksort which is good because it can work on the array to be sorted, not requiring these copy operations and storage allocations.

I am sorry but your entire implementation of quicksort is kind of incorrect. Also, using a loop inside of a recursive function negates the benefits of using recursion. If you want to implement that loop, I would suggest you nest it inside another loop to make the code simpler (won't be as efficient as recursion).
If you want to continue with this program, try making the following change:
When you write
simple_quick_sort(mergedArray);
return mergedArray;
you are not using the returned value from the function. You are just calling the function and doing nothing with the returned value. There might be more things that need fixing before this code works.
If you want to learn more about quick sort and recursion, I found this page http://www.geeksforgeeks.org/quick-sort/
I hope this helps!

Related

Find overall max element to the left of each element in an arrray (not the first max)

I'm trying to find the max element to the left of each element but i could write code for only the first max.
public static void main(String[] args) {
int a[]={3,0,0,2,0,4};
Stack<Integer> st=new Stack<Integer>();
ArrayList<Integer> al=new ArrayList<>();
for(int i=0;i<5;i++){
while(st.size()>0 && a[st.peek()]<a[i]){
st.pop();
}
if(st.empty()) al.add(a[i]);
else al.add(a[st.peek()]);
st.push(i);
}
System.out.println(al);
}
Using Stack
public static int[] maxLeftElement(int[] A)
{
final int n = A.length;
int[] ans = new int[n];
Stack<Integer> S = new Stack<>();
S.push(A[0]);
for (int i = 0;i < n;i++)
{
if (S.peek() <= A[i])
{
S.pop();
S.push(A[i]);
}
ans[i] = S.peek();
}
return ans;
}
Efficient Solution
In the above solution, there will be only one element in the stack throughout the execution of the function. Hence, it is quite clear to observe the stack does not offer any benefit whatsoever. Hence, it is better to replace it with a simple int.
public static int[] maxLeftElement(int[] A)
{
final int n = A.length;
int[] ans = new int[n];
int maxSoFar = A[0];
for (int i = 0;i < n;i++)
{
maxSoFar = Math.max(maxSoFar,A[i]);
ans[i] = maxSoFar;
}
return ans;
}
Intuition
For each A[i], we have to find max(A[0..i]), for all the valid i. If we think about the possible element, there could be only one max element in A[0..i].
Now, let the max element in A[0..i] is maxSoFar. We need to find the max left element for A[i+1], which will be max(A[0...i+1]). Trivially, max(A[0..i+1]) = max(A[0...i],A[i+1]) = max(maxSoFar,A[i+1]) which can be solved in constant time.
We already know max left element for A[0] will be A[0]. So, initially maxSoFar = A[0]. Hence, we can simple keep increasing i for all the valid values and compute max(maxOfFar,A[i]).
Why not stack?
Stack should be used when there is a need to store many elements in a particular order which can help us compute the answer for any A[i]. We do not need to keep track of multiple elements at any instant to obtain the answer for any A[i] for the problem in question. This rules out the possibility of using stack.

For k collections all of which have length = N, finding common elements with a O((k-1)*N)

I am supposed to write a code which is supposed to find the common elements existing in k collections of N-elements efficiently. All collections are sorted and they may have various sizes, but let's assume same sizes for the sake of simplicity here. Only thing that counts is the comparisons between elements; that should be less than O((k-1)*N).
I have developed the below code, but in case of mentioned scenario the number of comparisons is about (k-1)NN
Appreciate the help in advance.
//Arrays are sorted and the shortest array is chosen as the query automatically
boolean com;
loop1: for (int i = 0; i < QuetyList.length; ++i) {
com = false;
loop2: for (int k = 0; k < OtherLists.length; ++k) {
com = false;
loop3: for (int y = 0; y < OtherLists[k].size(); ++y) {
++comparisons;
if (QueryList[i].compareTo(OtherLists[k][y]) == 0) {
com = true;
break loop3;
}
++comparisons;
if (QueryList[i].compareTo(OtherLists[k][y]) < 0) {
break;
}
}
if (com == false) {
break;
}
}
if (com == true) {
commons.add(QueryList[i]);
}
}
Sample test
Comparable [] QuetyList = {200,200,200,200};
Comparable [] collection2 = {2,10,50,200};
Comparable [] collection3 = {2,10,40,200};
Comparable [][] OtherLists = {collection2,collection3};
This is for a homework. There is a chance you may have crossed sometime in your education. Thanks in advance.
The basic idea is to keep an index on every list you have, and only advance this index when the value at the index is the smallest among all the lists.
I can't see if it's doable for k lists at once, but it's certainly doable 2 lists at a time, each should take N comparisons, which should give you O(k * N) (k-1 runs of N comparison).
Something like:
public Comparable[] common(Comparable[] a, Comparable[] b) {
// List is more flexible, but the toArray at the end is a bit costly. You can probably figure a better way of doing this.
List<Comparable> res = new ArrayList<>();
int indexA = 0;
int indexB = 0;
while (indexA < a.length && indexB < b.length) {
// Exercice for the reader: replace with compareTo calls
if (a[indexA] == b[indexB]) {
// Common item!
res.add(a[indexA]);
indexA++;
indexB++;
} else if (a[indexA] < b[indexB]) {
// item in A is smaller, try the next
indexA++;
} else {
indexB++;
}
}
return res.toArray(new Comparable[0]);
}
From this, you can group your lists 2 by 2 until only one list remains.

Java Merge Sorting Algorithm Error - Not Sorting

I can't figure out why my algorithm for a Merge Sort program using ArrayLists won't work... If guys and gals could help me figure it out that would be amazing!! The format required for printing needs to be tabbed every number and place on a new line every 20 numbers. My program has also been limited to the standard Java packages. Sample input and output can be found here. Here's my code:
import java.io.*;
import java.util.*;
public class MergeSort {
public static void main(String[] args) throws IOException{
Scanner in = new Scanner(System.in);
Random r = new Random();
int size, largestInt, holder;
System.out.println("How many integers would you like me to create?");
size = in.nextInt();
ArrayList<Integer>list = new ArrayList<Integer>(size);
System.out.println("What would the largest integer be?");
largestInt = in.nextInt();
for(int i = 0; i < size; i++){
holder = r.nextInt(largestInt + 1);
list.add(holder);
}
mergeSort(list);
for (int j = 0; j < list.size(); j++) {
if(j == 19 || j == 39 || j == 59 || j == 79 || j == 99 || j == 119 || j == 139 || j == 159 || j == 179 || j == 199){
System.out.print(list.get(j));
System.out.println();
}
else{
System.out.print(list.get(j) + "\t");
}
}
}
static void mergeSort(ArrayList<Integer> list) {
if (list.size() > 1) {
int q = list.size()/2;
ArrayList<Integer> leftList = new ArrayList<Integer>();
for(int i = 0; i >0 && i <= q; i++){
leftList.add(list.get(i));
}
ArrayList<Integer> rightList = new ArrayList<Integer>();
for(int j = 0; j > q && j < list.size(); j++){
rightList.add(list.get(j));
}
mergeSort(leftList);
mergeSort(rightList);
merge(list,leftList,rightList);
}
}
static void merge(ArrayList<Integer> a, ArrayList<Integer> l, ArrayList<Integer> r) {
int totElem = l.size() + r.size();
int i,li,ri;
i = li = ri = 0;
while ( i < totElem) {
if ((li < l.size()) && (ri<r.size())) {
if (l.get(li) < r.get(ri)) {
a.set(i, l.get(li));
i++;
li++;
}
else {
a.set(i, r.get(ri));
i++;
ri++;
}
}
else {
if (li >= l.size()) {
while (ri < r.size()) {
a.set(i, r.get(ri));
i++;
ri++;
}
}
if (ri >= r.size()) {
while (li < l.size()) {
a.set(i, l.get(li));
li++;
i++;
}
}
}
}
}
Thanks in advance!
Your question is unclear, but since you need to implement a merge sort algorithm I assume this is the part that is broken for you. Format printing should be rather easy through trial and error once you have a properly sorted list.
I think you are greatly overcomplicating the problem in your solution. MergeSort is one of the simplest sorting algorithms out there, yet your code is far from simple.
Think about how Merge Sort works - it is recursive by nature because it is a divide and conquer method. It solves a large complex problem by splitting it into small easy problems, and basically just merges the result from all of these problems - your MergeSort algorithm just needs to encompass this.
If we write it up you need to do these steps:
(1) Check if the list contains only one element - then it is already sorted
(2) Split the input into equally sized lists and sorted these before proceeding (recursive step)
(3) Merge the two sorted lists, and return a single sorted list.
I see that you have a complex method for the merge part and use basic iteration for the splitting part. Java List (superclass of e.g. ArrayList) offers a .subList(fromIndex, toIndex) to split lists into smaller lists. You should use this. For the merging part:
Based on this animation from wikipedia
it should be rather simple how you should think about merging the two lists:
First maintain both lists as lists that are easy to remove objects from. Since at this point we know that the lists are gonna be sorted, we are ever only interested in the first object in each list (the smallest element).
Second, we only ever need to compare the first element of each list, remove the smallest of the two from its respective list and add it to our sorted list. We keep doing this until both lists are empty - at this point we have merged our lists.
In Java this indicates that we should use a datastructure for the merge part that allows us to look at the first element of each lists, and quickly remove the one we are interested in. In Java this data structure is LinkedList - ArrayList both performs terribly at this task and does not offer proper methods for doing this. LinkedList behaves as a queue and offers methods for easily checking and removing objects at the end of the list e.g. the first element.
So you should reconsider your implementation strategy and simplify your code based on how you should attack the MergeSort algorithm. If it seems comfusing here is a sample implementation of MergeSort in Java using only the standard API (no build in sorting method).
Hope it helps.
import java.util.LinkedList;
import java.util.Random;
import java.util.List;
public class Main {
public static void main(String[] args){
Random random = new Random();
LinkedList<Integer> unsorted = new LinkedList<Integer>();
for(int i = 0; i<100; i++){
unsorted.add(random.nextInt(100));
}
System.out.println("unsorted: " + unsorted.toString());
List<Integer> sorted = mergeSort(unsorted);
System.out.println("sorted: " + sorted.toString());
}
//Recursive function for sorting a LinkedList
private static LinkedList<Integer> mergeSort(LinkedList<Integer> unsorted){
//If the list only contains 1 object it is sorted
if(unsorted.size() == 1){
return unsorted;
}
//Split the list in two parts and create a new list to store our sorted list
LinkedList<Integer> left = mergeSort(new LinkedList<Integer>(unsorted.subList(0, unsorted.size()/2)));
LinkedList<Integer> right = mergeSort(new LinkedList<Integer>(unsorted.subList(unsorted.size()/2, unsorted.size())));
LinkedList<Integer> sorted = new LinkedList<Integer>();
//Actual loop for merging the two sublists. Using LinkedLists, this is efficient. (Compared to ArrayList)
while(!left.isEmpty() || !right.isEmpty()){
Integer leftInt = left.peekFirst();
Integer rightInt = right.peekFirst();
if(!(leftInt == null) && !(rightInt == null)){
if(leftInt < rightInt){
sorted.add(left.pollFirst());
}
else{
sorted.add(right.pollFirst());
}
}
else if(leftInt == null){
sorted.add(right.pollFirst());
}
else{
sorted.add(left.pollFirst());
}
}
return sorted;
}
}

Enhanced for loop starting part way through List

Im a beginner in Java and I had this doubt. Is it possible to use the Enhanced for loop in Java on an ArrayList, but start at the specified point rather than ArrayList[0].
For eg. ArrayList<Integer> calc = new ArrayList<Integer>;
// calc contains {0,1,2,3,4,5,6,7}
Can I use enhanced for loop and start iterating from calc[2] rather than calc[0]?? If possible, how can I do that?
In my particular case, using a enhanced for loop would be better, rather than a normal for loop.
The best way in Java would be like this:
for (Integer i : calc.subList(start, calc.size()) {
...
}
subList is an efficient view of the original list, so it's almost exactly what you need.
UPDATE
OK, motivated by Mikera's comments, I benchmarked it on jmh. This is the benchmarked code:
import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
public class Benchmark1
{
static final List<Integer> list = new ArrayList(asList(1,2,3,4,5,6,7,8,9,10));
static { for (int i = 0; i < 5; i++) list.addAll(list); }
#GenerateMicroBenchmark
public long testIterator() {
long sum = 0;
for (int i : list) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexed() {
long sum = 0;
for (int i = 0; i < list.size(); i++) sum += list.get(i);
return sum;
}
#GenerateMicroBenchmark
public long testSublistIterator() {
long sum = 0;
for (int i : list.subList(1, list.size())) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexedSublist() {
long sum = 0;
final List<Integer> l = list.subList(1, list.size());
for (int i = 0; i < l.size(); i++) sum += l.get(i);
return sum;
}
}
And these are the results:
Benchmark ops/msec
-------------------------
Indexed 1860.982
IndexedSublist 1642.059
Iterator 1818.657
SublistIterator 1496.994
Conclusions:
enhanced for on the main list is as fast as indexed iteration, once past the initialization cost;
traversal of the sublist is somewhat slower than of the main list, and iteration is somewhat slower than indexed traversal;
all the differences are negligible for all practical purposes.
You're stuck using a traditional loop here...
for (int i = 2; i < calc.size(); i++) {
Integer x = calc.get(i);
}
Well, unless you're willing to create a temporary subList just for using an enhanced for loop, which is fine, because sublists are views of the original list and don't create a new list object:
for (Integer x : calc.subList(2, calc.size())) {
}
for(Item e : list.subList(1, list.size())) {
// ...
}
You could iterate through the sublist, as below:
for (Integer integerMember : calc.subList(2, calc.size()) {
// operation here
}
It should be noted that the enhanced for loop is less efficient for ArrayList then standard indexing. This is because we have to create an Iterator object and call hasNext and next on it on each step of the loop, causing unnecessary overhead.
For this reason I would recommend indexing in the traditional way rather than using the sublist approach.

For loop - like Python range function

I was wondering if in Java there is a function like the python range function.
range(4)
and it would return
[0,1,2,3]
This was an easy way to make for enhanced loops. It would be great to do this in Java because it would make for loops a lot easier. Is this possible?
Java 8 (2014) has added IntStream (similar to apache commons IntRange), so you don't need external lib now.
import java.util.stream.IntStream;
IntStream.range(0, 3).forEachOrdered(n -> {
System.out.println(n);
});
forEach can be used in place of forEachOrdered too if order is not important.
IntStream.range(0, 3).parallel() can be used for loops to run in parallel
Without an external library, you can do the following. It will consume significantly less memory for big ranges than the current accepted answer, as there is no array created.
Have a class like this:
class Range implements Iterable<Integer> {
private int limit;
public Range(int limit) {
this.limit = limit;
}
#Override
public Iterator<Integer> iterator() {
final int max = limit;
return new Iterator<Integer>() {
private int current = 0;
#Override
public boolean hasNext() {
return current < max;
}
#Override
public Integer next() {
if (hasNext()) {
return current++;
} else {
throw new NoSuchElementException("Range reached the end");
}
}
#Override
public void remove() {
throw new UnsupportedOperationException("Can't remove values from a Range");
}
};
}
}
and you can simply use it like this:
for (int i : new Range(5)) {
System.out.println(i);
}
you can even reuse it:
Range range5 = new Range(5);
for (int i : range5) {
System.out.println(i);
}
for (int i : range5) {
System.out.println(i);
}
As Henry Keiter pointed out in the comment below, we could add following method to the Range class (or anywhere else):
public static Range range(int max) {
return new Range(max);
}
and then, in the other classes we can
import static package.name.Range.range;
and simply call
for (int i : range(5)) {
System.out.println(i);
}
Um... for (int i = 0; i < k; i++)? You don't have to write enhanced for loops all day, you know, although they are cool...
And just for the sake of argument:
for (int i : range(k)) char count: 22
for (int i = 0; i < k; i++) char count: 27
Discounting the implementation of range, it is pseudo even.
Use Apache Commons Lang:
new IntRange(0, 3).toArray();
I wouldn't normally advocate introducing external libraries for something so simple, but Apache Commons are so widely used that you probably already have it in your project!
Edit: I know its not necessarily as simple or fast as a for loop, but its a nice bit of syntactic sugar that makes the intent clear.
Edit: See #zengr's answer using IntStream in Java 8 .
If you really, really want to obtain an equivalent result in Java, you'll have to do some more work:
public int[] range(int start, int end, int step) {
int n = (int) Math.ceil((end-start)/(double)step);
int[] arange = new int[n];
for (int i = 0; i < n; i++)
arange[i] = i*step+start;
return arange;
}
Now range(0, 4, 1) will return the expected value, just like Python: [0, 1, 2, 3]. Sadly there isn't a simpler way in Java, it's not a very expressive language, like Python.
Its not available that true. But you make a static method and use it -
public static int[] range(int index){
int[] arr = new int[index];
for(int i=0;i<index;i++){
arr[i]=i;
}
return arr;
}
As far as I know, there's not an equivalent function in java. But you can write it yourself:
public static int[] range(int n) {
int[] ans = new int[n];
int i;
for(i = 0; i < n; i++) {
ans[i] = i;
}
return ans;
}
There's no Java equivalent to the range function, but there is an enhanced for-loop:
for (String s : strings) {
// Do stuff
}
You could also roll your own range function, if you're really attached to the syntax, but it seems a little silly.
public static int[] range(int length) {
int[] r = new int[length];
for (int i = 0; i < length; i++) {
r[i] = i;
}
return r;
}
// ...
String s;
for (int i : range(arrayOfStrings.length)) {
s = arrayOfStrings[i];
// Do stuff
}
What you can do to substitute the range in python in java can be done with the following code. NOTE: I am not going off of your code, I am just writing a small piece of code and showing it to you.
in python you would do.. . .
if -2 <= x <= 10:
print(x)
in java you would substitute this range and do. . ..
if(x >= -2 && x <= 10){
System.out.println("x")
}
By doing the above code in java, you don't need a range, but you have the
-2 <= x <=10 range and split it into x >= -2 and x <= 10. It means the same thing, but the one I explained in java may take the compiler a longer time to read. So if you are using python go with the former's code format, and if you are using java, use the latter's code format.

Categories