Dijkstra with a heap. How to update the heap after relaxation? - java

I am trying to implement Dijkstra algorithm.
foreach distance d
d = INFINITY
d[source] = 0
create_heap_based_on_Distances();
while(true)
bestedge = heap[0]
remove_minimum_from_heap //it will be heap[0]
foreach adjacency of bestedge
if (weight + bestedge_distance < current_distance)
{
current_distance = weight + bestedge_distance
// Now I have to update heap, how can I do that?
}
if (heap_empty) break
So, in the relaxation, how can I update the heap, so it would have the correct order? I don't have the heap's index for that node in that step. Does that mean I have to create a new array like nodes[edge] = heapIndex, so I could get a heap's index for that node? But it seems very inefficient as I need then to update insert_to_heap, remove_minimum functions.
C or JAVA code is okay.

Does that mean I have to create a new array like nodes[edge] = heapIndex, so I could get a heap's index for that node?
Yes.
But it seems very inefficient as I need then to update insert_to_heap, remove_minimum functions.
Array updates are very cheap, both in theory and in practice, and you only have to do a few of those per heap operation, so this is not inefficient at all. Also, the memory usage of such an array is very cheap compared to the storage cost of a graph data structure.

Does that mean I have to create a new array like nodes[edge] = heapIndex,
so I could get a heap's index for that node?
I don't what the exactly mean of node[edge]. In my opinion, it should be a Map(a array indeed) f that f[node]=HeapIndex(It gives the index of that node in Heap). Storage of the node[edge] is not efficient.
Then how to implement the MapHeap? I have implemented a efficient MapHeap, but not so much note in the code:
template<class DT>
struct MapHeap
{
DT f[HEAP_SIZE+5];//store the distance
int mp1[HEAP_SIZE+5];//val -> index
// I assume the val is unique.
// In the dijk, the val is the nodeId,so it must be unique.
// mp1[nodeId] gives the index of that node in my heap
int mp2[HEAP_SIZE+5];//index -> val
int nv;// number of node in my heap now
MapHeap():nv(0)
{
memset(mp1,-1,sizeof(mp1));
memset(mp2,-1,sizeof(mp2));
}
void print(int n)
{
for(int i=1;i<=n;i++) printf("%d ",f[i]);
puts("");
for(int i=1;i<=n;i++) printf("%d ",mp1[i]);
puts("");
for(int i=1;i<=n;i++) printf("%d ",mp2[i]);
puts("");
}
void print(){print(nv);}
bool resize(int n)
{
if (nv<0||nv>HEAP_SIZE) return 0;
for(int i=n+1;i<=nv;i++)
{
mp1[mp2[i]]=-1;
mp2[i]=-1;
}
nv=n;
return 1;
}
DT top()//get the smallest element
{
if (nv<1) return DT(-1);
return f[1];
}
DT get(int idx)
{
if (idx<1||idx>nv) return DT(-1);
return f[idx];
}
// it's for unpdating the heap. It should be pravite method.
// Because I write this code for competition, so I just ignore the accsee controling
void movedown(int now,int val,const DT &x)//this node is larger than son
{
for(;now*2<=nv;)
{
int a=now*2;
int b=now*2+1;
if (b<=nv&&f[b]<f[a]) a=b;
if (f[a]>=x) break;
f[now]=f[a];
mp1[mp2[a]]=now;
mp2[now]=mp2[a];
now=a;
}
f[now]=x;
mp1[val]=now;
mp2[now]=val;
}
void moveup(int now,int val,const DT &x)//this node is smaller than father
{
for(;now>1;now>>=1)
{
int par=now>>1;
if (f[par]<=x) break;
f[now]=f[par];
mp1[mp2[par]]=now;
mp2[now]=mp2[par];
}
f[now]=x;
mp1[val]=now;
mp2[now]=val;
}
bool pop(int idx=1)//pop a element, pop the smallest element by default
{
if (idx<1||idx>nv) return 0;
DT &x=f[nv];
int v1=mp2[nv];
int v2=mp2[idx];
mp1[v1]=idx;
mp2[idx]=v1;
mp1[v2]=-1;
mp2[nv]=-1;
nv--;
if (idx!=nv+1) movedown(idx,v1,x);
x=0;
return 1;
}
bool push(const DT &x,int val)//push a node, and with the value of val(in dijk, the val is the nodeId of that node)
{
int now=++nv;
if (now>HEAP_SIZE) return 0;
moveup(now,val,x);
return 1;
}
};

Related

I have an efficient algorithm to find the maximum integer in an array of millions, need advice on these two

