Java: Breadth-First-Traversal Order Over an Array - java

I wish to iterate over a sorted array in the order that a breadth first traversal would give if I put the array into a binary tree and performed a BFT on that (which is how I currently achieve this). Obviously this involves additional memory overhead since you need to build and store the array again in the binary tree. I know this should be similar to a binary search but I can't quite get the ordering right.
Here's how I currently achieve this:
BTree bst = sortedArrayToBST(array);
Queue<BTree> queue = new LinkedList<BTree>();
queue.add(bst);
while(!queue.isEmpty()) {
BTree node = queue.remove();
System.out.println(node.data);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
Here's what I have currently (but this obviously gives the wrong ordering):
public void bstIterate(int[] array, int start, int end) {
if(array.length == 0) return;
int med = array.length /2;
System.out.println(array[med]);
bstIterate(array,start,mid);
bstIterate(array,mid+1,array.length);
}
Can this be done without extra memory overhead, or do I have to store the items in a stack, vector or queue, and if so, how and would it require less memory than a binary tree?

I'm not sure this is particularly efficient, but one possible solution is to pass a depth parameter to your bstIterate method and call it repeatedly with increasing depth until it returns no more results.
Something like this:
public static boolean bstIterate(int array[], int start, int end, int depth) {
if (end <= start)
return false;
else {
int mid = start + (end-start)/2;
if (depth == 0) {
System.out.println(array[mid]);
return true;
}
else {
boolean res1 = bstIterate(array, start, mid, depth-1);
boolean res2 = bstIterate(array, mid+1, end, depth-1);
return res1 || res2;
}
}
}
which you would call like this:
int depth = 0;
while (bstIterate(array, 0, array.length, depth))
depth++;
Given this array:
int array[] = {1, 3, 4, 7, 9, 13, 18, 23, 25, 30};
that produces this tree:
13
4 25
3 9 23 30
1 7 18
and this output:
13
4
25
3
9
23
30
1
7
18
Is that what you had in mind?

I hope your sortedArrayToBST method is building a balanced binary tree from the given array. In that case the method you tried to implement will mimic a DFS (Depth first search) iteration over a BST. But your implementation is buggy, a correct implementation will look like this:
void bstIterate(int[] array, int start, int end) {
if (start > end) return;
int mid = start + (end - start) / 2; //it should not be array.lenght/2 because we are not updating the array at any point
bstIterate(array, start, mid-1); // mid is already printed so we no longer need it
bstIterate(array, mid+1, end);
}
//Now Call the method from you main
bstIterate(array, 0, array.length-1); //it should be array.length-1, as it is the last index of last element of the array
But from the question title I understand you are looking for BFS traversal over a sorted array by assuming the array as balanced binary tree.
Lets say our sorted array is this {1, 2, 3, 4, 5, 6, 7}. In that case a balanced BST will look like this:
4
/ \
2 6
/ \ / \
1 3 5 7
The BFS traversal on the above tree should output as follows: 4 2 6 1 3 5 7
I wrote a quick C++ implementation for this which will do the job in O(n) complexity (hope you can easily convert it to java):
#include <stdio.h>
#include <queue>
using namespace std;
class Node {
public:
int start;
int end;
};
void BFSiterate(int *arr, int start, int end) {
queue<Node>que;
Node n;
n.start = start;
n.end = end;
que.push(n);
while(!que.empty()) {
n = que.front();
que.pop();
int mid = n.start + (n.end - n.start) / 2;
printf("%d\n", arr[mid]);
Node x;
x.start = n.start;
x.end = mid-1;
if (x.start<=x.end)
que.push(x); //left
x.start = mid+1;
x.end = n.end;
if (x.start<=x.end)
que.push(x); //right
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7};
int len = sizeof(arr)/4;
BFSiterate(arr, 0, len-1);
return 0;
}

Related

Recursion stackoverflow Java

I need to count the number of numbers on the right that are less than the number arr[i]. My problem is that the stack overflows at large sizes and I can't solve it in any way. Please tell me how can I refactor my code to avoid the error StackOverflow ?
public class Smaller {
public static int[] smaller(int[] unsorted) {
int[] result = new int[unsorted.length];
for (int i = 0; i < unsorted.length; i++) {
result[i] = countSmaller(unsorted[i], 0, i + 1, unsorted);
}
return result;
}
private static int countSmaller(int currentNumber, int count, int index, int[] arr) {
if (index >= arr.length) {
return count;
}
return arr[index] < currentNumber
? countSmaller(currentNumber, count + 1, index + 1, arr)
: countSmaller(currentNumber, count, index + 1, arr);
}
}
I agree with comments questioning whether recursion is your best solution here, but if it's a requirement you can avoid stack overflow by chopping subproblems in half rather than whittling them down one-by-one. The logic is that the count in the remaining data will be the sum of the count in the first half plus the count in the second half of the remaining data. This reduces the stack growth from O(n) to O(log n).
I originally did a Python implementation due to not having a Java compiler installed (plus my Java skills being rusty), but found an online java compiler at tutorialspoint.com. Here's an implementation of the divide and conquer logic described in the previous paragraph:
public class Smaller {
public static int[] smaller(int[] unsorted) {
int[] result = new int[unsorted.length];
for (int i = 0; i < unsorted.length; i++) {
result[i] = countSmaller(unsorted[i], i+1, unsorted.length-1, unsorted);
}
return result;
}
private static int countSmaller(int threshold, int start, int end, int[] unsorted) {
if (start < end) {
int mid = start + (end - start) / 2;
int count = countSmaller(threshold, start, mid, unsorted);
count += countSmaller(threshold, mid+1, end, unsorted);
return count;
} else if ((start == end) && (unsorted[start] < threshold)) {
return 1;
}
return 0;
}
}
With O(log n) stack growth, this should be able to handle ridonculously big arrays. Since the algorithm as a whole is O(n2), run time will limit you long before recursive stack limitations will.
Original Python Implementation
Sorry for showing this in Python, but I don't have a Java compiler and I didn't want to risk non-functioning code. The following does the trick and should be easy for you to translate:
def smaller(unsorted):
result = []
for i in range(len(unsorted)):
result.append(countSmaller(unsorted[i], i+1, len(unsorted)-1, unsorted))
return result
def countSmaller(threshold, start, end, unsorted):
if start < end:
mid = start + (end - start) // 2 # double slash is integer division
count = countSmaller(threshold, start, mid, unsorted)
count += countSmaller(threshold, mid+1, end, unsorted)
return count
elif start == end and unsorted[start] < threshold:
return 1
return 0
data = [10, 9, 8, 11, 7, 6]
print(smaller(data)) # [4, 3, 2, 2, 1, 0]
print(smaller([])) # []
print(smaller([42])) # [0]

Java code for getting count in the sorted ArrayList for particular range

Need to find the count of the elements in the sorted ArrayList from the given range(x,y). And the count should have count of range elements also if it is in ArrayList.
So for, I have done this by traversing the whole list and getting the count.
Pseudo-code:
count = 0;
for (i=0; i<length(list); i++)
{
if (list[i]>= startrange and list[i]<=endrange)
{
count = count+1;
}
}
Current solution is taking more time because input array size is more than 1000000. Help me to optimize the solution.
Example:
Input array looks like this [1,4,5,8,9,12,16,19,23,26,28,29,30,31,33,35,37].
Input range: (12,30)
Output should be like 8
You said Need to find the count of the elements in the sorted ArrayList from the given range(x,y).
So, you can make use of binary search to make your code efficient.
In binary search, we first have 2 pointers, say low and high. Now, we start our search from middle element in this range. If the middle element is smaller than required one, we move to the right side of the range (mid + 1,high), else we move to the left side of the range (low,mid-1).
In this particular case, we have to do 2 binary searches. Let's take (12,30)as an example. One is to find the lowest index which has 12 and another binary search to find the highest index which has 30. Answer for this query would be highestIndex - lowestIndex + 1.
Snippet:
public class Main{
public static void main(String[] args) {
int[] arr = {1,4,5,8,9,12,16,19,23,26,28,29,30,31,33,35,37};
int[][] queries = {
{12,30},
{-1,37},
{1,49}
};
for(int[] q : queries){
System.out.println(binarySearch(arr,q[0],q[1]));
}
}
private static int binarySearch(int[] arr,int low,int high){
return highestIndex(arr,high) - lowestIndex(arr,low) + 1; // + 1 because of 0-based indexing
}
private static int highestIndex(int[] arr,int num){
int low = 0 , high = arr.length - 1;
while(low <= high){
int mid = low + (high - low) / 2; // (or (low + high)/2, as it doesn't matter in this context
if(arr[mid] <= num) low = mid + 1;
else high = mid - 1;
}
return high;
}
private static int lowestIndex(int[] arr,int num){
int low = 0 , high = arr.length - 1;
while(low <= high){
int mid = low + (high - low) / 2; // (or (low + high)/2, as it doesn't matter in this context
if(arr[mid] >= num) high = mid - 1;
else low = mid + 1;
}
return low;
}
}
Demo: https://onlinegdb.com/BJ4g3AXXL
Space Complexity of above code is O(1).
Time complexity of above code is O(Q * (log(N) + log(N))) ~ O(Q * 2 * log(N)) ~ O(Q * log(N)) asymptotically where Q is number of queries and N is size of the array.
Following Java 8 Stream one-liner will work fine & return the result as expected without using cumbersome for-loop .
int[] xyz = { 1, 4, 5, 8, 9, 12, 16, 19, 23, 26, 28, 29, 30, 31, 33, 35, 37 };
long elementCountWithinRange = Arrays.stream(xyz).filter(x -> (x > 12 && x <= 31)).count();
System.out.println(elementCountWithinRange); // will return 8
Note : Earlier similar answer given by #Gaurav Dhiman is incorrect as the expression won't compile as count() method returns a long and not an int . Also , even if you resolve that it will give below error :
The operator >= is undefined for the argument type(s) int[], int
To resolve that i have used Arrays.stream() instead of Stream.of() to create a Stream .
int cnt=Stream.of(arr).filter(o->(o>=12&& o<=30)).count();

Using binary search to count number of elements smaller/larger than a given number

Given a number current, find the number of values in an array which are larger and smaller than that value.
//sort array for binary search
int[] digits = Arrays.stream(sc.nextLine()
.split(" "))
.mapToInt(Integer::parseInt)
.sorted()
.toArray();
//for duplicate values, find higher index of current.
while(low <= high){
int mid = low + (high - low)/2;
if(digits[mid] > current){
high = mid - 1;
}else if (digits[mid] == current){
startindex = mid;
high = mid - 1;
}else{
startindex = mid;
low = mid +1;
}
}
//for duplicate values, find lower index of current.
int endindex = -1;
low = 0;
high = no_digits - 1;
while(low <= high){
int mid = low + (high - low)/2;
if(digits[mid] > current){
high = mid - 1;
}else if (digits[mid] == current){
endindex = mid;
low = mid + 1;
}else{
endindex = mid;
low = mid + 1;
}
}
System.out.println(endindex + "-" + startindex);
if(digits[0] > current){
smallest = 0;
largest = no_digits;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
} else if (digits[no_digits - 1] < current){
smallest = no_digits;
largest = 0;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
}else {
smallest = startindex;
largest = no_digits - endindex - 1;
System.out.println(String.format("Smaller: %d, Greater: %d", smallest, largest));
}
}
}
Sample input:
5 8 7 2 4 3 7 9 1 9 - Array of ints.
7
0
100
3
6
Output:
Smaller: 5, Greater: 3
Smaller: 0, Greater: 10
Smaller: 10, Greater: 0
Smaller: 2, Greater: 7
Smaller: 5, Greater: 5
My results:
6-5 //start and end index.
Smaller: 5, Greater: 3
-1--1
Smaller: 0, Greater: 10
9-9
Smaller: 10, Greater: 0
2-2
Smaller: 2, Greater: 7
4-4
Smaller: 5, Greater: 4
I managed to come out with the above algorithm which accounts for values larger or lower than any value in the array.
However, I am unable to find a solution to account for values that are nonexistent in the array without iterating though the array since I need to accomplish the above in O((N+Q) log N) time.
In this case, this would be the last test case where the value is 6. 6 does not exist in the array but I will still need to count all values higher/lower than 6.
Binary search algorithm produces the "insertion point" for values that do not exist in the array. Your startIndex and endIndex would give you the first "eligible" item, or the one right next to it. In other words, if you are looking for all values less than 6, the search for endpoint would yield the index of 5.
Note that you don't need to roll your own binary search algorithm: Java provides an implementation for you.
Reference: Arrays.binarySearch
EDIT The question has been edited, now it contains an additional requirement that the algorithm should work fast for multiple queries, more precisely: the overall runtime should be O((N + Q) * log(N)) where N is the size of the array and Q is the number of queries.
The approach below works only for Q = 1.
I don't see any reason not to do it in linear O(N) time.
// get this from scanner
int number = 5;
int[] array = {6, 2, 7, 4, 1, 42};
// the "algorithm"
int numLessThan = 0;
int numGreaterThan = 0;
for (int i: array) {
if (i < number) numLessThan++;
if (i > number) numGreaterThan++;
}
System.out.println(
"Num greater than: " + numGreaterThan + " " +
"Num less than: " + numLessThan
);
Output:
Num greater than: 3 Num less than: 3
If you insist on doing it with streams:
long numLessThan = Arrays.stream(array).filter(x -> x < number).count();
long numGreaterThan = Arrays.stream(array).filter(x -> x > number).count();
Even though it traverses the array twice, it is still O(N).
Since you use a Stream anyway, with a map-call no less, you're iterating the whole array anyway.
So just do
class Counters {
AtomicInteger smaller = new AtomicInteger(0);
AtomicInteger larger = new AtomicInteger(0);
private final int upperLimit;
private final int lowerLimit;
public Counters(int up, int down) {
upperLimit = up;
lowerLimit = down;
}
public void consider(int value) {
if (value > upperLimit) larger.incrementAndGet();
if (value < lowerLimit) smaller.incrementAndGet();
}
public int getSmaller() { return smaller.get(); }
public int getLarger() { return larger.get(); }
}
Counters c = new Counters(upper, lower);
IntStream.of(yourValues).parallel().forEach(c::consider);
// your output here
System.out.printf("Smaller: %d - Larger: %d", c.getSmaller(), c.getLarger());
or a more generic version
class MatchCounter<T> {
AtomicInteger count = new AtomicInteger(0);
private final Predicate<T> match;
public MatchCounter(Predicate<T> m) { match = m; }
public void consider(T value) {
if (m.test(value)) { count.incrementAndGet(); }
}
public int getCount() { return count.get(); }
}
MatchCounter<Integer> smaller = new MatchCounter<>(i -> i < lower);
MatchCounter<Integer> larger = new MatchCounter<>(i -> i > upper);
Consumer<Integer> exec = smaller::consider;
Stream.of(yourArray).parallel().forEach(exec.andThen(larger::consider));
System.out.printf("Smaller: %d - Larger: %d", smaller.getCount(), larger.getCount());
See Arrays which would come handy here.
void stats(int[] a, int sought) {
a = Arrays.copyOf(a, a.length);
Arrays.sort(a);
int index = Arrays.binarySearch(a, sought);
int smaller, larger;
if (index < 0) {
// Not found.
index = ~index; // Insertion position.
smaller = index;
larger = index:
} else {
// Found.
smaller = index;
while (smaller > 0 && a[smaller] == sought) {
--smaller;
}
while (index <= 0 && a[index] == sought) {
++index;
}
}
larger = a.length - index;
int equals = index - smaller;
System.out.printf("Smaller %d, equal %d, larger %d.%n",
smaller, equals, larger);
}
As you see, when finding an element, it would suffice to loop back O(N) which is less than sorting O(N log N).
Faster - O(log N) instead of O(N) for that part - would be if one could do a binary search on sought - 0.5 and sought + 0.5.
void stats(int[] a, int sought) {
a = Arrays.copyOf(a, a.length);
for (int i = 0; i < a.length; ++i) {
a[i] *= 2;
}
Arrays.sort(a);
int smallerI = Arrays.binarySearch(a, 2 * sought - 1);
int largerI = Arrays.binarySearch(a, 2 * sought + 1);
int smaller = ~smallerI;
int larger = a.length - ~largerI;
int equals = ~largerI - ~smallerI;
System.out.printf("Smaller %d, equal %d, larger %d.%n",
smaller, equals, larger);
}
This uses doubled integers, which has the drawback that the valid domain of array values is halved.
In your case your own binary search algorithm should opt for this latter case (without doubling), using an implicit sought + 0.5, never finding, looking for an insertion position.
Okay, so after your edit you state you want to run several queries over the same array so preparation time is less important.
To do that, build a red-black tree from the array; that will give you a sorted structure that allows a search in O(log N).
So what you do for the "smaller" count is go to the left until you find a node with a value equal or larger than the lower limit; count all left children of that. Analogue for the larger (go to the right, find equal or smaller, count to the right).
It won't matter if the item is not present in the array because you're looking for an "equal-or-larger" so if e.g. 6 is not present but you find a 5, you'll count from there - only you add 1 to the count.
You just have to filter and then count occurences. For example :
public static void main(String[] args) {
int[] values = {5, 8, 7, 2, 4, 3, 7, 9, 1, 9};
printCount(values, 7);
printCount(values, 0);
printCount(values, 100);
printCount(values, 3);
printCount(values, 6);
}
private static void printCount(int[] values, int value) {
long smallerCount = Arrays.stream(values).filter(v -> v < value).count();
long largerCount = Arrays.stream(values).filter(v -> v > value).count();
System.out.println(String.format("Smaller : %d, Larger: %d", smallerCount, largerCount));
}

