Download presentation
Presentation is loading. Please wait.
Published byMilton Wilkerson Modified over 9 years ago
1
CHAPTER 20 Advanced Data Structures
2
CHAPTER GOALS To learn about set and map data types To understand the implementation of hash tables To be able to program hash functions To learn about binary trees To be able to use tree sets and tree maps
3
Sets A set is an unordered collection of distinct elements Sets don't have duplicates Trying to add a duplicate has no effect
4
Fundamental Operations on a Set Adding an element Removing an element Containment testing (Does the set contain a given object?) Listing all elements ( in arbitrary order)
5
Sets Classes that realize the set interface o HashSet o TreeSet
6
Iterator Use an iterator to visit all elements in a set A set iterator does not visit the elements in the order in which they were inserted An element can not be added to a set at an iterator position A set element can be removed at an iterator position
7
Set Classes and Interface in the Standard Library
8
Code for Creating and Using a HashSet //Creating a hash set Set names = new HashSet(); //Adding an element names.add("Romeo"); //Removing an element names.remove("Juliet"); //Is element in set if (names.contains("Juliet") {...}
9
Listing All Elements with an Iterator Iterator iter = names.iterator(); while (iter.hasNext()) { String name = (String) iter.next(); //do something here }
10
File SetTest.java 01: import java.util.Iterator; 02: import java.util.Set; 03: 04: /** 05: This program tests the hash set class. 06: */ 07: public class SetTest 08: { 09: public static void main(String[] args) 10: { 11: Set names = new HashSet(101); // 101 is a prime 12: 13: names.add("Sue"); 14: names.add("Harry"); 15: names.add("Nina"); 16: names.add("Susannah"); 17: names.add("Larry");
11
18: names.add("Eve"); 19: names.add("Sarah"); 20: names.add("Adam"); 21: names.add("Tony"); 22: names.add("Katherine"); 23: names.add("Juliet"); 24: names.add("Romeo"); 25: names.remove("Romeo"); 26: names.remove("George"); 27: 28: Iterator iter = names.iterator(); 29: while (iter.hasNext()) 30: System.out.println(iter.next()); 31: } 32: }
12
Maps A map keeps associations between key and value objects Every key in a map has a unique value. A value may be associated with several keys
13
Maps Classes that realize the Map interface o HashMap o TreeMap
14
An Example of a Map
15
Code for Creating and Using a HashMap //Creating a HashMap Map favoriteColors = new HashMap(); //Adding an association favoriteColors.put("Juliet", Color.pink); //Changing an existing association favoriteColor.put("Juliet",Color.red);
16
Code for Creating and Using a HashMap //Getting the value associated with a key Color julietsFavoriteColor = favoriteColors.get("Juliet"); //Removing a key and its associated value favoriteColors.remove("Juliet");
17
Printing key/value Pairs Set keySet = favoriteColors.keySet(); Iterator iter = keySet.iterator(); while (iter.hasNext()) { Object key = iter.next(); Object value = favoriteColors.getkey(); System.out.println(key + "->" + value); }
18
Map Classes and Interface in the Standard Library
19
File MapTest.java 01: import java.awt.Color; 02: import java.util.HashMap; 03: import java.util.Iterator; 04: import java.util.Map; 05: import java.util.Set; 06: 07: /** 08: This program tests a map that maps names to colors. 09: */ 10: public class MapTest 11: { 12: public static void main(String[] args) 13: { 14: 15: Map favoriteColors = new HashMap(); 16: favoriteColors.put("Juliet", Color.pink); 17: favoriteColors.put("Romeo", Color.green);
20
18: favoriteColors.put("Adam", Color.blue); 19: favoriteColors.put("Eve", Color.pink); 20: print(favoriteColors); 21: } 22: 23: /** 24: Prints the contents of a map 25: @param m a map 26: */ 27: private static void print(Map m) 28: { 29: Set keySet = m.keySet(); 30: Iterator iter = keySet.iterator(); 31: while (iter.hasNext()) 32: { 33: Object key = iter.next(); 34: Object value = m.get(key); 35: System.out.println(key + "->" + value); 36: } 37: } 38: }
21
Hash Tables Hashing can be used to find elements in a data structure quickly without making a linear search A hash function computes an integer value (called the hash code) from an object A good hash function minimizes collisions, identical hash codes for different objects To compute the hash code of object x: int h = x.hashcode()
22
Sample Strings and Their Hash Codes
23
Simplistic Implementation of a Hash Table To implement o Generate hash codes for objects o Make an array o Insert each object at the location of its hash code To test if an object is contained in the set o Compute its hash code o Check if the array position with that hash code is already occupied
24
Simplistic Implementation of a Hash Table
25
Problems with Simplistic Implementation It is not possible to allocate an array that is large enough to hold all possible integer index positions It is possible for two different objects to have the same hash code
26
Solutions Pick a reasonable array size and reduce the hash codes to fall inside the array int h = x.hashCode(); if (h < 0) h = -h; h = h % size; When elements have the same hash code: ouse a link sequence to store multiple objects in the same array position oThese link sequences are called buckets
27
Hash Table with Linked Lists to Store Elements with Same Hash Code
28
Algorithm for Finding an Object x in a Hash Table Get the index h into the hash table oCompute the hash code. oReduce it modulo the table size Iterate through the elements of the bucket at position h For each element of the bucket, check whether it is equal to x If a match is found among the elements of that bucket, then x is in the set. Otherwise, x is not in the set
29
Hash Tables A hash table can be implemented as an array of buckets Buckets are sequences of links that hold elements with the same hash code The table size should be a prime number larger than the expected number of elements If there are few collisions, then adding, locating, and removing hash table elements takes constant time Big-Oh notation: O(1)
30
File HashSet.java 001: import java.util.Iterator; 002: import java.util.AbstractSet; 003: 004: /** 005: A hash set stores an unordered collection of objects, using 006: a hash table. 007: */ 008: public class HashSet extends AbstractSet 009: { 010: /** 011: Constructs a hash table. 012: @param bucketsLength the length of the buckets array 013: */ 014: public HashSet(int bucketsLength) 015: { 016: buckets = new Link[bucketsLength]; 017: size = 0;
31
018: } 019: 020: /** 021: Tests for set membership. 022: @param x an object 023: @return true if x is an element of this set 024: */ 025: public boolean contains(Object x) 026: { 027: int h = x.hashCode(); 028: if (h < 0) h = -h; 029: h = h % buckets.length; 030: 031: Link current = buckets[h]; 032: while (current != null) 033: { 034: if (current.data.equals(x)) return true; 035: current = current.next; 036: } 037: return false;
32
038: } 039: 040: /** 041: Adds an element to this set. 042: @param x an object 043: @return true if x is a new object, false if x was 044: already in the set 045: */ 046: public boolean add(Object x) 047: { 048: int h = x.hashCode(); 049: if (h < 0) h = -h; 050: h = h % buckets.length; 051: 052: Link current = buckets[h]; 053: while (current != null) 054: { 055: if (current.data.equals(x)) 056: return false; // already in the set 057: current = current.next;
33
058: } 059: Link newLink = new Link(); 060: newLink.data = x; 061: newLink.next = buckets[h]; 062: buckets[h] = newLink; 063: size++; 064: return true; 065: } 066: 067: /** 068: Removes an object from this set. 069: @param x an object 070: @return true if x was removed from this set, false 071: if x was not an element of this set 072: */ 073: public boolean remove(Object x) 074: { 075: int h = x.hashCode(); 076: if (h < 0) h = -h; 077: h = h % buckets.length;
34
078: 079: Link current = buckets[h]; 080: Link previous = null; 081: while (current != null) 082: { 083: if (current.data.equals(x)) 084: { 085: if (previous == null) buckets[h] = current.next; 086: else previous.next = current.next; 087: size--; 088: return true; 089: } 090: previous = current; 091: current = current.next; 092: } 093: return false; 094: } 095: 096: /** 097: Returns an iterator that traverses the elements of this set.
35
098: @param a hash set iterator 099: */ 100: public Iterator iterator() 101: { 102: return new HashSetIterator(); 103: } 104: 105: /** 106: Gets the number of elements in this set. 107: @return the number of elements 108: */ 109: public int size() 110: { 111: return size; 112: } 113: 114: private Link[] buckets; 115: private int size; 116: 117: private class Link
36
118: { 119: public Object data; 120: public Link next; 121: } 122: 123: private class HashSetIterator implements Iterator 124: { 125: 126: /** 127: Constructs a hash set iterator that points to the 128: first element of the hash set. 129: */ 130: public HashSetIterator() 131: { 132: bucket = 0; 133: previous = null; 134: previousBucket = buckets.length; 135: 136: // set bucket to the index of the first nonempty bucket 137: while (bucket < buckets.length && buckets[bucket] == null)
37
138: bucket++; 139: if (bucket < buckets.length) current = buckets[bucket]; 140: else current = null; 141: } 142: 143: public boolean hasNext() 144: { 145: return current != null; 146: } 147: 148: public Object next() 149: { 150: Object r = current.data; 151: 152: if (current.next == null) // move to next bucket 153: { 154: previousBucket = bucket; 155: bucket++; 156: 157: while (bucket < buckets.length && buckets[bucket] == null)
38
158: bucket++; 159: if (bucket < buckets.length) 160: current = buckets[bucket]; 161: else 162: current = null; 163: } 164: else // move to next element in bucket 165: { 166: previous = current; 167: current = current.next; 168: } 169: 170: return r; 171: } 172: 173: public void remove() 174: { 175: if (previous != null) 176: previous.next = previous.next.next; 177: else if (previousBucket < buckets.length)
39
178: buckets[previousBucket] = null; 179: else 180: throw new IllegalStateException(); 181: previous = null; 182: previousBucket = buckets.length; 183: } 184: 185: private int bucket; 186: private Link current; 187: private int previousBucket; 188: private Link previous; 189: } 190: }
40
File SetTest.java –01: import java.util.HashSet; –02: import java.util.Iterator; –03: import java.util.Set; –04: import javax.swing.JOptionPane; –05: –06: /** –07: This program demonstrates a set of strings. The user –08: can add and remove strings. –09: */ –10: public class SetTest –11: { –12: public static void main(String[] args) –13: { –14: Set names = new HashSet(); –15: –16: boolean done = false; –17: while (!done) –18: {
41
19: String input = JOptionPane.showInputDialog("Add name, Cancel when done"); 20: if (input == null) 21: done = true; 22: else 23: { 24: names.add(input); 25: print(names); 26: } 27: } 28: 29: done = false; 30: while (!done) 31: { 32: String input = JOptionPane.showInputDialog("Remove name, Cancel when done"); 33: if (input == null) 34: done = true; 35: else 36: { 37: names.remove(input); 38: print(names);
42
39: } 40: } 41: System.exit(0); 42: } 43: 44: /** 45: Prints the contents of a set 46: @param s a set 47: */ 48: private static void print(Set s) 49: { 50: Iterator iter = s.iterator(); 51: System.out.print("{ "); 52: while (iter.hasNext()) 53: { 54: System.out.print(iter.next()); 55: System.out.print(" "); 56: } 57: System.out.println("}"); 58: } 59: }
43
Hash Function A hash function computes an integer hash code from an object Choose a hash function so that different objects are likely to have different hash codes. Bad choice for hash function for a string o Adding the unicode values of the characters in the string o Because permutations ("eat" and "tea") would have the same hash code
44
Computing Hash Codes Hash function for a string s from standard library final int HASH_MULTIPLIER = 31; int h = 0; for (int i = 0; i < s.length(); i++) h = HASH_MULTIPLIER * h + s.charAt(i)
45
A hashCode method for the Coin class There are two instance fields: String coin name and double coin value Use String's hashCode method to get a hash code for the name To compute a hash code for a floating-point number: oWrap the number into a Double object oThen use Double's hashCode method Combine the two hash codes using a prime number as the HASH_MULTIPLIER
46
A hashCode method for the Coin class class Coin { public int hashCode() { int h1 = name.hashCode(); int h2 = new Double(value).hashCode(); final int HASH_MULTIPLIER = 29; int h = HASH_MULTIPLIER * h1 + h2; return h; }... }
47
Creating Hash Codes for your classes Use a prime number as the HASH_MULTIPLIER Compute the hash codes of each instance field For an integer instance field just use the field value Combine the hash codes int h = HASH_MULTIPLIER * h1 +h2; h = HASH_MULTIPLIER * h + h3; h = HASH_MULTIPLIER *h + h4;... return h;
48
Creating Hash Codes for your classes Your hashCode method must be compatible with the equals method if x.equals(y) then x.hashCode() == y.hashCode() In general, define either both hashCode and equals methods or neither
49
HashMap In a hash map, only the keys are hashed The keys need compatible hashCode and equals method
50
File Coin.java 01: /** 02: A coin with a monetary value. 03: */ 04: public class Coin 05: { 06: /** 07: Constructs a coin. 08: @param aValue the monetary value of the coin. 09: @param aName the name of the coin 10: */ 11: public Coin(double aValue, String aName) 12: { 13: value = aValue; 14: name = aName; 15: } 16: 17: /**
51
18: Gets the coin value. 19: @return the value 20: */ 21: public double getValue() 22: { 23: return value; 24: } 25: 26: /** 27: Gets the coin name. 28: @return the name 29: */ 30: public String getName() 31: { 32: return name; 33: } 34: 35: public boolean equals(Object otherObject) 36: { 37: if (otherObject == null) return false; 38: if (getClass() != otherObject.getClass()) return false;
52
39: Coin other = (Coin)otherObject; 40: return value == other.value && name.equals(other.name); 41: } 42: 43: public int hashCode() 44: { 45: int h1 = name.hashCode(); 46: int h2 = new Double(value).hashCode(); 47: final int HASH_MULTIPLIER = 29; 48: int h = HASH_MULTIPLIER * h1 + h2; 49: return h; 50: } 51: 52: public String toString() 53: { 54: return "Coin[value=" + value + ",name=" + name + "]"; 55: } 56: 57: private double value; 58: private String name; 59: }
53
File HashCodeTest.java 01: import java.util.HashSet; 02: import java.util.Iterator; 03: import java.util.Set; 04: 05: /** 06: A program to test hash codes of coins 07: */ 08: public class HashCodeTest 09: { 10: public static void main(String[] args) 11: { 12: Coin coin1 = new Coin(0.25, "quarter"); 13: Coin coin2 = new Coin(0.25, "quarter"); 14: Coin coin3 = new Coin(0.05, "nickel"); 15: 16: System.out.println("hash code of coin1=" 17: + coin1.hashCode());
54
18: System.out.println("hash code of coin2=" 19: + coin2.hashCode()); 20: System.out.println("hash code of coin3=" 21: + coin3.hashCode()); 22: 23: Set coins = new HashSet(); 24: coins.add(coin1); 25: coins.add(coin2); 26: coins.add(coin3); 27: 28: Iterator iter = coins.iterator(); 29: while (iter.hasNext()) 30: System.out.println(iter.next()); 31: } 32: }
55
Binary Search Trees Binary search trees allow for fast insertion and removal of elements A binary tree consists of two nodes, each of which has two child nodes All nodes in a binary search tree fulfill the property that: oDescendants to the left have smaller data values than the node data value oDescendants to the right have larger data values than the node data value
56
A Binary Search Tree
57
A Binary Tree That Is Not a Binary Search Tree
58
Implementing Tree Classes Implement a class for the tree containing a reference to the root node Implement a class for the nodes o A node contains two references ( to left and right child nodes) o A node contains a data field o The data field has type Comparable, so that you can compare the values in order to place them in the correct position in the binary search tree
59
Public interface for Tree and Node classes class Tree { public Tree() {... } public void insert(Comparable obj) {... } public void print() {... } private Node root; private class Node { public void insertNode(Node newNode) {... } public void printNodes() {... } public Comparable data; public Node left; public Node right; }
60
Insertion Algorithm If you encounter a non-null pointer, look at its data value o If the data value of that node is larger than the one you want to insert, continue the process with the left subtree o If the existing data is smaller, continue the process with the right subtree If you encounter a null node pointer, replace it with the new node
61
Insertion Algorithm - Tree class class Tree {... public void insert(Comparable obj) { Node newNode = new Node(); newNode.data = obj; newNode.left = null; newNode.right = null; if (root == null) root = newNode; else root.insertNode(newNode); }... }
62
Insertion Algorithm - Node class private class Node { public void insertNode(Node newNode) { if (newNode.data.compareTo(data) < 0) { if (left == null) left = newNode; else left.insertNode(newNode); } else { if (right == null) right = newNode; else right.insertNode(newNode); }... }
63
Binary Search Tree After Four Insertions The tree before the insertion of node with data "Romeo"
64
Binary Search Tree After Five Insertions The tree after the insertion of node with data "Romeo"
65
Algorithm for Printing Elements in Sorted Order Print the left subtree Print the data Print the right subtree
66
Tree Class Method to Implement Printing in Sorted Order class Tree { public void print() { if (root != null) root.printNodes(); }... }
67
Node Class Method to Implement Printing in Sorted Order private class Node { public void printNodes() { if (left != null) left.printNodes(); System.out.println(data); if (right != null) right.printNodes(); }... }
68
Binary Search Tree There is no insertion position o You can not select the position at which to insert an element The structure is self-organizing o Each element finds its own place If it is approximately balanced, then adding an element takes O(log(n)) time
69
File TreeTest.java 01: /** 02: This program tests the binary search tree class. 03: */ 04: public class TreeTest 05: { 06: public static void main(String[] args) 07: { 08: Tree names = new Tree(); 09: names.insert("Romeo"); 10: names.insert("Juliet"); 11: names.insert("Tom"); 12: names.insert("Dick"); 13: names.insert("Harry"); 14: 15: names.print(); 16: } 17: }
70
File Tree.java 01: /** 02: This class implements a binary search tree whose 03: nodes hold objects that implement the Comparable 04: interface. 05: */ 06: public class Tree 07: { 08: /** 09: Constructs an empty tree. 10: */ 11: public Tree() 12: { 13: root = null; 14: } 15: 16: /** 17: Inserts a new node into the tree.
71
18: @param obj the object to insert 19: */ 20: public void insert(Comparable obj) 21: { 22: Node newNode = new Node(); 23: newNode.data = obj; 24: newNode.left = null; 25: newNode.right = null; 26: if (root == null) root = newNode; 27: else root.insertNode(newNode); 28: } 29: 30: /** 31: Prints the contents of the tree in sorted order. 32: */ 33: public void print() 34: { 35: if (root != null) 36: root.printNodes(); 37: }
72
38: 39: private Node root; 40: 41: /** 42: A node of a tree stores a data item and references 43: of the child nodes to the left and to the right. 44: */ 45: private class Node 46: { 47: /** 48: Inserts a new node as a descendant of this node. 49: @param newNode the node to insert 50: */ 51: public void insertNode(Node newNode) 52: { 53: if (newNode.data.compareTo(data) < 0) 54: { 55: if (left == null) left = newNode; 56: else left.insertNode(newNode); 57: }
73
58: else 59: { 60: if (right == null) right = newNode; 61: else right.insertNode(newNode); 62: } 63: } 64: 65: /** 66: Prints this node and all of its descendants 67: in sorted order. 68: */ 69: public void printNodes() 70: { 71: if (left != null) 72: left.printNodes(); 73: System.out.println(data); 74: if (right != null) 75: right.printNodes(); 76: } 77:
74
78: public Comparable data; 79: public Node left; 80: public Node right; 81: } 82: }
75
TreeSet and HashSet Both implement the Set interface With a good hash function, hashing is generally faster than tree-based algorithms TreeSet's balanced tree guarantees reasonable performance TreeSet's iterator visits the elements in sorted order rather than the HashSet's random order
76
To use a TreeSet Either your objects must implement Comparable interface Or you must provide a Comparator object
77
To use a TreeMap Either the keys must implement the Comparable interface Or you must provide a Comparator object for the keys There is no requirement for the values
78
File TreeSetTest.java This program constructs a TreeSet of Coins using the CoinComparator object 01: import java.util.Comparator; 02: import java.util.Iterator; 03: import java.util.Set; 04: import java.util.TreeSet; 05: 06: /** 07: A program to test hash codes of coins 08: */ 09: public class TreeSetTest 10: { 11: public static void main(String[] args) 12: { 13: Coin coin1 = new Coin(0.25, "quarter"); 14: Coin coin2 = new Coin(0.25, "quarter");
79
15: Coin coin3 = new Coin(0.01, "penny"); 16: Coin coin4 = new Coin(0.05, "nickel"); 17: 18: class CoinComparator implements Comparator 19: { 20: public int compare(Object firstObject, Object secondObject) 21: { 22: Coin first = (Coin)firstObject; 23: Coin second = (Coin)secondObject; 24: if (first.getValue() < second.getValue()) return -1; 25: if (first.getValue() == second.getValue()) return 0; 26: return 1; 27: } 28: } 29: 30: Comparator comp = new CoinComparator(); 31: Set coins = new TreeSet(comp); 32: coins.add(coin1); 33: coins.add(coin2); 34: coins.add(coin3);
80
35: coins.add(coin4); 36: 37: Iterator iter = coins.iterator(); 38: while (iter.hasNext()) 39: System.out.println(iter.next()); 40: } 41: }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.