Which is better to use for an array of millions of integers(ages)
public static int findMax(int[] x) {
int max = 0;
int curr = 0;
for (int a : x) {
curr = Math.max(curr, a);
max = Math.max(max, curr);
}
return max;
}
public static int findMax(int[] x){
List<Integer> list = new ArrayList<>();
for (int y : x){
list.add(y);
}
return Collections.max(list);
}
The first one will definitely be faster than the second one, as you really don't want to be making an arraylist for no reason just to find the maximum of an array!
Also, there is no reason to use two different variables for the current and the max, just the max will suffice, like so:
public static int findMax(int[] x) {
int max = Integer.MIN_VALUE;
for (int a : x) {
max = Math.max(max, a);
}
return max;
}
Note: I used the minimum integer because the largest value in your array may be negative. Also, you could just use an if-condition instead of Math.max(), but it'll work either way. This also saves you an extra operation. The runtime is O(n) in every case.
They both look like they are O(n). You could always use a logger and see what the time is. The following is a link that talks about logging time executed: How do I time a method's execution in Java?

Given a stream of number, like 1,3,5,4,6,9, I was asked to print them like 1,3-6,9

Given a stream of number, like 1,3,5,4,6,9, I was asked to print them like 1,3-6,9. My approach was to hold min 2 numbers in a maxHeap and max 2 numbers in a minHeap. And I have come up with a following solution. Do you have any suggestion to make it more optimized? Its time complexity is O(nlogn).
public static ArrayList<Integer> mergingMiddleNums (int[] arr){
if (arr == null || arr.length < 3){
throw new IllegalArgumentException();
}
ArrayList<Integer> result = new ArrayList<>();
Queue<Integer> minHeap = new PriorityQueue<>();
Queue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
#Override
public int compare(Integer num1, Integer num2) {
return num2-num1;
}
});
for (int i = 0 ; i < 2 ; i++){
minHeap.add(arr[i]);
}
for (int i = 0 ; i < 2 ; i++){
maxHeap.add(arr[i]);
}
for (int i = 2 ; i <arr.length; i++){
if(arr[i] > minHeap.peek()){
minHeap.poll();
minHeap.add(arr[i]);
}
}
result.add(minHeap.poll());
result.add(minHeap.poll());
for (int i = 2 ; i <arr.length; i++){
if(arr[i] < maxHeap.peek()){
maxHeap.poll();
maxHeap.add(arr[i]);
}
}
result.add(maxHeap.poll());
result.add(maxHeap.poll());
Collections.sort(result);
return result;
}
It depends on whether your output needs to stream or not. Let's start with non-streaming output, because your current implementation addresses this.
Your code's overall complexity will be, at best, O(nLog(n)), but you can radically simplify your implementation by storing every incoming number in a collection, converting it to an array, and sorting it, before scanning over the items sequentially to identify continuous ranges. The most expensive operation here would be the sort, which would define your runtime. To save space, you could use a set or heap collection to avoid storing duplicates (the formation of which will be somewhere near O(nLog(n)) - which being the same runtime, remains collapsed at a total runtime of O(nLog(n))
If your code is expected to stream the printing along with output, that is, to print ranges as they are formed and move to the next range whenever the next number encountered is not directly adjacent to the current range, you can do it in O(n) by storing the numeric bounds of the current range as you go and either printing and resetting them if the currently-examined number is not adjacent or inside the bounds, or by expanding the bounds if it is.
A possible implementation would be to use a hashtable to store wether each integer was present in the input values or not. Then, it's simply a matter of iterating from the min value to the max and use the hashtable to find out where are the number clusters.
Such implementation would basically be O(n) with n=max-min (and not number of items in list). So if you have many numbers within a reasonably small range of values, then you could be better than a sort-based approach.
import java.util.HashMap;
import java.util.Map;
class Test {
private int min=0, max=-1;
private Map<Integer,Integer> map=new HashMap<Integer,Integer>();
public static void main(String args[]) {
int[] input={1,3,5,4,6,9};
Test t = new Test();
t.readNumbers(input);
t.outputRanges();
}
public void readNumbers(int[] values) {
// Get min and max values, and store all existing values in map
for(int v:values) {
if(first || v<min) min=v;
if(first || v>max) max=v;
first=false;
map.put(v, 1);
}
}
public void outputRanges() {
// Iterate from min to max and use map to find out existing
// values
int last=min-2;
boolean inRange=false;
first=true;
for(int i=min;i<=max;++i) {
if(map.get(i)==null) continue;
if(i==last+1) {
inRange=true;
} else {
if(inRange) {
closeRange(last);
inRange=false;
}
output(i);
}
last=i;
}
if(inRange) closeRange(last);
}
private boolean first;
private void commaUnlessFirst() {
if(!first) System.out.printf(",");
first=false;
}
private void output(int i) {
commaUnlessFirst();
System.out.printf("%d", i);
}
private void closeRange(int i) {
System.out.printf("-%d", i);
}
}

Is this a better way for Fibonacci Series with Recursion?