Algorithm to find the narrowest intervals, m of which will cover a set of numbers

Let's say you have a list of n numbers. You are allowed to choose m integers (lets call the integer a). For each integer a, delete every number that is within the inclusive range [a - x, a + x], where x is a number. What is the minimum value of x that can get the list cleared?
For example, if your list of numbers was
1 3 8 10 18 20 25
and m = 2, the answer would be x = 5.
You could pick the two integers 5 and 20. This would clear the list because it deletes every number in between [5-5, 5+5] and [20-5, 20+5].
How would I solve this? I think the solution may be related to dynamic programming. I do not want a brute force method solution.
Code would be really helpful, preferably in Java or C++ or C.
Hints
Suppose you had the list
1 3 8 10 18 20 25
and wanted to find how many groups would be needed to cover the set if x was equal to 2.
You could solve this in a greedy way by choosing the first integer to be 1+x (1 is the smallest number in the list). This would cover all elements up to 1+x+x=5. Then simply repeat this process until all numbers are covered.
So in this case, the next uncovered number is 8, so we would choose 8+x=10 and cover all numbers up to 10+x=12 in the second group.
Similarly, the third group would cover [18,24] and the fourth group would cover [25,29].
This value of x needed 4 groups. This is too many, so we need to increase x and try again.
You can use bisection to identify the smallest value of x that does cover all the numbers in m groups.
A recursive solution:
First, you need an estimation, you can split in m groups, then estimated(x) must be ~ (greather - lower element) / 2*m. the estimated(x) could be a solution. If there is a better solution, It has lower x than extimated(x) in all groups! and You can check it with the first group and then repeat recursively. The problem is decreasing until you have only a group: the last one, You know if your new solution is better or not, If there'is better, you can use it to discard another worse solution.
private static int estimate(int[] n, int m, int begin, int end) {
return (((n[end - 1] - n[begin]) / m) + 1 )/2;
}
private static int calculate(int[] n, int m, int begin, int end, int estimatedX){
if (m == 1){
return estimate(n, 1, begin, end);
} else {
int bestX = estimatedX;
for (int i = begin + 1; i <= end + 1 - m; i++) {
// It split the problem:
int firstGroupX = estimate(n, 1, begin, i);
if (firstGroupX < bestX){
bestX = Math.min(bestX, Math.max(firstGroupX, calculate(n, m-1, i, end, bestX)));
} else {
i = end;
}
}
return bestX;
}
}
public static void main(String[] args) {
int[] n = {1, 3, 8, 10, 18, 20, 25};
int m = 2;
Arrays.sort(n);
System.out.println(calculate(n, m, 0, n.length, estimate(n, m, 0, n.length)));
}
EDIT:
Long numbers version: Main idea, It search for "islands" of distances and split the problem into different islands. like divide and conquer, It distribute 'm' into islands.
private static long estimate(long[] n, long m, int begin, int end) {
return (((n[end - 1] - n[begin]) / m) + 1) / 2;
}
private static long calculate(long[] n, long m, int begin, int end, long estimatedX) {
if (m == 1) {
return estimate(n, 1, begin, end);
} else {
long bestX = estimatedX;
for (int i = begin + 1; i <= end + 1 - m; i++) {
long firstGroupX = estimate(n, 1, begin, i);
if (firstGroupX < bestX) {
bestX = Math.min(bestX, Math.max(firstGroupX, calculate(n, m - 1, i, end, bestX)));
} else {
i = end;
}
}
return bestX;
}
}
private static long solver(long[] n, long m, int begin, int end) {
long estimate = estimate(n, m, begin, end);
PriorityQueue<long[]> islands = new PriorityQueue<>((p0, p1) -> Long.compare(p1[0], p0[0]));
int islandBegin = begin;
for (int i = islandBegin; i < end -1; i++) {
if (n[i + 1] - n[i] > estimate) {
long estimatedIsland = estimate(n, 1, islandBegin, i+1);
islands.add(new long[]{estimatedIsland, islandBegin, i, 1});
islandBegin = i+1;
}
}
long estimatedIsland = estimate(n, 1, islandBegin, end);
islands.add(new long[]{estimatedIsland, islandBegin, end, 1});
long result;
if (islands.isEmpty() || m < islands.size()) {
result = calculate(n, m, begin, end, estimate);
} else {
long mFree = m - islands.size();
while (mFree > 0) {
long[] island = islands.poll();
island[3]++;
island[0] = solver(n, island[3], (int) island[1], (int) island[2]);
islands.add(island);
mFree--;
}
result = islands.poll()[0];
}
return result;
}
public static void main(String[] args) {
long[] n = new long[63];
for (int i = 1; i < n.length; i++) {
n[i] = 2*n[i-1]+1;
}
long m = 32;
Arrays.sort(n);
System.out.println(solver(n, m, 0, n.length));
}
An effective algorithm can be(assuming list is sorted) ->
We can think of list as groups of 'm' integers.
Now for each group calculate 'last_element - first_element+1', and store maximum of this value in a variable say, 'ans'.
Now the value of 'x' is 'ans/2'.
I hope its pretty clear how this algorithm works.
I think it's similarly problem of clusterization. For example You may use k-means clustering algorithm: do partitions of initial list on m classes and for x get maximum size divided by two of obtained classes.
1) You should look into BEST CASE, AVERAGE CASE and WORST CASE complexities with regards to TIME and SPACE complexities of algorithms.
2) I think David PĂ©rez Cabrera has the right idea. Let's assume average case (as in the following pseudo code)
3) Let the list of integers be denoted by l
keepGoing = true
min_x = ceiling(l[size-1]-l[0])/(2m)
while(keepGoing)
{
l2 = l.copy
min_x = min_x-1
mcounter = 1
while(mcounter <= m)
{
firstElement = l2[0]
// This while condition will likely result in an ArrayOutOfBoundsException
// It's easy to fix this.
while(l2[0] <= firstElement+2*min_x)
{ remove(l2[0]) }
mcounter = mcounter+1
}
if(l2.size>0)
keepGoing = false
}
return min_x+1
4) Consider
l = {1, 2, 3, 4, 5, 6, 7}, m=2 (gives x=2)
l = {1, 10, 100, 1000, 10000, 100000, 1000000}, m=2
l = {1, 10, 100, 1000, 10000, 100000, 1000000}, m=3

