A graph consists
of a set of vertices and
a collection of edges . is not necessarily a set.
The *order* of a graph is the number of its vertices, , and the *size* of a graph is the
number of its edges, . We will assume that the
order and size of a graph are finite.

is called an *undirected graph* if consists of unordered pairs
of vertices, , . is called a *directed
graph* or *digraph* if consists of ordered pairs of vertices, , . If
, , is called a *symmetric
graph* and is equivalent to an undirected graph.

The *underlying graph* of a given
directed graph is created by replacing every directed edge with its corresponding undirected edge
. *Mixed graphs* contain both
directed and undirected edges.

is
called a *subgraph* of if and . is said to be *induced* by the set of
vertices if . In other words, if includes all edges of that join two vertices in . If is a subgraph of , is called a *supergraph* of .

The vertices and edges in a graph may be
associated with information, called *labels*. In a social network graph
where vertices correspond to people and edges correspond to relationships among
people, vertex labels could contain first and last names and birthdays. Edge
labels could contain details of the relationships. A graph is called *edge-weighted*
if edge labels contain an edge’s length or weight. In a *vertex-weighted
graph*, vertex labels contain a weight.

Two or more edges that are represented by
the same pair of vertices are called *parallel edges*. An edge or is
called a *loop*. An undirected graph without parallel edges and loops is
called a *simple graph*.

Parallel edges and loops often have a special meaning. In many applications, they represent redundant or contradictory information and are thus not allowed. In a social network graph, for instance, it may not be desired that a person can have a relationship with himself. On the other hand, a network that models different types of relationships (e.g., work relationship, friendship) may allow parallel edges.

We use to
denote the *neighborhood* of an arbitrary vertex . For directed graphs, .
For undirected graphs, . Every vertex in is called *adjacent* to . For directed graphs, we
additionally define . We use and to
denote the *degree* and *indegree* of .

A *walk* between two vertices and is an alternating sequence of vertices and
edges where, for directed graphs, , ,
and for undirected graphs, , .

The *length* of a walk is the number
of edges in the walk. In edge-weighted graphs, the sum of the weight of all
edges in the walk is typically counted as its length. is
called the *source* of the walk, is
called its *destination*. All remaining vertices in the walk are called *intermediary
vertices*.

A *trail* is a walk in which all edges
are distinct. A *path* is a walk in which all vertices are distinct. Every
path is a trail. A *closed walk* is a walk in which the source is also the
destination. A *circuit* is a closed walk in which no edges repeat. A *cycle*
is a circuit in which no vertices repeat. For instance, is
a circuit but not a cycle. is neither a
circuit nor a cycle. A graph with no cycles is called an *acyclic graph*
or a *forest*.

Let and be two arbitrary vertices. is said to be *reachable* from if there exists a path from to . and are said to be *connected* if either is reachable from , or is reachable from . A graph is called connected if every pair of
vertices is connected. A connected graph with no cycles is called a *tree*.
A *connected component* of is a connected induced subgraph of such that no edge in contains a vertex from and a vertex from . The *transitive closure*
of is a supergraph of that contains edge if
is reachable from .

A *complete graph* is a simple graph with vertices in which every vertex is
adjacent to every other vertex. A *bipartite graph* is a graph whose
vertices can be divided into two disjoint sets such that no vertex is adjacent
to a vertex in the same set. An extensive survey of graph classes can be found
in [4].

The *density* of a graph describes its
size-to-order ratio. The terms *dense* and *sparse* are typically
used to compare the density of multiple graphs or graph classes. A complete
graph, for instance, is a maximally dense simple graph.

One of the most well-known problems in
graph theory is the *shortest path problem*. Its objective is to find a
path of minimal length between two given vertices. The problem is relevant to
many practical applications, including automated navigation, network planning,
and very-large-scale integration (VLSI) design.

A common generalization of the shortest
path problem is the *single-source shortest path problem*. Its objective
is to find all shortest paths from a given vertex to all other vertices in the
graph. The *shortest path tree* for an arbitrary source vertex is an acyclic subgraph of where contains and all vertices reachable from , and contains all edges in a shortest path for
each vertex in .

A computer system contains several
components for storing data. These components differ in terms of cost,
capacity, and performance and serve different purposes in the system. The *memory
hierarchy* is a scheme that orders the components from smallest, fastest,
and closest to the central processing unit (CPU) to largest, slowest, and
furthest from the CPU. The classical depiction of the memory hierarchy is shown
on the left of Figure 1. Data usually passes through the hierarchy
level-by-level, as indicated by the arrows.

* *

*Cache* is the
fastest memory in a computer. Modern personal computers have between two and
four megabytes (MB) of cache memory. Part of it is often built onto the same
chip as the CPU. The processor can access cached data within a few nanoseconds.

*Main memory*
stores data the computer actively operates on. Modern personal computers have
between one and three gigabytes (GB) of main memory. The typical time to
transfer data from main memory to cache is in the 10 to 100 nanosecond range.
It is generally assumed that access time does not depend on the order in which
data is retrieved.

Magnetic *disk drives* are today’s
medium of choice for storing large amounts of data. Unlike cache and most types
of main memory, disk drives are *nonvolatile*; that is, data is preserved
when the power is switched off. Modern disk drives have a capacity of up to two
terabytes (TB), and a personal computer can have several disk drives built in.
The time to retrieve a byte stored on a disk drive is approximately 10
milliseconds. Finding the real time is more complex because disk drives are
mechanical devices. The next section looks in detail at the properties of disk
drives.

