Add 'ods/' from commit 'cbb1f78f27b88978de401a0f9d90fbbd396c001f'
git-subtree-dir: ods git-subtree-mainline:97402604dfgit-subtree-split:cbb1f78f27
This commit is contained in:
171
ods/notes/chapter1.txt
Normal file
171
ods/notes/chapter1.txt
Normal file
@@ -0,0 +1,171 @@
|
||||
# Chapter 1
|
||||
|
||||
## Efficiency
|
||||
|
||||
Concerns:
|
||||
1. Number of operations
|
||||
2. Processor speeds
|
||||
3. Storage space
|
||||
|
||||
## Interfaces
|
||||
|
||||
* Interface / abstract data type
|
||||
|
||||
### Queue interface
|
||||
|
||||
* `add(x)` (aka `queue`): add `x` to the queue
|
||||
* `remove()` (aka `dequeue`): remove the next value from queue and return it
|
||||
|
||||
* Normal queue: the first element inserted is removed first
|
||||
* Priority queue: elements are inserted with a priority, and the smallest
|
||||
element is removed. This function is usually called `deleteMin`.
|
||||
* LIFO queue: a stack; add and remove are called `push` and `pop`.
|
||||
* Deque: generalisation of these
|
||||
* `addFirst(x)`
|
||||
* `removeFirst(x)`
|
||||
* `addLast(x)`
|
||||
* `removeLast(x)`
|
||||
* Stack: addFirst, removeFirst
|
||||
* Queue: addLast, removeFirst
|
||||
|
||||
### List interface
|
||||
|
||||
The List interface subsumes the Queue interface. A list is just a sequence of
|
||||
values, and a Queue becomes a special case of it.
|
||||
|
||||
Interface:
|
||||
|
||||
* size()
|
||||
* get(i): get i'th element
|
||||
* set(i, x): set the i'th element to x
|
||||
* add(i, x): insert x at position i
|
||||
* remove(i): remove the i'th element
|
||||
|
||||
### USet (unordered sets)
|
||||
|
||||
USets are a collection of unique items in no particular order; this mimics a
|
||||
mathematical set.
|
||||
|
||||
Interface:
|
||||
|
||||
* `size()`: returns the number of elements in the set
|
||||
* `add(x)`: add x to the set if it doesn't already exist
|
||||
* `remove(x)`: remove x from the set if it doesn't already exist
|
||||
* `find(y)`: membership test
|
||||
|
||||
Note that y and x may be distinct objects, and only need to satisfy an
|
||||
equality test. For example, a dictionary or hashmap is created using a tuple
|
||||
`(key, value)`; `find` compares on `key` and two objects are considered equal
|
||||
if their keys match.
|
||||
|
||||
### SSet (sorted set)
|
||||
|
||||
A USet where order matters. Its interface only changes in the `find` function:
|
||||
|
||||
* `find(x)`: find the smallest y s.t. y >= x. thereby returning a useful value
|
||||
even if x isn't in the set. AKA successor search.
|
||||
|
||||
Difference between USet and SSet: sorting requires more steps (run time) and
|
||||
complexity. A USet should be used unless an SSet is explicitly required.
|
||||
|
||||
## Mathematical background
|
||||
|
||||
(See notebook).
|
||||
|
||||
## The model of computation
|
||||
|
||||
Proper analysis requires a mathematical model of computation. The model in the
|
||||
book is on a w-bit word-RAM model.
|
||||
|
||||
* we can access cells of memory, each of which stores a w-bit word
|
||||
* basic operations (arithmetic and logical) take constant time
|
||||
* cells can be read or written in constant time
|
||||
* the memory manager allows allocating a block of k cells of memory in O(k)
|
||||
time
|
||||
* size constraint: w >= log(n) where n is the number of elements stored in a
|
||||
data structure
|
||||
* data structures use a generic type T such that T occupies one word
|
||||
|
||||
## Correctness, time complexity, and space complexity
|
||||
|
||||
Three factors for analysing a data structure:
|
||||
|
||||
* correctness: data structure must implement the interface
|
||||
* time complexity: run times of operations on the data structure should
|
||||
be as small as possible
|
||||
* space complexity: the storage space used by a data structure should be
|
||||
as small as possible
|
||||
|
||||
Run times come in three flavours:
|
||||
|
||||
1. Worst-case: an operation never takes longer than this
|
||||
2. Amortized: if a data structure has an amortized run time of f(n), then
|
||||
a sequence of m operations takes at most m f(n) time.
|
||||
3. Expected: the actual run time is a random variable, and the expected
|
||||
value of this run time is at most f(n).
|
||||
|
||||
## Exercises
|
||||
|
||||
1. See src/ch01ex01.cc --- note that the last three exercises were skipped for
|
||||
time.
|
||||
|
||||
2. A Dyck word is a sequence of +1’s and -1’s with the property that the
|
||||
sum of any prefix of the sequence is never negative. For example,
|
||||
+1,−1,+1,−1 is a Dyck word, but +1,−1,−1,+1 is not a Dyck word since the
|
||||
prefix +1 − 1 − 1 < 0. Describe any relationship between Dyck words and
|
||||
Stack push(x) and pop() operations.
|
||||
|
||||
A +1 corresponds to a push, and a -1 corresponds to a pop. At any point,
|
||||
the stack must not overflow.
|
||||
|
||||
3. A matched string is a sequence of {, }, (, ), [, and ] characters that are
|
||||
properly matched. For example, “{{()[]}}” is a matched string, but this
|
||||
“{{()]}” is not, since the second { is matched with a ]. Show how to use a
|
||||
stack so that, given a string of length n, you can determine if it is a
|
||||
matched string in O(n) time.
|
||||
|
||||
The program should push each opening character onto a stack. When a closing
|
||||
character is encountered, the top of the stack should be the matching
|
||||
opening character. See src/ch01ex03.cc.
|
||||
|
||||
4. Suppose you have a Stack, s, that supports only the push(x)
|
||||
and pop() operations. Show how, using only a FIFO Queue, q, you can
|
||||
reverse the order of all elements in s.
|
||||
|
||||
See src/ch01ex04.cc: you just pop each element from the stack → queue,
|
||||
then pop the elements off the queue. If you wanted to reverse the stack
|
||||
itself, you'd just push the elements back onto the stack.
|
||||
|
||||
5. Using a USet, implement a Bag. A Bag is like a USet—it supports the add(x),
|
||||
remove(x) and find(x) methods—but it allows duplicate elements to be
|
||||
stored. The find(x) operation in a Bag returns some element (if any) that
|
||||
is equal to x. In addition, a Bag supports the findAll(x) operation that
|
||||
returns a list of all elements in the Bag that are equal to x.
|
||||
|
||||
In progress: src/ch01ex05.cc.
|
||||
|
||||
6. From scratch, write and test implementations of the List, USet and SSet
|
||||
interfaces. These do not have to be efficient. They can be used later to
|
||||
test the correctness and performance of more efficient implementations.
|
||||
|
||||
In progress: src/ch01ex06.cc, src/ods/simplist.h, src/ods/uset.h.
|
||||
|
||||
7. Work to improve the performance of your implementations
|
||||
from the previous question using any tricks you can think of. Experiment
|
||||
and think about how you could improve the performance of add(i,x) and
|
||||
remove(i) in your List implementation. Think about how you could improve
|
||||
the performance of the find(x) operation in your USet and SSet
|
||||
implementations. This exercise is designed to give you a feel for how
|
||||
difficult it can be to obtain efficient implementations of these interfaces
|
||||
|
||||
Some initial ideas:
|
||||
1. A linked list could improve add --- instead of having to move elements
|
||||
in place, you would just insert in between. For a forward-iterating
|
||||
insertion (e.g. for j := 0; j < i; j++), there are decreasing benefits
|
||||
as you insert elements farther in the list. A potential improvement
|
||||
might be a doubly-linked list with the iteration direction determined by
|
||||
distance from the centre, though this comes at the cost of additional
|
||||
complexity. The same improvements would apply to remove.
|
||||
2. For the sorted list, a basic improvement for find would be to pick the
|
||||
middle of the list and do an equality check, basically bisecting to
|
||||
find where the value *would* be.
|
||||
Reference in New Issue
Block a user