I'm trying to implement multithreaded merge sort in Java. The idea is to recursively call to new threads on every iteration. Everything works properly, but problem is that regular single-thread version appears to be much more faster. Please, help fixing it.
I've tried to play with .join(), but it haven't brought any success.
My code:
public class MergeThread implements Runnable {
private final int begin;
private final int end;
public MergeThread(int b, int e) {
this.begin = b;
this.end = e;
}
#Override
public void run() {
try {
MergeSort.mergesort(begin, end);
} catch (InterruptedException ex) {
Logger.getLogger(MergeThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class MergeSort {
private static volatile int[] numbers;
private static volatile int[] helper;
private int number;
public void sort(int[] values) throws InterruptedException {
MergeSort.numbers = values;
number = values.length;
MergeSort.helper = new int[number];
mergesort(0, number - 1);
}
public static void mergesort(int low, int high) throws InterruptedException {
// check if low is smaller than high, if not then the array
// is sorted
if (low < high) {
// Get the index of the element which is in the middle
int middle = low + (high - low) / 2;
// Sort the left side of the array
Thread left = new Thread(new MergeThread(low, middle));
Thread right = new Thread(new MergeThread(middle+1, high));
left.start();
right.start();
left.join();
right.join();
// combine the sides
merge(low, middle, high);
}
}
private static void merge(int low, int middle, int high) {
// Copy both parts into the helper array
for (int i = low; i <= high; i++) {
helper[i] = numbers[i];
}
int i = low;
int j = middle + 1;
int k = low;
// Copy the smallest value from either the left or right side
// back to the original array
while (i <= middle && j <= high) {
if (helper[i] <= helper[j]) {
numbers[k] = helper[i];
i++;
} else {
numbers[k] = helper[j];
j++;
}
k++;
}
// Copy the rest of the left side of the array
while (i <= middle) {
numbers[k] = helper[i];
k++;
i++;
}
}
public static void main(String[] args) throws InterruptedException {
int[] array = new int[1000];
for(int pos = 0; pos<1000; pos++) {
array[pos] = 1000-pos;
}
long start = System.currentTimeMillis();
new MergeSort().sort(array);
long finish = System.currentTimeMillis();
for(int i = 0; i<array.length; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
System.out.println(finish-start);
}
}
There are several factors here. First of all, you are spawning too many threads. A lot more than the number of cores your processor has. If I understand your algorithm correctly you are doing something like log2(n) at the bottom level of your tree.
Given that you're doing processor intensive computations, not involving I/O, once you pass the number of cores with your thread count, the performance starts degrading pretty fast. Hitting something like several thousand threads will slow and in the end crash the VM.
If you want to actually benefit from having a multi-core processor in this computation you should try to use a fixed size thread-pool (upper bounded on the number of cores or thereabout) or an equivalent thread reuse policy.
Second point, if you want to do a valid comparison you should try with computations that last longer (sorting 100 numbers doesn't qualify). If not, you are taking a significant relative hit from the cost of creating threads.
Provide a threadcount in begining as number of cores or less.
Below link has performance analysis too.
Here if a good example https://courses.cs.washington.edu/courses/cse373/13wi/lectures/03-13/MergeSort.java
Below is the iterative serial version of MergeSort which is indeed faster than the recursive version and also doesnot involve calculation of middle so avoids the overflow error for it. However overflow errors can occur for other integers as well. You can try for parallelizing it if you are interested.
protected static int[] ASC(int input_array[]) // Sorts in ascending order
{
int num = input_array.length;
int[] temp_array = new int[num];
int temp_indx;
int left;
int mid,j;
int right;
int[] swap;
int LIMIT = 1;
while (LIMIT < num)
{
left = 0;
mid = LIMIT ; // The mid point
right = LIMIT << 1;
while (mid < num)
{
if (right > num){ right = num; }
temp_indx = left;
j = mid;
while ((left < mid) && (j < right))
{
if (input_array[left] < input_array[j]){ temp_array[temp_indx++] = input_array[left++]; }
else{ temp_array[temp_indx++] = input_array[j++]; }
}
while (left < mid){ temp_array[temp_indx++] = input_array[left++]; }
while (j < right){ temp_array[temp_indx++] = input_array[j++]; }
// Do not copy back the elements to input_array
left = right;
mid = left + LIMIT;
right = mid + LIMIT;
}
// Instead of copying back in previous loop, copy remaining elements to temp_array, then swap the array pointers
while (left < num){ temp_array[left] = input_array[left++]; }
swap = input_array;
input_array = temp_array;
temp_array = swap;
LIMIT <<= 1;
}
return input_array ;
}
Use the java executor service, thats a lot faster, even with threads exceeding the number of cores ( you can build scalable multithreaded applications with it ), I have a code that uses only threads but its very very slow, and Im new to executors so cant help much, but its an interesting area to explore.
Also there is a cost for parallelism, because thread management is a big deal, so go for parallelism at high N, if you are looking for a serial alternative to merge sort, I suggest the Dual-Pivot-QuickSort or 3-Partition-Quick-Sort as they are known to beat merge sort often. Reason is that they have low constant factors than MergeSort and the worst case time complexity has the probability of occuring only 1/(n!). If N is large, the worst case probability becomes very small paving way for increased probability of average case. You could multithread both and see which one among the 4 programs ( 1 serial and 1 multithreaded for each : DPQ and 3PQ ) runs the fastest.
But Dual-Pivot-QuickSort works best when there are no, or almost no duplicate keys and 3-Partition-Quick-Sort works best when there are many duplicate keys. I have never seen 3-Partition-Quick-Sort beat the Dual-Pivot-QuickSort when there are none or very few duplicate keys, but I have seen Dual-Pivot-QuickSort beat 3-Partition-Quick-Sort a very small number of times in case of many duplicate keys. In case you are interested, DPQ serial code is below( both ascending and descending)
protected static void ASC(int[]a, int left, int right, int div)
{
int len = 1 + right - left;
if (len < 27)
{
// insertion sort for small array
int P1 = left + 1;
int P2 = left;
while ( P1 <= right )
{
div = a[P1];
while(( P2 >= left )&&( a[P2] > div ))
{
a[P2 + 1] = a[P2];
P2--;
}
a[P2 + 1] = div;
P2 = P1;
P1++;
}
return;
}
int third = len / div;
// "medians"
int P1 = left + third;
int P2 = right - third;
if (P1 <= left)
{
P1 = left + 1;
}
if (P2 >= right)
{
P2 = right - 1;
}
int temp;
if (a[P1] < a[P2])
{
temp = a[P1]; a[P1] = a[left]; a[left] = temp;
temp = a[P2]; a[P2] = a[right]; a[right] = temp;
}
else
{
temp = a[P1]; a[P1] = a[right]; a[right] = temp;
temp = a[P2]; a[P2] = a[left]; a[left] = temp;
}
// pivots
int pivot1 = a[left];
int pivot2 = a[right];
// pointers
int less = left + 1;
int great = right - 1;
// sorting
for (int k = less; k <= great; k++)
{
if (a[k] < pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
else if (a[k] > pivot2)
{
while (k < great && a[great] > pivot2)
{
great--;
}
temp = a[k]; a[k] = a[great]; a[great] = temp;
great--;
if (a[k] < pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
}
}
int dist = great - less;
if (dist < 13)
{
div++;
}
temp = a[less-1]; a[less-1] = a[left]; a[left] = temp;
temp = a[great+1]; a[great+1] = a[right]; a[right] = temp;
// subarrays
ASC(a, left, less - 2, div);
ASC(a, great + 2, right, div);
// equal elements
if (dist > len - 13 && pivot1 != pivot2)
{
for (int k = less; k <= great; k++)
{
if (a[k] == pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
else if (a[k] == pivot2)
{
temp = a[k]; a[k] = a[great]; a[great] = temp;
great--;
if (a[k] == pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
}
}
}
// subarray
if (pivot1 < pivot2)
{
ASC(a, less, great, div);
}
}
protected static void DSC(int[]a, int left, int right, int div)
{
int len = 1 + right - left;
if (len < 27)
{
// insertion sort for large array
int P1 = left + 1;
int P2 = left;
while ( P1 <= right )
{
div = a[P1];
while(( P2 >= left )&&( a[P2] < div ))
{
a[P2 + 1] = a[P2];
P2--;
}
a[P2 + 1] = div;
P2 = P1;
P1++;
}
return;
}
int third = len / div;
// "medians"
int P1 = left + third;
int P2 = right - third;
if (P1 >= left)
{
P1 = left + 1;
}
if (P2 <= right)
{
P2 = right - 1;
}
int temp;
if (a[P1] > a[P2])
{
temp = a[P1]; a[P1] = a[left]; a[left] = temp;
temp = a[P2]; a[P2] = a[right]; a[right] = temp;
}
else
{
temp = a[P1]; a[P1] = a[right]; a[right] = temp;
temp = a[P2]; a[P2] = a[left]; a[left] = temp;
}
// pivots
int pivot1 = a[left];
int pivot2 = a[right];
// pointers
int less = left + 1;
int great = right - 1;
// sorting
for (int k = less; k <= great; k++)
{
if (a[k] > pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
else if (a[k] < pivot2)
{
while (k < great && a[great] < pivot2)
{
great--;
}
temp = a[k]; a[k] = a[great]; a[great] = temp;
great--;
if (a[k] > pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
}
}
int dist = great - less;
if (dist < 13)
{
div++;
}
temp = a[less-1]; a[less-1] = a[left]; a[left] = temp;
temp = a[great+1]; a[great+1] = a[right]; a[right] = temp;
// subarrays
DSC(a, left, less - 2, div);
DSC(a, great + 2, right, div);
// equal elements
if (dist > len - 13 && pivot1 != pivot2)
{
for (int k = less; k <= great; k++)
{
if (a[k] == pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
else if (a[k] == pivot2)
{
temp = a[k]; a[k] = a[great]; a[great] = temp;
great--;
if (a[k] == pivot1)
{
temp = a[k]; a[k] = a[less]; a[less] = temp;
less++;
}
}
}
}
// subarray
if (pivot1 > pivot2)
{
DSC(a, less, great, div);
}
}
Related
Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}
Basically i built this rudementary tim sort built for a simple project and it works with a sub of 32 all the way up to 1000 integers (the next thing i tried was 5000) and then it crashes with a index out of bounds exeception i tried increasing the sub to 64 but it just dosent seem to work i was wondering if anyone could tell me what im doing wrong here.
public static void timSort(List<Comparable> nums) {
int sub = 32;
for (int i = 0; i < nums.size(); i += sub)
{
if((nums.size() -1) < (i + 31)) {
inPlaceInsertion(nums, i, (nums.size() - 1));
}else {
inPlaceInsertion(nums, i, (i + 31));
}
}
for (int size = sub; size < nums.size(); size = 2 * size)
{
for (int left = 0; left < nums.size(); left += 2 * size)
{
int mid = left + size - 1;
int right;
if((nums.size() - 1) < (left + 2 * size - 1)) {
right = nums.size() -1;
}else {
right = left + 2 * size -1;
}
merge(nums, left, mid, right);
}
}
}
public static void inPlaceInsertion(List<Comparable> nums, int first, int last){
for(int i = first; i <= last; i++){
Comparable hold = nums.get(i);
int j;
steps++;
for(j = i; j > first && hold.compareTo(nums.get(j - 1)) < 0; j--) {
nums.set(j, nums.get(j - 1));
steps+=4;
}
nums.set(j, hold);
steps++;
}
}
private static void merge(List<Comparable> nums, int first, int mid, int last){
List<Comparable> newList = new ArrayList<Comparable>();
int loopCountA = 0;
int loopCountB = 0;
while(true) {
if(loopCountB == (last - mid)) {
while(first + loopCountA <= mid) {
newList.add(nums.get(first + loopCountA)); loopCountA++;
steps++;
}
break;
}else if(first + loopCountA > mid) {
while(loopCountB < (last - mid)) {
newList.add(nums.get(mid + (loopCountB + 1))); loopCountB++;
steps++;
}
break;
}else {
if(nums.get(mid + (loopCountB + 1)).compareTo(nums.get(first + loopCountA)) < 0) {
// here is where error is (line above)
newList.add(nums.get(mid + (loopCountB + 1)));
steps += 5;
loopCountB++;
}else {
newList.add(nums.get(first + loopCountA));
steps += 5;
loopCountA++;
}
}
}
for(int i = 0; (i - 1) < (last - first); i++) {
nums.set(first + i, newList.get(i));
steps+=2;
}
}
Here's the error...
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 5024 out of bounds for length 5000
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:372)
at java.base/java.util.ArrayList.get(ArrayList.java:458)
at Sorts.merge(Sorts.java:772)
at Sorts.timSort(Sorts.java:1193)
at Sorts.sortMenu(Sorts.java:255)
at Sorts.main(Sorts.java:33)
Simple main method which demonstrates it not working
int depthLimit
= (int)(2 * Math.floor(Math.log(nums.size()) /
Math.log(2)));
introSort(nums, 0, nums.size() -1, depthLimit);
I am working on a homework task where I am supposed to make a function that will do a binary insertion sort, but my function does not seem to work properly.
Here I have tried to combine a binary search function with a insertion sort function (it is specified in the homework task that it needs to be in the form of a function: insertionSort(int[] array, int lo, int hi))
public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int x= array[i];
while (lo < hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
pos = lo;
for (int j = i; j > pos; j--) {
array[j] = array[j-1];
}
array[pos] = x;
}
}
If I try to run it with the list {2,5,1,8,3}, the output will be
2 5 1 3 1 (if lo < hi and if lo > hi)
2 5 3 8 5 (if lo==hi)
What I am expecting though, is a sorted list...
Any idea of what I am doing wrong?
Just to give you a possible idea:
public static void insertionSort(int[] array) {
if (array.length <= 1) {
return;
}
// Start with an initially sorted part.
int loSorted = array.length - 1;
//int hiSorted = array.length;
while (loSorted > 0) {
// Take one from the array
int x = array[0];
// Where in the sorted part to insert?
int insertI = insertPosition(array, loSorted);
// Insert x at insertI
...
--loSorted;
}
}
whenever I need binary search, my function looks the following way:
public static void binarySearch(int arr[], int first, int last, int key){
int mid = (first + last)/2;
while( first <= last ){
if ( arr[mid] < key ){
first = mid + 1;
}else if ( arr[mid] == key ){
System.out.println("Element is found at index: " + mid);
break;
}else{
last = mid - 1;
}
mid = (first + last)/2;
}
if ( first > last ){
System.out.println("Element is not found!");
}
}
In your main method the call looks like:
public static void main(String[] args) {
int arr[] = {10,20,30,40,50};
int key = 30;
int last=arr.length-1;
binarySearch(arr,0,last,key);
}
I hope I was able to help you!
Thank you for your input. I changed the function a little bit, and it seems to be working now
` public static void insertionSort(int[] array, int lo, int hi){
int mid;
int pos;
for (int i = 1; i < array.length; i++) {
int j = i -1;
int x = array[i];
while (lo <= hi) {
mid = lo + (hi -lo)/2;
if (x == array[mid]) {
pos = mid;
break;
}
if (x > array[mid]) {
lo = mid+1;
}
else if (x < array[mid]) {
hi = mid-1;
}
}
while (j >= 0 && array[j] > x) {
array[j + 1] = array[j];
j = j - 1;
}
array[j + 1] = x;
}
}
the problem seemed to lay in the last part, where I was trying to move the elements into their right positions. The function is probably not perfect tho, so constructive criticism is welcome :)
I am designing a problem in which I have to use an int array to add or subtract values. For example instead of changing 100 to 101 by adding 1, I want to do the same thing using the int array. It work like this:
int[] val = new int[3];
val[0] = 1;
val[1] = 0;
val[2] = 0;
val[2] += 1;
so, If I have to get a value of 101, I will add 1 to val[2].
The only problem I have is finding a way to make int array work like how adding and subtracting from an ordinary integer data set works.
Is this possible using a for loop or a while loop?
Any help will be appreciated!
Here's your homework:
public static int[] increment(int[] val) {
for (int i = val.length - 1; i >= 0; i--) {
if (++val[i] < 10)
return val;
val[i] = 0;
}
val = new int[val.length + 1];
val[0] = 1;
return val;
}
Make sure you understand how and why it works before submitting it as your own work.
Solution of this problem is designed by using String
You can refer to this method which will return sum of 2 nos having input in String format.
Input String should contain only digits.
class Demo {
public static String add(String a1, String b1) {
int[] a = String_to_int_Array(a1);
int[] b = String_to_int_Array(b1);
int l = a.length - 1;
int m = b.length - 1;
int sum = 0;
int carry = 0;
int rem = 0;
String temp = "";
if (a.length > b.length) {
while (m >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (l >= 0) {
sum = a[l] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
l--;
}
if (carry > 0) {
temp = carry + temp;
}
} else {
while (l >= 0) {
sum = a[l] + b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
l--;
}
while (m >= 0) {
sum = b[m] + carry;
carry = sum / 10;
rem = sum % 10;
temp = rem + temp;
m--;
}
if (carry > 0) {
temp = carry + temp;
}
}
return temp;
}
public static int[] String_to_int_Array(String s) {
int arr[] = new int[s.length()], i;
for (i = 0; i < s.length(); i++)
arr[i] = Character.digit(s.charAt(i), 10);
return arr;
}
public static void main(String a[]) {
System.out.println(add("222", "111"));
}
}
Quick & dirty:
static void increment(int[] array){
int i = array.length-1;
do{
array[i]=(array[i]+1)%10;
}while(array[i--]==0 && i>=0);
}
Note the overflow when incementing e.g. {9, 9}. Result is {0, 0} here.
public static void increment() {
int[] acc = {9,9,9,9};
String s="";
for (int i = 0; i < acc.length; i++)
s += (acc[i] + "");
int i = Integer.parseInt(s);
i++;
System.out.println("\n"+i);
String temp = Integer.toString(i);
int[] newGuess = new int[temp.length()];
for (i = 0; i < temp.length(); i++)
{
newGuess[i] = temp.charAt(i) - '0';
}
printNumbers(newGuess);
}
public static void printNumbers(int[] input) {
for (int i = 0; i < input.length; i++) {
System.out.print(input[i] + ", ");
}
System.out.println("\n");
}
If someone is looking for this solution using JavaScript or if you can translate it to java, here's your optimum solution:
function incrementArr(arr) {
let toBeIncrementedFlag = 1, // carry over logic
i = arr.length - 1;
while (toBeIncrementedFlag) {
if (arr[i] === 9) {
arr[i] = 0; // setting the digit as 0 and using carry over
toBeIncrementedFlag = 1;
} else {
toBeIncrementedFlag = 0;
arr[i] += 1;
break; // Breaking loop once no carry over is left
}
if (i === 0) { // handling case of [9,9] [9,9,9] and so on
arr.unshift(1);
break;
}
i--; // going left to right because of carry over
}
return arr;
}
I'm reviewing algorithm stuff and stuck in a simple quick sort algorithm implementation in java
import java.util.Arrays;
import java.util.Random;
public class QuickSort {
int arr[];
boolean randomPick;
Random rand = null;
public QuickSort(int[] inputArray) {
arr = inputArray;
randomPick = false;
}
public QuickSort(int[] inputArray, boolean random) {
arr = inputArray;
if (random) {
randomPick = true;
rand = new Random(System.currentTimeMillis());
}
else {
randomPick = false;
}
}
public int[] sort() {
int start = 0;
int end = arr.length - 1;
try {
_sort(start, end);
}
catch (StackOverflowError e) {
System.out.println("StackOverflow: " + Arrays.toString(arr));
}
return arr;
}
private void _sort(int start, int end) {
int i = start;
int j = end;
int pivotLoc;
if (!randomPick) {
pivotLoc = (j + i) / 2;
}
else {
pivotLoc = rand.nextInt(j - i) + i;
}
int pivot = arr[pivotLoc];
while (i < j) { // swapping numbers around the pivot
while (arr[i] < pivot) {
i++;
}
while (arr[j] > pivot) {
j--;
}
if (i < j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
i++;
j--;
}
}
if (i - start > 1) {
_sort(start, i);
}
if (end - i > 1) {
_sort(i, end);
}
}
}
The code can either pick the middle number as the pivot or randomly pick a number as the pivot and it sorts the array by calling _sort recurrently. It works in the first case but fails in the second.
The situation is: when it reaches a subarray as this {3,5,5}, i==start==0 and j==end==2. Finally 5 and 5 are swapped, i becomes 2 and j becomes 1 (i++ and j--). Then since i - start>1 it will call _sort over and over and eventually evoke the stackoverflow error. However the error is supposed to happen in the first case (fixed pivot), which hasn't happened so far...
I don't know what's wrong with my code. I know it's not a pleasure to read code written by others but any help?
You've made a small mistake in your recursion condition, both the start and end compares are against i, the start should be against j
You have:
if (i - start > 1) {
_sort(start, i);
}
if (end - i > 1) {
_sort(i, end);
}
Needs to be:
if (j > start) {
_sort(start, j);
}
if (end > i) {
_sort(i, end);
}
And your i and j comparison needs to allow equals:
// here ----v
if (i <= j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
i++;
j--;
}