19
Babeş-Bolyai University Faculty of Mathematics and Computer Science Cluj-Napoca Path in a maze Documentation Coordinating professor: Dr. Lupșa Dana Subject: Data Structures and Algorithms Student: Lucaci Andrei Group: 913

Documentation for path in a maze - priority queue, red- black trees, stack, vector

Embed Size (px)

DESCRIPTION

Documentation for path in a maze - priority queue, red- black trees, stack, vector

Citation preview

Page 1: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Babeş-Bolyai UniversityFaculty of Mathematics and Computer Science

Cluj-Napoca

Path in a mazeDocumentation

Coordinating professor: Dr. Lupșa Dana

Subject: Data Structures and Algorithms

Student: Lucaci Andrei

Group: 913

June 2012

Page 2: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Contents:1. Problem statement…………………………………………………………………… 32. Code………………………………………………………………………………….. 33. How I organized my program………………………………………………………..114. Present the idea/method to solve the problem……………………………………… 125. Apply justification to proper example……………………………………………… 136. Application Input/Output…………………………………………………………… 137. Execution time………………………………………………………………………..148. Suitable DS…………………………………………………………………………...149. Pseudocode for the main algorithm…………………………………………………. 14

2

Page 3: Documentation for path in a maze - priority queue, red- black trees, stack, vector

1. Problem statementA robot is asked to navigate a maze. It is placed at a certain position (the starting position: S) in the maze and is asked to try to reach another position (the goal position: G). Maze has rectangular shape. Positions are identified by (x,y) coordinates. Positions in the maze will either be open (*) or blocked with an obstacle (X). At any given moment, the robot can only move 1 step in one of 4 directions. Valid moves are:

Go North: (x,y) Go East: (x,y) Go South: (x,y) Go West: (x,y)

The robot can only move to positions without obstacles and must stay within the maze. The robot should search for a path from the starting position (S) to the goal position (G) until it finds one or until it exhausts all possibilities.

S * X X * * ** X * * X * ** * * * * * ** X * X * * X* X * * * * X* * * * X * G* X * X * * *

Find optimum solution (shortest path).

5. Define ADT Priority Queue; representation: Red black tree.7. Define ADT Stack: represented on a static vector.

2. CodeClass RBtree{

constant integer black = 1;constant integer red = 0;struct RBnod {

Generic data;RBnod *p,*left,*right;integer color;

}

RBnod* root;RBnod* NIL;

}Description: a Red–Black Tree is a special type of binary tree, used in computer science to organize pieces of comparable data, such as text fragments or numbers. It is a self-balancing tree, meaning that it will obey the binary tree rules when it comes to insert or delete. A RBT has an average complexity per operation: θ(log(N)) where N is the number of Generic elements in the RBtree, namely T.

RBnod* find(T value)3

Page 4: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Description: This function is used to search for a nod with a known T valueInput Data: valuePrecondition: value is a TOutput Data: the return Postcondition: the return is pointer to a RBnod to the position where the T value is

situatedComplexity: BC,AC,WC: θ(log(N)) where N is the number of T elements

RBnod* min(RBnod* current) Description: This function is used to find the minimum nod of the RBtree starting

with a current position (the same as the ` T minFromRoot()` and ` T minVal(RBnod* current)` functions).

Input Data: currentPrecondition: current is a pointer to a RBnodOutput Data: the resultPostcondition: the result is a pointer to a RBnod that represents the position that has

the minimum T value considering only the nodes older than the RBnod currentComplexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

RBnod* max(RBnod* current) Description: This function is used to find the maximum nod of the RBtree starting

with a current position (the same as ` T maxVal(RBnod* current)` and ` T maxFromRoot()` functions).

Input Data: currentPrecondition: current is a pointer to a RBnodOutput Data: the resultPostcondition: the result is a pointer to a RBnod that represents the position that has

the maximum T value considering only the nodes older than the RBnod currentComplexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

RBnod* next(RBnod* current)Description: This function returned the pointer to the RBnod that has the next T

