Overview |
|
Many times when designing a piece of software the data structures at our disposal are
insufficient. As you've seen to implement the A* algorithm efficiently, you will need
a queue structure that Java doesn't provide. Moreover, while the traditional priority queue
(which we will discussion shortly) doesn't provide for all the functionality that you need.
In a perfect world, we could sit down and design a custom data structure to store our data, and provide efficient means of accessing it, but it isn't a perfect world, and this process and be very complicated. As we're not experts in designing data structures, we going to do the next best thing. Instead of comimg up with a data structure from scratch to do what we need, we will take existing data structures and combine them to provide the functionality that we need. Of course to make life simple, once we have combined the necessary data structures to give us the capabilities that we need, we'll put a nice clean interface on the front of it so that we don't have to worry about the messy details whenever we use it. |
Data Structures need for A* | |
As you've seen in the first milestone for project 2, you will need a queue structure
that holds Objects which a value associated with them, we'll call this the priority.
We need these operations:
|
Binary Heap and Priorty Queue |
|
Based on Cormen, Leiserson, Rivest, and Stein The binary heap will be used to implement the priority queue, it basically provides a an efficient binary tree in an array. So that the structure will be able to grow dynamically, we'll assume that a java.util.Vector is being used, those array notation will be used to for simplicity. We'll call our array A. The general binary tree relationships are defined in terms of array indices, for a node at array position i:
A[i] => A[Parent(i)] That is, every node is greater than or equal to the ones above it. To maintain this property, whenever we remove an element, we must use this routine: Heapify(A,i) l = Left(i); r = Right(i); if l <= heap_size and A[l] > A[i] then largest = l; else largest = i; if r <= heap_size and A[r] > A[largest] then largest = r; if largest != i then exchange A[i] and A[largest]; Heapify(A, largest);Which recursively rearranges the heap to make sure the property holds. Operations: Heap-Minimum()
Heap-Delete-Minimum() //Removes the minimum item in the heap if(heap_size) <0
Heap-Decrease-Key(i, key) //Helper function that increases the priority associated with item i to key if key > A[i] then error("Can't increase the key") A[i] = key; while i>0 and A[Parent(i)] > A[i] exchange A[i] and A[Parent(i)] i = Parent(i); Heap-Insert(key) heap_size++; A[heap_size] = INFINITY; Heap-Decrease-Key(heap_size, key); For those of you with access to CLRS, see chapter 6. |
Where the Hashtable Comes In |
|
Using the priority queue, it is inefficient, O(n), to see if an element is in the table, or to find where in the table to find an item, necessary to remove it (how do we remove something?). So we keep a hashtable that maps Objects -> Array Index. We will have to update this table everytime we move an item in the heap, but it will make our structure much more efficent (where do we have to add code to the heap to do this?). |
Exercise |
|
In Lab discussion of combining data structures, and the data structures need for Project 2. |