380 likes | 522 Views
CS503: Twelfth Lecture, Fall 2008 UML and Heaps. Michael Barnathan. Here’s what we’ll be learning:. Review of Lab 2. Software Engineering: UML Diagrams. Data Structures: Heaps. Priority Queues (revisited). Algorithms: Heapsort . Theory: “Greedy” algorithms. Blackjack Architecture.
E N D
CS503: Twelfth Lecture, Fall 2008UML and Heaps Michael Barnathan
Here’s what we’ll be learning: • Review of Lab 2. • Software Engineering: • UML Diagrams. • Data Structures: • Heaps. • Priority Queues (revisited). • Algorithms: • Heapsort. • Theory: • “Greedy” algorithms.
UML • This is called a Unified Modeling Language (UML) Diagram. • I generated it in a program called ArgoUML. • It is a useful tool for developing software architectures for complex systems. • The assignments are getting more complex. • You may want to start considering some sort of structured modeling tool, such as UML. • You can automatically generate “stubs” from the UML, too. These include: • All classes defined in the UML file. • All properties defined in those classes. • Method headers defined in the UML. • All you need to do then is fill in the body of the methods.
Symbols • There are four important relationships between classes in a UML diagram: • Inheritance (“IS-A”): • Association (“Uses”): • Aggregation (“HAS-A”): • Composition (“HAS-A and owns”): • The symbol is always on the base class.
Inheritance in UML • This models the “extends” keyword in Java. • One class should inherit from another if it “is” a special type of the other. • For example, the Dealer is a Player. He’s playing in the game and has all of the choices a Player has. • Except that he uses an algorithm to decide his move, which is why takeTurn() was overridden. • Just having common functionality doesn’t mean something should inherit. • E.g. “Truck” and “FrenchHorn” can both honk, but a Truck is not a FrenchHorn, or vice versa. • Use interfaces to model this instead.
Associations in UML • This models cases where one object needs another object to do something, but doesn’t actually own it. • For example, a Player requires a Deck to hit(). The card is being drawn from that Deck. • This is usually modeled by passing a Deck as an argument to the hit() function. • The method needs something to operate, so the caller supplies it.
Aggregations in UML • This is when one class has instances of another, but doesn’t manage them. • That is, it isn’t responsible for creating or destroying those objects. • For example, Player have a hand of Cards, represented using a LinkedList. • The Player doesn’t create or destroy those cards, however; it simply retrieves them from the Deck. • This is represented with an array or other collection of objects as a member variable. • Not local arrays. If you only need the objects within one function, it’s an association, not an aggregation.
Compositions in UML • Like aggregations, but compositions manage their objects. • Creating, destroying, or otherwise maintaining. • For example, a Deck is a composition of Cards. • When the Deck class is created, it creates 52 Card objects and places them in an array. • If the Deck were destroyed, the Cards would become inaccessible (except for the ones already in players’ hands).
Examples A game of Blackjack has Players. Dealer inherits from Player. Players use a Deck when they hit. And a Deck. Decks have Cards.
Multiplicities • The numbers on the ends of the arrows. • These answer the question “how many?” • Four common responses: • “One A uses one B”: 1..1 ____________ 1..1 • “One A uses many Bs”: 1..1 ____________ 0..* • “Many As use one B”: 0..* ____________ 1..1 • “Many As use many Bs”: 0..* ____________ 0..* • Read them from the arrow to the end. • Don’t worry about these as much as the general class model you construct.
Blackjack Code • Here’s the code corresponding to the diagram I just showed. • Let’s get it on a terminal… • Questions? Do you understand what this code is doing? • If you’re struggling with the labs, it’s imperative that you figure out how the code is broken down and what it is doing.
Heaps • Heaps are a special type of tree structure. • Because they’re complete trees, it actually makes sense to implement them using arrays. We’ll use trees for intuition. • There are two types: min-heaps and max-heaps. “Heap” usually refers to a max-heap. • These have the very nice property of storing the maximum value in the heap in the root node. (Or for a min-heap, the minimum). • This is called the heapproperty. • The root can be accessed immediately, which means you can find the maximum value in constant time. • And since these are recursive, you can find the maximum of each child heap in O(1) as well…
Example 9 4 5 2 1 9 > 4 and 5 4 > 2 and 1
CRUD: Heaps. • Insertion: ? • Access: O(log n). • Updating an element: ? • Deleting an element: ? • Search: O(n). • Traversal: O(n). • Finding the maximum: O(1). • Access and traversal are identical to trees. • This does not partition the dataset anymore, so we can’t perform binary search. • The constant-time max. is the primary reason these are useful structures. • As always, enforcing the heap property requires extra work on insertion.
Heap Insertion • Insert into the next empty space in the tree, from left to right. 8 4 5 3 2 2 1 9 Uh oh! This can violate the heap property.
Heap Insertion • If the heap property is violated, swap with the parent (or upheap) until it is valid. 8 4 5 3 2 2 1 9
Heap Insertion • If the heap property is violated, swap with the parent (or upheap) until it is valid. 8 4 5 3 2 9 1 2
Heap Insertion • If the heap property is violated, swap with the parent (or upheap) until it is valid. 8 9 5 3 2 4 1 2
Heap Insertion • If the heap property is violated, swap with the parent (or upheap) until it is valid. 9 Now it’s valid! 8 5 3 2 4 1 2
Analysis of Insertion • If we keep track of the last node, we can find where to insert in constant-time. • And if we use an array, we can go from child to parent in constant-time. • So each swap is O(1). • This means the upheap operation is going to dominate. • At worst, we’ll have to swap up to the root. • This means a number of swaps proportional to the height of the tree. • Heaps are naturally balanced trees. • So what is the complexity of insertion?
Updating • Find the value to update. • If the new value is greater than or equal to the old one, no further action is necessary. • If it is smaller, upheap to restore the heap property, as in insertion.
Heap Deletion Note: Deletion may only take place at the root. • Replace the root with the last leaf’s value. 8 4 5 3 2 2 1
Heap Deletion Note: Deletion may only take place at the root. • Replace the root with the last leaf’s value. 2 Heap property violated! 4 5 3 2 1
Heap Deletion • Downheap: Swap down from the root to the larger child until both children are less than the node being swapped or we hit a leaf. 2 4 5 3 2 1
Heap Deletion • Downheap: Swap down from the root to the larger child until both children are less than the node being swapped or we hit a leaf. 5 4 2 3 2 1
Heap Deletion • Downheap: Swap down from the root to the larger child until both children are less than the node being swapped or we hit a leaf. 5 4 3 2 2 1 Heap property restored!
Deletion Analysis • The swaps are O(1). • Finding the last node can be O(1). • The downheap again dominates. • We can perform up to height swaps. • What, therefore, is the complexity?
CRUD: Heaps. • Insertion: O(log n). • Access: O(log n). • Updating an element: O(log n). • Deleting an element: O(log n). • Search: O(n). • Traversal: O(n). • Finding the maximum: O(1). • Another tree-based compromise structure. • But no need to balance. • Very useful when you need to find a minimum or maximum quickly. • Where else did we use a maximum to define the order?
Priority Queues Using Heaps • Recall that we implemented priority queues by sorting by priority either on the enqueue or dequeue operations. • The idea: Use the priority as the key of the heap and simply bundle the actual data along with the node. • The node with maximum priority is always going to be at the root.
CRUD: Priority Queues • Enqueue (heaps): O(log n). • Dequeue (heaps): O(log n). • Peek at the top element: O(1). • Deletion from a heap takes O(log n) time, but peeking without deleting is O(1)! • This is a much better choice than the previous strategies we discussed.
Heapsort • Very simple sorting algorithm based on heaps: • Insert every element into a heap. • Retrieve and delete the root until the heap is empty. • The resulting data is sorted. • A min-heap returns the data in ascending order. • A max-heap in descending order. • Not a stable sort, and one of the most difficult to devise a stable variation to. • n elements, log(n) time for each -> O(n log n). • This algorithm competes with quicksort and mergesort due to the O(n log n) worst-case guarantee and requirement of only constant space. • It’s also an extremely simple sort to implement if you have a heap data structure.
Greedy Algorithms • Why does upheaping work? • Because the maximum at each level of the tree is guaranteed to be greater than anything below it. • Not just on the immediate level below it, but every level below it. • Finding the maximum is a good example of a “greedy” algorithm: one that makes the best possible short-term choice at each step. • For certain problems, this results in the best solution; e.g. the maximum of the whole heap at the root.
Another Example • There are pennies, nickels, dimes, and quarters. How would you make change of an arbitrary amount of money using the smallest number of coins? • Let’s say we want to make change of $0.81…
Never Reconsider • Greedy algorithms don’t reconsider their choices. They make them and move on. • You made change with quarters. • With what was left over, you went to dimes. • Then to nickels. • Then pennies. • You didn’t go back to quarters after checking the dimes. There was no need.
Is one grain of sand a heap? • We discussed heaps this time. Next time, we’ll get into hashing, one of the most useful topics we’ll discuss in the entire course. • The lesson: • It’s sometimes best not to reconsider your choices, but to make them and move on.