Where ever I see Recursive Fibonacci Series everyone tell that
a[i] = fib(i - 1) + fib( i - 2)
But it can also be solved with
a[i] = fib(i - 1) + a[i-2] // If array 'a' is a global variable.
If array 'a' is a global Variable, then a[i-2] will be calculated when it is calculating for a[i-2];
It can be solved with below program in java..
public class Fibonacci {
public static int maxNumbers = 10;
public static double[] arr = new double[maxNumbers];
public static void main(String args[])
{
arr[0] = 0;
arr[1] = 1;
recur(maxNumbers - 1);
}
public static double recur(int i)
{
if( i > 1)
{
arr[i] = recur(i - 1) + arr[i - 2];
}
return arr[i];
}
}
Further more, complexity is also less when compared with original procedure. Is there any disadvantage of doing this way?
You have done the first step for Dynamic Programming calculation of Fibonacci, idea of DP is to avoid redundant calculations, and your algorithm achieve its goal.
A "classic" Bottom-Up DP Fibonacci implementation is filling the elements from lower to higher:
arr[0] = 0
arr[1] = 1
for (int i = 2; i <= n; i++)
arr[i] = arr[i-1] + arr[i-2]
(Optimization could be storing curr,last alone, and modifying them at each iteration.
Your approach is basically the same in principle.
As a side note, the DP approach to calculate Fibonacci is taking O(n) time, where there is even more efficient solution with exponential of the matrix:
1 1
1 0
The above holds because you use the fact that
1 1 F_{n+1} 1*F{n+1} + 1*F{n} F_{n+2}
* = =
1 0 F_{n} 1*F{n+1} + 0*F{n} F_{n+1}
Using exponent by squaring on the above matrix, this can be solved in O(logn).
If you just want the nth fibonacci number you could do this:
static double fib(double prev, double curr, int n) {
if(n == 0)
return curr;
return fib(curr, prev+curr, n-1);
}
Initial conditions would be prev = 0, curr = 1, n = maxNumbers. This function is tail recursive because you don't need to store the return value of the recursive call for any additional calculations. The initial stack frame gets reused (which saves memory) and once you hit your base case the value that's returned is the same value that would be returned from every other recursive call.
By using an array like you do you only recalculate one of the two branches (the longest one in each iteration) ending up with a O(n) complexity.
If you were to keep track on how large fibonacci number you have caclulated earlier you can use that and produce O(max(n-prevn, 1)). Here is an altered version of your code that fills the array from bottom to i if needed:
public class Fibonacci {
public static final int maxNumbers = 93; // fib(93) > Long.MAX_VALUE
public static long[] arr = new long[maxNumbers];
public static int calculatedN = 0;
public static long fib(int i) throws Exception
{
if( i >= maxNumbers )
throw new Exception("value out of bounds");
if( calculatedN == 0 ) {
arr[0] = 0L;
arr[1] = 1L;
calculatedN = 1;
}
if( i > calculatedN ) {
for( int x=calculatedN+1; x<=i; x++ ){
arr[x] = arr[x-2] + arr[x-1];
}
calculatedN = i;
}
return arr[i];
}
public static void main (String args[]) {
try {
System.out.println(fib(50)); // O(50-2)
System.out.println(fib(30)); // O(1)
System.out.println(fib(92)); // O(92-50)
System.out.println(fib(92)); // O(1)
} catch ( Exception e ) { e.printStackTrace(); }
}
}
I changed double to long. If you need larger fibonacci numbers than fib(92) I would change from long to Biginteger.
You can also code using two recursive function but as the same value is calculating over again and again so all You can do a dynamic programming approach where You can store the value and return it where need.Like this one in C++
#include <bits/stdc++.h>
using namespace std;
int dp[100];
int fib(int n){
if(n <= 1)
return n;
if(dp[n]!= -1)
return dp[n];
dp[n] = fib(n-1) + fib(n-2);
return dp[n];
}
int main(){
memset(dp,-1,sizeof(dp));
for(int i=1 ;i<10 ;i++)
cout<<fib(i)<<endl;
}
This is only step from non recursive version:
https://gist.github.com/vividvilla/4641152
General this partially recursive approach looks incredibly messy

Need help in arrays product output

Consider the following Accumulator class with a missing method
'prodA(int m)'
which is supposed to return the product of all elements of the array A
if such product is less than or equal to m and return m otherwise.
For example if A is the array {2,4,3} then
prodA(2) will return 2
prodA(0) will return 0
prodA(50) will return 24
(Hint: the length of an array A is given by A.length)
Insert the code for the body of the method prodA where
marked.
public class Accumulator {
private int[] A;
public Accumulator(int[] X) {
A= new int[X.length];
for (int i=0; i<X.length; i++)
A[i] = X[i];
}
public int prodA(int m) {
// insert your code here
}
}
You simply multiply the elements of the array A, then check if the sum is smaller than m, if so, you return it, otherwise you return m.
I won't show you a full solution, but computing the multiplication of the elements is extremely easy, you should have an int res = 1; and then multiply it by each element from the array and reassign the result to res (using a loop).
int prod=1;
for(int i:A){
prod=prod*i;
}
if(prod<m)
return prod;
else
return m;
int product=1;
for(int num:A) {
product=product*num;
}
return (product<=m)?product:m;
There are not many things to consider here, but three come to my mind:
How to treat the empty array? I assume that the result should be 1 in this case, as it lends itself by being the neutral element of multiplication
How large is the array? Might it be worth to implement an "early return"? That is, when the array contains 1000000 elements, and you notice that the result of multiplying the first 2 elements already is greater than the limit, you could already return this limit, and not waste time by performing the remaining 999998 multiplications (assuming that the array does not contains zeros!)
How to structure the methods? I think that separating the computation of the product and the computation of the actual result, like return Math.min(limit, product(A)) with an appropriate product method that only has the single responsibility of computing a product of the elements of an array. However, this makes the "early return" impossible.
The "early return" could do something like this:
public int prodA(int m)
{
int product = 1;
for (int i = 0; i < A.length; i++)
{
product *= A[i];
if (product >= m)
{
return m;
}
}
return product;
}
while from a standpoint of reusability, something like this might be nicer:
public int prodA(int m)
{
return Math.min(m, product(A));
}
private static int product(int array[] )
{
int product = 1;
for (int i = 1; i < array.length; i++)
{
product *= array[i];
}
return product;
}
public int prodA(int m) {
int p=1;
for(int i=0;i<A.lenght.i++){
p=p*A[i];
}
if(p<=m)
return p;
else
return m;
}

Merge sort remove duplicates

I am trying to sort an array via merge sort, and while sorting, remove elements that I have deemed equal. I am recursively calling merge sort and then merging.
I get to this point and find that a and c are duplicates.
a b | c d
I determine which one I want based on certain criteria and I pick c. I increment the right hand counter and and the left hand counter and compare b and d. Say I pick d, then I pick b. I want my final list to only have the elements
c d b
However, what is happening is on the next recursive call, start and end are 0 and 3 so d is listed twice in the array on the next call. The array that the merge procedure works with is:
c d b d
Here is the code. Thanks in advance.
private static void merge(int[] data, int start, int mid, int end)
{
int firstCopied=0;
int secondCopied=0;
int index=0;
int length=end-start+1;
int[] temp = new int[end-start+1];
int firstSize=mid-start+1;
int secondSize=end-mid;
while(firstCopied < firstSize && secondCopied < secondSize)
{
if(data[start+firstCopied] < data[mid+1+secondCopied])
{
temp[index++] = data[start+firstCopied];
firstCopied++;
}
else if(data[start+firstCopied] > data[mid+1+secondCopied])
{
temp[index++] = data[mid+1+secondCopied];
secondCopied++;
}
else if(data[start+firstCopied]==data[mid+1+secondCopied])
{
boolean result = PickOne();
if(result)
{
temp[index++] = data[start+firstCopied];
}
else
{
temp[index++] = data[mid+1+secondCopied];
}
firstCopied++;
secondCopied++;
length--;
}
}
while(firstCopied < firstSize)
{
temp[index++] = data[start+firstCopied];
firstCopied++;
}
while(secondCopied < secondSize)
{
temp[index++] = data[mid+1+secondCopied];
secondCopied++;
}
for(int i=0; i<length; i++)
{
data[start+i]=temp[i];
}
}
The philosophy of the C++ Standard Library is to use algorithms that do one thing well. It's best to follow that approach since it will lead to more reusable code.
E.g. here's a mergesort sketch followed by a call to std::unique
template<typename BiDirIt>
void merge_sort(BiDirIt first, BiDirIt last)
{
auto const N = std::distance(first, last);
if (N < 2) return;
// sort each part individually, then merge back in-place
auto middle = first + N / 2;
merge_sort(first, middle);
merge_sort(middle, last);
std::inplace_merge(first, middle, last);
}
int data[] = { /* your data */ };
merge_sort(std::begin(data), std::end(data));
auto it = std::unique(std::begin(data), std::end(data));
for (auto ut = std::begin(data); ut != it; ++ut) {
// process unique data
}
If your data was in a std::vector instead of a C-array, you could call v.erase(v.begin(), it); to actually erase the non-unique data as well.
Your merge conceptually changes the length of the array. But there is no code to actually truncate data. I suggest you return length (instead of void) and use some final postprocessing step to either truncate the data to the final length, or at least avoid printing those past-the-end elements.
Make sure the elements in [start, mid] and [mid + 1, end] is sorted and unique, first.
Otherwise, duplicates will exists after your code run.

Categories

Resources