Java-Java程式設計思想第四版 第十七章 容器深入研究 練習
阿新 • • 發佈:2018-12-31
練習1:
/* Create a List (try both ArrayList and LinkedList) and fill it using * Countries. Sort the list and print it, then apply Collections.shuffle() * to the list repeatedly, printing it each time so that you can see how * the shuffle() method randomizes the list differently each time. */ import net.mindview.util.*; import java.util.*; import static net.mindview.util.Print.*; public class Ja17_1{ public static void main(String[] args){ List<String> ls=new ArrayList<String>(Countries.names(6)); Collections.sort(ls); print(ls); Collections.shuffle(ls); print(ls); Collections.shuffle(ls); print(ls); } }
練習2:
// Produce a Map and a Set containing all the countries that begin // with 'A'. import net.mindview.util.*; import java.util.*; import static net.mindview.util.Print.*; import java.util.regex.*; public class Ja17_2{ public static void main(String[] args){ Map<String,String> mp=new HashMap<String,String>(); for(int i=0;i<Countries.DATA.length;i++) if(Pattern.compile("A\\w+").matcher(Countries.DATA[i][0]).matches()) mp.put(Countries.DATA[i][0],Countries.DATA[i][1]); Set<String> se=mp.keySet(); print(mp); print(se); } }
練習3:
/* Using Countries, fill a Set multiple times with the same data * and verify that the Set ends up with only one of each instance. * Try this with HashSet, LinkedHashSet, and TreeSet. */ import net.mindview.util.*; import java.util.*; import static net.mindview.util.Print.*; import java.util.regex.*; public class Ja17_3{ public static void main(String[] args){ Set<String> hs=new HashSet<String>(Countries.names(6)); Set<String> ts=new TreeSet<String>(Countries.names(6)); Set<String> ls=new LinkedHashSet<String>(Countries.names(6)); print(hs); print(ts); print(ls); } }
練習4:
/* Create a Collection initializer that opens a file and breaks
* it into words using TextFile, and then uses the words as the
* source of data for the resulting Collection. Demonstrate that
* it works.
*/
import net.mindview.util.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class Ja17_4{
public static void main(String[] args){
String[] s=TextFile.read("Ja17_3.java").split("\\W+");
Set<String> se=new LinkedHashSet<String>(Arrays.asList(s));
print(se);
}
}
練習5:
// Modify Ja17_5.java to fully implement the flyweight
// by adding a custom EntrySet class like the one in Countries.java.
// See also alternate solution CountingMapData5Alt.java.
import java.util.*;
public class Ja17_5 extends AbstractMap<Integer,String> {
private static String[] chars =
"A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
.split(" ");
private static class Entry implements Map.Entry<Integer,String> {
int index;
Entry(int index) { this.index = index; }
public boolean equals(Object o) {
return Integer.valueOf(index).equals(o);
}
public Integer getKey() { return index; }
public String getValue() {
return
chars[index % chars.length] +
Integer.toString(index / chars.length);
}
public String setValue(String value) {
throw new UnsupportedOperationException();
}
public int hashCode() {
return Integer.valueOf(index).hashCode();
}
}
public class EntrySet extends AbstractSet<Map.Entry<Integer,String>>{
private int size;
public EntrySet(int size){this.size=size;}
class Iter implements Iterator<Map.Entry<Integer,String>>{
private Entry entry=new Entry(-1);
public boolean hasNext(){
return entry.index<size-1;
}
public Map.Entry<Integer,String> next(){entry.index++;return entry;}
public void remove(){}
}
public int size(){return size;}
public Iterator<Map.Entry<Integer,String>> iterator(){
return new Iter();
}
}
private Set<Map.Entry<Integer,String>> entries=new EntrySet(chars.length);
public Set<Map.Entry<Integer,String>> entrySet(){return entries;}
public static Map<Integer,String> select(final int size){
return new Ja17_5(){
public Set<Map.Entry<Integer,String>> entrySet(){
return new EntrySet(size);
}
};
}
/*
public Set<Map.Entry<Integer,String>> entrySet() {
// LinkedHashSet retains initialization order:
Set<Map.Entry<Integer,String>> entries =new EntrySet<Map.Entry<Integer,String>>();
for(int i = 0; i < size; i++)
entries.add(new Entry(i));
return entries;
}*/
public static void main(String[] args) {
System.out.println(new Ja17_5());
System.out.println(select(5));
}
}
練習6:
練習7:
/* Create both an ArrayList and a LinkedList, and fill each using the
* Countries.names() generator. Print each list using an ordinary
* iterator, then insert one list into the other by using a ListIterator,
* inserting at every other location. Now perform the insertion staring
* at the end of the first list and moving backwards.
*/
import net.mindview.util.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class Ja17_7{
public static void main(String[] args){
List<String> ll=new LinkedList<String>(Countries.names(6));
List<String> al=new ArrayList<String>(Countries.names(6));
ListIterator<String> lit=ll.listIterator();
ListIterator<String> lit2=al.listIterator();
while(lit.hasNext()){
lit.next();
if(lit.hasNext())lit.add(lit2.next());
else {lit.add(lit2.next());break;}
}
print(ll);
}
}
練習8:
/* Create a generic, singly linked list class called SList, which, to keep
* things simple, does not implement the List interface. Each Link object in
* the list should contain a reference to the next element in the list, but
* not the previous one (LinkedList, in contrast, is a doubly linked list,
* which means it maintains links in both directions). Create your own
* SListIterator which, again for simplicity, does not implement ListIterator.
* The only method in SList other than toString() should be iterator(), which
* produces an SListIterator. The only way to insert and remove elements from
* an SList is through SListIterator. Write code to demonstrate SList.
*/
import net.mindview.util.*;
import java.util.*;
import static net.mindview.util.Print.*;
class Link<T>{
Link<T> next;
T t;
public Link(T t,Link<T> next){
this.next=next;
this.t=t;
}
public Link(T t){this(t,null);}
public String toString(){
if(t==null)return "null";
else return t.toString();
}
}
class SList<T>{
private Link<T> headLink=new Link<T>(null);
public SListIterator<T> sListIterator(){
return new SListIterator<T>(headLink);
}
public String toString(){
if(headLink.next==null)return "SList: []";
SListIterator<T> sl=this.sListIterator();
StringBuilder sb=new StringBuilder();
while(sl.hasNext()){
sb.append(sl.next());
sb.append(sl.hasNext()?",":"");
}
return sb.toString();
}
}
class SListIterator<T>{
Link<T> current;
public SListIterator(Link<T> headLink){current=headLink;}
public boolean hasNext(){
return (current.next!=null);
}
public void insert(T t){
current.next=new Link<T>(t,current.next);
current=current.next;//
}
public Link<T> next(){
return current=current.next;
}
public void remove(){
if(current.next!=null)current.next=current.next.next;
}
}
public class Ja17_8{
public static void main(String[] args){
SList<String> a=new SList<String>();
SListIterator<String> sl=a.sListIterator();
sl.insert("fsd");
sl.insert("qwe");
SListIterator<String> sl2=a.sListIterator();
print(sl2.hasNext());
sl2.remove();
print(a);
}
}
練習9:
// Use RandomGenerator.String to fill a TreeSet, but use alphabetic
// ordering. Print the TreeSet to verify the sort order.
import net.mindview.util.*;
import java.util.*;
import static net.mindview.util.Print.*;
public class Ja17_9{
public static void main(String[] args){
TreeSet<String> set=new TreeSet<String>();
RandomGenerator.String a=new RandomGenerator.String();
for(int i=0;i<5;i++){
set.add(a.next());
}
print(set);
}
}
練習10:
// Using a LinkedList as your underlying implementation,
// define your own SortedSet.
import net.mindview.util.*;
import java.util.*;
import static net.mindview.util.Print.*;
class SortedSet<T> extends LinkedList<T>{
int compare(T t1,T t2){
return (t1.hashCode()<t2.hashCode()?1:(t1.hashCode()==t2.hashCode()?0:-1));
}
public boolean add(T t){
if(this.isEmpty()){add(0,t);}
if(!this.contains(t)){
Iterator<T> it=this.iterator();
int index=0;
while(it.hasNext()){
T t1=it.next();
if(compare(t1,t)==1){}
else if(compare(t1,t)==-1){index++;}
else throw new RuntimeException();
}
add(index,t);return true;
}
return false;
}
}
public class Ja17_10{
public static void main(String[] args){
RandomGenerator.String a=new RandomGenerator.String();
SortedSet<String> ss=new SortedSet<String>();
for(int i =0;i<4;i++)
ss.add(a.next());
print(ss);
}
}
練習11:
/* Create a class that contains an Integer that is initialized
* to a value between 0 and 100 using java.util.Random. Implement
* Comparable using this Integer field. Fill a PriorityQueue with
* objects of your class, and extract the values using poll() to
* show that it produces the expected order.
*/
import static net.mindview.util.Print.*;
import java.util.*;
class A implements Comparable<A>{
Random rand=new Random();
Integer i=rand.nextInt(100);
public int compareTo(A a){
return i>a.i?1:i==a.i?0:-1;
}
public String toString(){return i.toString();}
}
public class Ja17_11{
public static void main(String[] args){
PriorityQueue<A> pq=new PriorityQueue<A>();
for(int i=0;i<20;i++)
pq.offer(new A());
print(pq);
for(int j=0;j<pq.size();j++)
System.out.print(pq.remove()+", ");
}
}
PS:直接print的結果和poll, 和remove()都不一樣
練習12:
// Substitute a HashMap, a TreeMap and a LinkedHashMap
// in Ja17_12.java's main().
import static net.mindview.util.Print.*;
import java.util.*;
public class Ja17_12<K,V> {
private Object[][] pairs;
private int index;
public Ja17_12(int length) {
pairs = new Object[length][2];
}
public void put(K key, V value) {
if(index >= pairs.length)
throw new ArrayIndexOutOfBoundsException();
pairs[index++] = new Object[]{ key, value };
}
@SuppressWarnings("unchecked")
public V get(K key) {
for(int i = 0; i < index; i++)
if(key.equals(pairs[i][0]))
return (V)pairs[i][1];
return null; // Did not find key
}
public String toString() {
StringBuilder result = new StringBuilder();
for(int i = 0; i < index; i++) {
result.append(pairs[i][0].toString());
result.append(" : ");
result.append(pairs[i][1].toString());
if(i < index - 1)
result.append("\n");
}
return result.toString();
}
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>();
LinkedHashMap<String,String> map2 = new LinkedHashMap<String,String>();
TreeMap<String,String> map3 = new TreeMap<String,String>();
map.put("sky", "blue"); map.put("grass", "green"); map.put("ocean", "dancing"); map.put("tree", "tall"); map.put("earth", "brown"); map.put("sun", "warm");
map2.put("sky", "blue"); map2.put("grass", "green"); map2.put("ocean", "dancing"); map2.put("tree", "tall"); map2.put("earth", "brown"); map2.put("sun", "warm");
map3.put("sky", "blue"); map3.put("grass", "green"); map3.put("ocean", "dancing"); map3.put("tree", "tall"); map3.put("earth", "brown"); map3.put("sun", "warm");
print(map);
print(map2);
print(map3);
}
}
練習13:
/* Use AssociativeArray.java to create a word-occurrence counter,
* mapping String to Integer. Using the net.mindview.util.TextFile
* utility in this book, open a text file and break up the words
* in that file using whitespace and punctuation, and count the
* occurrence of the words in that file.
*/
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import java.util.*;
public class Ja17_13{
public static void main(String[] args){
ArrayList<String> al=new ArrayList<String>(new TextFile("Ja17_12.java","\\W+"));
Iterator<String> it=al.iterator();
LinkedHashMap<String,Integer> lhm=new LinkedHashMap<String,Integer>();
Integer i;
while(it.hasNext()){
String mm=it.next();
i=lhm.get(mm);
lhm.put(mm,i==null?1:i++);
}
print(lhm);
}
}
練習14:
// Show that java.util.Properties works in the above program (Maps.java).
import java.util.concurrent.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
public class Ja17_14 {
public static void printKeys(Map<Object,Object> map) {
printnb("Size = " + map.size() + ", ");
printnb("Keys: ");
print(map.keySet()); // Produce a Set of the keys
}
public static void test(Map<Object,Object> map) {
print(map.getClass().getSimpleName());
map.putAll(new CountingMapData(25));
// Map has 'Set' behavior for keys:
map.putAll(new CountingMapData(25));
printKeys(map);
// Producing a Collection of the values:
printnb("Values: ");
print(map.values());
print(map);
print("map.containsKey(11): " + map.containsKey(11));
print("map.get(11): " + map.get(11));
print("map.containsValue(\"F0\"): "
+ map.containsValue("F0"));
Object key=map.keySet().iterator().next();
print("First key in map: " + key);
map.remove(key);
printKeys(map);
map.clear();
print("map.isEmpty(): " + map.isEmpty());
map.putAll(new CountingMapData(25));
// Operations on the Set change the Map:
map.keySet().removeAll(map.keySet());
print("map.isEmpty(): " + map.isEmpty());
}
public static void main(String[] args) {
test(new Properties());
}
}
/*Properties
Size = 25, Keys: [24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
0]
Values: [Y0, X0, W0, V0, U0, T0, S0, R0, Q0, P0, O0, N0, M0, L0, K0, J0, I0, H0, G0, F0, E0, D0, C0, B0,
A0]
{24=Y0, 23=X0, 22=W0, 21=V0, 20=U0, 19=T0, 18=S0, 17=R0, 16=Q0, 15=P0, 14=O0, 13=N0, 12=M0, 11=L0, 10=K0,
9=J0, 8=I0, 7=H0, 6=G0, 5=F0, 4=E0, 3=D0, 2=C0, 1=B0, 0=A0}
map.containsKey(11): true
map.get(11): L0
map.containsValue("F0"): true
First key in map: 24
Size = 24, Keys: [23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
map.isEmpty(): true
map.isEmpty(): true*/
練習15:
// Repeat Exercise 13 using a SlowMap.
/* Use AssociativeArray.java to create a word-occurrence counter,
* mapping String to Integer. Using the net.mindview.util.TextFile
* utility in this book, open a text file and break up the words
* in that file using whitespace and punctuation, and count the
* occurrence of the words in that file.
*/
import containers.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import java.util.*;
public class Ja17_15{
public static void main(String[] args){
ArrayList<String> al=new ArrayList<String>(new TextFile("Ja17_14.java","\\W+"));
Iterator<String> it=al.iterator();
SlowMap<String,Integer> lhm=new SlowMap<String,Integer>();
Integer i;
while(it.hasNext()){
String mm=it.next();
i=lhm.get(mm);
lhm.put(mm,i==null?1:++i);
}
print(lhm);
}
}
練習16:
// Apply the tests in Maps.java to SlowMap to verify that it works.
// Fix anything in SlowMap that doesn't work properly.
//: containers/Maps.java
// Things you can do with Maps.
import java.util.concurrent.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import containers.*;
class SlowMap<K,V> extends AbstractMap<K,V> {
private List<K> keys = new ArrayList<K>();
private List<V> values = new ArrayList<V>();
public V put(K key, V value) {
V oldValue = get(key); // The old value or null
if(!keys.contains(key)) {
keys.add(key);
values.add(value);
} else
values.set(keys.indexOf(key), value);
return oldValue;
}
public V get(Object key) { // key is type Object, not K
if(!keys.contains(key))
return null;
return values.get(keys.indexOf(key));
}
public EntrySet entires=new EntrySet();
public EntrySet entrySet(){return new EntrySet();}
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
/*Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
Iterator<K> ki = keys.iterator();
Iterator<V> vi = values.iterator();
while(ki.hasNext())
set.add(new MapEntry<K,V>(ki.next(), vi.next()));
return set;*/
public int size(){return keys.size();}
public Iterator<Map.Entry<K,V>> iterator(){
return new Iterator<Map.Entry<K,V>>(){
private int index=-1;
public boolean hasNext(){return index<keys.size()-1;}
@SuppressWarnings("unchecked")
public Map.Entry<K,V> next(){
int i=++index;
return new MapEntry(keys.get(i),values.get(i));
}
public void remove(){keys.remove(index--);}
};
}
}
public static void main(String[] args) {
SlowMap<String,String> m= new SlowMap<String,String>();
m.putAll(Countries.capitals(15));
System.out.println(m);
System.out.println(m.get("BULGARIA"));
System.out.println(m.entrySet());
}
}
public class Ja17_16 {
public static void printKeys(Map<Integer,String> map) {
printnb("Size = " + map.size() + ", ");
printnb("Keys: ");
print(map.keySet()); // Produce a Set of the keys
}
public static void test(Map<Integer,String> map) {
print(map.getClass().getSimpleName());
map.putAll(new CountingMapData(25));
// Map has 'Set' behavior for keys:
map.putAll(new CountingMapData(25));
printKeys(map);
// Producing a Collection of the values:
printnb("Values: ");
print(map.values());
print(map);
print("map.containsKey(11): " + map.containsKey(11));
print("map.get(11): " + map.get(11));
print("map.containsValue(\"F0\"): "
+ map.containsValue("F0"));
Integer key = map.keySet().iterator().next();
print("First key in map: " + key);
map.remove(key);
printKeys(map);
map.clear();
print("map.isEmpty(): " + map.isEmpty());
map.putAll(new CountingMapData(25));
// Operations on the Set change the Map:
map.keySet().removeAll(map.keySet());
print("map.isEmpty(): " + map.isEmpty());
}
public static void main(String[] args) {
test(new HashMap<Integer,String>());
test(new SlowMap<Integer,String>());
}
}
練習17:
// Implement the rest of the Map interface for SlowMap.
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import containers.*;
public class Ja17_17<K,V> implements Map<K,V> {
private List<K> keys = new ArrayList<K>();
private List<V> values = new ArrayList<V>();
private EntrySet entries = new EntrySet();
private Set<K> keySet = new KeySet();
public Set<Map.Entry<K,V>> entrySet() { return entries; }
public Set<K> keySet() { return keySet; }
public V put(K key, V value) {
V oldValue = get(key); // The old value or null
if(!keys.contains(key)) {
keys.add(key);
values.add(value);
} else
values.set(keys.indexOf(key), value);
return oldValue;
}
public V get(Object key) { // key is type Object, not K
if(!keys.contains(key))
return null;
return values.get(keys.indexOf(key));
}
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public int size() { return keys.size(); }
public Iterator<Map.Entry<K,V>> iterator() {
return new Iterator<Map.Entry<K,V>>() {
private int index = -1;
public boolean hasNext() {
return index < keys.size() - 1;
}
@SuppressWarnings("unchecked")
public Map.Entry<K,V> next() {
int i = ++index;
return new MapEntry(
keys.get(i), values.get(i));
}
public void remove() {
keys.remove(index);
values.remove(index--);
}
};
}
}
public void clear() {
keys.clear();
values.clear();
}
public boolean containsKey(Object key) {
return keys.contains(key);
}
public boolean containsValue(Object value) {
return values.contains(value);
}
public boolean equals(Object o) {
if(o instanceof Ja17_17) {
if(this.entrySet().equals(((Ja17_17)o).entrySet()))
return true;
}
return false;
}
public int hashCode() {
return this.entrySet().hashCode();
}
public boolean isEmpty() {
return this.entrySet().isEmpty();
}
private class KeySet extends AbstractSet<K> {
public int size() { return keys.size(); }
public Iterator<K> iterator() {
return new Iterator<K>() {
private int index = -1;
public boolean hasNext() {
return index < keys.size() - 1;
}
public K next() {
int i = ++index;
return keys.get(index);
}
public void remove() {
keys.remove(index--);
}
};
}
}
public void putAll(Map<? extends K,? extends V> m) {
for(Map.Entry<? extends K,? extends V> me : m.entrySet())
this.put(me.getKey(), me.getValue());
}
public V remove(Object key) {
V v = this.get(key);
int i = keys.indexOf(key);
keys.remove(i);
values.remove(i);
return v;
}
public int size() { return keys.size(); }
public Collection<V> values() {
return values;
}
public String toString() {
return this.entrySet().toString();
}
public static void main(String[] args) {
Ja17_17<String,String> m = new Ja17_17<String,String>();
m.putAll(Countries.capitals(15));
print("m: " + m);
print("m.get(\"BURUNDI\"): " + m.get("BURUNDI"));
print("m.entrySet(): " + m.entrySet());
print("m.keySet(): " + m.keySet());
print("m.values() = " + m.values());
print("Two different maps: ");
Ja17_17<String,String> m2 = new Ja17_17<String,String>();
print("m.equals(m2): " + m.equals(m2));
m2.putAll(Countries.capitals(15));
print("Maps with same entries: ");
print("m.equals(m2): " + m.equals(m2));
m.clear();
print("After m.clear(), m.isEmpty(): " +
m.isEmpty() + ", m = " + m);
m2.keySet().clear();
print("After m2.keySet().clear(), m2.isEmpty(): "
+ m2.isEmpty() + ", m2 = " + m2);
}
}
練習18:
// Using SlowMap.java for inspiration, create a SlowSet.
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
public class Ja17_18<E> implements Set<E> {
private List<E> elements = new ArrayList<E>();
public boolean add(E e) {
if(elements.contains(e)) return false;
elements.add(e);
return true;
}
public boolean addAll(Collection<? extends E> c) {
return(elements.addAll(c));
}
public void clear() {
elements.clear();
}
public boolean contains(Object o) {
return elements.contains(o);
}
public boolean containsAll(Collection<?> c) {
int count = 0;
for(Object o : c)
if(elements.contains(o)) count++;
if(count == c.size()) return true;
return false;
}
public boolean equals(Object o) {
if(o instanceof Ja17_18) {
if((elements.size() == ((Ja17_18)o).size())) {
int count = 0;
for(int i = 0; i < elements.size(); i++)
if(elements.get(i).equals(((Ja17_18)o).elements.get(i)))
count++;
if(count == elements.size()) return true;
}
}
return false;
}
public int hashCode() {
int result = 0;
for(int i = 0; i < elements.size(); i++)
result += elements.get(i).hashCode();
return result;
}
public boolean isEmpty() {
return(elements.size() == 0);
}
public Iterator<E> iterator() {
return elements.iterator();
}
public boolean remove(Object o) {
return(elements.remove(o));
}
public boolean removeAll(Collection<?> c) {
int n = elements.size();
for(Object o : c) elements.remove(o);
if(n != elements.size()) return true;
return false;
}
public boolean retainAll(Collection<?> c) {
int n = elements.size();
for(int i = 0; i < elements.size(); i++) {
E e = elements.get(i);
if(!(c.contains(e))) elements.remove(e);
}
if(n != elements.size()) return true;
return false;
}
public int size() { return elements.size(); }
public Object[] toArray() {
return elements.toArray();
}
public <T> T[] toArray(T[] a) {
return elements.toArray(a);
}
public String toString() {
if(elements.size() == 0) return "[]";
StringBuilder s = new StringBuilder();
s.append("[");
for(int i = 0; i < elements.size() - 1; i++)
s.append(String.valueOf(elements.get(i)) + ", ");
s.append(String.valueOf(elements.get(elements.size() -1)));
s.append("]");
return s.toString();
}
public static void main(String[] args) {
Ja17_18<String> ss = new Ja17_18<String>();
ss.add("hi");
print(ss);
ss.add("there");
print(ss);
List<String> list = Arrays.asList("you", "cutie", "pie");
ss.addAll(list);
print(ss);
print("ss.size() = " + ss.size());
print("ss.contains(\"you\"): " + ss.contains("you"));
print("ss.contains(\"me\"): " + ss.contains("me"));
print("ss.containsAll(list): " + ss.containsAll(list));
Ja17_18<String> ss2 = new Ja17_18<String>();
print("ss2 = " + ss2);
print("ss.containsAll(ss2): " + ss.containsAll(ss2));
print("ss2.containAll(ss): " + ss2.containsAll(ss));
ss2.add("you");
ss2.add("cutie");
ss.removeAll(ss2);
print("ss = " + ss);
print("ss.hashCode() = " + ss.hashCode());
List<String> list2 = Arrays.asList("hi", "there", "pie");
ss2.remove("you");
print(ss2);
print("ss2.isEmpty(): " + ss2.isEmpty());
ss2.clear();
print("ss2.isEmpty(): " + ss2.isEmpty());
ss2.addAll(list2);
print("ss2 = " + ss2);
print("ss.equals(ss2): " + ss.equals(ss2));
String[] sa = new String[3];
print("ss.toArray(sa): " + ss.toArray(sa));
for(int i = 0; i < sa.length; i++) printnb(sa[i] + " " );
}
}
練習19:
// Repeat Exercise 13 using a SimpleHashMap.
import net.mindview.util.*;
import static net.mindview.util.Print.*;
import java.util.*;
import containers.*;
public class Ja17_19{
public static void main(String[] args){
ArrayList<String> al=new ArrayList<String>(new TextFile("Ja17_12.java","\\W+"));
Iterator<String> it=al.iterator();
SimpleHashMap<String,Integer> lhm=new SimpleHashMap<String,Integer>();
Integer i;
while(it.hasNext()){
String mm=it.next();
i=lhm.get(mm);
lhm.put(mm,i==null?1:++i);
}
print(lhm);
}
}
練習20:
// Modify SimpleHashMap so that it reports collisions, and test
// this by adding the same data twice so that you see collisions.
import java.util.*;
import containers.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
class SimpleHashMap<K,V> extends AbstractMap<K,V> {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
static final int SIZE = 997;
// You can't have a physical array of generics,
// but you can upcast to one:
@SuppressWarnings("unchecked")
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
public V put(K key, V value) {
V oldValue = null;
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K,V>>();
LinkedList<MapEntry<K,V>> bucket = buckets[index];
MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
boolean found = false;
ListIterator<MapEntry<K,V>> it = bucket.listIterator();
while(it.hasNext()) {
MapEntry<K,V> iPair = it.next();
if(iPair.getKey().equals(key)) {
print("collisions!collisions!");
oldValue = iPair.getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
buckets[index].add(pair);
return oldValue;
}
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return null;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return iPair.getValue();
return null;
}
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
for(LinkedList<MapEntry<K,V>> bucket : buckets) {
if(bucket == null) continue;
for(MapEntry<K,V> mpair : bucket)
set.add(mpair);
}
return set;
}
public static void main(String[] args) {
SimpleHashMap<String,String> m =
new SimpleHashMap<String,String>();
m.putAll(Countries.capitals(25));
System.out.println(m);
System.out.println(m.get("ERITREA"));
System.out.println(m.entrySet());
}
}
public class Ja17_20{
public static void main(String[] args){
SimpleHashMap<String,Integer> sh=new SimpleHashMap<String,Integer>();
sh.put("aa",1);
sh.put("aa",4);
}
}
練習21:
/* Modify SimpleHashMap.java to that it reports the number of
* "probes" necessary when collisions occur. That is, how
* many calls to next() must be made on the Iterators that
* walk the LinkedLists looking for matches?
*/
import java.util.*;
import containers.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
class SimpleHashMap<K,V> extends AbstractMap<K,V> {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
static final int SIZE = 997;
// You can't have a physical array of generics,
// but you can upcast to one:
@SuppressWarnings("unchecked")
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
public V put(K key, V value) {
V oldValue = null;
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K,V>>();
LinkedList<MapEntry<K,V>> bucket = buckets[index];
MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
boolean found = false;
ListIterator<MapEntry<K,V>> it = bucket.listIterator();
int count=0;
while(it.hasNext()) {
MapEntry<K,V> iPair = it.next();
count++;
if(iPair.getKey().equals(key)) {
print("collisions!collisions!: "+count);
oldValue = iPair.getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
buckets[index].add(pair);
return oldValue;
}
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return null;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return iPair.getValue();
return null;
}
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
for(LinkedList<MapEntry<K,V>> bucket : buckets) {
if(bucket == null) continue;
for(MapEntry<K,V> mpair : bucket)
set.add(mpair);
}
return set;
}
public static void main(String[] args) {
SimpleHashMap<String,String> m =
new SimpleHashMap<String,String>();
m.putAll(Countries.capitals(25));
System.out.println(m);
System.out.println(m.get("ERITREA"));
System.out.println(m.entrySet());
}
}
public class Ja17_21{
public static void main(String[] args){
SimpleHashMap<String,Integer> sh=new SimpleHashMap<String,Integer>();
sh.put("aa",1);
sh.put("bb",1);
sh.put("cc",1);
sh.put("ee",1);
sh.put("ff",1);
sh.put("mm",1);
sh.put("ee",4);
}
}
練習22:
// Implement the clear() and remove() methods for SimpleHashMap.
import java.util.*;
import containers.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
class SimpleHashMap<K,V> extends AbstractMap<K,V> {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
static final int SIZE = 997;
// You can't have a physical array of generics,
// but you can upcast to one:
@SuppressWarnings("unchecked")
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
public V remove(Object o){
V v=null;
if(this.get(o)!=null){
int index=Math.abs(o.hashCode())%SIZE;
for(MapEntry<K,V> ipair:buckets[index])
if(ipair.getKey().equals(o)){
int i=buckets[index].indexOf(ipair);
buckets[index].remove(i);
v=ipair.getValue();
break;
}
}
return v;
}
public void clear(){
for(LinkedList<MapEntry<K,V>> b:buckets){
if(b!=null)b.clear();
}
}
public V put(K key, V value) {
V oldValue = null;
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K,V>>();
LinkedList<MapEntry<K,V>> bucket = buckets[index];
MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
boolean found = false;
ListIterator<MapEntry<K,V>> it = bucket.listIterator();
int count=0;
while(it.hasNext()) {
MapEntry<K,V> iPair = it.next();
count++;
if(iPair.getKey().equals(key)) {
print("collisions!collisions!: "+count);
oldValue = iPair.getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
buckets[index].add(pair);
return oldValue;
}
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return null;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return iPair.getValue();
return null;
}
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();
for(LinkedList<MapEntry<K,V>> bucket : buckets) {
if(bucket == null) continue;
for(MapEntry<K,V> mpair : bucket)
set.add(mpair);
}
return set;
}
public static void main(String[] args) {
SimpleHashMap<String,String> m =
new SimpleHashMap<String,String>();
m.putAll(Countries.capitals(25));
System.out.println(m);
System.out.println(m.get("ERITREA"));
System.out.println(m.entrySet());
}
}
public class Ja17_22{
public static void main(String[] args){
SimpleHashMap<String,Integer> sh=new SimpleHashMap<String,Integer>();
sh.put("aa",1);
sh.put("bb",1);
sh.put("cc",1);
sh.put("ee",1);
sh.put("ff",1);
sh.put("mm",1);
sh.put("ee",4);
print(sh.remove("ee"));
print(sh);
sh.clear();
print(sh);
}
}
練習23:
// Implement the rest of the Map interface for SimpleHashMap.
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
public class SimpleHashMap23<K,V> implements Map<K,V> {
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
static final int SIZE = 997;
// You can't have a physical array of generics,
// but you can upcast to one:
@SuppressWarnings("unchecked")
LinkedList<MapEntry<K,V>>[] buckets = new LinkedList[SIZE];
public int size() {
int result = 0;
for(LinkedList bucket : buckets)
if(bucket != null) result += bucket.size();
return result;
}
// Three methods to help with proper iteration by EntrySet.iterator():
private int firstNonEmptyBucket() {
if(buckets.length < 1) return -1;
for(int j = 0; j < buckets.length; j++)
if(buckets[j] != null) return j;
return -1;
}
private int start(int i) {
int first = this.firstNonEmptyBucket();
if(i < first) return -1;
if(i == first) return 0;
int result = 0;
for(int j = first; j < i; j++)
if(buckets[j] != null) result += buckets[j].size();
return result;
}
private int end(int i) {
int first = this.firstNonEmptyBucket();
if(i < first) return -1;
return start(i) + ((buckets[i] == null) ? 0 : buckets[i].size());
}
private EntrySet entries = new EntrySet();
private KeySet keys = new KeySet();
public Set<Map.Entry<K,V>> entrySet() { return entries; }
public Set<K> keySet() { return keys; }
public boolean isEmpty() {
return this.size() == 0;
}
public V put(K key, V value) {
V oldValue = null;
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null)
buckets[index] = new LinkedList<MapEntry<K,V>>();
LinkedList<MapEntry<K,V>> bucket = buckets[index];
MapEntry<K,V> pair = new MapEntry<K,V>(key, value);
boolean found = false;
ListIterator<MapEntry<K,V>> it = bucket.listIterator();
while(it.hasNext()) {
MapEntry<K,V> iPair = it.next();
if(iPair.getKey().equals(key)) {
oldValue = iPair.getValue();
it.set(pair); // Replace old with new
found = true;
break;
}
}
if(!found)
buckets[index].add(pair);
return oldValue;
}
public void putAll(Map<? extends K, ? extends V> m) {
for(Map.Entry<? extends K,? extends V> me : m.entrySet())
this.put(me.getKey(), me.getValue());
}
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return null;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return iPair.getValue();
return null;
}
public void clear() {
for(LinkedList<MapEntry<K,V>> bucket : buckets)
if(bucket != null) bucket.clear();
}
public boolean containsKey(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return false;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return true;
return false;
}
public boolean containsValue(Object value) {
for(LinkedList<MapEntry<K,V>> bucket : buckets) {
if(bucket != null)
for(MapEntry<K,V> iPair : bucket)
if(iPair.getValue().equals(value)) return true;
}
return false;
}
public Collection<V> values() {
HashSet<V> vals = new HashSet<V>();
for(LinkedList<MapEntry<K,V>> bucket : buckets) {
if(bucket != null)
for(MapEntry<K,V> iPair : bucket)
vals.add(iPair.getValue());
}
return vals;
}
public boolean equals(Object o) {
if(o instanceof SimpleHashMap23) {
if(this.entrySet().equals(((SimpleHashMap23)o).entrySet()))
return true;
}
return false;
}
public int hashCode() {
return this.entrySet().hashCode();
}
public V remove(Object o) {
V v = null;
if(this.get(o) != null) {
int index = Math.abs(o.hashCode()) % SIZE;
for(MapEntry<K,V> iPair : buckets[index])
if(iPair.getKey().equals(o)) {
v = iPair.getValue();
int i =
buckets[index].indexOf(iPair);
buckets[index].remove(i);
break;
}
}
return v;
}
private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public int size() { return SimpleHashMap23.this.size(); }
public Iterator<Map.Entry<K,V>> iterator() {
return new Iterator<Map.Entry<K,V>>() {
private int index = -1;
public boolean hasNext() {
return index < SimpleHashMap23.this.size() - 1;
}
@SuppressWarnings("unchecked")
public Map.Entry<K,V> next() {
int i = ++index;
for(int j = 0; j < SIZE; j++) {
if((start(j) <= index) && (index < end(j)))
return new MapEntry(
buckets[j].get(index - start(j)).getKey(),
buckets[j].get(index - start(j)).getValue());
}
return null;
}
public void remove() {
for(int j = 0; j < SIZE; j++)
if(start(j) <= index && index < end(j))
buckets[j].remove(index - start(j));
index--;
}
};
}
}
private class KeySet extends AbstractSet<K> {
public int size() { return SimpleHashMap23.this.size(); }
public Iterator<K> iterator() {
return new Iterator<K>() {
private int index = -1;
public boolean hasNext() {
return index < SimpleHashMap23.this.size() - 1;
}
public K next() {
int i = ++index;
for(int j = 0; j < SIZE; j++) {
if((start(j) <= index) && (index < end(j)))
return buckets[j].get(index - start(j)).getKey();
}
return null;
}
public void remove() {
for(int j = 0; j < SIZE; j++)
if(start(j) <= index && index < end(j))
buckets[j].remove(index - start(j));
index--;
}
};
}
}
public String toString() {
return this.entrySet().toString();
}
public static void main(String[] args) {
SimpleHashMap23<String,String> map =
new SimpleHashMap23<String,String>();
map.putAll(Countries.capitals(3));
print("map = " + map);
print("map.entrySet(): " + map.entrySet());
print("map.keySet(): " + map.keySet());
print("map.values() = " + map.values());
print("map.isEmpty(): " + map.isEmpty());
print("map.containsKey(\"ALGERIA\"): " + map.containsKey("ALGERIA"));
print("map.containsValue(\"Algiers\"): " + map.containsValue("Algiers"));
print("map.get(\"ALGERIA\"): " + map.get("ALGERIA"));
print("map.remove(\"ALGERIA\"): " + map.remove("ALGERIA"));
print("After map.remove(\"ALGERIA\"), map.containsKey(\"ALGERIA\"): " +
map.containsKey("ALGERIA"));
print(" and map.get(\"ALGERIA\"): " + map.get("ALGERIA"));
print(" and map: = " + map);
map.clear();
print("After map.clear(), map = " + map);
print(" and map.isEmpty(): " + map.isEmpty());
map.putAll(Countries.capitals(3));
print("After map.putAll(Countries.capitals(3)), map = " + map);
SimpleHashMap23<String,String> map2 =
new SimpleHashMap23<String,String>();
map2.putAll(Countries.capitals(4));
print("After map2.putAll(Countries.capitals(4)), map2 = " + map2);
print(" and map.equals(map2): " + map.equals(map2));
map2.remove("BOTSWANA");
print("After map2.remove(\"BOTSWANT\"), map.equals(map2): " + map.equals(map2));
map.entrySet().clear();
print("After map.entrySet().clear, map = " + map);
map.putAll(Countries.capitals(3));
print("After map.putAll(Countries.capitals(3)), map = " + map);
map.keySet().clear();
print("After map.keySet().clear(), map = " + map);
}
}
練習24:
// Following the example in SimpleHashMap.java,
// create and test a SimpleHashSet.
import java.util.*;
import net.mindview.util.*;
import static net.mindview.util.Print.*;
class SimpleHashSet24<E> implements Set<E> {
static final int SIZE = 997;
@SuppressWarnings("unchecked")
LinkedList<E>[] buckets = new LinkedList[SIZE];
public int size(){
int result=0;
for(LinkedList<E> bucket:buckets){
if(bucket!=null)result+=bucket.size();
}
return result;
}
public boolean add(E e){
if(this.contains(e))return false;
int index=e.hashCode()%SIZE;
if(buckets[index]==null)buckets[index]=new LinkedList<E>();
buckets[index].add(e);
return true;
}
public boolean addAll(Collection<? extends E> c) {
int start = this.size();
for(E e : c) this.add(e);
return(this.size() > start);
}
public void clear() {
for(LinkedList<E> bucket : buckets)
if(bucket != null) bucket.clear();
}
public boolean contains(Object o) {
int index = Math.abs(o.hashCode()) % SIZE;
if(buckets[index] == null) return false;
for(E e : buckets[index])
if(e.equals(o)) return true;
return false;
}
public boolean containsAll(Collection<?> c) {
int count = 0;
for(Object o : c)
if(this.contains(o)) count++;
if(count == c.size()) return true;
return false;
}
public boolean equals(Object o) {
if(o instanceof SimpleHashSet24) {
if((this.size() == ((SimpleHashSet24)o).size())) {
int count = 0;
Iterator it = ((SimpleHashSet24)o).iterator();
while(it.hasNext())
if(this.contains(it.next())) count++;
if(count == this.size()) return true;
}
}
return false;
}
public int hashCode(){
int result=0;
for(LinkedList<E> bucket:buckets){
if(bucket!=null)
for(E e:bucket){
if(e!=null)result+=e.hashCode();
}
}
return result;
}
public boolean isEmpty() {
return(this.size() == 0);
}
// Three methods to help with proper iteration by SimpleHashSet.iterator():
private int firstNonEmptyBucket() {
if(buckets.length < 1) return -1;
for(int j = 0; j < buckets.length; j++)
if(buckets[j] != null) return j;
return -1;
}
private int start(int i) {
int first = this.firstNonEmptyBucket();
if(i < first) return -1;
if(i == first) return 0;
int result = 0;
for(int j = first; j < i; j++)
if(buckets[j] != null) result += buckets[j].size();
return result;
}
private int end(int i) {
int first = this.firstNonEmptyBucket();
if(i < first) return -1;
return start(i) + ((buckets[i] == null) ? 0 : buckets[i].size());
}
public Iterator<E> iterator() {
return new Iterator<E>() {
private int index = -1;
public boolean hasNext() {
return index < SimpleHashSet24.this.size() - 1;
}
public E next() {
int i = ++index;
for(int j = 0; j < SIZE; j++) {
if((start(j) <= index) && (index < end(j)))
return buckets[j].get(index - start(j));
}
return null;
}
public void remove() {
for(int j = 0; j < SIZE; j++)
if(start(j) <= index && index < end(j))
buckets[j].remove(index - start(j));
index--;
}
};
}
public boolean remove(Object o) {
int index = Math.abs(o.hashCode()) % SIZE;
if(buckets[index] == null) return false;
for(E e : buckets[index]) {
if(e.equals(o)) {
buckets[index].remove(e);
return true;
}
}
return false;
}
public boolean removeAll(Collection<?> c) {
int n = this.size();
for(Object o : c) this.remove(o);
if(n != this.size()) return true;
return false;
}
public boolean retainAll(Collection<?> c) {
int n = this.size();
for(LinkedList<E> bucket : buckets) {
for(E e : bucket)
if(!(c.contains(e))) this.remove(e);
}
if(n != this.size()) return true;
return false;
}
public Object[] toArray() {
Object[] result = new Object[this.size()];
Iterator<E> it = this.iterator();
for(int i = 0; i < this.size(); i++)
result[i] = it.next();
return result;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
Iterator<E> it = this.iterator();
for(int i = 0; i < this.size(); i++) {
E x = it.next();
try {
a[i] = (T)x;
} catch(ClassCastException e) {
throw new RuntimeException(e);
}
}
return a;
}
public String toString() {
if(this.size() == 0) return "[]";
StringBuilder s = new StringBuilder();
s.append("[");
for(LinkedList<E> bucket : buckets) {
if(bucket != null)
for(E e : bucket)
s.append(String.valueOf(e) + " ");
}
s.replace(s.length() - 1, s.length(), "]");
return s.toString();
}
}
public class Ja17_24{
public static void main(String[] args) {
SimpleHashSet24<String> shs = new SimpleHashSet24<String>();
print("New empty SimpleHashSet24, shs = " + shs);
shs.add("hi");
shs.add("there");
print("After shs.add(\"hi\") and shs.add(\"there\"), shs = " + shs);
List<String> list = Arrays.asList("you", "cutie", "pie");
shs.addAll(list);
print("After shs.addAll(list) (you, cutie, pie), shs = " + shs);
print("shs.size() = " + shs.size());
print("shs.contains(\"you\"): " + shs.contains("you"));
print("shs.contains(\"me\"): " + shs.contains("me"));
print("shs.containsAll(list): " + shs.containsAll(list));
SimpleHashSet24<String> shs2 = new SimpleHashSet24<String>();
print("New empty shs2 = " + shs2);
print("shs.containsAll(list): " + shs.containsAll(list));
print("shs2.containAll(list): " + shs2.containsAll(list));
print("shs.containsAll(shs2): " + shs.containsAll(shs2));
print("shs2.containAll(shs2): " + shs2.containsAll(shs2));
shs2.add("you");
shs2.add("cutie");
print("After shs2.add(\"you\"), shs2.add(\"cutie\"), shs2 = " + shs2);
shs.removeAll(shs2);
print("After shs.removeAll(shs2), shs = " + shs);
print("shs.hashCode() = " + shs.hashCode());
print("shs2 = " + shs2);
print("shs2.isEmpty(): " + shs2.isEmpty());
shs2.clear();
print("After shs2.clear(), shs2.isEmpty(): " + shs2.isEmpty());
List<String> list2 = Arrays.asList("hi", "there", "pie");
shs2.addAll(list2);
print("After shs2.addAll(list2) (hi, there, pie), shs2 = " + shs2);
print("shs.equals(shs2): " + shs.equals(shs2));
String[] sa = new String[3];
shs.toArray(sa);
printnb("After String[] sa = new String[3], shs.toArray(sa), sa holds: ");
for(int i = 0; i < sa.length; i++) printnb(sa[i] + " " );
}
}
練習25:
/* Instead of using a ListIterator for each bucket, modify MapEntry so that
* it is a self-contained singly linked list (each MapEntry should have a
* forward link to the next MapEntry). Modify the rest of the code in
* SimpleHashMap.java so that this new approach works correctly.
*/
import java.util.*;
import containers.*;
import net.mindview.util.*;
class SimpleHashMap<K,V> extends AbstractMap<K,V> {
class MapEntry25<K,V> implements Map.Entry<K,V> {
private K key;
private V value;
private MapEntry25<K,V> nextEntry = null;
public MapEntry25(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
public V setValue(V v) {
V result = value;
value = v;
return result;
}
public MapEntry25<K,V> getNextEntry() {
return this.nextEntry;
}
public void setNextEntry(MapEntry25<K,V> nextEntry) {
this.nextEntry = nextEntry;
}
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public boolean equals(Object o) {
if(!(o instanceof MapEntry25)) return false;
MapEntry25 me = (MapEntry25)o;
return
(key == null ?
me.getKey() == null : key.equals(me.getKey())) &&
(value == null ?
me.getValue() == null : value.equals(me.getValue()));
}
public String toString() { return key + "=" + value; }
}
// Choose a prime number for the hash table
// size, to achieve a uniform distribution:
static final int SIZE = 997;
// You can't have a physical array of generics,
// but you can upcast to one:
@SuppressWarnings("unchecked")
LinkedList<MapEntry25<K,V>>[] buckets =
new LinkedList[SIZE];
public V put(K key, V value) {
V oldValue = null;
MapEntry25<K,V> pair = new MapEntry25<K,V>(key, value);
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) {
buckets[index] = new LinkedList<MapEntry25<K,V>>();
LinkedList<MapEntry25<K,V>> bucket = buckets[index];
bucket.add(pair);
}
LinkedList<MapEntry25<K,V>> bucket = buckets[index];
if(buckets[index].size() > 0) {
for(MapEntry25<K,V> entry = bucket.get(0); entry != null;
entry = entry.getNextEntry()) {
if(entry.getKey().equals(key)) {
oldValue = entry.getValue();
entry.setValue(value);
return oldValue;
}
}
bucket.add(pair);
int i = bucket.indexOf(pair);
if(i > 0) bucket.get(i - 1).setNextEntry(pair);
return pair.getValue();
}
return oldValue;
}
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if(buckets[index] == null) return null;
for(MapEntry25<K,V> iPair : buckets[index])
if(iPair.getKey().equals(key))
return iPair.getValue();
return null;
}
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> set = new HashSet<Map.Entry<K,V>>();
for(LinkedList<MapEntry25<K,V>> bucket : buckets) {
if(bucket == null) continue;
for(MapEntry25<K,V> mpair : bucket)
set.add(mpair);
}
return set;
}
}
class MapEntry<K,V> implements Map.Entry<K,V> {
private K key;
private V value;
public MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
public V setValue(V v) {
V result = value;
value = v;
return result;
}
public int hashCode() {
return (key==null ? 0 : key.hashCode()) ^
(value==null ? 0 : value.hashCode());
}
public boolean equals(Object o) {
if(!(o instanceof MapEntry)) return false;
MapEntry me = (MapEntry)o;
return
(key == null ?
me.getKey() == null : key.equals(me.getKey())) &&
(value == null ?
me.getValue()== null : value.equals(me.getValue()));
}
public String toString() { return key + "=" + value; }
} ///:~
public class Ja17_25{
public static void main(String[] args) {
SimpleHashMap<String,String> m =
new SimpleHashMap<String,String>();
m.putAll(Countries.capitals(5));
System.out.println(m);
System.out.println(m.put("BENIN","New York?"));
System.out.println(m.put("BENIN","Porto-Novo"));
System.out.println(m.get("BENIN"));
System.out.println(m.entrySet());
}
}
練習26:
/* Add a char field to CountedString that is also initialized in the
* constructor; and modify the hashCode() and equals() methods to
* include the value of this char.
*/
import java.util.*;
import static net.mindview.util.Print.*;
class CountedString {
private static List<String> created =
new ArrayList<String>();
private String s;
private char ch;
private int id = 0;
public CountedString(String str) {
s = str;
created.add(s);
// id is the total number of instances
// of this string in use by CountedString:
for(String s2 : created)
if(s2.equals(s))
{id++;ch=(char)(id/2);}
}
public String toString() {
return "String: " + s + " id: " + id +
" hashCode(): " + hashCode();
}
public int hashCode() {
// The very simple approach:
// return s.hashCode() * id;
// Using Joshua Bloch's recipe:
int result = 17;
result = 37 * result + s.hashCode();
result = 37 * result + id;
result = 37 * result + (int)ch;
return result;
}
public boolean equals(Object o) {
return o instanceof CountedString &&
s.equals(((CountedString)o).s) &&
id == ((CountedString)o).id;
}
}
public class Ja17_26{
public static void main(String[] args) {
Map<CountedString,Integer> map =
new HashMap<CountedString,Integer>();
CountedString[] cs = new CountedString[5];
for(int i = 0; i < cs.length; i++) {
cs[i] = new CountedString("hi");
map.put(cs[i], i); // Autobox int -> Integer
}
print(map);
for(CountedString cstring : cs) {
print("Looking up " + cstring);
print(map.get(cstring));
}
}
}
練習27:
/* Modify the hashCode() in CountedString.java by removing the combination
* with id, and demonstrate that CountedString still works as a key. What
* is the problem with this approach?
*/
/* Add a char field to CountedString that is also initialized in the
* constructor; and modify the hashCode() and equals() methods to
* include the value of this char.
*/
import java.util.*;
import static net.mindview.util.Print.*;
class CountedString {
private static List<String> created =
new ArrayList<String>();
private String s;
private int id = 0;
public CountedString(String str) {
s = str;
created.add(s);
// id is the total number of instances
// of this string in use by CountedString:
for(String s2 : created)
if(s2.equals(s))
id++;
}
public String toString() {
return "String: " + s + " id: " + id +
" hashCode(): " + hashCode();
}
public int hashCode() {
// The very simple approach:
// return s.hashCode() * id;
// Using Joshua Bloch's recipe:
int result = 17;
result = 37 * result + s.hashCode();
return result;
}
public boolean equals(Object o) {
return o instanceof CountedString &&
s.equals(((CountedString)o).s) &&
id == ((CountedString)o).id;
}
}
public class Ja17_27{
public static void main(String[] args) {
Map<CountedString,Integer> map =
new HashMap<CountedString,Integer>();
CountedString[] cs = new CountedString[5];
for(int i = 0; i < cs.length; i++) {
cs[i] = new CountedString("hi");
map.put(cs[i], i); // Autobox int -> Integer
}
print(map);
for(CountedString cstring : cs) {
print("Looking up " + cstring);
print(map.get(cstring));
}
}
}
練習28:
/* Modify net/mindview/util/Tuple.java to make it a
* general-purpose class by adding hashCode(), equals(),
* and implementing Comparable for each type of Tuple.
*/
import net.mindview.util.*;
class TwoTuple<A,B> implements Comparable{
public final A first;
public final B second;
public TwoTuple(A a, B b) { first = a; second = b; }
public String toString() {
return "(" + first + ", " + second + ")";
}
public int hashCode(){
int result=17;
result=result*37+first.hashCode();
result=result*37+second.hashCode();
return result;
}
public boolean equals(Object o){
if(o.getClass().getSimpleName()==getClass().getSimpleName()){
TwoTuple to=(TwoTuple)o;
if(first.equals((TwoTuple)to.first))
if(second.equals((TwoTuple)to.second))
return true;
}
return false;
}
public int compareTo(Object o){
int c1=(o.getClass().getSimpleName().compareTo(getClass().getSimpleName()));
if(c1!=0)return c1;
TwoTuple to=(TwoTuple)o;
return ((this.hashCode()<to.hashCode())?-1:(this.hashCode()==to.hashCode()?0:1));
}
}
class ThreeTuple<A,B,C> extends TwoTuple<A,B> {
public final C third;
public ThreeTuple(A a, B b, C c) {
super(a, b);
third = c;
}
public String toString() {
return "(" + first + ", " + second + ", " + third +")";
}
}
class Tuple {
public static <A,B> TwoTuple<A,B> tuple(A a, B b) {
return new TwoTuple<A,B>(a, b);
}
public static <A,B,C> ThreeTuple<A,B,C>
tuple(A a, B b, C c) {
return new ThreeTuple<A,B,C>(a, b, c);
}
public static <A,B,C,D> FourTuple<A,B,C,D>
tuple(A a, B b, C c, D d) {
return new FourTuple<A,B,C,D>(a, b, c, d);
}
public static <A,B,C,D,E>
FiveTuple<A,B,C,D,E> tuple(A a, B b, C c, D d, E e) {
return new FiveTuple<A,B,C,D,E>(a, b, c, d, e);
}
public static <A,B,C,D,E,F>
SixTuple<A,B,C,D,E,F> tuple(A a, B b, C c, D d, E e,F f) {
return new SixTuple<A,B,C,D,E,F>(a, b, c, d, e,f);
}
} ///:~
public class Ja17_28{
public static void main(String[] args) {
}
}
練習29:
// Modify ListPerformance.java so that the Lists hold String objects instead
// of Strings. Use a Generator from the Arrays chapter to create test values.
import java.util.*;
import net.mindview.util.*;
import containers.*;
abstract class Test<C> {
String name;
public Test(String name) { this.name = name; }
// Override this method for different tests.
// Returns actual number of repetitions of test.
abstract int test(C container, TestParam tp);
}
class TestParam {
public final int size;
public final int loops;
public TestParam(int size, int loops) {
this.size = size;
this.loops = loops;
}
// Create an array of TestParam from a varargs sequence:
public static TestParam[] array(int... values) {
int size = values.length/2;
TestParam[] result = new TestParam[size];
int n = 0;
for(int i = 0; i < size; i++)
result[i] = new TestParam(values[n++], values[n++]);
return result;
}
// Convert a String array to a TestParam array:
public static TestParam[] array(String[] values) {
int[] vals = new int[values.length];
for(int i = 0; i < vals.length; i++)
vals[i] = Integer.decode(values[i]);
return array(vals);
}
}
class Tester<C> {
public static int fieldWidth = 8;
public static TestParam[] defaultParams= TestParam.array(
10, 5000, 100, 5000, 1000, 5000, 10000, 500);
// Override this to modify pre-test initialization:
protected C initialize(int size) { return container; }
protected C container;
private String headline = "";
private List<Test<C>> tests;
private static String stringField() {
return "%" + fieldWidth + "s";
}
private static String numberField() {
return "%" + fieldWidth + "d";
}
private static int sizeWidth = 5;
private static String sizeField = "%" + sizeWidth + "s";
private TestParam[] paramList = defaultParams;
public Tester(C container, List<Test<C>> tests) {
this.container = container;
this.tests = tests;
if(container != null)
headline