*Tertiary storage* comprises very large external storage systems, such as tape
libraries and optical jukeboxes. These systems are designed for data that is
not frequently accessed, such as backups or archives. Access time is high, but
cost per byte of storage is low.

The main component of a disk drive is the platters that rotate around a central spindle (see Figure 1). The upper and lower surface of each platter is coated with a thin layer of magnetic material. One disk head per surface is responsible for sensing (reading) and recording (writing) bits of information in the magnetic flux that passes under it. The disk heads are mounted to an actuator arm that moves the heads across the surfaces. The disk heads are always positioned in parallel, and typically only one head can either read or write at any one time.

The right part of Figure 1 illustrates how
data is organized on a surface. The concentric circles are called *tracks*.
Small gaps divide each track into *sectors*. Each sector can hold a fixed
amount of data, typically 512 bytes or 4 kilobytes (KB). A sector is the
smallest addressable unit in a disk drive. Every read or write operation
involves at least one sector. If part of a sector is corrupted, the entire
sector cannot be used.

Modern disk drives use a technique called *multiple
zone recording* to put more sectors on outer tracks than on inner tracks.
Multiple zone recording increases both the capacity of the disk and the speed
at which sectors in outer tracks can be accessed. A *cylinder* is a set of
tracks from all surfaces that are at the same radius from the spindle.

A common diameter for platters is 3.5 inches (8.9 cm), and a common rotational speed is 120 rotations per second. A typical disk has between 6 and 12 surfaces, each with around 50,000 tracks, each with between 1000 and 2000 512-byte sectors.

Each sector is uniquely identified by a
3-tuple of cylinder number, head number, and sector number (abbreviated *CHS*).
Cylinder numbering starts at 0 for the outmost cylinder and increases inward.
In a disk drive with 8 surfaces, disk heads are numbered from 0 to 7. Sectors
are numbered per track, starting at 1. In early computer systems, sectors had
to be addressed directly by their CHS tuples.

In modern computer systems, *logical
block addresses (LBAs)* have replaced CHS addresses. A LBA is a unique
integer for each sector. The sector with CHS tuple has
LBA 0. More generally, in the absence of multiple zone recording, , where is
the number of disk heads, and is the number of
sectors per track. Figure 2 shows LBAs for the sectors in the first two
cylinders in a disk with and .

File systems use LBAs to cluster sectors
with adjacent addresses into *blocks*, and make a block their smallest
addressable unit. The size of a block is chosen when the file system is
initialized. Typical block sizes are 4 KB and 8 KB. Choosing a larger block
size can reduce disk access time, choosing a smaller block size reduces
internal fragmentation. Two blocks are called *adjacent* if the sector
with the highest LBA in one block is adjacent to the sector with the lowest LBA
in the other block.

The delay between the time when data stored
on the disk is requested and the time when it arrives via the bus at its
destination (e.g., main memory) can be broken down into *data access time*
and *data transfer time*. Data access time can be further broken down into
seek time, rotational latency, and head switch time. The former two factors
dominate:

• *Seek time* is the delay for
positioning the disk heads over the cylinder that holds the first sector of the
requested data. A seek is composed of four phases [21]: A speedup phase, where
the actuator arm is accelerated; a coast phase, where the arm moves at maximum velocity;
a slowdown phase, where the arm is brought close to the desired track; and a
settle phase, where the head is adjusted to the desired location. Seeks of only
a few cylinders are dominated by the settle phase, seeks of a few hundreds
cylinders are dominated by the speedup phase, long seeks spend most time moving
at constant speed. Only for long seeks is seek time roughly proportional to
seek distance.

Moving the heads across the entire disk takes about 10 milliseconds in a typical disk drive.

• *Rotational latency* is the delay
between the time when the heads have been positioned over the correct cylinder
and the time when the first sector of the requested data passes by. Rotational
latency is inversely proportional to the rotational speed of the disk. On
average, rotational latency is half of the time needed for a full rotation. For
instance, the average rotational latency in a disk with a rotational speed of
120 rotations per second is milliseconds.

• *Head switch time* is the delay
for activating the correct disk head. A head switch is an electronic process
and typically takes less than a millisecond.

Data transfer time is the remaining delay after the correct head has been activated and positioned over the first sector of the requested data. Data transfer time depends mainly on the rotational speed of the disk. Additional factors are the number of gaps that have to be passed, and the number of head switches and track switches that take place. A head switch takes place when the requested data is stored in two or more tracks in the same cylinder. A track switch takes place when it is stored in two or more adjacent cylinders. In order for either switch to take place without much rotational latency, sectors on different surfaces are typically laid out with small offsets to each other.

The disk drive places incoming read or
write requests in a *request queue*. The order in which requests are then
serviced depends on the disk’s *scheduling algorithm*. A common algorithm
is the *elevator algorithm*. This algorithm services a new request that
arrives while the disk drive is still working on an old request if the new
request is in the current direction of the arm movement.

Disk drives can typically send and receive data faster over the bus than they can read it from or write it on the disk. To hide this difference, disk drives have cache memory that acts as a speed-matching buffer.

Many disk drives use this memory also to
perform *read-ahead*. Read-ahead is an optimization where the disk drive
continues to read data into the cache after a read request has been serviced.
If the next request is for the cached data, it can be sent over the bus
instantly. Read-ahead is usually only performed when the request queue is
empty.

Even if a disk does not implement read-ahead, some sectors before or after the first sector of the requested data may be available in the disk’s cache. These sectors are collected after the correct disk head has been activated and positioned over the correct track, while the drive waits for the first sector of the requested data to pass by.