170 likes | 339 Views
Iterators. CS101 2012.1. 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:
E N D
Iterators CS101 2012.1
What is an iterator? • Thus far, the only data structure over which we have iterated was the arrayfor (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 dimval 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<T> • Print all elements of a vector, using iterator vector<int> vec; // suitably filled for (vector<int>::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 We will see other kinds of iterators after we study C++ collection types beyond vector<T> 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 dign-1 = 0 to radix-1 for dign-2 = 0 to radix-1 … for dig0 = 0 to radix-1 print dign-1, dign-2, …, dig1, dig0 Don’t know how to do this for input variable nDigits Chakrabarti
Counting • Instead of writing nested loops… • Stick the loop indices into vector<int> dig • Given any state of dig, to get the next state: • Locate least significant digit that can be incremented (i.e., is less than radix1) • 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, …) • 0th item placed in 1 way, “way #0” • 1th item placed in 2 ways, “ways #0, #1” • Left of first item or right of first item • Three gaps now, 2th item in ways 0, 1, 2 • … and so on to the (n-1)th item • Suppose we had integer variables way0, way1, … , wayn-1 Chakrabarti
Permutation example way0 0 way1 0 1 way2 0 1 2 0 1 2 Chakrabarti
Nested for loops for way0 = 0 (up to 0) { for way1 = 0 to 1 { for way2 = 0 to 2 { … for wayn-1 = 0 to n-1 { convert way0, …, wayn-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<int> 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<int>& 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<int> way) vector<char> 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<int> containing column indices with nonzero elements • vector<vector<int>> nzCols; • For row rx, there are nzCols[rx].size() possible column options • Declare vector<int> 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, declarea “loop variable”, keep in vector • Earliest decision = lowest index ofloop variable Game trees • Different possiblemoves = branch out • Represent with “loop variable” Chakrabarti