value higher, than the current’s valueInput Data: currentPrecondition: current is a pointer to a RBnodOutput Data: the returnPostcondition: the result is a pointer to a RBnodComplexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

RBnod* prev(RBnod* current) Description: This function returned the pointer to the RBnod that has the previous T

value, lower than the current’s valueInput Data: currentPrecondition: current is a pointer to a RBnodOutput Data: the returnPostcondition: the result is a pointer to a RBnodComplexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

void insertB(RBnod* nod)

4

Page 5: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Description: This function inserts the T value into the RBtree, as like introducing a Nod in a normal binary tree

Input Data: nodPrecondition: nod is a pointer to a RBnodOutput Data: -Complexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

void remove(T value) Description: This function removes the T value from the RBtree, equilibrating it with

the use of the function: removeRepair() in case the RBnod removed had a black color.Input Data: valuePrecondition: value is a TOutput Data: -Complexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

void rotate_left(RBnod* x)Description: This is a specific function for a Red-Black tree that rotates the RBnod-es

from the left as in Figure 1Input Data: xPrecondition: x is a RBnod;Output Data: -Complexity: BC,AC,WC: O(1)

Fig(1) Left-rotation and Right-rotaion

void rotate_right(RBnod* x) Description: This is a specific function for a Red-Black tree that rotates the RBnod-es

from the right as in Figure 1Input Data: xPrecondition: x is a RBnod;Output Data: -Complexity: BC,AC,WC: O(1)

void insert(T value)Description: This function is a specific Red-Black tree function that inserts the T

value in the Red-Black treeInput Data: valuePrecondition: value is of typeTOutput Data: -Complexity: BC,AC,WC: θ(log(N)) where N is the number of T elements

void removeRepair(RBnod* x)Description: This function is a specific Red-Black tree function that takes all the

cases that forms when removing a black nod from the RBtree

5

Page 6: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Input Data: xPrecondition: x is a pointer to a RBtreeOutput Data: -Complexity: BC,AC,WC: θ (log(N)) where N is the number of T elements

Operations on the red-black tree:

RBtree::find(k){RBnod x=root;while x ≠ NIL and k ≠ info[x] do

if k < info[x]then x ← x

else x ← right[x]return x

}

RBtree::min(k){while left[x] ≠ NIL

do x ← left[x]return x

}

RBtree::next(k){if right[x] ≠ NIL

then return min(right[x])y ← p[x]while y ≠ NIL and x = right[y]

do x ← yy ← p[y]

return y}

RBtree::insertb(z){y ← NILx ← rootwhile x ≠ NIL do

y ← xif info[z] < info[x]

then x ← left[x]else x ← right[x]

p[z] ← yif y = NIL

then root[T] ← z else if info[z] < info[y]

then left[y] ← zelse right[y] ← z

}

6

Page 7: Documentation for path in a maze - priority queue, red- black trees, stack, vector

RBtree::remove(z){if left[z] = NIL or right[z] = NIL

then y ← zelse y ← next(z)

if left[y] ≠ NILthen x ← left[y]else x ← right[y]

if x ≠ NILthen p[x] ← p[y]

if p[y] = NILthen root[T] ← xelse if y = left[p[y]]

then left[p[y]] ← xelse right[p[y]] ← x

if y ≠ zthen info[z] ← info[y]

return y}

RBtree::rotate_left(x){y ← right[x] right[x] ← left[y] p[left[y]] ← xp[y] ← p[x] if p[x] = nil[T]

then root[T] ← yelse if x = left[p[x]]

then left[p[x]] ← yelse right[p[x]] ← y

left[y] ← x p[x] ← y

}

