Iterators CS
Chakrabarti What is an iterator? Thus far, the only data structure over which we have iterated was the array for (int ix = 0; ix < arr.size(); ++ix) { … arr[ix] … // access as lhs or rhs } In general there may not be such a simple notion of a single index; e.g., iterate over: All dim val map entries in sparse array All permutations of n items All non-attacking n-queen positions on an n by n chessboard
Chakrabarti Iterator as an abstraction We initialize an iterator Given any state of the iterator, we can ask if there is a next state or we have run out If there is a next state, we can move the iterator from the current to the next state We can fetch or modify data associated with the current state of the iterator
Chakrabarti Iterator on vector Print all elements of a vector, using iterator vector vec; // suitably filled for (vector ::iterator vx = vec.begin(); vx != vec.end(); ++vx) { cout << (*vx) << endl; } Iterator type “++” overloaded to mean “advance the iterator” Access the current contents of the iterator
Chakrabarti Iterator lineage categorycharacteristicvalid expressions all categories Can be copied and copy-constructedX b(a); b = a; Can be incremented++a, a++, *a++ Random Access Bidirectional Forward Input Accepts equality/inequality comparisonsa == b, a != b Can be dereferenced as an rvalue*a, a->m Output Can be dereferenced to be the left side of an assignment operation *a = t, *a++ = t Can be default-constructedX a;, X() Can be decremented--a, a-- *a-- Supports arithmetic operators + and - a + n, n + a, a – n, a – b Supports inequality comparisons (, =) between iterators a b a = b Supports compound assignment operations += and -=a += n, a -= n Supports offset dereference operator ([])a[n] We will see other kinds of iterators after we study C++ collection types beyond vector
Chakrabarti Counting in any radix Print all numbers in a given radix up to a given number of “digits” E.g. nDigits = 2, radix = 3 gives 00, 01, 02, 10,11, 12, 20, 21, 22 (Note radix could be arbitrarily large) for dig n-1 = 0 to radix-1 for dig n-2 = 0 to radix-1 … for dig 0 = 0 to radix-1 print dig n-1, dig n-2, …, dig 1, dig 0 Don’t know how to do this for input variable nDigits
Chakrabarti Counting Instead of writing nested loops… Stick the loop indices into vector dig Given any state of dig, to get the next state: Locate least significant digit that can be incremented (i.e., is less than radix 1) Increment this digit Reset to zero all less significant digits
Chakrabarti Printing permutations without recursion Given input n, print all n! permutations of n items (say characters a, b, …) 0 th item placed in 1 way, “way #0” 1 th item placed in 2 ways, “ways #0, #1” Left of first item or right of first item Three gaps now, 2 th item in ways 0, 1, 2 … and so on to the (n-1) th item Suppose we had integer variables way 0, way 1, …, way n-1
Chakrabarti Permutation example way 0 way 1 way 2 cba bcabaccabacbabc abba a
Chakrabarti Nested for loops for way 0 = 0 (up to 0) { for way 1 = 0 to 1 { for way 2 = 0 to 2 { … for way n-1 = 0 to n-1 { convert way 0, …, way n-1 into permutation } … } Unfortunately, we cannot read n as an input parameter and implement a variable number of nested for loops
Chakrabarti Variable number of nested loops? Vector of wayi variables has n! possible tuple values Is in 1-1 correspondence with the permutations of n items Design two functions … Given vector way that satisfies above properties, arrange way.size() items according to that correspondence From one way find the next way (the iteration)
Chakrabarti bool nextPerm(vector & way) bool didChange = false; for (int ch=0; ch < way.size(); ++ch) { if (way[ch] < ch) { ++way[ch]; didChange = true; for (int zx = 0; zx < ch; ++zx) { way[zx] = 0; } break; } return didChange; nextPerm is an iterator --- it modifies way to the next permutation if any, returning true if it succeeded
Chakrabarti printPerm(vector way) vector arrange(way.size(), 0);//empty for (int px=way.size()-1; px >= 0; --px) { // skip way[px] empty slots in arrange int wx = 0; for (int sx = way[px]; ; --sx) { while (arrange[wx] != 0) { ++wx; } if (sx == 0) { break; } ++wx; } arrange[wx] = 'a' + px; } print(arrange);
Chakrabarti Semi-magic square A semi-magic square contains non-negative integers Each row and column adds up to the same positive integer c A permutation matrix is a semi-magic square having c=1 Can always subtract a permutation matrix from a semi-magic square (but not greedily) In time proportional to the number of nonzero elements in the square Here we look at a brute force solution using iterators
Chakrabarti Iterator state For each row, keep a (sparse) vector containing column indices with nonzero elements vector > nzCols; For row rx, there are nzCols[rx].size() possible column options Declare vector colsTaken, where colsTaken[rx] can range between 0 and nzCols[rx].size()-1
Chakrabarti Nested loop way of thinking for colsTaken[0] = 0 … nzCols[0].size()-1 { for colsTaken[1] = 0 … nzCols[1].size()-1 { … … … for colsTaken[n-1] = 0 … nzCols[n-1].size()-1 { check if colsTaken[0…n-1] define a permutation matrix if so { subtract from magic; update nzCols; return } } // end of colsTaken[n-1] loop … … … } // end of colsTaken[1] loop } // end of colsTaken[0] loop Can easily turn into iterator style
Chakrabarti Other applications Maze with walls Starting point and destination For every decision point, declare a “loop variable”, keep in vector Earliest decision = lowest index of loop variable Game trees Different possible moves = branch out Represent with “loop variable”