Lecture 2026/02/26
Amortized Analysis, Tampering + forgery
void add (struct sequence *s, int i, int e){
if (s->size==s->cap){
s->array = realloc(s->array,___)
}
}realloc
increases block of memory to a new size.
if necessary, allocates a new larger block + frees old block w/ data copied over.
How big is to make new array?
naive:
One larger each time it is TO FALL.
Considering adding k-elements to the end to the end of the sequence when it is already full (size n )
(n+1)+(n+2)+(n+3)+....
⇒ O(n) time to add elts to the sequence every time.
Fix: Doubling strategy + use amortized analysis.
when the array is filled, double its size.
most calls will be cheap
If an array has cap k and is empty:
kinserts at a cost of1each (ksteps taken)1insert costsk+1- cap now2k(k+1steps taken )k-1inserts at a cost of1each (k-1steps taken )1insert costs2k+1- cap now4k(2k+1steps taken.2k-1inserts cost1each (2k-1steps )1insert costs4k+1- cap now8k(4k+1steps )
...
`2j−1k` inserts cost 1 each ( `2j−1k-1` steps )
1insert costs2^jk - cap now2^{j+1}+1steps.Sum the inserts vs. sum of steps.
k + 1 + k-1 + 1 + 2k -1 +1 + ... + (2^{j-1}k-1)+1
k + 1 + k + 2k + ... + 2^{j-1}k
K+1 + k ( 1 + 2 + ... + 2^{j-1});
k+ 1 + k ( 2^{j}-1)
k+1 + k2^{j}-kk2^{j}+1
total steps
k + k +1 + k-1 + 2k+1 + 2k-1 + 4k+1 + ... + 2^{j-1}k -1 + 2^{j}k +1
k + 2k + ... + 2^{j}k + 2^{j}k+ 1
k ( 1 + 2 + ... + 2^{j}) + 2^jk + 1
k(2^{j+1}-1) + 2^{j}k+1
2k2^{j} - k + 2^{j}k + 1
3(2^{j}k + 1 -k)
number of steps per insertion:
2jk+13⋅2jk−k+1
limj→∞(2jk+13⋅2jk−k+1)
3
Thus a constant number of steps (O(1)) # steps PER insertion when
taken over entire sequence of operations.
Note, people who use your Sequence ADT may not be using it correctly.
Defensive Programming
tampering + forgery of ADTs
e.g.
So the question becomes how to prevent?
Leave the Sequence Definition, OUT of the header file, so people can't define it.
In header file, just forward declare struct first.
Since the structure definition is out of the header file, the program will not know that the Sequence ADT has these different fields, size, cap, etc..., hence will throw an error to those trying to tamper/forge.
sort of why you have to leave information out of header-files
Unfortunately:
Now prevents the "good" users from using the Sequence ADT.
Fix:
prevent tampering + forgery, while allowing regular use:
always going to use Sequence *s, instead of sequences.
since we know pointers are all the same size.
What are the increasesCap helper, can we prevent main.c from using it, since it isn't an ADT operation?
Leave the
increaseCapdeclaration out ofSequence.h, thenmain.Cwould not be able to call it.
Unfortunately, this doesn't prevent a client from making their OWN declarations
e.g. making their own declarations of increaseCap.
Design our ADT, practice of increasing arrays/double array, how to structure files with ADTs, how to keep implementations secret, and talked about void statics.
cut-off for midterm.
More ADT practice - Racket - Mutable maps/dictionaries.
make-map:no params
precondition: true
Last updated