import java.util.Iterator; /* This class supports the abstract data type that models sets whose ** elements are drawn from a (preferably small) range of integers ** [floor..ceiling] (called the "universe"). ** ** @author R. McCloskey ** @version December 2022 */ public class SetIntRange { // class variable // -------------- public static long opCntr = 0; // for measuring performance // instance variables // ------------------ /* Representation notes: A set is represented, in part, by a bit vector, ** which is to say an array of boolean values. Specifically, the instance ** variable member[] is such that, for i in the range [0..N), where ** N = ceiling-floor+1, member[i] is true if and only if floor + i is a ** member of the set. */ protected int floor, ceiling; // universe is [floor..ceiling] protected final int N; // N = ceiling - floor + 1 (size of universe) protected int cardinality; // # members in this set protected boolean[] member; // bit vector to represent membership: // member[i] is true iff floor+i is a member // of this set // constructors // ------------ /* Initializes this set to have universe [floor .. ceiling] and no members. ** Note that the degenerate case of floor > ceiling is handled without ** error, with the resulting set having an empty universe (and hence ** necessarily having no members). ** ** @param floor : the smallest value in the universe of the new set ** @param ceiling : the largest value in the universe of the new set */ public SetIntRange(int floor, int ceiling) { this(floor, ceiling, true); } /* Initializes this set to have universe [floor .. ceiling] and to be ** either empty or else equal to its universe, according to whether the ** third argument is true or false, respectively. ** Note that the degenerate case of floor > ceiling is handled without ** error, with the resulting set having an empty universe (and hence ** necessarily having no members). ** ** @param floor : the smallest value in the universe of this new set ** @param ceiling : the largest value in the universe of this new set ** @param makeEmpty : determines whether this new set is to be initialized ** to be empty or to contain all the values in its universe */ public SetIntRange(int floor, int ceiling, boolean makeEmpty) { this.floor = floor; this.ceiling = ceiling; N = Math.max(0, ceiling - floor + 1); member = new boolean[N]; opCntr = opCntr + member.length; if (makeEmpty) { cardinality = 0; // No need to place false into elements of member[] } else { cardinality = Math.max(0, N); for (int i=0; i != member.length; i++) { member[i] = true; } } } /* Initializes this new set to have universe [floor .. ceiling] and to ** have as members precisely the values occurring in the given array. ** pre: for all i in [0..members.length), floor <= members[i] <= ceiling ** ** @param floor : the smallest value in the universe of this new set ** @param ceiling : the largest value in the universe of this new set ** @param members : array containing the initial members of this new set */ public SetIntRange(int floor, int ceiling, int[] members) { this(floor, ceiling); opCntr = opCntr + members.length; for (int i=0; i != members.length; i++) { this.absorb(members[i]); } } // observers // --------- /* Returns the smallest number in the universe of this set. */ public int floor() { opCntr++; return floor; } /* Returns the largest number in the universe of this set. */ public int ceiling() { opCntr++; return ceiling; } /* Reports whether or not the given number (k) is in this set's universe, ** which corresponds to the condition floor() <= k <= ceiling(). */ public boolean inUniverse(int k) { opCntr++; return floor <= k && k <= ceiling; } /* Returns the cardinality (i.e., # of members) of this set. */ public int cardinality() { opCntr++; return cardinality; } /* Reports whether or not this set is empty. */ public boolean isEmpty() { return cardinality() == 0; } /* Reports whether or not the given number (k) is a member of this set. */ public boolean isMemberOf(int k) { return inUniverse(k) && member[k-floor]; } /* Returns a string showing the members of this set. */ public String toString() { StringBuilder result = new StringBuilder("{"); if (isEmpty()) { result.append('}'); } else { StringBuilder s = new StringBuilder("{"); SetIntRangeIterator iter = new SetIntRangeIterator(this); result.append("" + iter.next()); while (iter.hasNext()) { result = result.append(", " + iter.next()); } result.append('}'); } return result.toString(); } // mutators // -------- /* Places the given number (k) into this set. ** If it was already a member, nothing changes. ** pre: inUniverse(k) */ public void absorb(int k) { opCntr++; int loc = k - floor; if (!member[loc]) { member[loc] = true; cardinality = cardinality + 1; } } /* Places into this set every member of the given set (s) that is ** also in this set's universe. */ public void absorb(SetIntRange s) { SetIntRangeIterator iter = new SetIntRangeIterator(s); while (iter.hasNext()) { int k = iter.next(); if (inUniverse(k)) { absorb(k); } } } /* Removes the given number (k) from this set. ** If it was not already a member, nothing changes. */ public void remove(int k) { if (inUniverse(k)) { int loc = k - floor; if (member[loc]) { member[loc] = false; cardinality = cardinality - 1; } } } /* Removes from this set every member of the given set (s). */ public void remove(SetIntRange s) { SetIntRangeIterator iter = new SetIntRangeIterator(s); while (iter.hasNext()) { int k = iter.next(); remove(k); } } /* Removes from this set every non-member of the given set (s), ** thereby resulting in this set becoming the intersection of ** itself and s. */ public void intersect(SetIntRange s) { for (int k = floor; k <= ceiling; k++) { if (!s.isMemberOf(k)) { this.remove(k); } } } /* Complements this set, which is to say that the status of every ** number in its universe changes from member to non-member, or ** vice versa. */ public void complement() { opCntr = opCntr + N; for (int i=0; i != N; i++) { member[i] = !member[i]; } cardinality = N - cardinality; } /* Makes this set equal to its universe. */ public void setToUniversal() { opCntr = opCntr + N; for (int i=0; i != N; i++) { member[i] = true; } cardinality = N; } /* Makes this set empty. */ public void setToEmpty() { opCntr = opCntr + N; for (int i=0; i != N; i++) { member[i] = false; } cardinality = 0; } // clone // ----- /* Returns a new set that is identical to this one. */ public SetIntRange clone() { SetIntRange result = new SetIntRange(floor, ceiling); result.cardinality = this.cardinality; result.member = member.clone(); return result; } // iterator // -------- /* Returns an iterator whose next() method can be used to iterate ** through the members of this set. */ public Iterator getIterator() { return new SetIntRangeIterator(this); } }