Data Structures and Algorithms in The C
Data Structures and Algorithms in The C
standard library
Complexity analysis
Answers the question How does the time needed for an algorithm
scale with the problem size N? "
Worst case analysis: maximum time needed over all possible inputs"
Best case analysis: minimum time needed"
Average case analysis: average time needed"
Amortized analysis: average over a sequence of operations"
The O notation
An algorithm is O(f (N)) if there are constants c and N0, such that for
N≥ N0 the time to perform the algorithm for an input size N is
bounded by t(N) < c f(N)
Consequences "
O(f(N)) is identically the same as O(a f(N))
O(a Nx + b Ny) is identically the same as O(Nmax(x,y))"
O(Nx) implies O(Ny) for all y ≥ x
Notations
N log N" 33 ns" 664 ns" 10 µs" 133 µs" 1.7 ms" 20 ms"
2N" 1 µs" 1014 a" 10285 a" 102996 a" 1030086 a" 10301013 a"
Complexity: example 1
double x;
std::cin >> x;
std::cout << std::sqrt(x);
Complexity: example 2
unsigned int n;
std::cin >> n;
for (int i=0; i<n; ++i)
std::cout << i*i << \n ;
Complexity: example 3
unsigned int n;
std::cin >> n;
for (int i=0; i<n; ++i) {
unsigned int sum=0;
for (int j=0; j<i; ++j)
sum += j;
std::cout << sum << \n ;
}
Complexity: example 4
Part 2:
double y;
std::cin >> y;
for (int i=0; i<n; ++i)
if (x[i]==y) {
std::cout << i << \n ;
break;
}
The complexity is O(N), but let’s look at the next elements added:"
mark one more element as used"
write additional element"
allocators
allocator
your allocator data sequences
function objects containers
negate, plus, multiplies, … list, vector, deque
your function sequence algorithms map, set, …
accumulate, inner_product, your container
predicates find, reverse, …
less, greater, equal_to, … builtin arrays,
sort, merge, … iostreams,
your predicate your algorithm your data structure
container adapters
stack, queue, priority_queue
Since this is not very important for numerical simulations I will not
go into details. Please read your C++ book"
C array" map
vector set
valarray multimap
deque multiset
list queue
priority_queue
stack"
Advantages"
Fast O(1) access to arbitrary elements: a[i] is *(a+i)"
Profits from cache effects"
Insertion or removal at the end is O(1)"
Searching in a sorted array is O(ln N)"
Disadvantage"
Insertion and removal at arbitrary positions is O(N)"
Inserting an element"
Need to copy O(N) elements"
a b c d e f g h
a b c d x e f g h
Removing an element"
Also need to copy O(N) elements"
a b c d e f g h
a b c e f g h
a b c d e
then just change the size:"
a b c d e f
a b c d e f g
Allows in O(1)"
Pushing an element to the top of the stack"
Accessing the top-most element"
in out
Removing the top-most element"
Allows in O(1)"
Pushing an element to the end of the queue"
Accessing the first and last element" in
Removing the first element"
out
The element with highest priority (as given by the < relation) is the first
one out"
If there are elements with equal priority, the first one in the queue is
the first one out"
head tail
Advantages"
Fast O(1) insertion and removal anywhere"
Just reconnect the pointers"
Disadvantage"
Does not profit from cache effects"
Access to an arbitrary element is O(N)"
Searching in a list is O(N)"
An array needs"
O(N) operations for arbitrary insertions and removals"
O(1) operations for random access"
O(N) operations for searches"
O(ln N) operations for searches in a sorted array"
A list needs"
O(1) operations for arbitrary insertions and removals"
O(N) operations for random access and searches"
d s
A binary tree
root
m
branch
d s
b g n x
a i w y
z leaf
Unbalanced trees
c
Solutions"
Rebalance the tree" d
Use self-balancing trees"
e
Look into a data structures book to learn more"
f
1. find"
1. vector"
2. copy"
2. list"
3. merge" 3. deque"
4. transform" 4. set"
"" "" "."
"."
"" "." 5. map"
N. "accumulate" 6. char[5]"
"" "."
" "."
"."
M. "foobar"
"
F. T. S. E.
Andrew Koenig
Generic traversal
Iterators
Container requirements
Sequence constructors
Constructors"
container() … empty container"
container(n) … n elements with default value"
container(n,x) … n elements with value x"
container(c) … copy of container c"
container(first,last) … first and last are iterators"
container with elements from the range [first,last["
Example:"
std::list<double> l;
// fill the list
…
// copy list to a vector
std::vector<double> v(l.begin(),l.end());
Assignments"
container = c … copy of container c"
container.assign(n) …assign n elements the default value"
container.assign(n,x) … assign n elements the value x"
container.assign(first,last) … assign values from the range
[first,last["
Watch out: assignment does not allocate, do a resize before!"
are based on deques, but can also use vectors and lists"
stack is first in-last out"
queue is first in-first out"
priority_queue prioritizes with < operator"
stack functions"
void push(const T& x) … insert at top"
void pop() … removes top"
T& top()
const T& top() const"
queue functions"
void push(const T& x) … inserts at end"
void pop() … removes front"
T& front(), T& back(),
const T& front(), const T& back()"
multimap"
can contain more than one entry (e.g. phone number) per key"
set"
unordered container, each entry occurs only once"
multiset"
unordered container, multiple entries possible
"
extensions are no problem"
if a data structure is missing, just write your own"
good exercise for understanding of containers"
// the phonebook
phonebook_t phonebook;
Almost Containers
C-style array"
string"
valarray"
bitset"
Example: find
Example: find_if
Attention:"
vector<int> v,w;
for (int k=0;k<100;++k){
v[k]=k; //error: v is size 0!
w.push_back(k); // OK:grows the array and assigns
}"
Same problem with copy:"
vector<int> v(100), w(0);
copy(v.begin(),v.end(),w.begin()); // problem: w of size 0!"
Solution1: vectors only"
w.resize(v.size()); copy(v.begin(),v.end(),w.begin()); "
Solution 2: elegant"
copy(v.begin(),v.end(),back_inserter(w)); // uses push_back"
also push_front and front_inserter for some containers "
Penna Population
The search range is halved in every step and we thus need at most
O(ln N) steps
Example: lower_bound
Algorithms overview
Nonmodifying" Modifying"
for_each transform
find, find_if, copy, copy_backward
find_first_of swap, iter_swap,
adjacent_find swap_ranges
count, count_if replace, replace_if,
mismatch replace_copy,
replace_copy_if
equal
fill, fill_n
search
generate, generate_n
find_end
search_n remove, remove_if,
remove_copy,
remove_copy_if
unique, unique_copy
reverse, reverse_copy
rotate, rotate_copy
random_shuffle"
Exercise
int main()
{
vector<string> data;
copy(istream_iterator<string>(cin),istream_iterator<string>(),
back_inserter(data));
sort(data.begin(), data.end());
unique_copy(data.begin(),data.end(),ostream_iterator<string>(cout,"\n"));
}
Summary