RBtree::removeRepair(x){while x ≠ root[T] and color[x] = BLACK do

if x = left[p[x]]then w ← right[p[x]]if color[w] = RED

then color[w] ← BLACK color[p[x]] ← RED rotate_left (p[x]) w ← right[p[x]]

if color[left[w]] = BLACK and color[right[w]] = BLACKthen color[w] ← RED x p[x]

else if color[right[w]] = BLACKthen color[left[w]] ← BLACK color[w] ← RED rotate_right(T, w)

7

Page 8: Documentation for path in a maze - priority queue, red- black trees, stack, vector

w ← right[p[x]] color[w] ← color[p[x]] color[p[x]] ← BLACK color[right[w]] ← BLACK

rotate_left (T, p[x]) x ← root[T]

else (same as then clause with "right" and "left" exchanged)color[x] ← BLACK

}

Class PriorityQueue:RBtree<Position> rbt;Position p;Position NIL;int size;

Description: this class use the same idea of a Priority Queue, but the main difference is that it is implemented over a Red-Black Tree.

void push(Position infos)Description: This function will insert into the ADT Priority queue an element of type

Position.Input Data: value.Precondition: value is of type Position.Output Data: -Complexity: BC,AC,WC: θ (log(N)) as in the RBT::insert() function.

Position pop()Description: This function will remove from the ADT Priority queue an element of

type Position.Input Data: -Precondition: -Output Data: -Postcondition: returns an element of type Position with the maximum priority.Complexity: BC,AC,WC: θ (log(N)) as in the RBT::remove() function.

bool isEmpty()Description: Checks if the Priority Queue is empty.Input Data: -Precondition: valid PQ.Output Data: -Postcondition: returns true if the PQ is empty or false otherwise.Complexity: O(1);

Position min()Description: Returns the element with the lowest priority and removes it.Input Data:Precondition: valid PQ.Output Data: -Postcondition: returns an element of type Position.

8

Page 9: Documentation for path in a maze - priority queue, red- black trees, stack, vector

Complexity: θ(logN) as in the RBT min function.

Position max()Description: Returns the element with the highest priority and removes it.Input Data: -Precondition: valid PQ.Output Data: -Postcondition: returns an element of type Position.Complexity: θ(logN) as in the RBT max function.

Position top()Description: Returns the element with the highest priority.Input Data: -Precondition: valid PQ.Output Data: -Postcondition: returns an element of type Position.Complexity: θ(logN) as in the RBT max function.

int PQsize()Description: Returns the size of the PQ.Input Data: -Precondition: valid PQ.Output Data: -Postcondition: returns an int which is the size of the PQ.Complexity: O(1).

void Empty()Description: Flushes all the data from the PQ.Input Data: -Precondition: valid PQ.Output Data: -Postcondition: will pop all the elements from the PQ.Complexity: N*θ(logN), where N is T value.

Operations on the Priority Queue:

Rbt: RBtree. PriorityQueue::push(T elem)

Rbt.insert(elem)Size++

PriorityQueue::pop()if (rbt.getRoot() ≠ rbt.getNIL())Position result ← rbt.getDt(rbt.max(rbt.getRoot()))rbt.remove(result)size--return result

PriorityQueue::isEmpty()return rbt.isEmpty()

9

Page 10: Documentation for path in a maze - priority queue, red- black trees, stack, vector

PriorityQueue::min()return rbt.min()

PriorityQueue::max()return rbt.max()

PriorityQueue::empty()for (i=0; i<size) do

pop()end_for

Class Stack:T elem;int size;T vector[1000];int vect[1000];int nrElem;T NIL;

Description: ATD stack implemented on a static vector.

T push(T elem)Description: Pushes information onto the stack.Precondition: stack is not full.Postcondition: returns the element inserted.

T pop()Description: Pops the element from the top of the stack and returns it.Precondition: stack is not empty.Postcondition: returns the element and deletes it from the stack.

void initEmpty()Description: initializes the vector on which the stack is built with the NIL (T).Precondition: valid stack.Postcondition: -

bool isEmpty()Description: checks if the stack is empty.Precondition: valid stack.Postcondition: return true on success or false otherwise.

(*)T getPrev()Description: returns the value of the element just below the top of the stack. Not a

pure-stack function.Preconition: more than 2 elements in the stack.Postcondition: returns an element of type T.

Class bfsifstream f_in;

10

Page 11: Documentation for path in a maze - priority queue, red- black trees, stack, vector

