430 likes | 570 Views
2nd Midterm Exam. December 2 6 th , 2008, Fr i day 1 7 :40 – 1 9 :20 Places w ill be announced later
E N D
2nd Midterm Exam • December 26th, 2008, Friday • 17:40 – 19:20 • Placeswill be announced later FENS G032 Acar - Avcı FENS G035 Aydeniz - Büyükkıdık FASS G022 Büyüknacar - Demir FASS G049 Demirci - Eroğlu FASS G052 Erol - Gürsel FENS L045 Gürtunca - Konukoğlu FASS G062 Korudu - Pek FENS G077 Pelen - Zilan • Sample question set and solutions are posted • Close everything except two A4-size cheat notes • In the final exam, two sheet limit won’t change! • Exam covers the topics until the beginning of structs and vectors! • Details are sent to SUCourseand as anemail to the class email list.
Extra Recitations for Review Purposes • by Tolga Eren • Several recitations will be held until MT2 • First Meeting to determine the coverage and time • Wednesday December 17, 19:40 in FASS G022 • Exact times will be determined in this first meeting • Actually this is done and two recitations were held previous week • Remaining ones • December 23, Tuesday, 19:40 – 22:30 (may last longer) in FENS G035 • December 35, Thursday, 8:40 – 10:30 in FENS L045
Announcements about HW6 • You may need to use clear() member function before you try to reopen an input file stream object • (i) that you failed to open previously (for example due to wrong file name), or • (ii) that you opened and processed but for some reason if the error flags are set (for example due to reaching the end of the file). • Possible reasons for run time errors in this homework • Attempting to read from a file that has not been opened yet • Attempting to write to a file that has not been opened yet • (Although you do not need to use these string member functions) range and index problems while trying to access characters of a string using find, substr and at member functions.
Announcements about HW6 • “Should we check if the output file is opened successfully or not?” • Not required, but advised • There might be some cases that the output files are not opened successfully • If you check and the output file is not opened, then do not continue with the program. • What happens if the files are opened but the content is irrelevant? • What happens if the file names are entered in the wrong order? • What happens if both file names are the same? • All of these questions are reduced into the same main question: should we make the content check for the files that are opened successfully? • NO. As mentioned in the HW document, the content of the files are assumed to be correct. What you have to do is only to check if the files are opened successfully or not and continue to read file names until opened. Once opened, we assume that the first file is the business database, and the second one is the distance database files.
7th and last homework • 7th and last homework will be assigned this week • Due Jan 7 Wednesday, 19:00 • About vectors • This week recitations will be about vectors and this homework
structs (7.4) • Used as data aggregates for an entity • can be different types of data • e.g. for student • id, name, GPA, address, ... • Similar to classes, but everything is public • structs can have constructors • structs can have member functions • we will not deal with constructors and member functions for structs unless they are necessary • mostly we will use structs for combining data for an entity into a single structure
Structs • Example: struct for student • First struct must be defined by giving it a name and its fields (data) struct student // student is struct name { unsigned int id; //fields of student struct string name, lastname; double gpa; }; // dont forget ; at the end • Then variables of that type are declared and used. • dot operator is used to refer fields of a struct variable student stu; stu.name = "Ali"; stu.gpa = 4.0; cout << stu.gpa; • See structdemo.cpp (not in book) stu gpa id 4.0 name Ali lastname
What can and can’t be done with structs • Structs can be passed to functions as parameters • use const-reference if not changing (using value parameter is syntactically OK, but not preferred due to performance reasons) • use reference parameter if changing • struct fields behave as variables/objects of field type • id is an integer • name is a string • You may read, write, use as operands in operations, etc. • However, processing the entire struct variable is restrictive • cannot read or write (using >> and <<) structs unless those operators are specially defined for that struct • cannot use operators between two structs unless those operators are specially defined for that struct • see 7.4.2 for operator definitions for structs, but you are not responsible • structs are useful mostly in vectors (arrays) as we shall see
Vectors and Arrays • Arrays are collections of several elements of the same type • E.g. 100 integers, 20 strings, 125 students, 12 dates, etc. • Single name is given to the entire array • But each element is accessed separately • Any element of an array can be accessed just as quickly as any other element (this is called “random access” but do not get confused with RandGen type of randomness) • In C/C++ there is a built-in array type • We will see it, but later • Vectors are a class-based version of arrays • First we will see vectors.
Vectors • We’re using the class tvector • Copy tvector.h and tvector.cpp to your project folder • need #include "tvector.h" • But do NOT add tvector.cpp to your project • It is already included within tvector.h • If you mistakenly add tvector.cpp to your project, then you get lots of errors. • tvector is a tapestry class that has the same functionality and based on the standard C++ class vector, but safer • “Safe” means programming errors are caught rather than ignored
Why do we need arrays/vectors? • Consider the following example (not in the book): • pick n random numbers between 0 and 6 and count total number of occurrences of all outcomes (0, 1, 2, 3, 4, 5, 6) • n is an input • we need 7 counters • 7 declarations • 7 initializations • 7 conditions to increment after each occurrence • 7 cout statements to display the result • Fortunately, we have shorter way: ARRAYS/VECTORS • We can use vectors to store counters for all possible outcomes of the random numbers under a single name • easier processing in loops • see next slide for the program
randStats 0 1 2 3 4 5 6 Example Previous example using vectors - see randnums.cpp int num; int k; RandGen random; tvector<int> randStats(7); // vector for counters int n = PromptRange("how many random numbers",1,20000); for(k=0; k <= 6; k++) // initialize counters to zero { randStats[k] = 0; } for(k=0; k < n; k++) // pick all random numbers { num = random.RandInt(7); // between 0 and 6 randStats[num] = randStats[num]+ 1; // and increment // corresponding counter } cout << "number\t\t# of occurrences" << endl; for(k=0; k <= 6; k++) { cout << k << "\t\t" << randStats[k] << endl; }
Vector/Array basics • Vectors/Arrays are homogeneous • each item (sometimes called element) has the same type • this type must be specified at declaration • Items in a vector/array are numbered (e.g. 1st, 3rd, or 105th) • those are called index or subscript • numbering starts with 0 • we have to use the index value to refer an element in a vector/array • Example definition and use of vectors (array definition is a bit different) tvector<int> ivals(10); // ivals can store 10 ints ivals[0] = 3; // 0th element becomes 3 tvector<string> svals(20); // svals can store 20 strings svals[4] = "cs201"; // 4th element contains "cs201"
Vector basics • Syntax of vector declaration • tvector is a class, its declaration is construction • 3 different methods tvector<type>variable_name; empty vector (will see later) tvector<type>variable_name (size_expression); vector with size_expression elements in it tvector<type>variable_name (size_expression, init_value); vector with all size_expression elements initialized to init_value
Vector basics • size_expression can be any expression of type integer (or cast into integer) • not necessarily a constant value (this is actually a very important flexibility as compared to built-in arrays) • examples tvector <int> letters (int('Z')-int('A') + 1); • creates a vector of 26 integer elements and name it letters cin >> num; tvector <double> counters (num); • creates a vector of doubles; total number of elements is input • Index values start with 0, and end with size-1 • type is type of the vector elements • can be built-in types (int, double, ...) or user defined types or classes or structs (string and date are class examples; student is struct example) • classes must have default constructors to be used in vector definition as element type
Defining tvector objects • Can specify # elements in a vector, optionally an initial value tvector<int> counts(300); // 300 ints, values not initialized tvector<int> nums(200,0); // 200 ints, all zero tvector<double> d(10,3.14); // 10 doubles, all pi tvector<string> w(10,"cs");// 10 strings, all "cs" tvector<string> words(10); // 10 strings, all "" • If the vector type is a class, then this class must have a default constructor • Default constructor is the one without parameters • Cannot define tvector<Dice> cubes(10); since Dice doesn’t have default constructor • Vectors of classes are initialized with the default constructor • that is why all words are ""(empty string) • Vectors of built-in types are not initialized (unless explicitly initialized with the second argument of tvector definition)
counter letters 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 Example tvector definitions tvector<int> counter(9, 0); each element is an integer(all initialized to 0) 0 0 0 0 0 0 0 0 0 tvector<char> letters(18) each element is a char (not initialized yet) 9 10 11 12 13 14 15 16 17 tvector<Date> holidays(6); each element is a date object that contains todays date holidays 15 12 2008 15 12 2008 15 12 2008 15 12 2008 15 12 2008 15 12 2008 0 1 2 3 4 5
0 1 2 3 4 5 6 7 8 How to reach a single vector/array element • specify the index value within square brackets after the vector/array name var_name[index_expr] • the value of index expression must be between 0 and vector size - 1 • Examples tvector<int> nums(9); nums[5] = 102; nums[0] = nums[5]*2-1; nums[nums[5]/20-3] = 55; nums[10] = 5; // error nums 203 55 102
Passing vectors to functions as parameters • Vectors can be passed as parameters to functions • Pass by reference (if function changes the vector) void Count (tvector<int> & counts); • Pass by const-reference (if no changes made). • void Print(const tvector<int> & counts); • Passing by value makes a copy, requires time and space, so not preferred • IMPORTANT!!!vector size cannot be given in parameter definition. Three solutions to this problem: • the size may be passed as another parameter • the size may be fixed and known • tvector has a member function, size, to return the size of a vector (shall see later)
Example • Counting letters of a file • display number of occurrences of each letter at the end • counting iscase insensitive • see letters.cpp (the one in book is a bit different)
tvector as a return type • Vector can be return type of a function tvector<int> Count (istream & input, int & total); • Example: modify letters.cpp such that count returns the vector (not as reference parameter) • see letters2.cpp
gpa gpa gpa id id id 1250 1251 1260 3.2 name name name lastname lastname lastname class Vectors of structs 0 • We can define vectors of structs struct student { unsigned int id; string name, lastname; double gpa; }; tvector<student> class(11); // a vector with 11 students class[1].gpa = 3.2; for (i = 0; i <= 10; i++) class[i].id = i + 1250; 1 10
Vector of struct • Example • define a struct for a track on a CD • track number and title are fields • define an vector for 10 tracks • shuffle these 10 tracks at random • see shuffle.cpp (in book, but this version is slightly modified)
Vectors as lists • The “vector as counters” example constructs and initializes a vector with a specific number of elements • Other uses of vector require the vector to “grow” to accommodate new elements • Consider reading words from a text file, storing them in a vector • How big should we define vector initially? What are potential problems? • When a vector is used as a list, we’ll use a different method for adding elements to the vector so that the vector can “grow”
Reading words into a vector (problematic version) tvector<string> words(1000); string w; int i = 0; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while (input >> w) { words[i]=w; i++; } cout << "read " << i << " words" << endl; • What is the problem? • there might be more than 1000 words in the file • in this case index runs out of range
Reading words into a vector (with index range control but still problematic) tvector<string> words(1000); string w; int i = 0; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while ((input >> w) && (i < 1000)) { words[i]=w; i++; } cout << "read " << i << " words" << endl; • What is the problem? • works fine if there are no more than 1000 words • but if there are more than 1000 words, the rest is not read
Reading words into a vector (no problems) • One method would be to pass over the file two times • one to find out number of words • second to read the words into array • Another method is to benefit from tvector class utilities as in the following code tvector<string> words; //create empty vector string w; string filename = PromptString("enter file name: "); ifstream input(filename.c_str()); while (input >> w) { words.push_back(w); //adds the next word to the vector //also increases the size if necessary } cout << "read " << words.size() << " words" << endl;
Using tvector::push_back • The method push_back adds new objects to the “end” of a vector, • Internally, the vector keeps track of its capacity • If there is capacity, then there is no problem; the new item is added to the end of the vector • When the capacity is full and push_back attempts to add a new element to the vector, then the vector automatically “grows” by doubling the capacity • 0, 2, 4, 8, 16, 32, ... • If you want to use push_back mechanism, then the vector should be defined initially without specifying a size • empty vector (zero size)
Size versus Capacity • Capacity is the allocated size of the vector • Size is how many elements are in the vector so far • They are not the same concepts, but related as described in the previous slide and illustrated below tvector<string> names; // size is 0, capacity is 0 names.push_back("Ali"); // size is 1, capacity is 2 names.push_back("Husnu"); // size is 2, capacity is 2 names.push_back("Ayse"); // size is 3, capacity is 4 names.push_back("Cem"); // size is 4, capacity is 4 names.push_back("Jale"); // size is 5, capacity is 8
size()member function • size() member function basically returns the number of elements in the vector • When a vector is defined with no initial capacity, and push_back is used to add elements, size() member function returns the number of elements exist in the vector • This is the number of calls of push_back() if no elements are deleted • If elements deleted using pop_back(), size updated too (decremented) • If a non-empty vector is created, then the capacity and the size is set to the number of elements of the vector. This capacity is considered full, so the first push_back causes to double the capacity. • What about size() in case the vector is created as a non-empty one • returns the size specified during declaration if no push_back() is used • returns the size specified during declaration + the number push_back()s, if push_back() is used
capacity()and reserve() • The capacity of vector is accessible using capacity()member function • programmers don’t often need this value • An initial capacity of N elements can be specified using reserve(N) member function
Demo Example • Read some strings from keyboard and store in a tvector of strings. At the end display the vector. • version 1: no reserve • version 2 (decomment the reserve lines): with reserve • version 3: vector is created as a non-empty (decomment second definition and comment out first one and reserve lines) • See tvectordemo.cpp (not in the book)
Vector Processing Examples – 1 (vectorproc.cpp – not in book) • write a function that takes a tvector of integers as parameter and returns the maximum of numbers in it • process all array elements – for loop from 0 to vector’s size-1 int max (const tvector<int> & v) //pre: vector v is not empty //post: return max of elements in v { int i, max_so_far = INT_MIN; for (i=0; i < v.size(); i++) { if (v[i] > max_so_far) { max_so_far = v[i]; } } return max_so_far; }
Vector Processing Examples – 2 (vectorproc.cpp – not in book) • write a function that takes a tvector of integers as parameter and returns true if the vector is sorted in ascending manner, false otherwise • may not process all vector elements • In this type of rule-checking applications, a possible method is to assume that the rule is satisfied before the loop and find a counterexample in the loop bool issorted (const tvector<int> & v) //post: returns true if the array is acsending sorted { bool s = true; // initially assume that array is sorted //in the function try to break this assumption int i =1; while (i < v.size() && s == true) { //check until the end of array or until a counterexample is found if (v[i-1] > v[i]) // if not sorted s = false; // counterexample is found i++; } return s; }
Searching a vector • We can search for one occurrence, return true/false or the index of occurrence • Search the vector starting from the beginning • Stop searching when match is found • We can search and count the number of occurrences and return count • Search entire vector • Similar to one occurrence search, but do not stop after first occurrence • We can search for many occurrences, but return occurrences in another vector rather than returning count • In all these cases, we search the vector sequentially starting from the beginning • This type of search is called “sequential search”
Counting search int countmatches(const tvector<string> & a, const string& s) // post: returns # occurrences of s in a { int count = 0; int k; for(k=0; k < a.size(); k++) { if (a[k] == s) { count++; } } return count; } • How can we change this code to return the index of the first occurrence? • see next slide
One occurrence search int firstmatch(const tvector<string> & a, const string& s) // post: returns the index of occurrence of s in a, -1 // otherwise { int k; for(k=0; k < a.size(); k++) { if (a[k] == s) { return k; } } return -1; } • Does not search the entire array if one match is found • good for efficiency purposes • How could you modify this to return true/false?
Collecting search • Collect the occurrences in another vector void collect(const tvector<string> & source, tvector<string> & matches) // pre: matches is empty // post: matches contains all elements of source with // first letter 'A' { int k; for(k=0; k < source.size(); k++) { if (source[k].substr(0,1) == "A") { matches.push_back(source[k]); } } }
Binary search • Alternative to sequential search for sorted vectors • If a vector is sorted we can use the sorted property to eliminate half of the vector elements with one comparison • Consider the number guessing game. Which number (between 1 and 100) do we guess first in number guessing game? • Apply the same idea for searching in the sorted vector • Idea of creating program to do binary search • Check the middle element • If it has the searched value, then you’re done! • If not, eliminate half of the elements of the vector using sortedness property of the vector • search the rest using the same idea • continue until match is found or there is no match • how could you understand that there is no match? • let’s develop the algorithm on an example • we need two index values, low and high, for the search space
Binary Search (search for 62) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 102434 5255 62 67 75 80 819092100101111 Low = 0 mid=7high =14 Low = 0 mid=3high =6 Low = 4 high =6 mid = 5 - FOUND
Binary Search (search for 60) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 102434 5255 62 67 75 80 819092100101111 Low = 0 mid=7high =14 Low = 0 mid=3high =6 Low = 4 high =6 mid = 5 Low=4 high=4 mid = 4 Low= 5 high = 4 => NO MATCH FOUND – STOP
Binary search code int bsearch(const tvector<string>& list, const string& key) // pre: list.size() == # elements in list // post: returns index of key in list, -1 if key not found { int low = 0; // leftmost possible entry int high = list.size()-1; // rightmost possible entry int mid; // middle of current range while (low <= high) { mid = (low + high)/2; if (list[mid] == key) // found key, exit search { return mid; } else if (list[mid] < key) // key in upper half { low = mid + 1; } else // key in lower half { high = mid - 1; } } return -1; // not in list }
Comparing Sequential and Binary Search • Given a list of N elements: • Binary search makes on the order of log2N operation O(log2N) • Linear (sequential) search takes on the order of N operations O(N)