001 /* 002 * $Id: KsubSet.java 3571 2011-03-18 22:02:51Z kredel $ 003 */ 004 005 package edu.jas.util; 006 007 008 import java.util.Iterator; 009 import java.util.LinkedList; 010 import java.util.List; 011 import java.util.NoSuchElementException; 012 013 014 /** 015 * K-Subset with iterator. 016 * @author Heinz Kredel 017 */ 018 public class KsubSet<E> implements Iterable<List<E>> { 019 020 021 /** 022 * data structure. 023 */ 024 public final List<E> set; // Iterable<E> also ok 025 026 027 public final int k; 028 029 030 /** 031 * KsubSet constructor. 032 * @param set generating set. 033 * @param k size of subsets. 034 */ 035 public KsubSet(List<E> set, int k) { 036 if (set == null) { 037 throw new IllegalArgumentException("null set not allowed"); 038 } 039 this.set = set; 040 if (k < 0 || k > set.size()) { 041 throw new IllegalArgumentException("k out of range"); 042 } 043 this.k = k; 044 } 045 046 047 /** 048 * Get an iterator over subsets. 049 * @return an iterator. 050 */ 051 public Iterator<List<E>> iterator() { 052 if (k == 0) { 053 return new ZeroSubSetIterator<E>(set); 054 } 055 if (k == 1) { 056 return new OneSubSetIterator<E>(set); 057 } 058 return new KsubSetIterator<E>(set, k); 059 } 060 061 } 062 063 064 /** 065 * Power set iterator. 066 * @author Heinz Kredel 067 */ 068 class KsubSetIterator<E> implements Iterator<List<E>> { 069 070 071 /** 072 * data structure. 073 */ 074 public final List<E> set; 075 076 077 public final int k; 078 079 080 final List<E> rest; 081 082 083 private E current; 084 085 086 private Iterator<List<E>> recIter; 087 088 089 private final Iterator<E> iter; 090 091 092 /** 093 * KsubSetIterator constructor. 094 * @param set generating set. 095 * @param k subset size. 096 */ 097 public KsubSetIterator(List<E> set, int k) { 098 if (set == null || set.size() == 0) { 099 throw new IllegalArgumentException("null or empty set not allowed"); 100 } 101 this.set = set; 102 if (k < 2 || k > set.size()) { 103 throw new IllegalArgumentException("k out of range"); 104 } 105 this.k = k; 106 iter = set.iterator(); 107 current = iter.next(); 108 //System.out.println("current = " + current); 109 rest = new LinkedList<E>(set); 110 rest.remove(0); 111 //System.out.println("rest = " + rest); 112 if (k == 2) { 113 recIter = new OneSubSetIterator<E>(rest); 114 } else { 115 recIter = new KsubSetIterator<E>(rest, k - 1); 116 } 117 } 118 119 120 /** 121 * Test for availability of a next subset. 122 * @return true if the iteration has more subsets, else false. 123 */ 124 public boolean hasNext() { 125 return recIter.hasNext() || (iter.hasNext() && rest.size() >= k); 126 } 127 128 129 /** 130 * Get next subset. 131 * @return next subset. 132 */ 133 public List<E> next() { 134 if (recIter.hasNext()) { 135 List<E> next = new LinkedList<E>(recIter.next()); 136 next.add(0, current); 137 return next; 138 } 139 if (iter.hasNext()) { 140 current = iter.next(); 141 //System.out.println("current = " + current); 142 rest.remove(0); 143 //System.out.println("rest = " + rest); 144 if (rest.size() < k - 1) { 145 throw new NoSuchElementException("invalid call of next()"); 146 } 147 if (k == 2) { 148 recIter = new OneSubSetIterator<E>(rest); 149 } else { 150 recIter = new KsubSetIterator<E>(rest, k - 1); 151 } 152 return this.next(); // retry 153 } 154 throw new NoSuchElementException("invalid call of next()"); 155 } 156 157 158 /** 159 * Remove the last subset returned from underlying set if allowed. 160 */ 161 public void remove() { 162 throw new UnsupportedOperationException("cannnot remove subsets"); 163 } 164 165 } 166 167 168 /** 169 * One-subset iterator. 170 * @author Heinz Kredel 171 */ 172 class OneSubSetIterator<E> implements Iterator<List<E>> { 173 174 175 /** 176 * data structure. 177 */ 178 public final List<E> set; 179 180 181 private Iterator<E> iter; 182 183 184 /** 185 * OneSubSetIterator constructor. 186 * @param set generating set. 187 */ 188 public OneSubSetIterator(List<E> set) { 189 this.set = set; 190 if (set == null || set.size() == 0) { 191 iter = null; 192 return; 193 } 194 iter = set.iterator(); 195 } 196 197 198 /** 199 * Test for availability of a next subset. 200 * @return true if the iteration has more subsets, else false. 201 */ 202 public boolean hasNext() { 203 if (iter == null) { 204 return false; 205 } 206 return iter.hasNext(); 207 } 208 209 210 /** 211 * Get next subset. 212 * @return next subset. 213 */ 214 public List<E> next() { 215 List<E> next = new LinkedList<E>(); 216 next.add(iter.next()); 217 return next; 218 } 219 220 221 /** 222 * Remove the last subset returned from underlying set if allowed. 223 */ 224 public void remove() { 225 throw new UnsupportedOperationException("cannnot remove subsets"); 226 } 227 228 } 229 230 231 /** 232 * Zero-subset iterator. 233 * @author Heinz Kredel 234 */ 235 class ZeroSubSetIterator<E> implements Iterator<List<E>> { 236 237 238 /** 239 * data structure. 240 */ 241 private boolean hasNext; 242 243 244 /** 245 * ZeroSubSetIterator constructor. 246 * @param set generating set (ignored). 247 */ 248 public ZeroSubSetIterator(List<E> set) { 249 hasNext = true; 250 } 251 252 253 /** 254 * Test for availability of a next subset. 255 * @return true if the iteration has more subsets, else false. 256 */ 257 public boolean hasNext() { 258 return hasNext; 259 } 260 261 262 /** 263 * Get next subset. 264 * @return next subset. 265 */ 266 public List<E> next() { 267 List<E> next = new LinkedList<E>(); 268 hasNext = false; 269 return next; 270 } 271 272 273 /** 274 * Remove the last subset returned from underlying set if allowed. 275 */ 276 public void remove() { 277 throw new UnsupportedOperationException("cannnot remove subsets"); 278 } 279 280 }