ofstream f_out;char Mat[DIM][DIM];int p[DIM][DIM],v[DIM][DIM], elem, DimX,DimY;;Position Start,Stop;PriorityQueue pq;Stack<Position> solution;string filename, fileexit;

Description: this is a class that sums the programs soling part. It contains the solving part, the reading part, and the saving/printing/writing part of the program.

void solve()Description: this function will solve the maze problem by applying a breadth first search, and then, by a greedy algorithm it will return the shortest path or null, if there is no other solution.Precondition: -Postcondition: -

void readFromFile()Description: this function will read from a file the into the matrix the elements.Precondition: a valid file.Postcondition: -

void init()Description: this is the initializing function. It will set the starting and the ending

positions, as well the free and the closed spots of the maze.Precondition: -Postcondition: -

void saveToFile()Description: this function will write to a file the solution of the program.Precondition: a valid file.Postcondition: -

void generalInfo()Description: prints the name of the two file: read and write.Precondition: valid files.Postcondition: -

void start()Description: sums up the functions from the bfs class into a “starting” point.Precondition: -Postcondition: -

3. How I organized my program.The whole code is divided into several files: bfs.h, main.cpp, Position.h, priorityqueue.h, RBtree.h, stack.h, testQue.h, ex.in, ex1.in, sol.txt, sol1.txt.bfs.h – the part where I read/solve/write the program.

11

Page 12: Documentation for path in a maze - priority queue, red- black trees, stack, vector

main.cpp – the part where I call the bfs class object to solve the problem. It is the actual starting point of the program. Position.h – the part where I implement a class which helps me to work with the robot. It is a position class for the robot position and his movement in the maze. Its objects contains pairs of two ints, which are actually the coordinates of x and y.Priorityqueue.h – the part where I implement an ADT Priority Queue over a Red-black tree.RBtree.h – the part where I implement the actual Red-black tree.Stack.h – the part where I implement an ADT Stack over a static vector.testQueue.h – the part where I test out my Priority Queue.ex.in, ex1.in – files that contains mazes.sol.txt, sol1.txt – files that contains the solutions of the mazes.

4. Present the idea/method used to solve the problem:My problem statement is to solve the robot problem. From my point of view the best way to solve this problem was to apply a BFS on the maze, and, than to trace back on which path the robot can go. The BFS procedure looks like this:Breadth-First-Search( Maze m ) EnQueue( m.StartNode ) While Queue.NotEmpty c <- DeQueue If c is the goal Exit Else Foreach neighbor n of c If n "Unvisited" Mark n "Visited" EnQueue( n ) Mark c "Examined" End procedure

So, the BFS algorithm will search through the whole maze for valid moves. If, for example, there is a free space, but surrounded by walls, it will not consider it as a valid position. After it searched the whole maze, it will trace back, applying a greedy algorithm and will give the shortest path to that point. If, by applying all the moves, it will not find a suitable way to get to the ending point of the matrix, it will then return with nothing, meaning that there is no solution in place for that maze. This BFS algorithm and the greedy algorithms are implemented in the bfs class’s function solve().Another important part of the program is reading the information into the maze, and, than saving it into files. For this matter I use 2 functions, readFromFile and saveToFile, which will do the job. In these files I work with the stream operators ifstream and ofstream.The readFromFile function will read a given file, and will place in the matrix the corresponding characters.The fixation of the starting and the ending part of the program is done in the init() function. Here the starting position is marked with ‘*’ after it has been saved to a variable and the ending position is marked also with ‘*’ after it has been saved to another variable.The saving part of the program is done, as I stated above, in the saveToFile function. In this function, the appropriate moves will be printed out, and the number of steps as well. If there is no valid path, it will write that there is no solution.

12

Page 13: Documentation for path in a maze - priority queue, red- black trees, stack, vector

5. Apply justification to some appropriate example:I will take for example a maze of size 5x5, that will look like this:

S * x * x

* x * * *

* * * x *

* x * x G

x * * x x

