Related
I am new to programming and today I wanted to try out the LeetCode problem 234. Palindrome Linked List:
Given the head of a singly linked list, return true if it is a palindrome or false otherwise.
Example 1:
Input: head = [1,2,2,1]
Output: true
but I couldn't even manage the first problem.
I first tried to convert the linked list to a string and compare like:
String[i] == String[length-i-1]
which worked for small lists but not for the gigantic test list where I got:
Time Limit Exceeded
In my second attempt I used recursion like this:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode? next;
* ListNode([this.val = 0, this.next]);
* }
*/
class Solution {
bool isPalindrome(ListNode? head) {
ListNode? current = head;
while(current?.next != null)
current = current?.next;
if (current?.val != head?.val)
return false;
else{
current = null;
isPalindrome(head?.next);
}
return true;
}
}
This also works with small lists, but for the test list I get a run time error:
Stack overflow
I wonder where this issue comes from.
Is it due to the maximum number of nested calls? And where can I find the recursion depth of Dart?
Or is there just a way simpler solution for this?
There are several issues with your attempt:
current = null will only set that variable to null. It does not affect the list. If you want to remove the last element from the list, you'll need access to the node that precedes it, and set its next property to null.
The boolean that the recursive call returns is always ignore. Instead execution continues with the return true statement, which will lead to incorrect results (when false was expected).
Before mentioning another problem, here is the correction for your algorithm:
bool isPalindrome(ListNode? head) {
ListNode? current = head;
ListNode? prev = null;
while(current?.next != null) {
prev = current; // follow behind current
current = current?.next;
}
if (current?.val != head?.val)
return false;
else if (prev == null)
return true; // List has only one node
else {
prev?.next = null; // Detach the tail node
return isPalindrome(head?.next); // Return the recursive result!
}
}
This will do the job correctly, but it is too slow. At every level of recursion almost all of the same nodes are iterated again (with that while loop), so for a list with 100 nodes, there are 100+98+96+94+...+2 iterations. In other words, the time complexity of this algorithm is quadratic. You'll need a different idea for the algorithm.
One idea for an efficient algorithm that doesn't require extra O(n) space, is to:
find the middle node of the list. You can for instance first determine the length of the list with a first iteration, and then in a second iteration you can stop half way.
reverse the second half of the list, giving you two shorter lists. Here you could use recursion if you wanted to.
and then compare those two lists node by node.
There are several Q&A on this algorithm, also on this site, so I'll leave that for your further research.
If you cannot make it work, here is a solution (spoiler!):
class Solution {
int listSize(ListNode? head) {
int size = 0;
while(head?.next != null) {
head = head?.next;
size++;
}
return size;
}
ListNode? nodeAt(ListNode? head, int index) {
while(head?.next != null && index > 0) {
head = head?.next;
index--;
}
return index == 0 ? head : null;
}
ListNode? reverse(ListNode? head) {
ListNode? prev = null;
ListNode? next;
while (head != null) {
next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
bool isEqual(ListNode? head1, ListNode? head2) {
// Only compares the nodes that both lists have:
while (head1 != null && head2 != null) {
if (head1.val != head2.val) return false;
head1 = head1.next;
head2 = head2.next;
}
return true;
}
bool isPalindrome(ListNode? head) {
return isEqual(head, reverse(nodeAt(head, listSize(head) >> 1)));
}
}
I can't quite understand your recursion solution without pointers. I solved it using a list. It is not the best solution but is simple.
// Definition for singly-linked list.
// class ListNode {
// int val;
// ListNode? next;
// ListNode([this.val = 0, this.next]);
// }
class Solution {
bool isPalindrome(ListNode? head) {
List<int> stack = [];
ListNode? p = head;
while (p != null) {
stack.add(p.val);
p = p.next;
}
print(stack);
bool isP = true;
while(head!.next!=null&&isP){
var a = stack.removeLast();
print('removed $a');
print('head val ${head.val}');
isP = head.val==a;
head=head.next!;
}
return isP;
}
}
The problem with your solution is
After a while loop current is rightmost node in the list
while (current?.next != null) {
current = current?.next;
}
comparing leftmost and rightmost node of LinkedList
if (current?.val != head?.val)
return false;
Start over with head shifted one place to the right
else {
current = null;
isPalindrome(head?.next);
}
But current is still rightmost node after a while loop
while (current?.next != null) {
current = current?.next;
}
And this will return false
if (current?.val != head?.val)
{
return false;
}
After second recursion program exits returning true
I'm trying to compare two lists to determine which entries from the second list are new, edited, or removed. I have the following code that takes a very long time to run on large lists. The use case here is to compare a list of data from an Api at start, and then fetch new data and determine changes compared to our original list.
class Geofence {
final String createdAt;
final String lastModified;
final String name;
final String description;
final String id;
final List<Coordinates> coordinateList;
final double area;
final String entranceDescription;
final bool enabled;
Geofence({
#required this.createdAt,
#required this.name,
#required this.id,
#required this.coordinateList,
#required this.enabled,
this.description,
this.area,
this.lastModified,
this.entranceDescription,
}) : assert(createdAt != null),
assert(name != null),
assert(id != null),
assert(coordinateList != null),
assert(enabled != null);
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Geofence &&
runtimeType == other.runtimeType &&
id == other.id &&
name == other.name &&
enabled == other.enabled &&
lastModified == other.lastModified &&
description == other.description &&
coordinateList == other.coordinateList &&
area == other.area &&
entranceDescription == other.entranceDescription &&
enabled == other.enabled;
#override
int get hashCode => id.hashCode;
}
// _previousGeofences = <Geofence>[ // multiple items returned from Api ]
// _fetchedGeofences = <Geofence>[ // multiple items returned from Api ]
if (_previousGeofences.isNotEmpty && _fetchedGeofences.isNotEmpty) {
final newItems = <bool>[],
editedItems = <bool>[],
removedItems = <bool>[];
// Determine new items
for (final map in _fetchedGeofences) {
var foundItems =
_previousGeofences.any((Geofence item) => item.id == map.id);
if (!foundItems) {
newItems.add(foundItems);
}
}
// Determine removed items
for (final map in _previousGeofences) {
final foundItems =
_fetchedGeofences.any((Geofence item) => item.id == map.id);
if (!foundItems) {
removedItems.add(foundItems);
}
}
// Determine edited items
for (final map in _previousGeofences) {
final foundItems =
_fetchedGeofences.any((Geofence item) => item == map);
if (!foundItems) {
editedItems.add(foundItems);
}
}
I'm trying to learn what shortcuts in Dart I can utilize to help speed this up and be of better quality.
Let's make some assumptions:
Each list can contain at most one object with each id value.
An "edited" object in the new list is an object with the same ID
as an object in the original list, but with different property values.
An "unchanged" object is a value with the same ID and equal other properties.
A new object is one in the new list with an ID not in the original list.
A deleted object is one in the original list with an ID that is not in the new list.
That suggests to me that you should change equality to be ID based and have another method to compare for changes:
class Geofence {
final String createdAt;
final String? lastModified;
final String name;
final String? description;
final String id;
final List<Coordinates> coordinateList;
final double? area;
final String? entranceDescription;
final bool enabled;
Geofence({
required this.createdAt,
required this.name,
required this.id,
required this.coordinateList,
required this.enabled,
this.description,
this.area,
this.lastModified,
this.entranceDescription,
});
/// Whether two objects have the same ID and have equal values
/// for each property.
bool isUnchanged(Geofence other) =>
identical(this, other) ||
id == other.id &&
name == other.name &&
enabled == other.enabled &&
lastModified == other.lastModified &&
description == other.description &&
coordinateList == other.coordinateList &&
area == other.area &&
entranceDescription == other.entranceDescription &&
enabled == other.enabled;
#override
bool operator ==(Object other) =>
identical(this, other) || other is Geofence && id == other.id;
#override
int get hashCode => id.hashCode;
}
With that, you can do efficient lookup in a hash-table based on ID.
I'd do something like:
List<Geofence> modified = [];
List<Geofence> removed = [];
List<Geofence> added = [];
List<Geofence> unmodified = [];
Set<Geofence> original = {..._previousGeofences};
for (var fence in _fecthedGeofences) {
var o = original.lookup(fence);
if (o == null) {
added.add(fence);
} else {
original.remove(fence);
if (o.isUnchanged(fence)) {
unmodified.add(fence);
} else {
modified.add(fence);
}
}
}
removed.addAll(original);
After this, each ID occurring in either _previousGeofences or _fetchedGeofences also occurs in precisely one of the four lists, depending on whether it occurred in one or both, and if both, whether its content has changed.
The shortcuts to use here is:
Be clear about the underlying assumptions of your model.
Use a hash-table based lookup instead of linear lookup (and ensure the class supports that).
I got the following error:
[error][1] (E/DartVM (14988): Exhausted heap space, trying to allocate 536870928 bytes.
E/flutter (14988): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Out of Memory)
When trying to implement a breadth_first search algorithm to find the shortest path in a graph. I found the algorithm written in C# and I am trying to rewrite it in dart/flutter.
The original code in C# can be found here.
My dart code:
import 'dart:collection';
import 'package:stack/stack.dart';
class Node<T>{
int id;
Node(this.id);
String toString() => '$id';
}
class Graph<T>{
final Map<Node, List<Node>> adj;
Graph(this.adj);
void AddEdge(Node node1,Node node2){
if(!adj.containsKey(node1))
adj[node1]=List<Node>();
if(!adj.containsKey(node2))
adj[node2]=List<Node>();
adj[node1].add(node2);
adj[node2].add(node1);
}
Stack<Node> ShortestPath(Node source, Node dest){
var path=Map<Node<T>,Node<T>>();
var distance=Map<Node<T>,int>();
//adj.keys.forEach(( node) => distance[node]=-1);
for(var node in adj.keys){
distance[node]=-1;
}
distance[source]=0;
var q=Queue<Node<T>>();
q.add(source);
while(q.isNotEmpty){
var node=q.removeFirst();
for(var adjs in adj[node].where((n) => distance[n]==-1)){
distance[adjs]=distance[node]+1;
path[adjs]=node;
q.add(adjs);
}
}
var res=Stack<Node>();
var cur=dest;
while(cur != res){
res.push(cur);
cur=path[cur];
}
res.push(source);
return res;
}
}
void main() {
var g = new Graph({});
var n1 = new Node<int>(1);
var n2 = new Node<int>(2);
var n3 = new Node<int>(3);
var n4 = new Node<int>(4);
var n5 = new Node<int>(5);
var n6 = new Node<int>(6);
var n7 = new Node<int>(7);
g.AddEdge(n1, n2);
g.AddEdge(n1, n3);
g.AddEdge(n1, n4);
g.AddEdge(n4, n5);
g.AddEdge(n2, n6);
g.AddEdge(n4, n7);
g.AddEdge(n5, n6);
g.AddEdge(n6, n7);
var answ=g.ShortestPath(n1, n7);
print(answ);
}
So what is the wrong with my program, and if anyone know better way to find shortest path in graph to use it in dart it will be great.
Thanks in advance
First, you main problem is properly that your while loop is not correct according to the C# implementation:
var res=Stack<Node>();
var cur=dest;
while(cur != res){
res.push(cur);
cur=path[cur];
}
res.push(source);
return res;
This loop will never finish res and cur are entirely different types where cur are a Node and res are a Stack. If you check the C# implementation you can see this is not correct:
var res = new Stack<Node<T>>();
var cur = dest;
while(cur != source) {
res.Push(cur);
cur = path[cur];
}
res.Push(source);
return res;
So I think by comparing against source it will properly solve the problem. But there are a lot of smaller problems in you code where types are not really great and where you could make it a lot more type safe by using generics more places.
I have therefore added more typing information to you code (which I needed to do to catch the type error). I have also dropped the usage of the Stack class since I don't think it makes much sense. Also, the Stack class you got had no toString implementation so I just thought it was easier to just use a List and return that as the result:
import 'dart:collection';
class Node<T> {
int id;
Node(this.id);
#override
String toString() => '$id';
}
class Graph<T> {
final Map<Node<T>, List<Node<T>>> adj;
Graph(this.adj);
void AddEdge(Node<T> node1, Node<T> node2) {
if (!adj.containsKey(node1)) adj[node1] = <Node<T>>[];
if (!adj.containsKey(node2)) adj[node2] = <Node<T>>[];
adj[node1].add(node2);
adj[node2].add(node1);
}
List<Node<T>> ShortestPath(Node<T> source, Node<T> dest) {
final path = <Node<T>, Node<T>>{};
final distance = <Node<T>, int>{};
//adj.keys.forEach(( node) => distance[node]=-1);
for (final node in adj.keys) {
distance[node] = -1;
}
distance[source] = 0;
final q = Queue<Node<T>>();
q.add(source);
while (q.isNotEmpty) {
final node = q.removeFirst();
for (final adjs in adj[node].where((n) => distance[n] == -1)) {
distance[adjs] = distance[node] + 1;
path[adjs] = node;
q.add(adjs);
}
}
final res = <Node<T>>[];
var cur = dest;
while (cur != source) {
res.add(cur);
cur = path[cur];
}
res.add(source);
return res;
}
}
void main() {
final g = Graph<int>({});
final n1 = Node<int>(1);
final n2 = Node<int>(2);
final n3 = Node<int>(3);
final n4 = Node<int>(4);
final n5 = Node<int>(5);
final n6 = Node<int>(6);
final n7 = Node<int>(7);
g.AddEdge(n1, n2);
g.AddEdge(n1, n3);
g.AddEdge(n1, n4);
g.AddEdge(n4, n5);
g.AddEdge(n2, n6);
g.AddEdge(n4, n7);
g.AddEdge(n5, n6);
g.AddEdge(n6, n7);
final answ = g.ShortestPath(n1, n7);
print(answ); // [7, 4, 1]
}
I am previously working with Netlogo for years and I am very much getting used to developing the agent-based model based on a set of procedures. An example of supply chain simulation model structure looks like below:
;;the main simulation loop
#ScheduledMethod(start = 1, interval = 1)
public void step() {
place-order-to-suppliers() ;;procedures involving customer agent behaviors (a number of methods)
receive-shipment-from-suppliers() ;;procedures involving both supplier and customer agents and their behaviors (methods)
receive-order-from-customers() ;;procedures involving supplier agent only
ship-order-to-customers() ;;procedures involving supplier agent only
summarize() ;;procedures involving global summary behaviors independent of any agents, as well as local summary behaviors per each type of agents (customer and supplier)
}
The above structure is very useful and intuitive to develop a simulation model. We first cut the simulation world into several key parts (procedures), within which we further develop specific methods related to associated agents and behaviors. The essential part is to establish a higher level procedure (like a package) which could be useful to integrate (pack) the different types of agents and their behaviors/interactions altogether in one place and execute the model in a desired sequential order based on these procedures.
Are there any hints/examples to implement such modular modelling strategy in Repast?
Update:
Below is a simple model I wrote which is about how boy and girl interacts in the party (the full reference can be found https://ccl.northwestern.edu/netlogo/models/Party). Below is the code for Boy Class (the girl is the same so not pasted again).
package party;
import java.util.ArrayList;
import java.util.List;
import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.parameter.Parameters;
import repast.simphony.query.PropertyGreaterThan;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.grid.Grid;
import repast.simphony.space.grid.GridPoint;
import repast.simphony.util.ContextUtils;
public class Boy {
private ContinuousSpace<Object> space;
private Grid<Object> grid;
private boolean happy;
private int id, x, y,tolerance;
private boolean over;
Boy (Grid<Object> grid, int id, int x, int y) {
this.grid = grid;
this.id = id;
this.x = x;
this.y = y;
Parameters p = RunEnvironment.getInstance().getParameters();
int get_tolerance = (Integer) p.getValue("tolerance");
this.tolerance = get_tolerance;
}
// #ScheduledMethod(start = 1, interval = 1,shuffle=true)
// public void step() {
// relocation();
// update_happiness();
// endRun();
//
// }
public void endRun( ) {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
public void update_happiness() {
over = false;
Context<Object> context = ContextUtils.getContext(this);
Parameters p = RunEnvironment.getInstance().getParameters();
int tolerance = (Integer) p.getValue("tolerance");
GridPoint pt = grid.getLocation(this);
int my_x = this.getX();
int boy_count = 0;
int girl_count = 0;
Query<Object> query = new PropertyEquals<Object>(context, "x", my_x);
for (Object o : query.query()) {
if (o instanceof Boy) {
boy_count++;
}
else {
girl_count++;
}
}
int total = boy_count + girl_count;
double ratio = (girl_count / (double)total);
// System.out.println((girl_count / (double)total));
if (ratio <= (tolerance / (double)100)) {
happy = true;
// System.out.println("yes");
}
else {
happy = false;
// System.out.println("no");
}
over = true;
// System.out.println(over);
}
public void relocation() {
if (!happy) {
List<Integer> x_list = new ArrayList<Integer>();
for (int i = 5; i <= 50; i = i + 5) {
x_list.add(i);
}
int index = RandomHelper.nextIntFromTo(0, 9);
int group_x = x_list.get(index);
while(group_x == this.getX()){
index = RandomHelper.nextIntFromTo(0, 9);
group_x = x_list.get(index);
}
int group_y = 35;
while (grid.getObjectAt(group_x,group_y) != null) {
group_y = group_y + 1;
}
this.setX(group_x);
grid.moveTo(this, group_x,group_y);
}
}
public int getTolerance() {
return tolerance;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public int getID() {
return id;
}
public boolean getHappy() {
return happy;
}
public boolean getOver() {
return over;
}
public void setTolerance(int tolerance) {
this.tolerance = tolerance;
}
}
---------------------------------------------------------------------------------
The running of above code can follow the standard Repast Annotated scheduling method. However, since I want do some integration of the different agents and their methods altogether to allow the creation of bigger procedures(methods), I managed to create a Global Scheduler Agent Class to manage this modeling strategy. Below is the code:
package party;
import java.util.ArrayList;
import java.util.List;
import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.engine.schedule.ScheduleParameters;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.engine.schedule.Schedule;
import repast.simphony.query.PropertyEquals;
import repast.simphony.query.Query;
import repast.simphony.util.ContextUtils;
import repast.simphony.util.collections.IndexedIterable;
public class Global_Scheduler {
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void updateHappiness() {
Context<Object> context = ContextUtils.getContext(this);
IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);
for (Object b: boy_agents) {
((Boy) b).update_happiness();
}
for (Object g: girl_agents) {
((Girl) g).update_happiness();
}
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void relocate() {
Context<Object> context = ContextUtils.getContext(this);
IndexedIterable<Object> boy_agents = context.getObjects(Boy.class);
IndexedIterable<Object> girl_agents = context.getObjects(Girl.class);
for (Object b: boy_agents) {
((Boy) b).relocation();
}
for (Object g: girl_agents) {
((Girl) g).relocation();
}
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void summary() {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int total_count = 0;
int boy_count = 0;
int girl_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
total_count ++;
boy_count++;
}
if (o instanceof Girl) {
total_count ++;
girl_count++;
}
}
System.out.println("Total happy person: " + total_count);
System.out.println("Total happy boys: " + boy_count);
System.out.println("Total happy girls: " + girl_count);
}
#ScheduledMethod(start = 1, interval = 1,shuffle=true)
public void endRun( ) {
Context<Object> context = ContextUtils.getContext(this);
Query<Object> query = new PropertyEquals<Object>(context, "happy", true);
int end_count = 0;
for (Object o : query.query()) {
if (o instanceof Boy) {
end_count ++;
}
if (o instanceof Girl) {
end_count ++;
}
}
if (end_count == 70) {
RunEnvironment.getInstance().endRun();
}
}
}
The above code using the global scheduler agent to run the model is working fine and the outcome should behave the same. However, I am not sure if the execution of the model really follows the sequence (i.e. update_happiness() -> relocate() -> summary() -> end_run(). I would also like to know if there are better and simpler way to achieve such modeling strategy?
The code example you provided will almost work exactly as-is in a repast model agent - you simply need to change the comment line prefix ;; to // and implement the methods place-order-to-suppliers(), etc in the agent class. The agent behavior structure in a typical ABM follows this exact structure. A general 'step' method that combines the various sub-steps according to the desired order of execution.
There are a number of behavior scheduling approaches outlined in the Repast FAQ: https://repast.github.io/docs/RepastReference/RepastReference.html#_scheduling . Scheduling via annotation as you've provided in the example will repeat the behavior on a regular interval, or at a single time step. You can also schedule dynamically in the model by directly putting an action on the Repast schedule. This type of scheduling is good for event-based behavior, like scheduling a one-time behavior that is triggered by some other event in the model. You can also schedule with #Watch annotations that trigger behaviors based on a set of conditions specified in the annotation.
You can use priorities in your #ScheduledMethod annotations, e.g.,
#ScheduledMethod(start = 1, interval = 1, shuffle=true, priority=1)
where a higher priority will run before a lower priority.
Can someone please explain how could I solve a maze using breadth first search? I need to use breadth first search to find shortest path through a maze, but I am so confused.
This is the pseudo code from my book:
void breadth_first_search(tree T) {
queue!;
node u, v;
initialize(Q);
v = root of T;
visit v;
enqueue(Q, v);
while (!empty(Q)) {
dequeue(Q, v);
for (each child u of v) {
visit u;
enqueue(Q, u);
}
}
}
So if I have a maze that is stored in a 2D matrix, is the "root" (i.e. the starting point), going to be in maze[x][y]?
Here's a full BFS Maze solver. It returns a full shortest path to the end point if found. In the maze array arr: 0 denotes unexplored spaces, 5 is a wall space, and 9 is the goal space. Spaces are marked with a -1 after they have been visited.
import java.util.*;
public class Maze {
public static int[][] arr = new int[][] {
{0,0,0,0,0,0,0,0,0},
{5,5,5,0,0,0,0,0,0},
{0,0,0,5,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,9},
};
private static class Point {
int x;
int y;
Point parent;
public Point(int x, int y, Point parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent() {
return this.parent;
}
public String toString() {
return "x = " + x + " y = " + y;
}
}
public static Queue<Point> q = new LinkedList<Point>();
public static Point getPathBFS(int x, int y) {
q.add(new Point(x,y, null));
while(!q.isEmpty()) {
Point p = q.remove();
if (arr[p.x][p.y] == 9) {
System.out.println("Exit is reached!");
return p;
}
if(isFree(p.x+1,p.y)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x+1,p.y, p);
q.add(nextP);
}
if(isFree(p.x-1,p.y)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x-1,p.y, p);
q.add(nextP);
}
if(isFree(p.x,p.y+1)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y+1, p);
q.add(nextP);
}
if(isFree(p.x,p.y-1)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y-1, p);
q.add(nextP);
}
}
return null;
}
public static boolean isFree(int x, int y) {
if((x >= 0 && x < arr.length) && (y >= 0 && y < arr[x].length) && (arr[x][y] == 0 || arr[x][y] == 9)) {
return true;
}
return false;
}
public static void main(String[] args) {
Point p = getPathBFS(0,0);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(arr[i][j]);
}
System.out.println();
}
while(p.getParent() != null) {
System.out.println(p);
p = p.getParent();
}
}
}
Short answer: yes
Explanation:
That pseudo code is representing the path through the maze as a path to the leaf of a tree. Each spot in the maze is a node on the tree and each new spot you can go to from there is a child of that node.
In order to do breadth first search, an algorithm first has to consider all paths through the tree of length one, then length two, etc. until it reaches the end, which will cause the algorithm to stop since the end has no children, resulting in an empty queue.
The code keeps track of the nodes it needs to visit by using a queue (Q). It first sets the start of the maze to the root of the tree, visits it (checks if it is the end), then removes the root from the queue and repeats the process with each child. In this way, it visits the nodes in post-order i.e. root, (each child of root), (each child of first child), (each child of second child), etc. until it gets to the end.
edit: As it stands, the algorithm may not terminate when it reaches the end because of other nodes after it in the queue. You will have to wright the condition for termination yourself.