Arrays - Vectors Data Types Data Type: I. set of values II. set of operations over those values Example: Integer I. whole numbers, -32768 to 32767 II. +, -, *, /, %, ==,!=, <, >, <=, >=,... Which operation is invalid or inaccurate for float? Data Types (C/C++) Scalar (or Basic) Data Types (atomic values) o Arithmetic types Integers short, int, long char, bool Floating points float, double, long double Composite (or Aggregate) Types: Arrays: ordered sequence of values of the same type Structures: named components of various types Spring 2018 Husain Gholoom Lecturer in Computer Science Page 1
Review: Arrays An array contains multiple values of the same type. Values are stored consecutively in memory. An array definition in C++: int numbers[5]; Array indices (subscripts) are zero-based numbers[0]... numbers[4] The subscript can be ANY integer expression: numbers[2], numbers[i], numbers[(i+2)/2] What operations can be performed over (entire) arrays??? First-Class vs Second-Class objects First-Class Objects can be manipulated in the usual ways without any restrictions - copy (=, assignment) - comparison (==, <,...) - input/output (<<, >>) Second-Class Objects can be manipulated only in restricted ways, may have to define operations yourself - Usually primitive (built-in) data types ( bool, int, float... ) - Primitive arrays are not first-class objects (copying elements of an array). Spring 2018 Husain Gholoom Lecturer in Computer Science Page 2
First-Class vs Second-Class Objects: strings First-Class Object: string class (standard library) - = - size() member function - ==, <,... - + Second-Class Object: C-String (char array) - strcpy - strlen - strcat - strcmp Example of Second-Class Object Special functions The usual operators #include <string> int main () { char str1[]="sample string"; char str2[40]; char str3[40]; strcpy (str2,str1); strcpy (str3,"copy successful"); cout << str1<< endl << str2 << endl << str3 ; strcat (str3," Done"); cout << endl << str3; Spring 2018 Husain Gholoom Lecturer in Computer Science Page 3
First-Class vs Second-Class objects: arrays First- Class Object: vector class (standard template library) - = - size() member function - ==, <,... The usual operators Second-Class Object: primitive array - = does not copy elements - length undefined - ==, <,... do not perform as expected usual operations are not defined Vector and String Included in standard (template) library Class definitions used for first class objects The definitions provide an interface that hides the implementation from the programmer. Programmer does not need to understand the implementation to use the types. Vector: like an array, can contain elements of any single given type. Spring 2018 Husain Gholoom Lecturer in Computer Science Page 4
Using vectors Include file To define a vector give it a name, element type, and optional size (default is 0): vector<int> a(3); // vector a with 3 int elements // a[0], a[1], and a[2] Can use [ ] to access the elements (0-based): a[3] = 12; Vector Operation : The push_back() function appends val to the end of the vector. The pop_back() function removes the last element of the vector. vector<int> the_vector; for (int i = 0; i < 10; i++) the_vector.push_back(i); cout << "push_back -- > "; for (int i = 0; i < 10; i++) cout << the_vector[i] << " "; cout << endl << endl; for (int i = 0; i < 5; i++) the_vector.pop_back(); cout << "pop_back -- > "; for (int i = 0; i < 5; i++) cout << the_vector[i] << " "; Sample run: push_back - - > 0 1 2 3 4 5 6 7 8 9 pop_back - - > 0 1 2 3 4 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 5
The size() function returns the number of elements in the vector. resize(int N ) : Resizes the vector V so that it contains exactly N elements. Example vector<int> the_vector; the_vector.push_back(6); the_vector.push_back(9); the_vector.push_back(12); the_vector.push_back(15); the_vector.push_back(18); cout << endl << "vector size is " << the_vector.size() << endl; cout << "push_back -- > "; for (int i = 0; i < the_vector.size(); i++) cout << the_vector[i] << " "; cout << endl << endl; for (int i = 0; i < 2; i++) the_vector.pop_back(); cout << endl << "vector size is " << the_vector.size() << endl; cout << "pop_back -- > "; for (int i = 0; i < the_vector.size(); i++) cout << the_vector[i] << " "; cout << endl << endl; the_vector.resize(1); cout << "after resize -- > "; for (int i = 0; i < the_vector.size(); i++) cout << the_vector[i] << " "; Sample Run vector size is 5 push_back -- > 6 9 12 15 18 vector size is 3 pop_back -- > 6 9 12 after resize -- > 6 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 6
The front() function returns a reference to the first element in the vector. The back() function returns a reference to the last element in the vector. Example vector<int> the_vector; the_vector.push_back(6); the_vector.push_back(9); the_vector.push_back(12); the_vector.push_back(15); the_vector.push_back(18); cout << "The first element is " << the_vector.front() << " and \nthe last element is " << the_vector.back() << endl; Sample Run The first element is 6 and the last element is 18 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 7
The assign() function either gives the current vector the values from start to end, or gives it num copies of val. This function will destroy the previous contents of the vector. Example vector<int> v; v.assign(10, 42); for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; cout << "\n\nthe size of the vector is " << v.size() << endl; v.push_back(15); v.push_back(120); cout << "\n\nthe size of the vector is " << v.size() << endl; v.assign(5, 40); for (int i = 0; i < v.size(); i++) { cout << v[i] << " "; cout << "\n\nthe size of the vector is " << v.size() << endl; cout << endl; Sample run : 42 42 42 42 42 42 42 42 42 42 The size of the vector is 10 The size of the vector is 12 40 40 40 40 40 The size of the vector is 5 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 8
The next example shows how assign() can be used to copy one vector to another: vector<int> v1; for (int i = 0; i < 10; i++) v1.push_back(i); vector<int> v2; v2.assign(v1.begin(), v1.end()); for (int i = 0; i < v2.size(); i++) cout << v2[i] << " "; // Note : you can use as shown in the example v3 = v2. vector<int> v3; v3 = v2; cout <<"\n" ; for (int i = 0; i < v3.size(); i++) cout << v3[i] << " "; Sample run : 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 9
The at() function returns a reference to the element in the vector at index loc. The at() function is safer than the [] operator, because it won't let you reference items outside the bounds of the vector. For example, consider the following code: vector<int> v(5, 1); for (int i = 0; i < 10; i++) { cout << "Element " << i << " is " << v[i] << endl; Sample run : Element 0 is 1 Element 1 is 1 Element 2 is 1 Element 3 is 1 Element 4 is 1 Element 5 is 0 Element 6 is 0 Element 7 is 0 Element 8 is 0 Element 9 is 0 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 10
This code overruns the end of the vector, producing potentially dangerous results. The following code would be much safer: vector<int> v(5, 1); for (int i = 0; i < 10; i++) { cout << "Element " << i << " is " << v.at(i) << endl; Sample run : Element 0 is 1 Element 1 is 1 Element 2 is 1 Element 3 is 1 Element 4 is 1 terminate called throwing an exception Spring 2018 Husain Gholoom Lecturer in Computer Science Page 11
The capacity() function returns the number of elements that the vector can hold before it will need to allocate more space. The reserve( int n ) function requests that the vector capacity be at least enough to contain n elements. For example, the following code uses two different methods to set the capacity of two vectors. One method passes an argument to the constructor that suggests an initial size, the other method calls the reserve function to achieve a similar goal: vector<int> v1(10); cout << "The capacity of v1 is " << v1.capacity() << endl; cout << "The size of v1 is " << v1.size() << endl; vector<int> v2; cout << "The size of v2 is " << v2.size() << endl; v2.reserve(20); cout << "The capacity of v2 is " << v2.capacity() << endl; Sample run: The capacity of v1 is 10 The size of v1 is 10 The size of v2 is 0 The capacity of v2 is 20 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 12
The function clear() deletes all of the elements in the vector. The empty() function returns true if the vector has no elements, false otherwise. For example vector<int> v; for (int i = 0; i < 5; i++) { v.push_back(i); for (int i = 0; i < 5; i++) { cout << v[i] << " "; cout << endl; v.clear(); if (v.empty()) cout << "vector is empty"; else cout << "vector is not empty"; Sample run: 0 1 2 3 4 vector is empty Spring 2018 Husain Gholoom Lecturer in Computer Science Page 13
You can also use empty() as the stopping condition on a while loop to clear a vector and display its contents in reverse order: vector<int> v; for (int i = 0; i < 5; i++) { v.push_back(i); while (!v.empty()) { cout << v.back() << endl; v.pop_back(); Sample run : 4 3 2 1 0 What is the output of the following program vector<int> v; for (int i = 0; i < 5; i++) v.push_back(i); v.clear(); while (!v.empty()) { cout << v.back() << endl; v.pop_back(); Spring 2018 Husain Gholoom Lecturer in Computer Science Page 14
The begin() function returns an iterator pointing to the first element in the vector. The end() function returns an iterator pointing to the last element in the vector The erase() function either deletes the element at location loc, or deletes the elements between start and end (including start but not including end). The return value is the element after the last element erased. For Example vector<char> alphavector; for (int i = 0; i < 10; i++) alphavector.push_back(i + 65); for (int i = 0; i < alphavector.size(); i++) cout << alphavector[i]; cout << endl; // use erase to remove all but the first two and last three elements // of the vector alphavector.erase(alphavector.begin() + 2, alphavector.end() - 3); for (int i = 0; i < alphavector.size(); i++) cout << alphavector[i]; Sample run: ABCDEFGHIJ ABHIJ Spring 2018 Husain Gholoom Lecturer in Computer Science Page 15
The max_size() function returns the maximum number of elements that the vector can hold or the maximum length that a vector can hold. Is the theoretical maximum number of items that could be put in your vector. On a 32- bit system, you could in theory allocate 4Gb == 2^32 which is 2^32 char values, 2^30 int values or 2^29 double values. The max_size() function should not be confused with the size() or capacity() functions, which return the number of elements currently in the vector and the number of elements that the vector will be able to hold before more memory will have to be allocated, respectively. For Example vector<int> v1(20); for (int i = 0; i < 10; i++) v1.push_back(i); cout << "size\t" << v1.size() << endl; cout << "capacity\t" << v1.capacity() << endl; cout << "max size\t" << v1.max_size(); Sample run: size 30 capacity 40 max size 4611686018427387903 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 16
The insert() function either: inserts val before loc, returning an iterator to the element inserted, inserts num copies of val before loc, or inserts the elements from start to end before loc. For Example vector<int> vec(8); for (size_t i = 0; i < 5; i++) vec[i] = i + 1; cout << "Before insert\t"; Sample run: Before insert 1 2 3 4 5 6 0 0 After insert 1 2 10 3 4 5 6 0 After 2nd insert 500 500 500 500 500 1 2 10 Size of the vector is??????? for (size_t i = 0; i < 8; i++) cout << vec[i] << " "; vec.insert(vec.begin() + 2, 10); cout << "\nafter insert\t"; for (size_t i = 0; i < 8; i++) cout << vec[i] << " "; vec.insert(vec.begin(), 5, 500); cout << "\nafter 2nd insert\t"; for (size_t i = 0; i < 8; i++) cout << vec[i] << " "; cout <<"\nsize of the vector is " << vec.size(); Spring 2018 Husain Gholoom Lecturer in Computer Science Page 17
Here is another example of the insert() function. In this code, insert() is used to append the contents of one vector onto the end of another: vector<int> v1; v1.push_back(0); v1.push_back(1); v1.push_back(2); v1.push_back(3); vector<int> v2; v2.push_back(5); v2.push_back(6); v2.push_back(7); v2.push_back(8); cout << "Before, v2 is: \t"; for (int i = 0; i < v2.size(); i++) { cout << v2[i] << " "; cout << endl; v2.insert(v2.end(), v1.begin(), v1.end()); cout << "After, v2 is: \t"; for (int i = 0; i < v2.size(); i++) { cout << v2[i] << " "; Sample run : Before, v2 is: 5 6 7 8 After, v2 is: 5 6 7 8 0 1 2 3 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 18
The size() function returns the number of elements in the current vector. The function resize() changes the size of the vector to size. If val is specified then any newly- created elements will be initialized to have a value of val. vector<double> student_marks; // no size specified: vector contains // no elements int num_students; cout << "\nnumber of students: " << flush; cin >> num_students; student_marks.resize(num_students); cout << "\n" << student_marks.size(); cout << "\n\nnew Number of students: " << flush; cin >> num_students; student_marks.resize(num_students); cout << "\n" << student_marks.size(); cout << "\n\nnew Number of students: " << flush; cin >> num_students; student_marks.resize(num_students); cout << "\n" << student_marks.size(); Sample run : Number of students: 3 3 New Number of students: 5 5 New Number of students: 7 7 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 19
The swap() function exchanges the elements of the current vector with those of from. For Example vector<string> v1; v1.push_back("i'm in v1!"); vector<string> v2; v2.push_back("and I'm in v2!"); v1.swap(v2); cout << "The first element in v1 is cout << "The first element in v2 is " << v1.front() << endl; " << v2.front() << endl; Sample run: The first element in v1 is And I'm in v2! The first element in v2 is I'm in v1! Spring 2018 Husain Gholoom Lecturer in Computer Science Page 20
Vector & Parameter passing (for large objects) Call by value is the default int findmax(vector<int> a); Problem: lots of copying if a is large Call by reference can be used int findmax(vector<int> & a); Problem: may still want to prevent changes to a Call by constant reference: int findmax(const vector<int> & a); the const won t allow a to be changed Spring 2018 Husain Gholoom Lecturer in Computer Science Page 21
Example : /* */ Suppose that we want to input an unknown number of numbers and then print them out forwards and then backwards, using a vector. We will push ints onto the back of a vector called v. We will then print each item in v in turn. We then will print the vector backwards. Other operations will be also used such erase, copy, find the size. etc. You can download the code from [ Vector.cpp ] but here are the highlights. First we must declare the facilities we want to use #include<iostream> void print( const vector<int>& ) ;//utility function outputs a vector of ints void print_backwards( const vector<int> &); /*Then we describe the main program: */ int main() { vector<int> v; vector<int> v1; int number; cout <<"Input some numbers and then end the input any other char "; while(cin>>number){ v.push_back(number); //while(more) print(v); print_backwards(v); // Test to see if v is empty cout <<" Is the Vector v Empty " << v.empty() << endl <<endl ; // Find how many items are in v cout <<" Size of the Vector v is " << v.size() << endl << endl ; // Access the i'th item safely: // What happens if value of i > size of the array vector int i = 3; cout << " Access the i th Item " <<v.at(i) << endl << endl; // get the back item of v: cout <<" Back Item of the Vector v is " << v.back() << endl << endl ; // change the back item: v.back() = ( v.at(2) + 100 ); cout <<" Back Item of the Vector v after the change is " << v.back() << endl << endl ; Spring 2018 Husain Gholoom Lecturer in Computer Science Page 22
// Assign a copy of v to v1 : v1 = v; print(v1); // end main // Remove First element of the vector. v1.erase( v1.begin( ) ); print(v1); // Remove range of element of the vector. v1.erase( v1.begin( ) + 1, v1.begin( ) + 5 ); print(v1); /* The two procedures that print out the data: */ void print( const vector<int>& a) { cout << endl; cout << "----------------"<<endl; for(int i=0; i<a.size(); i++) cout << a[i] << " "; //print cout << endl; cout << "----------------"<<endl; void print_backwards( const vector<int> &a) { cout << "----------------"<<endl; for(int i=a.size() - 1; i>=0; i--) cout << a[i] << " "; cout << endl; cout << "----------------"<<endl; //print_backwards Spring 2018 Husain Gholoom Lecturer in Computer Science Page 23
Sample Run Input some numbers and then end the input any other char 1 2 3 4 5 6 7 8 9 # ---------------- 1 2 3 4 5 6 7 8 9 ---------------- ---------------- 9 8 7 6 5 4 3 2 1 ---------------- Is the Vector v Empty 0 Size of the Vector v is 9 Access the i th Item 4 Back Item of the Vector v is 9 Back Item of the Vector v after the change is 103 ---------------- 1 2 3 4 5 6 7 8 103 ---------------- ---------------- 2 3 4 5 6 7 8 103 ---------------- ---------------- 2 7 8 103 ---------------- Spring 2018 Husain Gholoom Lecturer in Computer Science Page 24
Example using vector resize // Read an unlimited number of ints with no attempts at error // recovery; fill the vector parameter with the data; its size // after the return tells how many items were read. void getints( vector<int> & array ) { int itemsread = 0; int inputval; cout << "Enter any number of integers: "; while( cin >> inputval ) { if( itemsread == array.size( ) ) array.resize( array.size( ) * 2 + 1 ); array[ itemsread++ ] = inputval; array.resize( itemsread ); int main( ) { vector<int> array; getints( array ); for( int i = 0; i < array.size( ); i++ ) cout << array[ i ] << endl; Sample Run Enter any number of integers: 1 2 3 4 5 6 7 8 9 10 / 1 2 3 4 5 6 7 8 9 10 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 25
Multidimensional Arrays Multidimensional arrays, the most common multidimensional arrays, are used to store information that we normally represent in table form. Twodimensional arrays, like one-dimensional arrays, are homogeneous. This means that all of the data in a two-dimensional array is of the same type. Examples of applications involving two-dimensional arrays include: a seating plan for a room (organized by rows and columns), a monthly budget (organized by category and month), and a grade book where rows might correspond to individual students and columns to student scores. Multidimensional array: an array that is accessed by more than one index Multidimensional arrays can be declared and initialized as follows: int A[3][4] = {{8, 2, 6, 5, //row 0 {6, 3, 1,0, //row 1 {8, 7, 9, 6; //row 2 int A[3][4]; // 3 rows, 4 columns cout >> A[0][0] ; // displays 8 on screen Spring 2018 Husain Gholoom Lecturer in Computer Science Page 26
There are no first-class versions of this in the STL Most books define this as a matrix. The primitive version can have more than 2 dimensions. Two- Dimensional Arrays as Function Parameters As with one-dimensional arrays, a two-dimensional array is automatically passed as a pass-by-reference parameter void displayarray(int A[][4], int x) { for ( int i = 0 ; i < x ; i++) { for ( int j = 0 ; j < 4 ; j++) cout << A[i][j]<< "\t"; cout <<endl; int A[3][4] = { { 8, 2, 6, 5, //row 0 { 6, 3, 1, 0, //row 1 { 8, 7, 9, 6 ; //row 2 displayarray(a,3); Spring 2018 Husain Gholoom Lecturer in Computer Science Page 27
Multidimensional vector array constructors You can create a 2D array by doing int a[5][7], but vector<int> a(5,7) won't create a 2D vector - it will create a 5-element vector full of 7s. Instead, you need to create a vector of vectors. Example int main() { // Example to create a 3 by 5 "matrix" using vector. // First, create a vector with 5 elements vector<int> v2(5, 99); // Then create a vector of 3 elements. // Each element is a copy of v2 //The space between the 2 '>' signs is necessary vector<vector<int> > _2dv(3, v2); // Print out the elements for (int i = 0; i < _2dv.size(); i++) { for (int j = 0; j < _2dv[i].size(); j++) cout << _2dv[i][j] << " "; cout << endl; Sample run 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 28
Passing 2d vector array to a function You can pass by value or by reference, or by pointer(not recommended). If you're passing to a function that doesn't change the contents, you can either pass by value, or by const reference. Example void matrixsize(vector<vector<int> > matrix); void populatematrix(vector<vector<int> > &matrix) ; void resizematrix(vector<vector<int> > &matrix) ; void printmatrix(vector<vector<int> > matrix); const int NO_OF_ROWS = 7; const int NO_OF_COLUMNS = 7; int main() { // Example to create a 7 by 7 "matrix" using vector. // First, create a vector with 0 elements vector<int> v2; // Then create a vector of 0 elements. // Each element is a copy of v2 //The space between the 2 '>' signs is necessary vector<vector<int> > _2dv(0, v2); Spring 2018 Husain Gholoom Lecturer in Computer Science Page 29
// Passing 2d vector array to functions matrixsize(_2dv); // display size the martrix resizematrix(_2dv); // resize the martrix printmatrix(_2dv); // display matrix content populatematrix(_2dv); // populate the matrix printmatrix(_2dv); // display the matrix void populatematrix(vector<vector<int> > & matrix) { for ( int i = 0 ; i < matrix.size() ; i++) for ( int j = 0 ; j < matrix.size() ; j++) matrix[i][j] = i+j; void matrixsize(vector<vector<int> > matrix) { cout <<"matrix size " << matrix.size() << endl; void resizematrix(vector<vector<int> > &matrix) { matrix.resize( NO_OF_ROWS, vector <int>( NO_OF_COLUMNS ) ); void printmatrix(vector<vector<int> > matrix){ matrix size 0 cout <<"\n\n"; for (int i = 0; i < matrix.size(); i++) { for (int j = 0; j < matrix.size(); j++) cout << matrix[i][j] << " "; cout << endl; 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 4 5 6 7 8 9 4 5 6 7 8 9 10 5 6 7 8 9 10 11 6 7 8 9 10 11 12 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 30
Structure, Vector, and Array struct Soldier { int health; int ID; ; vector<soldier> army; for (int i = 0; i < 10; i++) { Soldier temp; temp.health = 100; temp.id = i; army.push_back(temp); // Accessing elements through the [] operator for (unsigned int i = 0; i < army.size(); i++) { cout << "Soldier ID = " << army[i].id << ", health = " << army[i].health << endl; Sample Run Soldier ID = 0, health = 100 Soldier ID = 1, health = 100 Soldier ID = 2, health = 100 Soldier ID = 3, health = 100 Soldier ID = 4, health = 100 Soldier ID = 5, health = 100 Soldier ID = 6, health = 100 Soldier ID = 7, health = 100 Soldier ID = 8, health = 100 Soldier ID = 9, health = 100 Spring 2018 Husain Gholoom Lecturer in Computer Science Page 31