Recursive brute force maze solver Java

In an attempt to write a brute force maze solving C program, I've written this java program first to test an idea. I'm very new to C and intend to convert it after getting this right in java. As a result, I'm trying stick away from arraylists, fancy libraries, and such to make it easier to convert to C. The program needs to generate a single width path of shortest steps to solve a maze. I think my problem may be in fragmenting a path-storing array passed through each recursion. Thanks for looking at this. -Joe
maze:
1 3 3 3 3
3 3 3 3 3
3 0 0 0 3
3 0 3 3 3
0 3 3 3 2
Same maze solved by this program:
4 4 4 4 4
4 4 4 4 4
4 0 0 0 4
3 0 3 3 4
0 3 3 3 2
number notation are explained in code
public class javamaze {
static storage[] best_path;
static int best_count;
static storage[] path;
//the maze - 1 = start; 2 = finish; 3 = open path
static int maze[][] = {{1, 3, 3, 3, 3},
{3, 3, 3, 3, 3},
{0, 0, 0, 0, 3},
{0, 0, 3, 3, 3},
{3, 3, 3, 3, 2}};
public static void main(String[] args) {
int count1;
int count2;
//declares variables used in the solve method
best_count = 0;
storage[] path = new storage[10000];
best_path = new storage[10000];
int path_count = 0;
System.out.println("Here is the maze:");
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
System.out.print(maze[count1][count2] + " ");
}
System.out.println("");
}
//solves the maze
solve(findStart()/5, findStart()%5, path, path_count);
//assigns an int 4 path to the maze to visually represent the shortest path
for(int count = 0; count <= best_path.length - 1; count++)
if (best_path[count] != null)
maze[best_path[count].getx()][best_path[count].gety()] = 4;
System.out.print("Here is the solved maze\n");
//prints the solved maze
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++){
System.out.print(maze[count1][count2] + " ");
}
System.out.print("\n");
}
}
//finds maze start marked by int 1 - this works perfectly and isn't related to the problem
public static int findStart() {
int count1, count2;
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
if (maze[count1][count2] == 1)
return (count1 * 5 + count2);
}
}
return -1;
}
//saves path coordinate values into a new array
public static void save_storage(storage[] old_storage) {
int count;
for(count = 0; count < old_storage.length; count++) {
best_path[count] = old_storage[count];
}
}
//solves the maze
public static Boolean solve(int x, int y, storage[] path, int path_count) {
//checks to see if grid squares are valid (3 = open path; 0 = wall
if (x < 0 || x > 4) { //array grid is a 5 by 5
//System.out.println("found row end returning false");
return false;
}
if (y < 0 || y > 4) {
//System.out.println("Found col end returning false");
return false;
}
//when finding finish - records the number of moves in static int best_count
if (maze[x][y] == 2) {
if (best_count == 0 || best_count > path_count) {
System.out.println("Found end with this many moves: " + path_count);
best_count = path_count;
save_storage(path); //copies path counting array into a new static array
}
}
//returns false if it hits a wall
if (maze[x][y] == 0)
return false;
//checks with previously crossed paths to prevent an unnecessary repeat in steps
for(storage i: path)
if (i != null)
if (i.getx() == x && i.gety() == y)
return false;
//saves current recursive x, y (row, col) coordinates into a storage object which is then added to an array.
//this array is supposed to fragment per each recursion which doesn't seem to - this may be the issue
storage storespoints = new storage(x, y);
path[path_count] = storespoints;
//recurses up, down, right, left
if (solve((x-1), y, path, path_count++) == true || solve((x+1), y, path, path_count++) == true ||
solve(x, (y+1), path, path_count++) == true || solve(x, (y-1), path, path_count++) == true) {
return true;
}
return false;
}
}
//stores (x, y) aka row, col coordinate points
class storage {
private int x;
private int y;
public storage(int x, int y) {
this.x = x;
this.y = y;
}
public int getx() {
return x;
}
public int gety() {
return y;
}
public String toString() {
return ("storage coordinate: " + x + ", " + y + "-------");
}
}
This wasn't originally intended to be an answer but it sort of evolved into one. Honestly, I think starting in Java and moving to C is a bad idea because the two languages are really nothing alike, and you won't be doing yourself any favors because you will run into serious issues porting it if you rely on any features java has that C doesn't (i.e. most of them)
That said, I'll sketch out some algorithmic C stuff.
Support Structures
typedef
struct Node
{
int x, y;
// x and y are array indices
}
Node;
typedef
struct Path
{
int maxlen, head;
Node * path;
// maxlen is size of path, head is the index of the current node
// path is the pointer to the node array
}
Path;
int node_compare(Node * n1, Node * n2); // returns true if nodes are equal, else false
void path_setup(Path * p, Node * n); // allocates Path.path and sets first node
void path_embiggen(Path * p); // use realloc to make path bigger in case it fills up
int path_toosmall(Path * p); // returns true if the path needs to be reallocated to add more nodes
Node * path_head(Path * p); // returns the head node of the path
void path_push(Path * p, Node * n); // pushes a new head node onto the path
void path_pop(Path * p); // pops a node from path
You might to change your maze format into an adjacency list sort of thing. You could store each node as a mask detailing which nodes you can travel to from the node.
Maze Format
const int // these constants indicate which directions of travel are possible from a node
N = (1 << 0), // travel NORTH from node is possible
S = (1 << 1), // travel SOUTH from node is possible
E = (1 << 2), // travel EAST from node is possible
W = (1 << 3), // travel WEST from node is possible
NUM_DIRECTIONS = 4; // number of directions (might not be 4. no reason it has to be)
const int
START = (1 << 4), // starting node
FINISH = (1 << 5); // finishing node
const int
MAZE_X = 4, // maze dimensions
MAZE_Y = 4;
int maze[MAZE_X][MAZE_Y] =
{
{E, S|E|W, S|E|W, S|W },
{S|FINISH, N|S, N|START, N|S },
{N|S, N|E, S|E|W, N|S|W },
{N|E, E|W, N|W, N }
};
Node start = {1, 2}; // position of start node
Node finish = {1, 0}; // position of end node
My maze is different from yours: the two formats don't quite map to each other 1:1. For example, your format allows finer movement, but mine allows one-way paths.
Note that your format explicitly positions walls. With my format, walls are conceptually located anywhere where a path is not possible. The maze I created has 3 horizontal walls and 5 vertical ones (and is also enclosed, i.e. there is a continuous wall surrounding the whole maze)
For your brute force traversal, I would use a depth first search. You can map flags to directions in a number of ways, like maybe the following. Since you are looping over each one anyway, access times are irrelevant so an array and not some sort of faster associative container will be sufficient.
Data Format to Offset Mappings
// map directions to array offsets
// format is [flag], [x offset], [y offset]
int mappings[][] =
{
{N, -1, 0},
{S, 1, 0},
{E, 0, 1},
{W, 0, -1}
}
Finally, your search. You could implement it iteratively or recursively. My example uses recursion.
Search Algorithm Pseudocode
int search_for_path(int ** maze, char ** visited, Path * path)
{
Node * head = path_head(path);
Node temp;
int i;
if (node_compare(head, &finish)) return 1; // found finish
if (visited[head->x][head->y]) return 0; // don't traverse again, that's pointless
visited[head->x][head->y] = 1;
if (path_toosmall(path)) path_embiggen(path);
for (i = 0; i < NUM_DIRECTIONS; ++i)
{
if (maze[head->x][head->y] & mappings[i][0]) // path in this direction
{
temp = {head->x + mappings[i][1], head->y + mappings[i][2]};
path_push(path, &temp);
if (search_for_path(maze, visited, path)) return 1; // something found end
path_pop(path);
}
}
return 0; // unable to find path from any unvisited neighbor
}
To call this function, you should set everything up like this:
Calling The Solver
// we already have the maze
// int maze[MAZE_X][MAZE_Y] = {...};
// make a visited list, set to all 0 (unvisited)
int visited[MAZE_X][MAZE_Y] =
{
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
// setup the path
Path p;
path_setup(&p, &start);
if (search_for_path(maze, visited, &path))
{
// succeeded, path contains the list of nodes containing coordinates from start to end
}
else
{
// maze was impossible
}
It's worth noting that because I wrote this all in the edit box, I haven't tested any of it. It probably won't work on the first try and might take a little fiddling. For example, unless start and finish are declared globally, there will be a few issues. It would be better to pass the target node to the search function instead of using a global variable.

Categories

Resources