The BFS will be applying like this:S (0,0) starting point.Try to go to (0, 1). If (0,1) = * and is not outside the border, it will mark it as reached. Try to go to (0, 2). If (0,2) = * and is not outside the border, it will mark it as reached.Try to go to (0, 3). If (0,3) = * and is not outside the border, it will mark it as reached.Try to go to (0, 4). If (0,4) = * and is not outside the border, it will mark it as reached, but (0,4) is != * so it will no marked it as reached. Instead it will go to the previous and try to go to another place.Try to go to (1, 3). If (1,3) = * and is not outside the border, it will mark it as reached. Try to go to (1, 4). If (1,4) = * and is not outside the border, it will mark it as reached, but (1,4) is != * so it will no marked it as reached. And so on.On its way back, it will store the appropriate positions into a stack called solutions by apply a greedy algorithm, from which they will be extracted as the optimal solution. If we take for example the same maze, but with closed S:S x x * *x x * * ** * * x ** x * x Gx * * x x it will try to go to all positions, but being surrounded by closed spots it will return with no solution.

6. Application Input/Output:The application takes it’s input from ex.in or ex1.in and will output it in sol.txt and sol1.txt.The console menu of the programs lets the user choose from two options: given the already set mazes, it can either run the program, and see the result from the sol.txt or sol1.txt, or it can choose to see the execution time of each maze. Of course, the mazes can be changed to a maximum size of 99 on width or height.The console menu looks like this:

1. Solve from a given set.2. See the execution time for the function from the given set.Type the 'menu' keyword to view again the menu.Type the 'q' character to exit the program.

The 1st option, as I said, it will only solve the maze, but the 2nd will show the timing also.

13

Page 14: Documentation for path in a maze - priority queue, red- black trees, stack, vector

The menu offers some additional help, if typed the keyword menu, it will print out again the menu, and if it’s typed the character ‘q’ it will terminate the program. Note that any other command will be ignored by the program, and it will not be taken into consideration.

7. Execution time:

For a maze of size 8x8 with valid paths the execution time is around 0.002 seconds.

For a maze of size 8x8 with no valid paths the execution time is around 0.001 seconds.

For a maze of size 16x16 with valid paths the execution time is around 0.003-0.005 seconds.

For a maze of size 16x16 with no valid paths the execution time is around 0.003-0.005 seconds.

The execution time can be improved by using an advanced machine.

8. Suitable DS:

In my opinion the Priority Queue and the Stack as DS are very good for this kind of problems. But, I think it can be done with other DS as with vectors or regular queues.

Working with the PQ as the reached configuration DS and with Stack as the processed configuration DS helped me to solve this problem. The reached configurations could have been done using a Stack DS, but when working with PQ as the processed configuration DS it would have yield serious problems, and, probably, I would have had to use iterators over the PQ.

Working with other DS would have changed a bit how the program works. In stl vectors or dequeues for example, you can access the elements by position, which can bring either advantages or disadvantages into the program.

9. PseudoCode for the main algorithm:pq: PriorityQueuesolution: Stackcurrent: Positionnext: Position

subalg. solve() pq.push(Start) while (not pq.isEmpty()) current <- pq.pop() if (current=Stop) then

break endif for (i=1; i<5) do

next <- Position(current.getX()+xk[i], current.getY()+yk[i]) if (next.rdcorner(Position(DimX, DimY)) &&

next.lucorner(Position(-1,-1))) thenif (not v[next.getX()][next.getY()] && Mat[next.getX()]

[next.getY()]=='*' then v[next.getX()][next.getY()]=1 p[next.getX()][next.getY()]=i pq.push(next)end_if

end_ifend_for

14

Page 15: Documentation for path in a maze - priority queue, red- black trees, stack, vector

end_while if (p[Stop.getX()][Stop.getY()]=0) then

return end_if for (current=Stop; p[current.getX()][current.getY()]) do

solution.push(current)prev <- p[current.getX()][current.getY()]current <- Position(current.getX()-xk[prev], current.getY()-

yk[prev] end_forend_subalg

15