Vectors of structs
We can define vectors of structs
id
gpa
1250
0
name
lastname
struct student
{
unsigned int id;
string name, lastname;
double gpa;
};
id
1251
1
gpa
3.2
name
lastname
vector<student> class(11);
// a vector with 11 students
id
class[1].gpa = 3.2;
1260
name
for (i = 0; i <= 10; i++)
class[i].id = i + 1250;
10
lastname
gpa
shuffle.cpp program
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)
vector<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)
vector<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 vector class utilities as in
the following code
vector<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 vector::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 reached and push_back attempts to add a
new element to the vector, then the vector automatically “grows” by
adding half of the current capacity to the capacity
0, 1, 2, 3, 4, 6, 9, 13, 19, 28, ... n+(n/2) …
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
vector<string> names;
// size is 0, capacity is 0
names.push_back("Ali");
// size is 1, capacity is 1
names.push_back("Husnu"); // size is 2, capacity is 2
names.push_back("Ayse");
// size is 3, capacity is 3
names.push_back("Cem");
// size is 4, capacity is 4
names.push_back("Jale");
// size is 5, capacity is 6
names.push_back("Hale");
// size is 6, capacity is 6
names.push_back("Veli");
// size is 7, capacity is 9
names.push_back("Gonca");
// size is 8, capacity is 9
names.push_back("Fatma");
// size is 9, capacity is 9
names.push_back("Yesim");
//size is 10, capacity is 13
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
increases the capacity.
What about size() in case the vector is created as a nonempty 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
Vector Processing Examples – 1
(vectorproc.cpp – not in book)
write a function that takes a vector 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 vector<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 vector 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 vector<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 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 vector<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 vector<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 vector<string> & a,
vector<string> & matches)
// pre: matches is empty
// post: matches contains all elements of a with
//
first letter 'A'
{
int k;
for (k=0; k < a.size(); k++)
{
if (a[k].substr(0,1) == "A")
{
matches.push_back(a[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
What number (between 1 and 100) do we guess first in
number guessing game?
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
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
10 24 34 52 55 62 67 75 80 81 90 92 100 101 111
low=0
low=0
mid=7
mid=3
low=4
high=6
high=6
mid=5
=>
FOUND
high=14
Binary Search (search for 60)
0
1
2
3
4
5
6
7
8
9
10
11
12 13
14
10 24 34 52 55 62 67 75 80 81 90 92 100 101 111
low = 0
low=0
mid=7
mid=3
high =14
high=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 vector<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)
{
return mid;
}
else if (list[mid] < key)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return -1;
}
// found key, exit search
// key in upper half
// key in lower half
// not in list
Comparing Sequential and Binary Search
Table 8.1 Comparing sequential / linear search with binary search
Number of Items Examined (at worst)
List Size
Binary Search
Sequential Search
1
1
1
10
4
10
1,000
11
1,000
5,000
14
5,000
100,000
18
100,000
1,000,000
21
1,000,000
A Computer Science Tapestry page 375
• Given a list of N elements:
• Binary search makes on the order of log N operation
O(log N)
• Linear (sequential) search takes on the order of N operations
O(N)
Sorting
One of the fundamental operations in Computer
Science
Given a randomly ordered array, sort it
ascending
descending
Many algorithms exists
some in Chapter 11
we will discuss two of them – Selection Sort (11.1.1)
and Insertion Sort (11.1.2)
Analysis in 11.4
Selection Sort
N is the number of elements in vector/array
Find smallest element, move into 0th vector/array location
examine all N elements
0 .. N-1
Find next smallest element, move into 1st location
0th location is already the minimum
examine N-1 elements
1 .. N-1
Find next smallest element, move into 2nd location
0th and 1st locations are already the minimum two elements
examine N-2 elements
2 .. N-1
Generalize
for kth element, 0 <= k <= N-2
- find the minimum between kth and last element (element
with index N-1) of array
- swap the kth element with the minimum one
Selection Sort: The Code
void SelectSort(vector<int> & a)
// pre: a contains a.size() elements
// post: elements of a are sorted in non-decreasing order
{
int j, k, temp, minIndex, numElts = a.size();
for(k=0; k < numElts - 1; k++)
{
minIndex = k;
// minimal element index
for(j=k+1; j < numElts; j++)
{
if (a[j] < a[minIndex])
{
minIndex = j;
// new min, store index
}
}
temp = a[k];
// swap min and k-th elements
a[k] = a[minIndex];
a[minIndex] = temp;
}
}
insertion and deletion
It’s easy to insert at the end of a vector, use
push_back()
However, if the vector is sorted and if we want to keep it sorted,
then we can’t just add to the end
We have to find an appropriate position to insert the element and do
some shifts.
If we need to delete an element from a sorted vector,
how can we “close-up” the hole created by the deletion?
Shift elements left by one index, decrease size
We decrease size using pop_back()
pop_back() changes size, not capacity
Inserting an element into a sorted array
2
7
11 18
21 22 26 89 99
Insert NewNum which is e.g. 23
• Is the array “capacity” sufficient for an extra
element?
• What would you do to insert newNum in the right
spot?
Insertion into sorted array
0
1
2
3
2
7
11 18
4
5
6
7
8
21 22 26 89 99
NewNum = 23
2
7
11 18
21 22 26 26 89 99
0
1
2
4
3
5
6
7
8
9
Insert into sorted vector
void insert(vector<int>& a, int newnum) // NOT const vector
// pre: a[0] <= … <= a[a.size()-1], a is sorted
// post: newnum inserted into a, a still sorted
{
int count = a.size(); //size before insertion
a.push_back(newnum);
//increase size – newnum is inserted at
// the end but the inserted value is not important
int loc = count;
// start searching insertion loc from end
while (loc > 0 && a[loc-1] > newnum)
{ a[loc] = a[loc-1];
loc--;
// shift right until the proper insertion cell
}
a[loc] = newnum; //actual insertion
}
See vectorproc.cpp (not in book)
What about deletion?
Remove the element at a given position (pos)
void remove(vector<string>& a, int pos)
// post: original a[pos] removed, size decreased
{
int lastIndex = a.size()-1;
a[pos] = a[lastIndex];
a.pop_back();
}
What about if vector is sorted, what changes?
What’s the purpose of the pop_back() call?
Deletion from sorted vector
Ex: Delete element at position 3
0
1
2
3
2
7
11 18
4
5
6
7
8
Size is 9
21 22 26 89 99
First shift all elements on the right
of 3rd element one cell to the left
0
1
2
3
2
7
11 21 22 26 89 99 99
0
1
2
2
7
11 21 22 26 89 99 99
3
4
4
5
5
6
6
7
7
Size is now 8
8
pop back the last element of vector
Deletion from sorted vector
void remove(vector<int> & a, int pos)
// pre: a is sorted
// post: original a[pos] removed, a is still sorted
{
int lastIndex = a.size()-1;
int k;
for(k=pos; k < lastIndex; k++)
{
a[k] = a[k+1];
} //shift all elements on the right of pos one cell left
a.pop_back(); //remove the last element of the array
}
Does pop_back() actually remove an element?
no, it just decreases the size so that the last element
becomes unreachable
Capacity remains the same
See vectorproc.cpp (not in book)
Insertion Sort
Insert 1st element before or after 0th
first 2 sorted
Insert 2nd element (element with index 2) in
proper location
first 3 sorted
Generalize
insert kth element (element with index k) within first
k elements
first k+1 sorted
run this for all k between 1 .. N-1
Insertion Sort – The Code
void InsertSort(vector<string> & a)
// precondition: a contains a.size() elements
// postcondition: elements of a are sorted in nondecreasing order
{
int k,loc, numElts = a.size();
for(k=1; k < numElts; k++)
{
string hold = a[k];
// insert this element
loc = k;
// location for insertion
// shift elements to make room for hold (i.e. a[k])
while (0 < loc && hold < a[loc-1])
{
a[loc] = a[loc-1];
loc--;
}
a[loc] = hold;
}
}
Which one faster?
No exact answer! It depends on the vector to be sorted
already ordered, totally disordered, random
Let’s see how many iterations do we have in Selection Sort
Outer loop k: 0 .. N-2
Inner loop j: k+1 .. N-1
(N-1) + (N-2) + (N-3) + .. + 1 = N(N-1)/2 = (N2 – N)/2
Worst case, best case, average case???
Complexity is O(N2)
order of N2
Big-oh notation used to describe algorithmic complexities. This is not
a precise amount of operations and comparisons. Minor terms and
coefficients are not taken into consideration
Which one faster?
Let’s analyze Insertion Sort
Outer loop k: 1 .. N-1
N-1 iterations for the outer loop
What about inner loop?
worst case, best case differ
worst case: k times, so total is 1+2+3+…+(N-1) = N(N-1)/2, complexity is
O(N2)
best case: inner loop does not iterate, complexity is O(N), but best case
complexity analysis is not done too often
what are the best and worst cases?
average case: inner loop iterates k/2 times, order is still O(N2)
Complexities of both Selection and Insertion Sort are O(N2)
Which one would you prefer to use?
Let’s run timesorts.cpp (modified from book) – needs several Tapestry
.h and .cpp files in the project folder to run (comparer.h, ctimer.h,
ctimer.cpp, prompt.h, prompt.cpp, randgen.h, randgen.cpp, sortall.h,
sortall.cpp – red ones to be added to the project).
Built-in Arrays
C++ native array type
Two versions
fixed size arrays
array size is fixed and must be specified with a constant
expression at the declaration
we will see this type now
array pointers
array size is dynamically allocated
we will not see it in this course
use of both types are the same except definition
vector versus built-in arrays
vector is a class based on built-in arrays
vector has member functions and operators, built-in
arrays do NOT
vector is more flexible, but slower
Built-in Array declaration
As we said, we will discuss fixed size built-in arrays, not the pointer
version with dynamic allocation
size must be able to be determined at compile time
constant, literal or an expression that involves constants and literals only
const int CLASSSIZE = 100;
// constant
string
double
int
// array of 100 strings
// array of 500 doubles
// array of 200 integers
names[CLASSIZE];
grades[CLASSIZE*5];
list[200];
The following array declaration is INVALID
int size;
cout "Enter how many students ? ";
cin >> size;
string names[size]; // array size cannot be a variable
Built-in array initialization at declaration
You may specify a list of initial values at declaration. See
following example:
string dayNames [] = {"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday","Friday", "Saturday"};
dayNames is an array with 7 elements of type string
0th element is “Sunday”, 1st is “Monday”, ...
not necessary to specify size (7), since the number of elements make
the size clear
but you can specify the size, if you wish
string dayNames [7] = {"Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday","Friday", "Saturday"};
Assignment rules in arrays
vectors with the same element type can be assigned to
each other by =
LHS vector becomes the same as the RHS vector
size and capacity also become the same
Built-in arrays cannot be assigned to each other by =
int coins[] ={1,5,10,25};
int temp[4];
temp = coins;
temp[1] = coins[2];
// illegal
// legal – array element assignment
How can we assign coins to temp?
element by element
for (i=0; i<4; i++)
temp[i] = coins[i];
Passing built-in arrays as parameters
A built-in array can be passed only as reference
parameter or const-reference parameter
cannot be passed as value parameter
But, we do not use ampersand character, &, at
parameter declaration
and we do not specify the array size in array parameter
however array size is generally passed as another
integer parameter since we do not have a size()
member function for built-in arrays
reference parameter
void Change(int list[], int numElts);
void Print(const int list[], int numElts);
const-reference parameter
Built-in array demo
See fixlist.cpp (slightly modified from the version in
book)
Why did we use const in Print?
to avoid accidental changes in array list
Why did we pass numElts as parameter for the
number of elements in the array?
because we don’t know the total number of elements in the
array while writing the functions
Example – Fibonacci numbers
Used in many areas of Mathematics and Computer Science
F0 = 1
F1 = 1
Fn = Fn-1 + Fn-2
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
You can see many examples of Fibonacci numbers in nature
E.g. Increase of number of branches of trees in time
See http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fibnat.html
for more examples
const int MAX_SIZE = 100;
int list[MAX_SIZE];
int k;
list[0] = list[1] = 1;
for (k=2; k < MAX_SIZE, k++)
{
list[k] = list[k-1]+list[k-2];
}
Use of strings as arrays
Characters in a string can be referred as an array using [ ]
string s="cs201";
...
s[0] = 'n'; // makes 0th character of s 'n'
...
for (k=0; k<s.length(); k++)
cout << s[k] << " ";
In general,
s[k]
means s.at(k)
The Matrix
To represent two dimensional arrays
Given rows and columns:
We define a matrix as a vector of vectors
vector<vector<int>> mat(rows, vector<int>(cols));
vector<vector<int>> mat(3, vector<int>(5));
0
1
2
3
4
0
1
2
100
mymatrix[2][3] = 100;
First index is for row, second is for column
Possible Matrix definitions
Possible matrix declarations
4 different declarations
vector<vector<int>> matrix_name;
empty matrix (zero rows, zero columns)
vector<vector<int>> matrix_name(rows);
matrix with rows many empty vector<int>’s
vector<vector<int>> matrix_name(rows, vector<int>(cols));
matrix with rows*cols elements all initialized to 0
vector<vector<int>> matrix_name(rows,
vector<int>(cols, init_value));
matrix with rows*cols elements all initialized to init_value
To get the size of rows and columns
mymatrix.size()
number of rows in matrix
mymatrix[0].size()
number of columns in matrix
Example: Let’s run matdemo.cpp
© Copyright 2026 Paperzz