Cs126notes 3
Cs126notes 3
Abstraction
“Fundamentally, computer science is a
science of abstraction—creating the right
model for a problem and devising the
appropriate mechanizable techniques to
solve it. Confronted with a problem, we
must create an abstraction of that problem
that can be represented and manipulated
inside a computer. Through these
manipulations, we try to find a solution to
the original problem.”
A. V. Aho & J. D. Ullman, Foundations of Computer Science
Problem Description
• Develop a program which models
UW's Registrar's Office. The office
maintains a list of all students and all
courses offered by the university. For
each student, maintain personal
information (name, ID, plan and
transcript). For each course, maintain
general information (course title,
instructor, term offered, and credit
weight).
• Note: The goal today is not to
implement this entire program. The
goal is to give some suggestions on
how to start the process of
implementation.
CS 126 Slide 5
Introduction to Design
• What classes are needed?
• For each class:
− What methods are needed?
− What information is needed? Not needed?
Student[] students
int numStudents
Course[] coursesOffered Student
int numCourses
String name
RegistrarsOffice(String sFile, int studentID
String cFile) String plan
Course[] taughtBy(String prof, CourseRecord[] transcript
String term) int numCourses
void cancelClass(String name,
String term) Student(String n,
void addClass(Course c) int id,
void removeStudent(int sID) String major)
void addStudent(Student s) void addCourse(CourseRecord c)
double getCredits(int sID) void recordGrade(String cName,
String term,
int grade)
double calcAverage()
Course
CourseRecord
String name Course course
String instructor int grade
String term
double creditWeight
CourseRecord(Course c, int g)
Course(String n, CourseRecord(Course c)
String prof, int getGrade()
String when, void assignGrade(int g)
double credit)
String getInstructor()
boolean equals(Course other)
double getCreditWeight()
CS 126 Slide 7
Implementation Strategies
(or, How Do I Start?)
• Start early!
• Read the description several times.
• Draw a picture of the data.
• Look at
− Class dependencies
− “Isolated” classes
Æ Determine start class and implement.
− Potential Problem here:
∗ What if there is a cycle in the chart?
ÆProgram in "slices"
Testing a Class
(or, Is it Correct?)
• Include a main method in each class.
• Create (instantiate) objects of the
class type.
• Include code calling completed
methods.
• Compare observed results to
expected results.
• Note: In a subsequent lecture, we will
discuss testing strategies in detail.
CS 126 Slide 10
Student
String name
int studentID
String plan
CourseRecord[] transcript
int numCourses
Student(String n,
int id,
String major)
void addCourse(Course c)
void recordGrade(String cName,
String term,
int grade)
double calcAverage()
GraduateStudent
String supervisor
double income
GraduateStudent(String n,
int id,
String major,
double money,
String theSupervisor)
void auditCourse(Course c)
void changeSupervisor(String newSuper)
void setFunding(double newAmt)
CS 126 Slide 13
• examples:
− real numbers with addition, subtraction, absolute
value, square root, ...
− ordered sequences of characters with
concatenate, substring, length, ...
− sets of objects with union, intersection, size, ...
− points in the plane with x-coordinate, distance, ...
ADTs (cont’d)
• Use the principle of information hiding
coined by David Parnas in 1972
“Every module [should be] characterized by its
knowledge of a design decision which it hides
from all others.”
− particularly important to hide decisions that are
likely to change (when they are found to be wrong
or the environment has changed)
− benefits software maintenance and reuse
• ADT List
− collection of n objects indexed from 1 to n
∗ <i1, i2, i3, … , in>
− can create an empty list
∗ createList()
− can get the number of items in List s
∗ s.size()
− can access element at an arbitrary index of List s
∗ s.get(index)
− can insert new elements into List s
∗ s.add(index, item)
− can remove elements from List s
∗ s.remove(index) or s.removeAll()
− special check for empty List
∗ s.isEmpty() ≡ (s.size() == 0)
CS 126 Slide 16
Assertions in programs
• An assertion is:
− a logical claim about the state of a program
− located at a specific point in the program
− assumed true whenever that point is reached
Properties of assertions
− comments
− snapshots of what is claimed to be true during
execution at some specific point in the code
− noteworthy static statements
− not descriptions of action or change
CS 126 Slide 17
Specification by assertions
• preconditions: assertions that must be
true when the method is invoked
• postconditions: assertions that will be
true when the method returns
Specify the syntax and semantics of each method:
− its signature :
∗ name of method and type of result
∗ names and types of parameters
− assumed properties of its inputs
− intended effects of its execution
public static int valueAt(int[] a, int i);
// pre: 0 ≤ i < a.length
// post: returns a[i]
public boolean equals(Object other);
// post: returns true iff this has the same value as other
}
CS 126 Slide 19
ADTs in Java
• Classes provide representations and
implementations of an ADT allowing
for their instantiation
• We would like to separate these
details from the ADT’s specification
• Java provides specific mechanism
that it calls an interface.
− Java “interface” is a set of method signatures.
∗ no code for the methods
∗ no constructors
− Java interfaces can extend other Java interfaces.
∗ interfaces form a hierarchy
− A class implements one or more interfaces.
∗ For each method in an interface, such a class
must provide a method that matches the
interface method signature exactly.
interface Vehicle {...}
class MotorizedVehicle implements Vehicle {...}
class Car extends MotorizedVehicle {...}
• Casting
− When an object is constructed (using new), its type
is established.
Square sq = new Square(3);
− An object of type T can always be treated as if it
were of a supertype of T (upcast).
Rectangle rec = sq;
∗ Thus all objects can be treated as type Object.
∗ If an object is cast to some supertype (upcast),
it can later be downcast to its original type.
sq = (Square)rec; /* could raise exception */
CS 126 Slide 23
Wrapper classes
To use primitive values in situations requiring objects,
need to “wrap” them. For example:
public final class java.lang.Integer
extends java.lang.Number {
...
public Integer(int value);
// post: constructs wrapper object to hold value
ADT Hierarchy
• ADT SortedList is a finite collection of
objects maintained in a specified
order together with the operations:
− createSortedList, sortedIsEmpty, sortedSize,
sortedAdd(item), sortedRemove(item),
sortedGet(index), locateIndex(item)
Representation Independence
• Define all variables using the name of
the ADT’s interface, not any of the
classes that implement that interface.
ListInterface s;
...
s.add(i, x);
− ADT user need not be aware of representation.
− Implementation can be changed without altering
any user code.
module 1
module 3
implementation
data factory 3 of ADT
Software testing
“A man is his own easiest dupe, for what he wishes to be true
he generally believes to be true.” Demosthenes
Black-box testing
• Design test cases based on specifications
• Recall: pre- and postconditions define
a contract.
− test input should meet preconditions
− test runs should compare output to expected
results implied by postconditions
White-box testing
• Design test cases based on the
structure of the code.
• Execute every line of code.
− Branch testing: tests for each alternative
− Loop testing: tests to iterate
∗ 0 times ∗ exactly once
∗ several times ∗ as often as possible
− Exit testing: tests to cause each condition for loop
or method exit
− Exception testing: test of exception handling
Continuing example:
public void removeMe(Object[] array) {
// pre: array not null
// post: removes first occurrence of this, if any, closing
// gap and setting the last entry to null
int i;
for (i = 0; i < array.length; i++) {
if (array[i] == this) break;
}
if (i == array.length) return;
while (i < array.length - 1) {
array[i] = array[i + 1];
i++;
}
array[i] = null;
}
CS 126 Slide 30
Systematic testing
Test plan: collection of tests to perform; for each test:
∗ describe condition(s) being tested
∗ input data
∗ expected results
Test log: record of the results of running tests
∗ pairing test from test plan to output produced
Test harness: program that reads test plan from a
data file, executes it, and writes test log to output file
Regression testing: testing modified code with
identical inputs used to test that code previously
Implementation of List
• might choose a data structure that will
allow random access to elements at a
given index
• a partially filled array of a fixed size
might be a reasonable choice if an
upper bound on the number of items
to be inserted into the List is known
• What if we do not know an upper
bound on the size?
− use a partially filled array which is resized when
full is a data structure that will grow and shrink
gracefully as objects are inserted into and
removed from a List
− this is precisely what a Vector or ArrayList is
(java.util)
− Carrano & Prichard only discuss this briefly on pp.
228-229
count 45
grades 73 99 65
student 93123456
Jane Doe
where reference Honours CS
or primitive value
is stored where object or array
is stored
CS 126 Slide 33
Line # Code
1,2,3 int i, j; int[] a, b; Student p, q, r;
4,5,6 i = 5; j = 6; j = i;
7,8,9,10 a = new int[3]; b = a; b[0] = 5; a[1]++;
11 p = new Student(8, "Jo", "CS");
12 q = new Student(9, "Lee", "C&O");
13 r = p;
14 j = p.silly(i, a, q);
r
CS 126 Slide 34
Implementation of List as a
partially-filled array
• Uses two instance variables:
int numItems; // number of elements in List
Object[] items; // storage for List’s elements
list numItems 4
items ? ... ?
i1 i2 i3 i4
...
4 i1 i2 i3 i4
numItems items
items[translate(numItems)] = null;
numItems--;
return toRemove;
}
list numItems 5
items
8 20 3 15 7
dup
CS 126 Slide 37
numItems
list 2
head
8 20
item item
next next
O1 O2 O3 O4
0
CS 126 Slide 38
myNode
temp
newNode
CS 126 Slide 39
Implementation of List as a
Singly-Linked List
public class ListReferenceBased implements
ListInterface {
private Node head;
private int numItems;
private Node find(int index) {
// pre: 1 ≤ index ≤ numItems
// post: Returns a reference to the node at position index
Node curr = head;
for (int skip = 1; skip < index; skip++) {
curr = curr.getNext();
}
return curr;
}
public Object remove(int index) {
// pre: 1 <= index <= size()
// post: removes and returns the item at position index in the
// list and other items are renumbered accordingly
Object toRemove;
if (index == 1) {
toRemove = head;
head = head.getNext(); }
else {
Node prev = find(index - 1);
Node curr = prev.getNext();
toRemove = curr;
prev.setNext(curr.getNext());
}
numItems--;
return toRemove;
}
...
}
CS 126 Slide 40
O1 O2 O3 O4
• doubly-linked lists
4
O1 O2 O3 O4
ADT Deque
• alternative linear collection
• functionality:
− add only at either of the two ends
− read at ends
− test for membership via contains
− remove at ends
• implementation alternatives:
− as linked list (singly-linked, doubly-linked, circular)
− as Vector or ArrayList (partially-filled array)
− as ADT List
• efficiency trade-offs?
CS 126 Slide 42
Measuring efficiency
• some possible measures:
− the amount of time it takes to code
− the amount of memory the code uses
− the amount of time it takes to run
− the amount of memory the data uses
Comparing implementations
• first approximation: abstraction that
ignores low level details
− calculate number of method invocations for critical
methods used
− typically interested in methods that read object’s
values or change object’s values
− for collections, often interested in
∗ number of data values encountered (e.g., how
many calls to getNext())
∗ number of data values moved or modified (e.g.,
how many calls to setNext() or setItem())
ADT Stack
• A linear collection, (s1, s2, ..., sn), of
elements accessed from one end only
− top: sn
• Applications:
− processing nested elements (e.g., subroutine flow
control)
− reversing element ordering
CS 126 Slide 46
class BalanceChecker {
StackInterface s =
DataFactory.makeStack();
...
public boolean check(String in) {
s.popAll();
for (int i=0; i < in.length(); i++) {
if (in.charAt(i) == '(')
s.push(new Integer(i));
else if (in.charAt(i) == ')') {
if (s.isEmpty())
return false;
Integer open =(Integer)s.pop();
// open.intValue() position has matching ′(′
}
}
return (s.isEmpty());
}
}
Array-Based Implementation of
Stack
0 1 2 length-1
1 s1 s2 ...
top items
CS 126 Slide 48
Linked-List-Based Implementation
of Stack
S4 S3 S2 S1
CS 126 Slide 49
ADT Queue
• A linear collection, (q1, q2, ..., qn), of
elements accessed in sequence
− front: q1; rear: qn
• Applications:
− communications channel
− items waiting to be serviced
CS 126 Slide 51
producer consumer
q1 q2 q3 q4
2 q1 q2 ...
count items
2 1 x q1 q2 ...
0 1 2 length-1
2 length-1 q2 ... q1
• Implementation details...
see Carrano & Prichard, Chapter 8
CS 126 Slide 54
Ariane 5
On 4 June 1996, the maiden flight of the Ariane 5 launcher
ended in failure. Only about 40 seconds after initiation of
the flight sequence, at an altitude of about 3700 m, the
launcher veered off its flight path, broke up and exploded.
[Ariane 5 Flight 501 Failure, Report by the Inquiry Board, July 1996]
What happened?
− “At 36.7 seconds after H0 (approx. 30 seconds after lift-off) the
computer within the back-up inertial reference system, which was
working on stand-by for guidance and attitude control, became
inoperative. This was caused by an internal variable related to
the horizontal velocity of the launcher exceeding a limit which
existed in the software of this computer.
− “Approx. 0.05 seconds later the active inertial reference system,
identical to the back-up system in hardware and software, failed
for the same reason. Since the back-up inertial system was
already inoperative, correct guidance and attitude information
could no longer be obtained and loss of the mission was
inevitable.
− “As a result of its failure, the active inertial reference system
transmitted essentially diagnostic information to the launcher’s
main computer, where it was interpreted as flight data and used
for flight control calculations.
− “On the basis of those calculations the main computer
commanded the booster nozzles, and somewhat later the main
engine nozzle also, to make a large correction for an attitude
deviation that had not occurred.”
CS 126 Slide 55
Ariane 5 (cont’d)
The inertial reference system of Ariane 5 is essentially common to a
system which is presently flying on Ariane 4.
So, how did the failure happen?
− “The part of the software which caused the interruption in the
inertial system computers is used before launch to align the
inertial reference system and, in Ariane 4, also to enable a rapid
realignment of the system in case of a late hold in the countdown.
This realignment function, which does not serve any purpose on
Ariane 5, was nevertheless retained for commonality reasons and
allowed, as in Ariane 4, to operate for approx. 40 seconds after
lift-off.
− “In Ariane 4 flights using the same type of inertial reference
system there has been no such failure because the trajectory
during the first 40 seconds of flight is such that the particular
variable related to horizontal velocity cannot reach, with an
adequate operational margin, a value beyond the limit present in
the software.
− “Ariane 5 has a high initial acceleration and a trajectory which
leads to a build-up of horizontal velocity which is five times more
rapid than for Ariane 4. The higher horizontal velocity of Ariane 5
generated, within the 40-second timeframe, the excessive value
which caused the inertial system computers to cease operation.”
Lessons learned:
R5 … Identify all implicit assumptions made by the code and its
justification documents on the values of quantities provided
by the equipment. Check these assumptions against the
restrictions on use of the equipment….
Design Implementation
Architecture
Recursive Definitions
• common in mathematics
Recursive definition defines an object in terms of
smaller objects of the same type.
b
<x<>>
<a<b<>>> <>
}
CS 126 Slide 61
is or
allergies cold
9 *
+ 2
1 4
Recursive Programs
• Solution defined in terms of solutions
for smaller problems of the same type
int solve (int n) {...
value = solve(n-1) + solve(n/2);
...}
if (n < 2) return 1;
else return fib(n-1) + fib(n-2);
}
B
A
D
A
CS 126 Slide 69
Linked Implementation
• Carrano & Prichard Chapter 11
• sublist can be implemented using the
Node class, similarly, linked
implementation for binary trees can use
a TreeNode class:
• three data fields (item, leftChild,
rightChild)
root
item ?
leftChild rightChild
item ? item ?
item ?
leftChild rightChild
Tree Traversals
• want to traverse a tree in some orderly
manner
• we visit each node exactly once (e.g.,
print its contents or determine if it meets
certain criteria)
• one option is to visit the nodes level by
level:
− for each level of the tree
visit each node at that level
X
B S
K O I A
C L
Z E
− traversal: X B S K O I A C L Z E
Iterators
• Auxiliary types that provide access to the
elements of a collection
− each element is “visited” once, and only once
Depth-First Traversals
• visit tree’s components (root, left subtree,
right subtree) in some order
• preorder traversal:
− visit the root
− visit the left subtree recursively
− visit the right subtree recursively
congestion?
allergies cold
Inorder Traversal
• ordering:
− visit the left subtree recursively
− visit the root
− visit the right subtree recursively
- *
* 7 2 3
2 +
3 5
− traversal: 2 * 3 + 5 – 7 – 2 * 3
− but need to insert ( before visiting any subtree and
) after visiting any subtree
((((2)*((3)+(5)))-(7))-((2)*(3)))
or perhaps (((2*(3+5))-7)-(2*3))
Postorder traversal
• ordering
− visit the left subtree recursively
− visit the right subtree recursively
− visit the root
- *
* 7 2 3
2 +
3 5
2 3 5 + * 7 – 2 3 * -
− unambiguous without parentheses !
− “reverse Polish notation” created in 1920s by
logician Jan Lukasiewicz
CS 126 Slide 78
• height of a tree:
− if the tree is empty, its height is 0
− otherwise, its height is
1 + max{height TL, height TR }, where TL and TR
designate left and right subtrees
public int height() {
// post: Returns height of subtree.
if (isEmpty()) return 0;
else {
int leftHt = leftSubtree().height();
int rightHt = rightSubtree().height();
return 1 + Math.max(leftHt,rightHt);
}
}
CS 126 Slide 79
ADT Table
• Components: associations from keys
(from some domain space) to values
− simple (partial) functions: values are atomic
− databases: values are records of field-value pairs
(often including the key-value pair too)
− sets: values are empty; ~ characteristic function
• Examples:
− mapping from student ID to name
− mapping from student ID to student record
− set of student IDs for students in CS 126 (mapping
from ID to “taking CS 126”)
• Intuitive operations:
− look up given key ≡ tableRetrieve
− insert a new association ≡ tableInsert
− delete association for a given key ≡ tableDelete
Simple Representations
• Keep table as a sequence of
associations in no particular order,
with no keys repeated.
− using a partially-filled array
− using a linked list
• efficiency of operations:
Consider a partially-filled array representation.
Look at number of comparisons of two keys and
number of elements whose locations in the
partially-filled array change:
∗ e.g., how many comparisons are executed
during a call to “retrieve” in the worst case? or
in the best case? how many moves are
needed during a call to “delete”?
Similar analyses can be applied to reason about
linked list representations.
Bounding Efficiency
• Running time of a program is a
function of the “size” of the problem
being solved
− for collections: size = number of elements
Big-O Notation
• Intuitively:
− keep dominant term,
− remove leading constant,
− put O(..) around it
running time
of A1
n sufficiently large n
c2 * g2(n)
running time
of A2
n sufficiently large n
Comparing Algorithms
[Jon Bentley, “Programming Pearls: Algorithm Design
Techniques,” Comm. ACM 27, 9 (Sept. 1984) pp. 865-871]
Σ A[k]
k=i
0 1 2 3 4 5 6 7 8 9 10 11
A 25 -5 -12 -9 14 12 -13 5 8 -2 18 -8
Alternative Approach
• O(n) algorithm: possible through more
clever analysis
− in single pass over array, keep track of best range
so far as well as best starting point for a range
ending at current index
• Bentley’s implementations:
− O(n3) algorithm in finely-tuned FORTRAN on a
Cray-1 supercomputer
− O(n) algorithm in interpreted BASIC on a Radio
Shack TRS-80 Model III microcomputer
Bentley’s Results
Cray TRS-80
n 3.0n3 ns 19.5n ms
10 3 µs .195 s
100 .003 s 1.95 s
1000
2500
104
105
106
...
Faster hardware isn’t good enough!
CS 126 Slide 89
Binary Search
Given a partially filled array, data, with
counter numItems, of comparable
objects in ascending order, find the index
matching a target key if it is present,
otherwise return the index of the slot
where it would be inserted.
int position(Comparable target){
// pre: target is non-null and data values ascending
// post: retuns index s.t. 0 <= index <= numItems, and
// data[0..index-1] < target, and
// data[index..numItems-1] >= target
return search(0, numItems, target);
}
int search(int lo, int hi, Comparable key) {
// pre: 0 ≤ lo ≤ hi ≤ numItems; key not null
// post: returns ideal position of key in data[lo..hi]
Comparable m;
int mid = (lo + hi)/2;
if (lo == hi) return lo;
else {
m = (Comparable)data[mid];
if (m.compareTo(key) < 0) // m < key
return search(mid+1, hi, key);
else return search(lo, mid, key);
}
}
CS 126 Slide 91
tableDelete
tableInsert
(with array large
enough)
tableInsert
(with array fully
occupied)
<k >k
20 50 10 30
10 30 70 50
60 40 70
60
CS 126 Slide 94
...
• Efficiency?
CS 126 Slide 95
Sorting Introduction
• Remember our dictionary that was
sorted in alphabetical order: how did
the information become sorted?
• The remaining lectures will be
devoted to different sorting algorithms
and their efficiencies.
• Here are some assumptions we’ll use
when sorting:
− All the data can fit in memory.
− Data is stored in an array of size n.
− Data is all “comparable”:
public interface Comparable {
public int compareTo(Object other);
// pre: other is not null
// post: returns value less than 0 if this is less than other;
// returns 0 if this equals other; otherwise returns
// value greater than zero
}
− Contents of the array are to be modified so that the
data is rearranged into non-decreasing order.
CS 126 Slide 97
Selection Sort
• Idea: repeatedly extract maximal element
from among those still unsorted
int indexOfLargest(Comparable[] theArray, int size) {
// pre: 0 ≤ size ≤ theArray.length, theArray is non-null and
// elements of array between 0 and size –1 are non-null
// post: returns index result such that theArray[i] <= theArray[result]
// for all i in {0,...,size-1}
int indexSoFar = 0;
for (int currIndex=1; currIndex<size; currIndex++) {
// theArray[indexSoFar] >= theArray[0..currIndex-1]
if (theArray[currIndex].
compareTo(theArray[indexSoFar]) > 0) {
indexSoFar = currIndex;
}
}
return indexSoFar;
}
0 last n
sorted
0 next n
CS 126 Slide 100
Efficiency of Sorting
• How much space is needed?
− Always need space to hold the data itself; the critical
question is how much auxiliary space is needed.
− How much space is needed for Selection Sort beyond
that used for the input arguments?
Merge
• Important subroutine: merge
− Input is two sorted ranges in an array.
− Identify candidate at start of each input range.
− Repeatedly copy the smaller of the two candidates
to the temporary array.
− When one input range is exhausted, simply copy
the rest of the other one to the temporary array.
− Copy the temporary array back to the input array.
1st half 2nd half
merged
lo next hi
• time = space =
Analysis of Mergesort
• If n is a power of 2, the “tree of
problems to solve” looks like:
n
n/2 n/2
2 2 ... 2 2
1 1 1 1 ... 1 1 1 1
• Runtime =
• Auxiliary space =
CS 126 Slide 106
Quicksort
• Idea: pick some pivot element and
place it where it belongs;
• sort all elements less than the pivot;
• sort all elements greater than the
pivot
• Quicksort also uses divide and
conquer, but the sizes of the two
problems depend on the input.
see Carrano & Prichard, pp 491-503
p <p ≥p ?
Quicksort Itself
• Like mergesort, a recursive method
with a non-recursive wrapper
• Contrast the order of the calls
quickSort(Comparable[] theArray, int n)
calls
quickSortRec(theArray, 0, n-1);
• Worst case
− each segment split on its first element ⇒ O(n2)
− but how likely are splits into 0 and n-1 elements?
Speeding Up Quicksort
• Try to avoid bad splits (e.g., do not
just choose first elements as pivots).
− randomization works well
− worst case still O(n2), but less likely in practice to
have “bad” inputs
Sorting Summary
select insert merge quick
best O(n2) O(n) O(n log n) O(n log n)
time
average O(n2) O(n2) O(n log n) O(n log n)
time
worst O(n2) O(n2) O(n log n) O(n2)
time
time for O(n2) O(n) O(n log n) O(n log n) ∗
sorted
input
†
aux. O(1) O(1) O(n) O(log n) ‡
space
− Other properties: stability
What is computing?
• Late 19th Century
− Formal approaches to set theory and algebra
Early computers
• Motivating applications in 1940s
− perform military computations
− break codes
− census
− later, business applications
Programming languages
• Algorithmic languages
− Grace Murray Hopper’s A-0 compiler (1951)
− Fortran (1957), Cobol (1959)
− Algol (1960)
− PL/I (1965)
− BCPL (1966), B (1972), C (1975)
− Pascal (1970), Modula (1975)
− Ada (1979)
• Object-oriented languages
− Simula (1967)
− Smalltalk (1972)
− Alphard (1976), Clu (1979)
− C++ (1983)
− Java (1995)
CS 126 Slide 116
Some CS Notables
• Hardware
− J. Cocke, I. Sutherland, D. Englebart
− Supercomputers, personal computers
− storage devices, peripherals, graphics
− communications & distributed computing
• Operating systems
− F. Brooks, E. W. Dijkstra
− Multics (MIT), Unix (Bell Labs)
− DOS, Mac-OS, Windows
• Correctness
− R. W. Floyd, E. W. Dijkstra, C. A. R. Hoare
− structured programming, software engineering
CS 126 Slide 118