Optimizing quick sort - algorithm

I am implementing quick sort algorithm in java and here is the code :
public class quickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSorter(0, length - 1);
}
private void quickSorter(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
// calculate pivot number, I am taking pivot as middle index number
int pivot = array[lowerIndex+(higherIndex-lowerIndex)/2];
// Divide into two arrays
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSorter(lowerIndex, j);
if (i < higherIndex)
quickSorter(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
Then I implement it with (median of three)
public class quickSort {
private int array[];
private int length;
public void sort(int[] inputArr) {
if (inputArr == null || inputArr.length == 0) {
return;
}
this.array = inputArr;
length = inputArr.length;
quickSorter(0, length - 1);
}
private void quickSorter(int lowerIndex, int higherIndex) {
int i = lowerIndex;
int j = higherIndex;
int mid = lowerIndex+(higherIndex-lowerIndex)/2;
if (array[i]>array[mid]){
exchangeNumbers( i, mid);
}
if (array[i]>array[j]){
exchangeNumbers( i, j);
}
if (array[j]<array[mid]){
exchangeNumbers( j, mid);
}
int pivot = array[mid];
// Divide into two arrays
while (i <= j) {
while (array[i] < pivot) {
i++;
}
while (array[j] > pivot) {
j--;
}
if (i <= j) {
exchangeNumbers(i, j);
//move index to next position on both sides
i++;
j--;
}
}
// call quickSort() method recursively
if (lowerIndex < j)
quickSorter(lowerIndex, j);
if (i < higherIndex)
quickSorter(i, higherIndex);
}
private void exchangeNumbers(int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
and the testing main :
public static void main(String[] args) {
File number = new File ("f.txt");
final int size = 10000000;
try{
quickSortOptimize opti = new quickSortOptimize();
quickSort s = new quickSort();
PrintWriter printWriter = new PrintWriter(number);
for (int i=0;i<size;i++){
printWriter.println((int)(Math.random()*100000));
}
printWriter.close();
Scanner in = new Scanner (number);
int [] arr1 = new int [size];
for (int i=0;i<size;i++){
arr1[i]=Integer.parseInt(in.nextLine());
}
long a=System.currentTimeMillis();
opti.sort(arr1);
long b=System.currentTimeMillis();
System.out.println("Optimaized quicksort: "+(double)(b-a)/1000);
in.close();
int [] arr2 = new int [size];
Scanner in2= new Scanner(number);
for (int i=0;i<size;i++){
arr2[i]=Integer.parseInt(in2.nextLine());
}
long c=System.currentTimeMillis();
s.sort(arr2);
long d=System.currentTimeMillis();
System.out.println("normal Quicksort: "+(double)(d-c)/1000);
}catch (Exception ex){ex.printStackTrace();}
}
The problem is that this method of optimization should improve performance by 5%
but, what happens actually is that I have done this test many times and almost always getting better result on normal quicksort that optimized one
so what is wrong with the second implementation

A median of three (or more) will usually be slower for input that's randomly ordered.
A median of three is intended to help prevent a really bad case from being quite as horrible. There are ways of making it pretty bad anyway, but at least avoids the problem for a few common orderings--e.g., selecting the first element as the pivot can produce terrible results if/when (most of) the input is already ordered.

Related

Binary Search Symbol Table implementation going inside infinite loop

I am trying to implement 'Binary Search in an ordered array' from the book 'Algorithms (fourth edition) by Robert Sedgewick & Kevin Wayne' (on page 381). However my code is going inside infinite loop. Please help. Below is the code:
public class BinarySearchST<Key extends Comparable<Key>, Value>{
private Key keys[];
private Value values[];
private int N;
public BinarySearchST(int capacity){
keys = (Key[]) new Comparable[capacity];
values = (Value[]) new Object[capacity];
}
public int size(){
return N;
}
public boolean isEmpty(){
return N == 0;
}
public int rank(Key key){
int lo = 0, hi = N-1;
while(lo <= hi){
int mid = (lo + (hi - lo))/2;
int comp = key.compareTo(keys[mid]);
if(comp < 0) hi = mid - 1;
else if(comp > 0) lo = mid + 1;
else return mid;
}
return lo;
}
public Value get(Key key){
if(isEmpty()) return null;
int rank = rank(key);
if(rank < N && key.compareTo(keys[rank]) == 0)
return values[rank];
else
return null;
}
public void put(Key key, Value value){
int rank = rank(key);
if(rank < N && key.compareTo(keys[rank]) == 0){//key already existing, just update value.
values[rank] = value;
return;
}
for(int i = N; i > rank; i--){
keys[i] = keys[i-1]; values[i] = values[i-1];
}
keys[rank] = key;
values[rank] = value;
N++;
}
public static void main(String[] args){
BinarySearchST<String, Integer> st = new BinarySearchST<String, Integer>(10);
st.put("A", 10);
st.put("B", 100);
st.put("C", 1000);
StdOut.println(st.get("A"));
}
}
This appears to be correct to me, but looks like some issue inside put() for loop.
use int mid = (lo + hi)/2.
You are using int mid = (lo+(hi-lo))/2 which reduces to hi/2. So, eventually your middle will be less than your lo and will not converge causing infinite loop.

Sorting algorithm is skipping the last element in my array

I have a simple algorithm to order numbers in an array, all of the elements become ordered except for the last one. I have tried changing the bounds of my loops to fix this, but it just creates an infinite loop instead.
while (pointer < arrayLength){
int min = findMinFrom(pointer);
for (int i = pointer; i < arrayLength; i ++){
if (A[i] == min){
swap(i, pointer);
pointer ++;
}
compNewS ++;
}
}
You see what's the problem? Your pointer will be updated only if A[i] == min if not then it will keep looping. Put your pointer++ out of that condition.
This can be done with only two loops but here is an adjusted version of your code:
public class Numbers {
private static int [] A ;
public static void main(String [] args) {
int [] array = {3,2,1,4,5,6,7,8,9,7};
A = array;
newSort(array, array.length);
for(int i = 0; i < A.length;i++)
System.out.println(A[i]);
}
public static void newSort(int[] array, int arrayLength){
int pointer = 0;
int p = 0;
while(p < array.length) {
int min = findMinFrom(p,array);
int temp = array[p];
array[p] = min;
array[min] = temp;
p++;
}
}
public static int findMinFrom(int p, int[] array){
int min = p;
for (int i = p; i < array.length; i ++){
if (A[i] < array[p]){
min =i;
}
}
return min;
}
}

Two ways of doing Counting Sort

Here are my two implementations of Counting Sort
In this implementation which is a very simple one, all I do is count the number of occurrences of the element, and insert as many times as the occurrences in the output array.
Implementation 1
public class Simple
{
static int[] a = {5,6,6,4,4,4,8,8,8,9,4,4,3,3,4};
public static void main(String[] args)
{
fun(a);
print(a);
}
static void fun(int[] a)
{
int max = findMax(a);
int[] temp = new int[max+1];
for(int i = 0;i<a.length;i++)
{
temp[a[i]]++;
}
print(temp);
//print(temp);
int k = 0;
for(int i = 0;i<temp.length;i++)
{
for(int j = 0;j<temp[i];j++)
a[k++] = i;
}
print(a);
}
static int findMax(int[] a)
{
int max = a[0];
for(int i= 1;i<a.length;i++)
{
if(a[i] > max)
max = a[i];
}
return max;
}
static void print(int[] a)
{
for(int i = 0;i<a.length;i++)
System.out.print(a[i] + " ");
System.out.println("");
}
}
Implementation 2
In this implementation which I saw on a lot of places online, you create an array saying how many elements there exists less than or equal to, that element, and then insert the element at that position. Once you insert, you reduce the count of the number of elements that are less than or equal to that element, since you have included that element. By the element, this array turns to all zeros. As you can see this implementation is fairly complex compared to the previous one, and am not sure why this is widely popular online.
public class NotVerySimple {
public static void main(String[] args) {
static int[] a = {5,6,6,4,4,4,8,8,8,9,4,4,3,3,4};
sort(a);
}
static void sort(int[] a)
{
int min = smallest(a);
int max = largest(a);
int[] A = new int[max - min + 1];
for(int i = 0;i<a.length;i++)
{
A[a[i] - min]++;
}
for(int i = 1;i<A.length;i++)
A[i] = A[i-1] + A[i];
int[] B = new int[a.length];
for(int i = 0;i<a.length;i++)
{
B[ A[a[i] - min] - 1 ] = a[i];
A[a[i] - min]--;
}
print(B);
}
static int smallest(int[] a)
{
int ret = a[0];
for(int i = 1;i<a.length;i++)
{
if(a[i] < ret)
ret = a[i];
}
return ret;
}
static int largest(int[] a)
{
int ret = a[0];
for(int i = 1;i<a.length;i++)
{
if(a[i] > ret)
ret = a[i];
}
return ret;
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x+ " ");
}
}
Are there any advantages of the second complex implementation as compared to the first simple one, which makes it so popular?

Are these complexity classes correct?

I have a few problems to do and I have a decent understanding of how they work I just want feedback on if I am correct. I need to figure out the big-oh-notation of the following.
1.
public static int[] mystery1(int[] list) {
int[] result = new int[2*list.length];
for (int i=0; i<list.length; i++) {
result[2*i] = list[i] / 2+list[i] % 2;
result[2*i+1] = list[i] / 2;
}
I think this one would be Nlog(N)
2.
public static int[] mystery2(int[] list) {
for (int i=0; i<list.length/2; i++) {
int j = list.length-1-i;
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
return list;
}
I think this one would be O(logN) because it's diving by 2 until it finishes
3.
public static void mystery3(ArrayList<String> list) {
for (int i=0; i<list.size-1; i+=2) {
String first = list.remove(i);
list.add(i+1, first);
}
}
I think this one would be O(N)
4.
public static void mystery4(ArrayList<String> list) {
for (int i=0; i<list.size-1; i+=2) {
String first = list.get(i);
list.set(i, list.get(i+1));
list.set(i+1, first);
}
}
I think this one would be O(N).
All are O(N) except Mystrey3 which is O(N^2)= due to add.list

Dyanmic Task Scheduling Interview Street

The task scheduling problem for n tasks is solved by greedy algorithm. I have encountered this particular sort of problem in various coding challenges which asks to find out minimum of maximum overshoot dynamically. One of them is stated below:
Interview Street Problem:
You have a long list of tasks that you need to do today. Task i is specified by the deadline by which you have to complete it (Di) and the number of minutes it will take you to complete the task (Mi). You need not complete a task at a stretch. You can complete a part of it, switch to another task and then switch back.
You've realized that it might not actually be possible complete all the tasks by their deadline, so you have decided to complete them so that the maximum amount by which a task's completion time overshoots its deadline is minimized.
My Approach
Now consider an intermediate stage where we have found the solution for i-1 tasks and have arranged them in sorted order. We have also stored the index of the task which had the maximum overshoot with i-1 tasks say maxLate. After the arrival of the *i*th task we check if D[i] < D[maxlate] then the new maxLate will be either old maxLate of the ith task.
I am confused for the case when D[i] > D[maxlate]. Is a linear scan necessary for this case?
Also suggest a good data structure for updating the new list and keeping them in sorted order.
Thanks for your help.
First of all, you need to prove that given a set of task (m_i, d_i), the best schedule is finish the jobs according to their deadlines, i.e. emergent jobs first.
And the problem is equivalent to:
for each job in original order:
dynamically insert this job (m_i, d_i) into a sorted job_list
query max{ (sum(m_k for all k <= n) - d_n) for all n in job_list }
This algorithm run in O(N^2) where N is the number of jobs, which is too slow for getting accepted in interview street. However, we can use some advanced data structure, to speed up the insert and query operation.
I use a segment tree with lazy update to solve this problem in O(NlgN) time, and here's my code
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
class SegTree
{
public:
SegTree(int left, int right, const vector<int>& original_data)
{
this->left = left;
this->right = right;
this->lazy_flag = 0;
left_tree = right_tree = NULL;
if (left == right)
{
this->value = this->max_value = original_data[left];
}
else
{
mid = (left + right) / 2;
left_tree = new SegTree(left, mid, original_data);
right_tree = new SegTree(mid + 1, right, original_data);
push_up();
}
}
void modify(int left, int right, int m_value)
{
if (this->left == left && this->right == right)
{
leaf_modify(m_value);
}
else
{
push_down();
if (left <= mid)
{
if (right >= mid + 1)
{
left_tree->modify(left, mid, m_value);
right_tree->modify(mid + 1, right, m_value);
}
else
{
left_tree->modify(left, right, m_value);
}
}
else
{
right_tree->modify(left, right, m_value);
}
push_up();
}
}
int query(int left, int right)
{
if (this->left == left && this->right == right)
{
return this->max_value;
}
else
{
push_down();
if (left <= mid)
{
if (right >= mid + 1)
{
int max_value_l = left_tree->query(left, mid);
int max_value_r = right_tree->query(mid + 1, right);
return max(max_value_l, max_value_r);
}
else
{
return left_tree->query(left, right);
}
}
else
{
return right_tree->query(left, right);
}
}
}
private:
int left, right, mid;
SegTree *left_tree, *right_tree;
int value, lazy_flag, max_value;
void push_up()
{
this->max_value = max(this->left_tree->max_value, this->right_tree->max_value);
}
void push_down()
{
if (this->lazy_flag > 0)
{
left_tree->leaf_modify(this->lazy_flag);
right_tree->leaf_modify(this->lazy_flag);
this->lazy_flag = 0;
}
}
void leaf_modify(int m_value)
{
this->lazy_flag += m_value;
this->max_value += m_value;
}
};
vector<int> vec_d, vec_m, vec_idx, vec_rank, vec_d_reorder;
int cmp(int idx_x, int idx_y)
{
return vec_d[idx_x] < vec_d[idx_y];
}
int main()
{
int T;
scanf("%d", &T);
for (int i = 0; i < T; i++)
{
int d, m;
scanf("%d%d", &d, &m);
vec_d.push_back(d);
vec_m.push_back(m);
vec_idx.push_back(i);
}
sort(vec_idx.begin(), vec_idx.end(), cmp);
vec_rank.assign(T, 0);
vec_d_reorder.assign(T, 0);
for (int i = 0; i < T; i++)
{
vec_rank[ vec_idx[i] ] = i;
}
for (int i = 0; i < T; i++)
{
vec_d_reorder[i] = -vec_d[ vec_idx[i] ];
}
// for (int i = 0; i < T; i++)
// {
// printf("m:%d\td:%d\tidx:%d\trank:%d\t-d:%d\n", vec_m[i], vec_d[i], vec_idx[i], vec_rank[i], vec_d_reorder[i]);
// }
SegTree tree(0, T-1, vec_d_reorder);
for (int i = 0; i < T; i++)
{
tree.modify(vec_rank[i], T-1, vec_m[i]);
int ans = tree.query(0, T-1);
printf("%d\n", max(0,ans));
}
}
class Schedule {
int deadLine = 0;
int taskCompletionTime = 0;
int done = 0;
Schedule(int deadline, int taskCompletionTime) {
this.deadLine = deadline;
this.taskCompletionTime = taskCompletionTime;
}
}
class TaskScheduler {
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int max = 0;
ArrayList<Schedule> sch = new ArrayList<Schedule>();
for(int i = 0; i < n; i++) {
int deadLine = in.nextInt();
int taskCompletionTime = in.nextInt();
Schedule s = new Schedule(deadLine, taskCompletionTime);
int j = i-1;
while(j >= 0 && sch.get(j).deadLine > s.deadLine) {
Schedule s1 = sch.get(j);
if(s1.deadLine <= s.deadLine) break;
s1.done += s.taskCompletionTime;
max = Math.max(max, s1.done - s1.deadLine);
j--;
}
sch.add(j+1, s);
if(j < 0)
s.done = s.taskCompletionTime;
else
s.done = sch.get(j).done + s.taskCompletionTime;
max = Math.max(max, s.done - s.deadLine);
System.out.println(max);
}
}
}

Resources