Sorting Searching

Download as pdf or txt
Download as pdf or txt
You are on page 1of 351

EATCS

Monographs on Theoretical Computer Science


Editors: W. Brauer G. Rozenberg A. Salomaa

Advisory Board: G. Ausiello S. Even


M. Nivat Chr. Papadimitriou D. Scott
Kurt Mehlhorn

Data Structures and Algorithms 1:

Sorting and Searching

With 87 Figures

Springer-Verlag
Berlin Heidelberg New York Tokyo 1984
Editors
Prof. Dr. Wilfried Brauer
FB Informatik der UniversiHit
Rothenbaum-Chausee 67-69, 2000 Hamburg 13, Germany
Prof. Dr. Grzegorz Rozenberg
Institut of Applied Mathematics and Computer Science
University of Leiden, Wassenaarseweg 80, P. O. Box 9512
2300 RA Leiden, The Netherlands
Prof. Dr. Arto Salomaa
Department of Mathematics, University of Turku
20500 Turku 50, Finland

Author
Prof. Dr. Kurt Mehlhorn
FB 10, Angewandte Mathematik und Informatik
UniversiUit des Saarlandes, 6600 Saarbrucken, Germany

With the permission of B. G. Teubner publishers, Stuttgart,


arranged, solely authorized and revised English translation of the original
German edition: Effiziente Aligorithmen (1977)

ISBN-13 :978-3-642-69674-9 e-ISBN -l3 :978-3-642-69672-5


DOl: 10.lO07/978-3-642-69672-5

This work is subject to copyright. All rights are reserved, whether the whole or part of material
is concerned, specifically those oftranslation, reprinting, re·use of illustrations, broadcasting,
reproduction by photocopying machine or similar means, and storage in data banks. Under
§ 54 of the German Copyright Law where copies are made for other than private use a fee is
payable to "Verwertungsgesellschaft Wort", Munich.
© Springer-Verlag Berlin Heidelberg 1984
Softcover reprint of the hardcover 1st edition 1984

The use registered namens, trademarks, etc. in the publication does not imply, even in the
absence of a specific statement, that such names are exempt from the relevant protective laws
and regulations and therefore free for general use.

2145/3140-543210
For Ena, UIi, Steffi, and Tim
Preface

The design and analysis of data structures and efficient algorithms has
gained considerable importance in recent years. The concept of
"algorithm" is central in computer science, and "efficiency" is central
in the world of money.
I have organized the material in three volumes and nine chapters.
Vol. 1: Sorting and Searching (chapters I to III)
Vol. 2: Graph Algorithms and NP-completeness (chapters IV to
VI)
Vol. 3: Multi-dimensional Searching and Computational Geo-
metry (chapters VII and VIII)
Volumes 2 and 3 have volume 1 as a common basis but are indepen-
dent from each other. Most of volumes 2 and 3 can be understood
without knowing volume 1 in detail. A general kowledge of algorith-
mic principles as laid out in chapter 1 or in many other books on
algorithms and data structures suffices for most parts of volumes 2 and
3. The specific prerequisites for volumes 2 and 3 are listed in the
prefaces to these volumes. In all three volumes we present and analyse
many important efficient algorithms for the fundamental computa-
tional problems in the area. Efficiency is measured by the running
time on a realistic model of a computing machine which we present in
chapter I. Most of the algorithms presented are very recent inven-
tions; after all computer science is a very young field. There are hardly
any theorems in this book which are older than 20 years and at least
fifty percent of the material is younger than 10 years. Moreover, I
have always tried to lead the reader all the way to current research.
We did not just want to present a collection of algorithms; rather we
also wanted to develop the fundamental principles underlying effi-
cient algorithms and their analysis. Therefore, the algorithms are
usually developed starting from a high-level idea and are not pre-
sented as detailed programs. I have always attempted to uncover the
principle underlying the solution. At various occasions several solu-
tions to the same problem are presented and the merits of the various
solutions are compared (e.g. 11.1.5, III. 7 and V.4). Also, the main
algorithmic paradigms are collected in chapter IX, and an orthogonal
view of the book is developed there. This allows the reader to see
where various paradigms are used to develop algorithms and data
structures. Chapter IX is included in all three volumes.
Developing an efficient algorithm also implies to ask for the optimum.
Techniques for proving lower bounds are dealt with in sections 11.1.6,
VIII

11.3, V.7, VILLI, VII.2.3; most of chapter VI on NP-completeness


also deals in some sense with lower bounds.
The organization of the book is quite simple. There are nine chapters
which are numbered using roman numerals. Sections and subsections
of chapters are numbered using arabic numerals. Within each section,
theorems and lemmas are numbered consecutively. Cross references
are made by giving the identifier of the section (or subsection) and the
number of the theorem. The common prefix of the identifiers of origin
and destination of a cross reference may be suppressed, i. e., a cross
reference to section VII.1.2 in section VII.2 can be made by either
referring to section VII. 1.2 or to section 1.2.
Each Chapter has an extensive list of exercises and a section on
bibliographic remarks. The exercises are of varying degrees of
difficulty. In many cases hints are given or a reference is provided in
the section on bibliographic remarks.
Most parts of this book were used as course notes either by myself or
by my colleagues N. Blum, Th. Lengauer, and A. Tsakalidis. Their
comments were a big help. I also want to thank H. Alt, O. Fries,
St. Hertel, B. Schmidt, and K. Simon who collaborated with me on
several sections, and I want to thank the many students who helped to
improve the presentation by their criticism. Discussions with many
colleagues helped to shape my ideas: B. Becker, J. Berstel, B. Com-
mentz-Walter, H. Edelsbrunner, B. Eisenbarth, Ph. Flajolet,
M. Fontet, G. Gonnet, R. Guttier, G. Hotz, S. Huddleston, 1.
Munro, J. Nievergelt, Th. Ottmann, M. Overmars, M. Paterson, F.
Preparata, A. Rozenberg, M. Stadel, R. E. Tarjan, J. van Leeuwen,
D. Wood, and N. Ziviani.
The drawings and the proof reading was done by my student Hans
Rohnert. He did a fantastic job. Of course, all remaining errors are
my sole responsibility. Thanks to him, there should not be too many
left. The typescript was prepared by Christel Korten-Michels, Mar-
tina Horn, Marianne Weis and Doris Schindler under sometimes
hectic conditions. I thank them all.

Saarbrucken, April 1984 Kurt Mehlhorn


Preface to Volume 1

Volume 1 deals with sorting and searching. In addition, there is a


chapter on fundamentals. Sorting and searching are the oldest topics
in the area of data structures and efficient algorithms. They are still
very lively and significant progress has been made in the last 10 years.
I want to mention just a few recent inventions here; they and many
others are covered extensively in the book: randomized algorithms,
new methods for proving lower bounds, new hashing methods, new
data structures for weighted and/or dynamic data, amortized analysis
of data structures, .... Many of these new techniques have never
appeared in book form before. I have tried td combine them with the
classical knowledge about sorting and searching so as to lead the
reader from the basics to current research.
Chapter I (Fundamentals) covers the basics of computer algorithms.
First, a realistic model of computation (deterministic or probabilistic
random access stored program machine) is defined, and the concepts
of running time and storage space are introduced. Then a high level
programming language and its connection with the machine model is
discussed. Finally, some basic data structures such as queues, stacks,
linked lists, and static trees are introduced, and some of their
properties are derived. The material covered in this chapter lays the
ground for all other chapters; the material (except for the section on
randomized algorithms) is usually covered in introductory computer
science courses.
In Chapter II (Sorting)-we deal with sorting, selection, and lower
bounds.We start with a detailed discussion of several general sorting
methods, most notably heapsort, quicksort, and mergesort. The
section on quicksort also contains a treatment of recurrence equations
which arise frequently in the analysis of recursive programs. In section
2 we deal with sorting by distribution (bucketsort). We apply it to
sorting words and sorting reals. The last section, finally, discusses fast
algorithms for the selection problem. The sections on efficient
algorithms are contrasted with methods for proving lower bounds. We
first discuss methods for proving lower bounds in various decision tree
models and then show how to lift some of these lower bounds to
(restricted) RAM models.
Chapter III (Sets) is an in depth treatment of (one-dimensional)
searching problems; multi-dimensional searching is discussed in chap-
ter VII. We cover digital search trees, hashing, weighted trees,
balanced trees, and dynamic weighted trees as methods for represent-
ing subsets of an infinite (or at least very large) universe. In section 7
x

we compare the data structures introduced in the first six sections. The
last section covers data structures for subsets of a small universe where
direct access using arrays becomes feasible. In the course of chapter
III we also deal with important algorithmic paradigms, e. g. dynamic
programming, balancing, and amortization.
There are no special prerequisites for volume 1. However, a certain
mathematical maturity and previous exposure to .programming and
computer science in general is required. The Vordiplom (= examina-
tion at the end of the second year within the German university
system) in Computer Science certainly suffices.

Saarbriicken, April 84 Kurt Mehlhorn


Contents Vol. 1: Sorting and Searching

I. Foundations........... 1

1. Machine Models: RAM and RASP 3


2. Randomized Computations . . . . 12
3. A High Level Programming Language 22
4. Structured Data Types 24
4.1 Queues and Stacks 24
4.2 Lists .. . 26
4.3 Trees . . . . . . 30
5. Recursion . . . . 33
6. Order of Growth 37
7. Secondary Storage 37
8. Exercises..... 38
9. Bibliographic Notes . 39

II. Sorting......... 40

1. General Sorting Methods 42


1.1 Sorting by Selection, a First Attempt 42
1.2 Sorting by Selection: Heapsort . . 45
1.3 Sorting by Partitioning: Quicksort 50
1.4 Sorting by Merging . . . . . . . 59
1.5 Comparing Different Algorithms 66
1.6 Lower Bounds . . . . 68
2. Sorting by Distribution . . . 80
2.1 Sorting Words . . . . . . . 80
2.2 Sorting Reals by Distribution 84
3. The Lower Bound on Sorting, Revisited 85
4. The Linear Median Algorithm 94
5. Exercises...... 98
6. BibliographicNotes . . . . . . 100

III. Sets . . . . . . . . . 102

1. Digital Search Trees 104


1.1 Tries . . . . . . . . 104
1.2 Static Tries or Compressing Sparse Tables 108
XII

2. Hashing............ 118
2.1 Hashing with Chaining . . . . 118
2.2 Hashing with Open Addressing 124
2.3 Perfect Hashing . . . 127
2.4 Universal Hashing .. 139
2.5 Extendible Hashing. . 145
3. Searching Ordered Sets 151
3.1 Binary Search and Search Trees . 152
3.2 Interpolation Search . . . . . . 155
4. Weighted Trees . . . . . . . . . 158
4.1 Optimum Weighted Trees, Dynamic Programming, and
Pattern Matching . . . . . . . . . . 159
4.2 Nearly Optimal Binary Search Trees 177
5. Balanced Trees . . . . . 187
5.1 Weight-Balanced Trees . . . . . 189
5.2 Height-Balanced Trees . . . . . 199
5.3 Advanced Topics on (a, b)-Trees 213
5.3.1 Mergable Priority Queues 213
5.3.2 Amortized Rebalancing Cost and Sorting Presorted
Files . . . . . 217
5.3.3 FingerTrees . . . . . . . 228
5.3.4 Fringe Analysis . . . . . . 241
6. Dynamic Weighted Trees . 249
6.1 Self-Organizing Data Structures and Their Amortized
and Average Case Analysis . 252
6.1.1 Self-Organizing Linear Lists 256
6.1.2 Splay Trees . . . . . . . . . 263
6.2 D-trees........... 275
6.3 An Application to Multidimensional Searching 284
7. A Comparison of Search Structures 286
8. Subsets of a Small Universe . . . 289
8.1 The Boolean Array (Bitvector) . 289
8.2 The o (log log N) Priority Queue 290
8.3 The Union-Find Problem 298
9. Exercises...... 305
10. Bibliographic Notes . 315

IX. Algorithmic Paradigms 317


Appendix .. 325
Bibli?graphy . 328
Subject Index 335
Contents Vol. 2: Graph Algorithms and NP-Completeness

IV. Algorithms on Graphs


1. Graphs and their Representation in a Computer
2. Topological Sorting and the Representation Problem
3. Transitive Closure of Acyclic Digraphs
4. Systematic Exploration of a Graph
5. A Close Look at Depth First Search
6. Strongly-Connected and Biconnected Components of Directed and Undi-
rected Graphs
7. Least Cost Paths in Networks
7.1 Acyclic Networks
7.2 Non-negative Networks
7.3 General Networks
7.4 The All Pairs Problem
8. Minimum Spanning Trees
9. Maximum Network Flow and Applications
9.1 Algorithms for Maximum Network Flow
9.2 (0,1)-Networks, Bipartite Matching and Graph Connectivity
9.3 Weighted Network Flow and Weighted Bipartite Matching
10. Planar Graphs
11. Exercises
12. Bibliographic Notes

V. Path Problems in Graphs and Matrix Multiplication


1. General Path Problems
2. Two Special Cases: Least Cost Paths and Transitive Closure
3. General Path Problems and Matrix Multiplication
4. Matrix Multiplication in a Ring
5. Boolean Matrix Multiplication and Transitive Closure
6. (Min, +)-Product of Matrices and Least Cost Paths
7. A Lower Bound on the Monotone Complexity of Matrix Multiplication
8. Exercises
9. Bibliographic Notes

VI. NP-Completeness
1. Turing Machines and Random Access Machines
2. Problems, Languages and Optimization Problems
3. Reductions and NP-complete Problems
4. The Satisfiability Problem is NP-complete
5. More NP-complete Problems
6. Solving NP-complete Problems
6.1 Dynamic Programming
6.2 Branch and Bound
7. Approximation Algorithms
7.1 Approximation Algorithms for the Traveling Salesman Problem
7.2 Approximation Schemes
7.3 Full Approximation Schemes
8. The Landscape of Complexity Classes
9. Exercises
10. Bibliographic Notes

IX. Algorithmic Paradigms


Bibliography
Subject Index
Contents Vol. 3: Multidimensional Searching and Computational
Geometry

VII. Multidimensional Data Structures


1. A Black Box Approach to Data Structures
1.1 Dynamization
1.2 Weighting and Weighted Dynamization
1.3 Order Decomposable Problems
2. Multi-dimensional Searching Problems
2.1 D-dimensional Trees and Polygon Trees
2.2 Range Trees and Multidimensional Divide and Conquer
2.3 Lower Bounds
2.3.1 Partial Match Retrieval in Minimum Space
2.3.2 The Spanning Bound
3. Exercises
4. Bibliographic Notes

VIII. Computational Geometry


1. Convex Polygons
2. Convex Hulls
3. Voronoi Diagrams and Searching Planar Subdivisions
3.1 Voronoi Diagrams
3.2 Searching Planar Subdivisions
3.2.1 Removal of Large Independent Sets
3.2.2 Path Decompositions
3.3.3 Searching Dynamic Planar Subdivisions
3.3 Applications
4. The Sweep Paradigm
4.1 Intersection of Line Segments and Other
Intersection Problems in the Plane
4.2 Triangulation and its Applications
4.3 Space Sweep
5. The Realm of Orthogonal Objects
5.1 Plane Sweep for Iso-Oriented Objects
5.1.1 The Interval Tree and its Applications
5.1.2 The Priority Search Tree and its Applications
5.1.3 Segment Trees
5.1.4 Path Decomposition and Plane Sweep for Non-Iso-Oriented Objects
5.2 Divide and Conquer on Iso-Oriented Objects
5.2.1 The Line Segment Intersection Problem
5.2.2 The Measure and Contour Problems
5.3 Intersection Problems in Higher-Dimensional Space
6. Geometric Transforms
6.1 Duality
6.2 Inversion
7. Exercises
8. Bibliographic Notes

IX. Algorithmic Paradigms


Bibliography
Subject Index
I. Foundations

We use computer algorithms to solve problems, e.g. to compute the maxi-


mum of a set of real numbers or to compute the product of two integers.
A problem P consists of infinitely problem instances. An instance of
the maximum problem is e.g. to compute the maximum of the following
set of 5 numbers 2,7,3,9,8. An instance of the multiplication problem
is e.g. to compute the product of 257 and 123. We associate with every
problem instance pEP a natural number g(p), its size. Sometimes, size
will be a tuple of natural numbers; e.g. we measure the size of a graph
by a pair consisting of the number of nodes and the number of edqes. In the
maximum problem we can define size as the cardinality of the input set
(5 in our example), in the multiplication problem we can define size
as the sum of the lengths of the decimal representations of the factors
(6 in our example). Although the definition of size is arbitrary, there
is usually a natural choice.

Execution of a program on a machine requires resources, e.g. time and


space. Resource requirements depend on the input. We use TA(p) to de-
note the run time of algorithm A on problem instance p. We can deter-
mine TA(p) by experiment and measure it in milliseconds.

Global information about the resource requirements of an algorithm is


in general more informative than information about resource require-
ments on particular instances. Global information such as maximal run
time on an input of size n cannot be determined by experiment. Two
abstractions are generally used: worst case and average case behaviour.

Worst case behaviour is maximal run time on any input of a particular


size. We use TA(n) to denote the

TA(n) = SUp{TA(p); pEP and g(p) = n}

(worst case) run time of algorithm A on an input of size n. Worst case


behaviour takes a pessimistic look at algorithms. For every n we single
out the input with maximal run time.

Sometimes, we are given a probability distribution on the set of prob-


lem instances. We can then talk about average (expected) case behaviour;
2

it is defined as the expectation of the run time on problems of a particu-


lar size

T!V (n) = E({TA(P); pEP and g(p) = n})

In this book (chapters II and III) computing expectations always re-


duces to computing finite sums. Of course, average case run time is
never iarger than worst case run time and sometimes much smaller. How-
ever, there is always a problem with average case analysis: does the
actual usage of the algorithm conform with the probability distribution
on which our analysis is based?

We can now formulaize one goal of this book. Determine TA(n) for impor-
tant algorithms A. More generally, develop methods for determining
TA(n). Unfortunately, this goal is beyond our reach for many algorithms
in the moment. We have to confine ourselves to determine upper and
lower bounds for TA(n), i.e. to asymptotic analysis. A typical claim
will be: T(n) is bounded above by some quadratic function. We write
T(n) = O(n 2 ) and mean that T(n) ~ cn 2 for some c > 0, nO and all n 2 nO.
Or we claim that T(n) grows at least as fast as n log n. We write
T(n) = ~(n log n) and mean that there are constants c > 0 and nO such
that T(n) 2 c n log n for all n 2 nO. We corne back to this notation in
section I.6.

We can also compare two algorithms A1 and A2 for the same problem. We
say, that A1 is faster than A2 if TA (n) ~ TA (n) for all n and that
1 2
A1 is asymptotically faster than A2 II IjTI TA1 (n)/TA2 (n) o. Of
n~=

course, if A1 is asymptotically faster than A2 then A2 may still be


more efficient than A1 on instances of small size. This trivial obser-
vation is worth being exemplified.

Let us assume that we have 4 algorithms A,B,C,D for solving problem P


2
with run times TA(n) = 1000 n, TB(n) = 200 n log n, Tc(n) = 10 nand
TO = 2 n milliseconds (log denotes log to base two throughout this
book). Then 0 is fastest for 0 ~ n ~ 9, C is fastest for 10 ~ n ~ 100
and A is fastest for n 2 101. Algorithm B is never the most efficient.

How large a problem instance can we solve in one hour of computing


time? The answer is 3600 (1500, 600, 22) for algorithm A(B,C,D). If
maximal solvable problem size is too small we can do either one of two
things. Buy a larger machine or switch to a more efficient algorithm.
3

Assume first that we buy a machine which is ten times as fast as the
present one, or alternatively that we are willing to spend 10 hours of
computing time. Then maximal solvable problem size goes up to 36000
(13500, 1900, 25) for algorithms A(B,C,O). We infer from this example,
that buying a faster machine hardly helps if we use a very inefficient
algorithm (algorithm 0) and that switching to a faster algorithm has a
more drastic effect on maximally solvable problem size. More generally,
we infer from this example that asymptotic analysis is a useful concept
and that special considerations are required for small instances. (cf.
sections II.1.5 and V.4)

So far, we discussed the complexity of algorithms, sometimes, we will


also talk about the complexity of problems. An upper bound on the complexi-
ty of a problem is established by devising and analysing an algorithm;
i.e. a problem P has complexity 0(n 2 ) if there is an algorithm for P
whose run time is bounded by a quadratic function. Lower bounds are
harder to obtain. A problem P has complexity n(n 2 ) if every algorithm
for P has run time at least n(n 2 ). Lower bound proofs require us to
argue about an entire class of algorithms and are usually very diffi-
cult. Lower bounds are available only in very rare circumstances (cf.
II.1.6.,II.3.,II1.4. and V.7.).

We will next define run time and storage space in precise terms. To do
so we have to introduce a machine model. We want this machine model to
abstract the most important features of existing computers, so as to
make our analysis meaningful for every-day computing, and to make it
simple enough, to make analysis possible.

I. 1. Machine ModelS: RAM and RASP

A random access machine (RAM) consists of 4 registers, the accumulator


a and index registers Y1 'Y 2 'Y 3 (the choice of three index registers is
arbitrary), and an infinite set of storage locations numbered 0,1,2, •.. ,
(see figure next page).
4

Cl. 1 accululator
o

Y1 index reg 1

2
y2 1 index reg 2
3

y3 1 index reg 3

The instruction set of a RAM consists of the following list of one


address instructions. We use reg to denote an arbitrary element of CI.,

Y1'Y2'Y3' i to denote a non-negative integer, op to denote an operand


of the form i, p(i) or reg, and mop to denote a modified operand of the
form p(i + Yj). In applied position operand i evaluates to number i,
p(i) evaluates to the content of location i, reg evaluates to the con-
tent of reg and p(i + Yj) evaluates to the content of locaction num-
bered (i + content of Yj). Modified operands are the only means of
address calculation in RAMs. We discuss other possibilities at the end
of the section. The instruction set consists of four groups:

Load and store instructions

reg op , e.g. Y1 p (2)


CI. .... mop , e.g. CI. P(Y2 + 3)
op reg , e.g. p (3) CI.

mop CI. , e.g. P(Y2 + 3) .... CI.

Jump instructions

go to k , k E IN 0
if reg IT then go to k , k E IN 0

where IT E ( =, *, <, ~, >, ~ is a comparison operator.

Arithmetic instructions
CI. .... CI. IT mop

where IT E ( +, x, div, mod} is an arithmetic operator.


5

Index register instructions

1 :5 j :5 3, i E IN 0

A RAM program is a sequence of instructions numbered 0,1,2, •••• Inte-


ger k in jump instructions refers to this numbering. Flow of control
runs through the program from top to bottom except for jump instruc-
tions.

Example: A RAM program for computing 2 n : We assume that n is initially


stored in location o. The output is stored in location 1.

0: Y1 -
1 : a. - 1
p(O)

2: i f Y1 0 then goto 6 n+1

-
3: a. - a. x 2 n
4: Y1 Y1 - 1 n
5: goto 2 n
6: p (1) - a.

The right column shows the number of executions of each instruction on


input n. [J

In our RAMs there is only one data type: integer. It is straightfor-


ward to extend RAMs to other data types such as boolean and reals; but
no additional insights are gained by doing so. Registers and locations
can store arbitrary integers, an unrealistic assumption. We balance
this unrealistic assumption by a careful definition of execution time.
Execution time of an instruc·tion consists of two parts: storage access
time and execution time of the instruction proper. We distinguish two
cost measures: unit cost and logarithmic cost. In the unit cost measure
we abstract from the size of the operands and charge one time unit for
each storage access and instruction execution. The unit cost measure
is reasonable whenever algorithms use only numbers which fit into
single locations of real computers. All aqorithms in this book (except
chanter VI) are of this kind for practical problem sizes and we will
therefore always use unit cost measure outside chapter VL However, the
reader should be warned. Whenever, he analyses an algorithm in the unit
cost measure, he should give careful thought to the size of the operands
6

involved. In the logarithmic cost measure we explicitely account for


the size of the operands and charge according to their lenght L( ).
If binary representation is used then

if n 0
L(n)
otherwise

and this explains the name logarithmic cost measure. The logarithmic
cost measure has to be used if the numbers involved do not fit into
single storage locations anymore. It is used exclusively in chapter VI.
In the following table we use m to denote the number moved in load and
store instructions, and m1 and m2 to denote the numbers operated on in
an arithmetic instruction. The meaning of all other quantities is im-
mediate from the instruction format.

Cost for Storage Access

Operand Unit Cost Logarithmic Cost


i 0 0
reg 0 0
p (i) 1 L(i)
p (i + y.) 1 L(i) + L(y.)
J J

Cost for Executing the Instruction Proper

Load and Stores + L(m)


Jumps + L(k)
Arithmetic + L (m 1 ) + L(m 2 )
Index + L(y. ) + L(i)
J

The cost of a conditional jump if reg IT 0 then goto k is independent of


the content of reg because all comparison operators require only to
check a single bit of the binary representation of reg.

Under the unit cost measure the cost of an instruction is 1 + # of


storage accesses, under the logarithmic cost measure it is 1 + # of
storage accesses + sum of the lengths of the numbers involved. Thus the
execution time of an instruction is independent of the data in the unit
7

cost measure, and it depends on the data in the logarithmic cost meas-
ure.

Example continued: In our example program the instructions have the


following costs

Instruction Unit Cost Logarithmic Cost


o 2 L(O) + + L(p(O»
1 1 + L(1)
2 + L(6)
3 + L(a) + L(2)
4 + L(Y1) + L(l)
5 1 + L(2)
6 2 L(1) + 1 + L(a)

We thus have total cost 4n + 6 under the unit cost measure and 8(n 2 ) un-
der the logarithmic cost measure (compare I.6. for a definition of 8).
n-1
Note that a cost of r (1 + L(2 i ) + L(2» = 8(n 2 ) arises in line 3. Note
i=O
however, that one can improve the cost of computing 2 n to 8(10g n) un-
der the unit cost measure and 8(n) under the logarithmic cost measure.
(cf. exercise 1). [J

We infer from this example that the cost of a program can differ dras-
tically under the two measures. It is therefore important to always
check whether the unit cost measure can be reasonably used. This will
be the case in chapters II to V, VII, and VIII.

Analogously, we use unit and logarithmic cost measure for storage space
also. In the unit cost measure we count the number of storage locations
and registers which are used in the computation and forget about the
actual contents, in the logarithmic cost measure we sum the lengths of
the binary representations of the contents of registers and storage
locations and maximize over time.

Example continued: Our example program uses registers a and Y1 and lo-
cations 0 and 1. Hence its space complexity is 4 under the unit cost
measure. The content of all 4 cells is bounded by 2n , two of them ac-
tually achieve that value. Hence space complexity is 8(L(2 n » = 8(n)
under the logarithmic cost measure. [J
8

Address modification by index register is the only means of address


modification in RAMs. Most realistic computers allow two other tech-
niques for address modification: general address substitution and di-
rect address calculation. General address substitution allows us to use
any location as an index register, i-.e. modified operands of the form
p (i+p (j)) can be used also. The cost of fetching such an operand is 2 in the
unit cost and L(i) + L(j) + L(p(j)) in the logarithmic cost measure. It
is not too hard to simulate the enlarged instruction set by our original
instruction set with only a constant increase in cost. Let us for exam-
ple consider instruction a ~ p(i + p(j)). It is simulated by

Y1 p(j)
a p(i + Y1)

However, the content of Y1 is destroyed by this piece of code. We there-


fore have to save the content of Y1 before executing it. Let us assume
that location 0 is not used (exercise 2 discusses this assumption in de-
tail) in the program to be simulated. Then we only have to bracket the
above piece of code by p(o) ~ Y1 and Y1 - p(O). We obtain

New Instruction Unit Cost Logarithmic Cost

a ~ p(Hp(j) 3 1 + L(i) + L(j) +


L(p(j)) + L(p(i+p(j)))

Simulating Program

p(O) Y1 8 6 + L(i) + L(j) +


Y1 p(j) 2 L(p(j)) + L(p(Hp(j)))
a p (Hy 1) + 2 L(y 1 )
Y1 p (0)

The cost of the simulating program is only larger by a constant factor


under the unit cost measure. We thus have

Lemma 1: General address substitution reduces the cost of RAM-programs


by only a constant factor under the unit cost measure.

The situtation is slightly more complicated for the logarithmic cost


measure. Factor L(Y 1 ) cannot be estimated in a simple way. We therefore
change the simulation method and obtain a simple connection between the
9

cost of the original program and the cost of the simulating program.
We want that location 0 always contains the content of Y1' We achieve
this goal by inserting p(O) ..... Y1 after every instruction which modifies
Y1 and by inserting Y1 ..... p(O) before every instruction which uses Y1'
For example, we replace a ..... p(i +~) by Y1 ..... p(O): a ..... p(i + Y1 ) and
Y1 ..... p(i) by Y1 ..... p(i): p(O) ..... Y1 • This modification increases the cost
only by a constant factor ~nder both measures. Finally, we replace the
instructions using general address substitution as described above,
i.e. we replace e.g. a"'" p(i + p(j» by Y1 ..... p(j): a ..... p(i + Y1 ). Note,
that we do not have to include this piece of code into brackets
p(O) ..... Y1 and Y1 ..... p(O) as before because we took care of saving Y1
elsewhere. We thus have (details are left to exercise 3).

Theorem 1: General address substitution can reduce the time complexity


of RAM programs by at most a constant factor under both cost measures.

We discuss direct address calculation next. We extend the RAM model by


a program store (PS) and call the extended model RASP (Random Access
Stored Program Machine). PS consists of infinitely many locations,
numbered 0,1,2, •••• Each location has two parts. The first part con-
tains the name of the instruction (opcode), the second part contains
the operand, i.e. either an address or the number of an instruction.

Example continued: The RASP-version of our example program is shown


below. We use the RAM-instruction as the opcode, data addresses are
replaced by symbol a and instruction addresses are replaced by k.

Opcode Address

o Y1 ..... p(a) 0

a ..... a 1

2
-i f Y1 = o then goto k 6

3 a ..... a'a 2

4 Y1 ..... y 1-a 1

5 goto k 2

6 p (a) ..... a 1 []
10

The number of opcodes is finite because there are only four registers
and only a finite number of instructions. For the sequel, we assume a
fixed bijection between opcodes and some initial segment of the natural
numbers. We use Num to denote that bijection.

In addition to the RAM instruction set, the RASP instruction set con-
tains so called ~-instructions. ~-instructions operate on the program
store. They are:

a. .... lTk(i)
a. .... lTk(i+Yj ) i E INo'
lTk(i) .... a. :=;; k :=;; 2,
lTk (i+y j) .... a. :=;; j :=;; 3,

Instruction a. .... lTk(i) loads the k-th component of location i of PS into


the accumulator a.. If k = 1 then mapping Num is applied also. The se-
mantic of all other instructions is defined similarly.

Execution times of RASP-instructions are defined as in the RAM case with


one change. RASP programs can grow during execution and therefore the
time required to modify the instruction counter cannot be neglected any
longer. We therefore add L(k) to the cost of an instruction stored in cell
k under the logarithmic cost measure. We have the following relations.

Theorem 2: Executing a RAM program of time complexity T(n) on a RASP


takes:=;; c • T(n) time units, where c E IR is a constant, depending on
the RAM program but not on the input.

Theorem 3: There is a c > 0 such that every RASP program of time com-
plexity T(n) can be simulated in :=;; c • T(n) time units on a RAM. This
holds true under both cost measures.

Theorem 2 follows immediately from the observation, that a RAM program


uses only a fixed number of storage locations of the program store and
that therefore the additive factor L(k) (k being the content of the
program counter) can be bounded by a constant which is independent of
the particular input. Thus the "RASP-cost" of a RAM-instruction is at
most c times the "RAM-cost" where c = 1 + L(length of RAM program to
be executed on a RASP). Theorem 3 is somewhat harder to prove. One has
to write a RAM program which interprets RASP programs. Data store, pro-
11

gram store and registers of the RASP are stored in the data store of
the RAM, more precisely, we use location 1 for the accumulator, loca-
tions 2, 3 and 4 for the index registers, locations 5, 8, 11, 14, •.•
for the data store, and locations 6, 7, 9, 10, 12, 13, .,. for the pro-
gram store. Two adjacent cells are used to hold the two components of
a location of the program store of the RASP. Location 0 is used as an
instruction counter; it always contains the number of the RASP instruc-
tion to be executed next. The interpreter has the following structure:

(1) loop: load the opcode of the RASP-instruction to be executed into


the accumulator.

(2 ) decode the opcode and transfer control to a modul which sim-


ulates the instruction.

(3) simulate the instruction and change the instruction counter.

( 4) goto loop

We leave the details for the reader (exercise 3). According to theorems
2 and 3, time complexity on RAMs and RASPs differ only by a constant
factor. Since we will neglect constant factors anyway in most of what
follows, the choice of machine model is not crucial. We prefer the RAM
model because of its simplicity.

So far, RAMs (and RASPs) have no ability to interact with their environ-
ment, i.e. there are no I/O facilities. We will live with that defect
except for chapter VI and always assume that the input (and output)
is stored in the memory in some natural way. For chapter VI on NP-com-
pleteness we have to be more careful. We equip our machines with two
semi-infinite tapes, a read only input tape and a write only output
tape. The input tape contains a sequence of integers. There is one head
on the input tape which is positioned initially on the first element of
the input sequence. Execution of the instruction a ~ Input transfers
the integer under the input head into the accumulator and advances the
input head by one position. The cost of instruction a ~ Input is 1 in
the unit cost measure and 1 + L(n) in the logarithmic cost measure where
n is the integer to be read in. Similarly, the statement Output - a
transfers the content of a onto the output tape. Whenever a RAM attempts
12

to read from the input tape and there is no element on the input tape
left the computation blocks. We will then say that the output is unde-
fined and that the time complexity of that particular compution is the
number of time units consumed until blocking occurred.

I. 2. Randomized Computations

There are two important extensions of RAMs which we have to discuss:


randomized RAMs and nondeterministic RAMs. We discuss randomized RAMs
now and postpone discussion of nondeterministic RAMs to chapter VI. A
randomized RAM (R-RAM) has the ability to toss a perfect coin and to
make further computation dependent on the outcome of the coin toss, i.e.
there is an additional instruction

0. .... random

which assigns to 0. either 0 or 1 with probability 1/2 each. The cost


of this instruction is 1 in both cost measures. We illustrate this new
concept by a very simple example, an R-RAM which computes constant o.

1: 0."" random
2: if 0. * 0 then goto

Apparently, the content of 0. is 0 when the program stops. However, the


run time of the algorithm depends on the outcome of the coin tosses.
More precisely, if the random choice comes out 0 at the k-th toss for
the first time, k ~ 1, then the run time is 2k in the unit cost measure.
Since the coin is assumed to be fair, the probability of this happening
is 2- k and therefore ezpected run time is L 2- k 2k = 4. Note that ex-
k~1
pected run time is small, although there is a chance that the program
never halts.

The notion of R-RAM is most easily made precise by reducing it to ordi-


nary RAMs, with two input facilities. The first input facility takes
the actual input p for the randomized computation (as above, we leave
the exact nature of that input facility unspecified), the second input
facility is a read only input tape which contains a sequence of O's
and 1's. Execution of 0. .... random reads the next element (if there is
one) from the input tape and transfers it into the accumulator 0.. Let
13

A be a RAM-program. For s a sequence of O's and 1's it thus makes


senseto talk about A(p,s), the output of A on input p and sequence s of
coin tosses, and TA(p,s), the run time of A on input p and sequence s
of coin tosses. Again, we leave it unspecified, whether the output is
written into the memory or on an output tape. The expected run time of
randomized algorithm A on input p is then defined by

r k TA(p,s)
sE {O, 1}

TA(p) is well defined because of

Lemma 1: for all k and p: 2 -k r TA (p,s)


sE{O,1}k

Proof: Let s E {0,1}k, and let t = sO or t = s1. If the computation of


A on input p and sequence s of coin tosses stops regularly, i.e. is not
blocked because sequence s is exhausted, then TA(p,s) = TA(p,t). If it
is not blocked but never halts then TA(p,s) = ~ = TA(p,t). If it is
o

We can now define TA(n) and T:v(n) as described above. Of course T:v(n)
is only defined with respect to a probability distribution on the in-
puts.

What does it mean to say, that a randomized algorithm A computes a


function f : P ..... Y? Of course, the output of A can depend on the partic-
ular sequence s of coin tosses used in the computation.

Definition: Let f : P ..... Y and e: : IN ..... IR be functions. Randomized


algorithm A computes f with error probability at most e: if for all
pEP
k
lim I {s E {O, 1} : f(p) A(p,s)}1 ~ 1 - e:(g(p»,
k ..... ~ 2k

here g(p) is the size of input p. o

An argument similar to the one used in lemma 1 shows that the limit in
the definition above always exists. Of course, only the case e:(n) < 1/2
is interesting. Then A gives the desired output with probability larger
14

than 1/2. A randomized algorithm A is called a Las Vegas algorithm for


function f if it computes f with probability 0 of error, i.e. E(n) = 0
in the above definition. In particular, whenever A(p,s) stops and is
defined then A(p,s) = f(p). Las Vegas algorithms are a particularly
nice class of randomized algorithms because the output is completely
reliable. We see examples of Las Vegas algorithms in 11.1.3 and
III. 1 .2.

Of course, we want the probability of error to be as small as possible.


Suppose, that we have a randomized algorithm A which computes f : P - Y
with probability of error at most E(n). If E(n) is too large we might
just run A several times on the same input and then determine the out-
put by a majority vote. This should increase our confidence in the out-
put.

Lemma 2: Let 8 > O. If randomized algorithm A computes f : P - Y with


error probability at most E(n) = E < 1/2 in time TA(n) and if TA 0 g is
computable in time O(TA ) then there is a randomized algorithmB which
-1
computes f in time c·m· (1/2 - E) TA(n) with error at most 8. Here
m = (log 8)/log(1-(1/2 - E)2) and c is a constant. Moreover, B always
-1
halts within c·m·(1/2 - E) TA(n) time units.

Proof: Consider any pEP. Let n = g(p), T = (4/(1 - 2E»TA (n) and
m = 2· (log 8)/log(1-(1/2 - E)2). On input PtB computes T,chooses m ran-
dom sequences s1,s2, ..• ,sm of length T each, and simulates A on inputs(p,s1)'
.•• , (p,sm) for up to T time units each. It then outputs whatever the
majority of the simulated runs of A output. Apparently B runs for at
most 0«1 + m)T) = 0(m(1/2 - E)-1 TA(n» time units. Moreover,
f(p) *
B(PtS1 •.•.sm)iff A(p,si) * f(p) for at least m/2 distinct i's.
Next note that

I {s E {0,1}
T
; f(p) * A(p,s)} I
2T

T
:0:; lim I {s E {0,1f; f(p) * A(p,s)} I +
I {s E {0,1} ; TA(p,s) 2': T} I

k-oo 2k

+ (1/2 - E)/2 1/2 - 1/2(1/2 - E)


15

since A computes f with error at most £ (and therefore the first term
is bounded by £) and since for pEP with g(p) = n we have
TA (n) ~ TA (p) ~ r {TA (p, s) ; s E {0,1}T}/2 T
~ r {TA (p, s) ; s E {O, 1} T and TA (p, s) ~ T}/2 T
~ T·I {s E {O, 1} T and TA(p,s) ~ T} 1/2T
and therefore the second term is bounded by T/TA(n) 4/ (1-2£). Let
y = 1/2 - 1/2(1/2-£). Then
I {s1 ••• sm E {0,1} ; B(p,S1' ••• sm) * f(p)} 1 m .
Tm
.
~ r (~)y~(1_y)m-~
2Tm i=m/2 ~

since y < 1/2

by definition of m. []

It is "Torth illustrating lemma 2 by an example. Assume t..hat £ = 0.49 and


0= 0.03. Then m = 2 log 0/log(1-(1/2-£)2) = 2 log 0.03/log 0.9999 I'>! 70127. Thus
we have to repeat a computation which gives the correct answer with pro~
ability 0.51 about 70000 times in order to raise the level of confidence
to 0.97 • If we start with a more reliable machine, say £ = 0.25, then m
reduces to 2 log 0.03/log 0.9375 101 108. From this example we see that bring-
ing the error from 0.49 down to 0.25 is the hard part, increasing the
level of confidence further is easy. Randomized algorithms have a fair
coin available to them and deterministic algorithms do not. It is there-
fore important to know how good a randomized algorithm can be simulated
by a deterministic algorithm. We approach this problem from two sides.
First we show that for fixed problem size one can always replace the
fair coin by a fixed sequence of O's and 1's of reasonable length (Theo-
rem 1), and then we show how to use good pseudo-random number generators
in randomized computations.
Theorem 1: Let n E IN, N = I {p E P; g(p) ~ n} I, let 0 = 1/ (N+1) and let A,B, £ and
f as in lemma 2. Then there is a sequence s E {O,1}I!'I!', m and T as in the
proof of lemma 2, such that f(p) = B(p,s) for all pEP, g(p) ~ n.
Proof: B computes f with error probability at most o. Let
Pn = {p E P; g(p) ~ n}. Then for all p E Pn
r{s E {0,1}Tm; B(p,s) * f(p)} ~ 0.2mT = 2mT /(N+1) and therefore
r r if B(p,s) * f(p) then 1 else 0
sE {O, 1} Tm pEP n
16

L L if B(p,s) * f(p) then else 0


pEP n sE {a, 1} Tm

Thus there is at least one s E {0,1}Tm such that


L if B(p,S) *
f(p) then else 0 < 2mT /2 mT = 1. Hence B(p,s) f(p)
pEP n
for all p E Pn • c

We illustrate Theorem 1 by an ex~~nle. Assu~e that P = {O,1}* and


.. n+1
g(p) = Ipl, the length of bit string p. Then IPnl ~ 2 • Assume also
that we start with a randomized machine A with £ = 1/4 and running time
TA(n) = n k for some k. Taking 0 = 1/(2 n + 1 +1). Lemma 2 yields a ~achine
k+1
B with worst case running time TB(n) = O«-log o)TA(n» = O(n ) and
error probability at most o. Moreover, by theorem 1, there is a fixed
0-1 sequence s of length O(nk + 1 ) which can be used by B instead of a
true random number generator. Unfortunately, the proof of theorem 1
does not suggest on efficient method for finding a suitable s.

The question now arises whether we can use a pseudo-random number


generator (say built-in procedure RANDOM on your favorite computer)
to generate coin toss sequences for randomized algorithms. A typical
pseudo-random number generator works as follows. It consists of a
function T: {0,1}m ~ {0,1}m which is designed such that there is no
"obvious" connection between argument x and value T (x). The most popular
choice of function T is
T(x) = (ax + c) mod 2m
where the argument x is interpreted as a number between 0 and 2m - 1,
multiplied by a multiplier a in the same range, incremented by an
increment c in the same range, and finally truncated to the last m bits.
A user of a pseudo-random number generator provides a "seed" xOE {0,1}m
and then uses the transformation T to generate a sequence x1,x2,x3'···'~
with x i + 1 = T(X i ). Thus a pseudo-random number generator takes a bit
sequence Xo of length m and produces a bit sequence (take the concat-
enation of x1' ••• '~) of length km for some k. We can therefore define
a pseudo-random number generator as a mapping p: {0,1}m ~ {0,1}E(m)
where E(m) ~ m. It takes a seed x E {0,1} m and produces a sequence p(x)
of length E (m) •

The choice of the seed is left to the user and we will not further
discuss it. We might use a physical device or actually toss a coin.
17

However, we will discuss the desirable properties of mapping p in more


detail. The mapping p takes a bit string of length m and produces a bit
string of length E(m). If E(m) > m then p(x) is certainly not a random
(in the sense that all strings of lenth E(m) are equally likely) string
even if x is a random string of length m. After all, only 2 m out of the
2E (m) possible strings of length E(m) are in the range of p • Suppose
now that we can generate random strings x of length m, is i t then safe
to use the pseudo-random strings p(x) of length E(m) in a randomized
algorithm? At first glance the answer seems no because pseudo-random
strings are not random strings.

However, they might be "random enough" to be used anyway instead of a


true random sequence. In order to make this precise we need to introduce
a measure of quality for pseudo-random number generators. We do so by
introducing the concept of a statistical test. Consider for example the
function h: {0,1} * ~ {0,1} which yields one if the number of zeroes and
ones in the argument differs by at most 10%. Then h applied to a random
bi t string yields one with very high probability and we might require the
same for a random element in the range of p • If this were the case
then the statistical test h cannot distinguish between true random
sequences and the sequences obtained by applying p to shorter random
sequences. If this were true for all statistical tests (a notion still
to be defined) then the sequences generated by p are rightfully called
pseudo-random.

In qeneral, we define a statistical test to be any function h:{0,1} * ~


{0,1} which yields a one for at least half of the arguments of any fixea
length. A randomized algorithm A can easily be turned into a statistical
test h A • The test hA calls a sequence s E {a, 1} * "good" (Le. yields a
one) if the run time of algorithm A when using sequence s of coin tosses
does not exceed its expected run time by more than a factor of, say, two.
Then most random sequences are good, i.e. hA is a statistical test, and
if pseudo-random number generator p "passes" test h A , then this should
also be true for many(a precise definition is given below) sequences in
the range of p • Note that for this argument to work i t suffices to
know that p passes the statistical test hA derived from algorithm A.
Thus, if A's run time is polynomially bounded (we restrict attention to
polynomially time bounded algorithms because we saw in the introduction
of this chapter that algorithms with exponential run time are hopelessly
18

inefficient) and p passes all statistical tests of polynomial time


complexity then p will also pass the test hA and hence we can hope to
use the pseudo-random sequences generated by p instead of true random
sequences in operating algorithm A.

We will now make these concepts precise. Part c) of the definition below
defines in precise terms what we mean with the phrase that a mapping p
passes a statistical test h. We give two variants of the definition
which are geared towards the two applications of pseudo-random number
generators to be described later: fast simulation of randomized algo-
rithms by deterministic algorithms and reducing the number of coin
tosses in randomized computations.

Definition: a) A function h: {O,1} * ~ {O,1} is polynomially time


computable if there is a deterministic algorithm computing h whose
running time is bounded by a polynomial.

b) A statistical test is a function

h: {O,1}* ~ {O,1} with l{xE{O,1}k ; h(x) = 1}1 ~ 2k - 1 for all k.

c) Let E: :IN ~ :IN be a function, let pdo, 1} * ~ {O,1} *


be such that I p (x) I = E (m) for I xl = m and let mO: :IN ~ :IN be a function.
Let h be a statistical test and let h be computable in time tnt for some
t. Then p passes test h if for all m ~ molt)
{xE{O,1}E(m); x E range p and h(x) = 1} *¢
Furthermore, p passes test h well if for all m ~ molt)

I {xE{O,1}E(m); x E range p and h(x) = 1}1 ~ 2m/8

Remark: If P passes test h well then a random element in the range of p


makes h true (one) with probability exceeding 1/8 while a true random
element of {O,1}E(m) makes h true with probability exceeding 1/2. The
choice of cut-points a 1 = 1/2 and a 2 = 1/8 is arbitrary; however
o < a 2 ~ a 1 is essential.

d) A mapping p is a good (very good) pseudo-random number


generator if it passes all polynomial time computable statistical tests
(well) • o

The reader should pause at this point and should try to grasp the
19

intuition behind this definition. We defined a statistical test to be


any predicate on bit strings which at least half of the strings of any
fixed length satisfy (part b). Furthermore, we restrict attention to
simple (= polynomial time computable predicates) (parts a and c). A
pseudo-random number generator p passes all statistical tests if the
range of p has no simple structure, i.e. if there is no large and
computa tionally simple subset of {O, 1 }E (m), namely a set {x E (0, 1 ) E (m) i
h(x) = 1} for some statistical test h, which either p misses completely
or p does not hit with sufficiently high probability. In other words,
the properties of a random element in range(p) are hard to predict, and
hence the elements produced by p are rightfully called pseudo-random
sequences. Note that "being random" is the same as "being hard to
predict" .

It is not known whether (very) good random number generators in the


sense of this definition exist. However, it can be shown that very good
random number generators with E(m) = mk for any k and p computable in
polynomial time exist if anyone of the following number theoretic prob-
lems is hard: the discrete logarithm problem or the problem of factor-
ing integers. We have to refer the reader to the literature for a dis-
cussion of these results (cf. A.C. Yao: Theory and Applications of
Trapdoor Functions, IEEE FOCS 1982, 80-91). We proceed under the as-
sumption that a (very) good polynomially time computable pseudo-random
nurilier generator p exists with E(m) = m2 , say. We show that good pseudo-
random nQ~er generators can be used to speed up the simulation of
randomized algorithms by deterministic algorithms and that very good
generators can be used to reduce the required number of true random
choices. The latter consequence is important if generation of truely
random bits would ever become possible, yet be expensive.

For concreteness and simplicity, let A be a Las Vegas algorithm with


polynomial running time, i.e. TA(n) ~ tnt for some t E IN and let p be
a good pseudo-random number generator with E (m) = m2 . Let pEP, n = g(p)
be such that 12tnt ~ m . Then h :
o p
{O,1}* ~ {O,1} with

h (s)
P otherwise

is computable in time tnt and we have h (s)


p
= 1 for at least fifty per-
cent of the bit strings of length 2tnt. This follows from the fact that
20

the running time of TA on p and s can exceed twice the expected value
for at most half of the sequences of coin tosses. Hence

{s E {0,1}E(m), s E range p and h (s) 1} '" ¢


p

for all m ~ 12tnt or

{s E {0,1}E(m); s E range p and TA(p,s) ~ 2nt} '" ¢

This relationship directly leads to a deterministic simulation of prob-


abilistic machines which is more efficient than the naive one. Let
pEP, g(p) = n and let m = 12 tnt. Consider the following piece of code:

for all x E {0,1}m


do let s ~ p(x),
run A on p and s for up to 2tn t steps,
if A halts within that number of steps
then output, whatever A outputs and halt fi
end

Since A is a Las Vegas algorithm and since there is an s E p({0,1}m)


with TA(p,S) ~ 2nt, the simulation always prod~the correct answer.
Also the running time of the simulation is 0(2 2tn (tnt+q(m»), where q is
the polynomial bound on the time needed to compute p. Thus the existence
of good pseudo-random number generators leads to more efficient simu-
lations of probabilistic machines by deterministic machines. Note that
t
the naive simulation has running time O(2 tn tnt).

Assume now that p is a very good pseudo-random number generator. Then

where m,n and p are as defined above. In other words, a random


x E {41}m produces an s = p(x) such that TA(p,S) ~ 2tnt with probability
atleast 1/8. This observation leads to the following implementation of
algorithm A which uses fewer coin tosses than A.
21

repeat generate a random sequence of m bits and call it X;


s - pIx)
until A on p and s halts within 2tnt steps;
output, whatever A outputs on p and s.

Since a random x E {O,1}m produces an s = pIx) E {O,1}E(m) with


TA(p,s) ~ 2tnt with probability at least 1/8 only 8 iterations of the
loop are required on the average. Hence the algorithm above simulates
A in time O(TA(n» = oInt) and uses only O(~) random choices. Thus
if true random choices are possible but costly, this is a significant
improvement. This finishes our discussion on the use of (very) good
pseudo-random number generators in randomized computations.

We close this section with a remark on the relation between the ex-
pected time complexity of deterministic algorithms and the running time
of probabilistic algorithms.

Let A be a Las Vegas algorithm which computes function f: P ~ Y. Let


us assume for simplicity that for every n E IN A makes at most a(n) coin
tosses on any input pEP with g(p) = n. Then

L TA (p,S)/2 a (n)
SE{O,1}a(n)

Suppose also that we are given a probability distribution ~ on the set


P of problem instances. Let B a deterministic algorithm for f, whose
expected running time on inputs of size n is minimal (B is certain to
exist if P n , the set of problem instances size n,is finite), i.e. for
all deterministic algorithms C

E({TB(p); pEP and g(p) = n}) ~ E({TC(p); pEP and g(p)= n})

where expectations are taken with respect to probability distribution~.

For every fixed s E {O,1}a(n) algorithm A with sequence s of coin tosses


is a deterministic algorithm and hence
22

Since this inequality holds for every s we have

L
sE {O, 1} a (n)

L ~(p) L TA (p,S)/2 a (n)


pEP sE {O, 1} a (n)
n

Thus the expected running time of Las Vegas algorithm A on inputs of


size n can be no better than the expected running time of the best
deterministic algorithm. We will use this fact to derive lower bounds
on the randomized complexity of some sorting problems in chapter II.
For sorting and some related problems we will derive n(n log n) lower
bounds on the expected running time of a large class of deterministic
algorithms in chapter II. The inequality derived above immediately ex-
tends that lower bound to the corresponding class of randomized algorithms.

I. 3. A High Level Programming Language

Only a few algorithms in this book are formulated in RAM code, most
algorithms are formulated in a high level Algol-like programming lan-
guage. We feel free to introduce additional statements into the language,
whenever the need arises and whenever translation to RAM code is obvious.
Also we make frequent use of complex data structures such as lists,
stacks, queues, trees and graphs. We choose this very high level de-
scription of many algorithms because it allows us to emphasize the
principles more clearly.

Most statements of our programming language are known from Algol-like


languages. In particular, we use the conditional statement
if <condition> then <statement> else <statement> fi,
the iterative statement
while <condition> do <statement> od,
the for-loop
for i from <expression> step <expression> to <expression>
do <statement> od.
23

If step size is unspecified then i t is 1 by default. We also use a


second form of the for-loop
for i E set do <statement> od
with the following semantics. The statement is executed Isetl-times;
i runs through the members of set in some unspecified order. Assign-
ments are written in the form <variable> - <expression>. Translation of
all statements above into RAM code is simple. We describe the transla-
tion in the case of a while-statement while B do Sod. Let P be a RAM
- 1
program for B1 , i.e. P 1 evaluates expression B and leaves a 0 (1) in
the accumulator,if B evaluates to false (true). Let P 2 be a RAM program
for A. Then the following piece of RAM code realizes the while-loop.

P1
if a = 0 then goto exit;
P2
goto first instruction of P 1 ;
exit:

This program also defines the complexity of the while-loop; i t is the


sum of the time units spent on the repeated testing of the condition
and execution of the body.

Variables in our programs contain unstructured elementary values or


structured values. The elementary data types are integer, real, boolean,
pointer and an additional unspecified data type. We use this additional
data type in sorting algorithms; the data to be sorted will be of the
unspecified type. The operations defined on this additional data type
are given on a case by case basis. Structured data types are strings
over some alphabet, records, arrays, lists, stacks, queues, trees and
graphs. Strings are treated in 11.2., graphs in IV.1., all other struc-
tured types are treated in 1.4 •• The type of a variable will be obvious
from the context in most cases; in this case we will not declare vari-
ables explicitely.

Procedures playa major role in our programs. Parameters are restricted


to elementary types. Then parameter passing takes constant time (cf.
1.5.). Non-recursive procedures are easily reduced to RAM code; one on-
ly has to substitute the procedure body at the place of call. The situ-
ation is more complicated for recursive procedures. We treat recursive
procedures in 1.5 .•
24

I. 4. Structured Data Types

Records and arrays are the most simple ways of structuring data. An
array A of n elements consists of n variables A[1], ••. ,A[n] of the same
type. An array is stored in n consecutive storage locations, e.g. in
locations BA+1, BA+2, ••• ,BA+n. Here BA stands for ~ase ~ddress. If x
is a variable stored in location i then accessing array element A[x] is
realized by means of index registers. The following piece of code

Y1 p(i)
a P(BA+Y1 )

loads A[x] into the accumulator for a cost of 3 in the unit cost meas-
ure and (2 + L(i) + L(BA) + 2L(x) + L(A[x]}} in the logarithmic cost
measure. Again the logarithmic cost is proportional to the length of
the numbers involved.

Records are fixed size collections of variables of different type, e.g.


record age : integer, income : real end. A variable x of this record
type is easily simulated by two simple variables, a variable x.age of
type integer and a variable x.income of type real.

Queues, stacks, lists and trees are treated in the sections below. They
are all reduced to arrays.

I. 4.1 Queues and Stacks

Queues and stacks are used to represent sequences of elements which can
be modified by insertions and deletions. In the case of queues inser-
tions are restricted to the end of the sequence and deletions are re-
stricted to the front of the sequence. A typical example is a waiting
line in a student cafeteria. Queues are also known under the name FIFO
(first in - first out) store. In the case of stacks, insertions and
deletions are restricted to the end of the sequence: LIFO (last in -
last out) store. Very often, the names Push and Pop are used instead of
insertion into and deletion from a stack.

A stack K is most easily realized by an infinite array K[1], K[2], .••


and an index TOP of type integer. The stack consists of elements K[1],
••• ,K[TOP]; K[TOP] is the top element of the stack. The following piece
25

of code realizes operation push(K,a)

TOP TOP + 1;
K[TOP] .. a

and the following piece of code deletes an element from the stack and
assigns it to variable x, i.e. it realizes x .. pOpeK)

if TOP = 0 then error fi;


x .. K[TOP];
TOP .. TOP - 1

Of course, infinite arrays are rarely available. Instead we have to


use a finite array of, say, n elements. In this case a push-operation
should also check whether overflow occurs. In either case, the stack"
operations push and pop take constant time in the unit cost measure.

A queue S is also realized by an array. We immediately treat the case


of a finite array S[1 •• n]. We conceptually think of array S as a closed
line, i.e. S[1] follows S[n], and use two indices FRONT and END to denote
the borders of the queue. More precisely, if FRONT < END then the queue
consists of S[FRONT], •.• ,S[END-1], if FRONT> END then the queue con-
sits of S[FRONT], ••• ,S[N],S[1], .•• ,S[END-1] and if FRONT = END then the
queue is empty. Then deleting an element from S and assigning it to x
is realized by

if FRONT = END then error fi;


x --- S [FRONT];
FRONT --- 1 + (FRONT mod n)

and inserting an element a into a queue is realized by

S[END] --- a;
END --- 1 + (END mod n);
if FRONT = END then error fi

Insertions into and deletions from queues take constant time in the unit
cost measure.
26

1. 4.2 Lists

Linear lists are used to represent sequences which can be modified any-
where. In linear lists the elements of a sequence are not stored in
consecutive storage locations, rather each element explicitely points
to its successor.

element
1

There are many versions of linear lists: singly linked, doubly linked,
circular, • . • . We discuss singly linked lists here and leave the
others for the exercises. In singly linked linear lists each element
points to its successor. There are two realizations of linear lists:
one by records and one by arrays. We discuss both, although internally
the record representation boils down to the array representation. We
use both representations throughout the book whichever is more conven-
ient. In the record representation an element of a linear list is a
record of ~ element = record cont: real, next: telement end and
HEAD is a variable of type telement. HEAD always points to the first
element of the list. The pictorial representation is as given above.
Closer to RAM code is the realization by two arrays. Real array
CONTENT[1 •• n] contains the contents of the elements and integer array
NEXT[1 .. n] contains the pointers. HEAD is an integer variable. Our
example list can be stored as follows:

HEAD:
OJ CONTENT NEXT

element 4 o
2 element 1 4
3 element 3 1
4 element 2 3

Here HEAD = 2 means that row 2 of the arrays contains the first element
of the list, the second element is stored in row 4, . . • . The last ele-
ment of the list is stored in row 1; NEXT[1] = 0 indicates that this
element has no successor.
27

We will next describe insertion into, deletion fran and creation of linear
lists. We give two versions of each program, one using records and one
using arrays. In either case we assume that there is a supply of unused
elements and that c call of procedure newr (~p: telement)
(newa(var p: integer» takes a node from the supply and lets p point to
it in the record (array) version and that a call of procedure dis-
poser(~ p: telement) (disposea(~ p: integer» takes the node point-
ed to by p and returns it to the supply. Suffixes r and a distinguish
between the representations. We discuss later how the supply of ele-
ments is implemented. In our example a call newa(p) might assign 5 to
p because the fifth row is unused and a call newr(p) results in
P:~CI3-lI··

Prodedure Create takes one parameter and makes it the head of an empty
list. Again we use suffixes r and a to distinguish the record and the
array version.

proc Creater(~ HEAD: telement); proc Creater(~ HEAD: integer);


HEAD nil HEAD - 0
end end

Procedure Insert takes two parameters, a pointer to the element after


which we want to insert and the content of the new element.

proc Insertr(p:telement,a:real); proc Inserta(p:integer, a:real);


~ q: telement; var q: integer;
(1) newr(q); newa(q);
(2) qt .cont a; CONTENT[q] - a;
(3) qt • next pt .next; NEXT[q] NEXT[p];
(4) pt .next q NEXT[p] q
end end

The following sequence of diagrams illustrates a call Insertr(p,a).

I~ before the call


28

after executing (1)

after executing (2) and (3)

after executing (4)

Procedure Delete takes one parameter, a pointer to the element which


precedes the element which we want to delete.

proc Deleter (p: telement); proc Deletea(p: integer);


var q: telement; var q: integer;
q - pt. next; q - NEXT[p];
pt. next - qt. next; NEXT[p] - NEXT[q];
disposer(q) disposea(q)
end end

Finally, we have a function to test whether a list is empty.

function Emtyr (HEAD: telement); function Emtya (HEAD: Hnteger);


Emtyr - (HEAD = nil) Emtya -(HEAD = 0)
end end

It remains to discuss the supply of unused nodes in more detail. Supply


is again a linear list with head FREE. We will only describe the array
version of procedures new and dispose because these procedures are
usually built-in functions in programming languages which contain
records. Internally, records are always realized by arrays and therefore
29

newr(disposer) are identical to newa(disposea). A supply of n elements


is created by

proc Inita (n: integer);


var i: integer;
FREE +- 1;
for i from to n-l
do NEXT[i] i+l od;
NEXT[n] +- 0
end

and newa and disposea are realized by

proc newa(var q: integer);


q +- FREE;
if FREE =0 then supply exhausted fi;
FREE +- NEXT [FREE] ;
NEXT[q] +- 0
end

and

proc disposea(var: q integer);


NEXT [q] +- FREE;
FREE +- q;
q +- 0
end

We summarize in

Theorem 1: Creating a supply of n nodes takes time O(n) in the unit


cost measure, creation of an empty list, insertion into, deletion from
a linear list and testing for emptiness take time 0(1) in the unit
cost measure. []

One often uses linear lists to realize stacks and queues. In par-
ticular, several stacks and queues may share the same supply of unused
nodes. This will guarantee high storage utilization if we have know-
ledge about the total length of all stacks and queues but no knowledge
about individual length. Typical examples can be found in chapter IV.
30

We store a graph by listing for each node its set of successors. In a


graph of n nodes and m edges these lists have total length m, but
nothing is known in advance about the length of individual lists.

I . 4.3 Trees

Trees consist of nodes (branching points) and leaves. Let


V = {v 1 ,v2 , ••. } be an infinite set of nodes and let B = {b 1 ,b 2 ,b 3 , ..• }
be an infinite set of leaves. We define the set of trees over V and B
inductively.

Definition: a) Each element b i E B is a tree. Then b i is also root of


the tree.

b) If T1 , ••• ,Tm(m ~ 1) are trees with pairwise disjoint sets of nodes


and leaves and v E V is a new node then the m+1 tuple T = <v,T 1 , ••. ,Tm>
is a tree. Node v is the root of the tree, p(v) = m is its degree and
Ti is the i-th subtree of T. [J

Trees can also be defined graph-theoretically. In graph-theoretic


literature trees as defined above are usually called ordered rooted
trees. We always draw trees with the root at the top and the leaves
at the bottom. Nodes are drawn as circles and leaves are drawn as
rectangles.

We use the following terms when we talk about trees. Let T be a tree
with root v and subtrees Ti , 1 ~ i ~ m. Let wi = root(T i ). Then wi is
the i~th son of v and v is the father of wi. Descendant (ancestor)
31

denotes the reflexive, transitive closure of relation son (father). Wj


is a brother of wi' j * i. In the tree above, b 1 and v 4 are brothers,
v 1 is father of v3 and b S is descendant of v 2 •

Definition (depth): Let v be a node or leaf of tree T. If v is the root


of T then depth(v,T) = O. If v is not the root of T then v belongs to
Ti for some i. Then depth(v,T) 1 + depth (v,T i ) . We mostly drop the
second argument of depth when it is clear from the context.

Definition (height of a tree): Let T be a tree. Then


height(T) = max {depth(b,T); b is leaf of T}.

In our example, we have depth(v 3 ) = 1, depth (v 4 ) = 2 and height(T) 3.

Definition: Tree T is a binary tree if all nodes of T have degree


exactly 2.

Our example tree is a binary tree. A binary tree with n nodes has n+1
leaves. The 1st (2nd) subtree is also called left (right) subtree.

Information can be stored in the leaves and nodes of a tree. In some


applications we use only one possibility. A binary tree is realized by
three arrays LSON, RSON and CONTENT or equivalently by records with
three fields. Figure 1 gives the storage representation of our example
tree. We have associated rows withnodes and leaves in some arbitrary
way. If information is only stored in the nodes and not in the leaves
then leaves do not have to be stored explicitly. All rows corresponding
to leaves can be deleted and pointers pointing to leaves are set to O.
A O-pointer then represents a subtree consisting of a single leaf. In
the diagrams we will not draw leaves in this case. (cf. figures 2 and 3).

root CONTENT LSOHN RSOHN


m 1 Content of v2 0 4
2 Content of v4 0 0
3 Content of v1 1 2
4 Content of v3 0 0

figure 2
32

root CONTENT LSOHN RSOHN

0 Content of v 4 8 4
2 Content of v 2 3 1
3 Content of b 1 0 0
4 Content of b S 0 0
5 Content of v 1 2 7
6 Content of b 2 0 0
7 Content of v3 6 9
8 Content of b 4 0 0
9 Content of b 3 0 0

figure 1

figure 3

Systematic exploration of a tree is needed frequently. A binary tree


consists of three components: a root, a left subtree and a right sub-
tree. Thus three methods of tree traversal come naturally:

Preorder traversal: visit the root, traverse the left subtree, traverse
the right subtree: Root, L, R.

Postorder traversal: traverse the left subtree, traverse the right sub-
tree, visit the root: L, R, Root.

Symmetric traversal: traverse the left subtree, visit the root, trav-
erse the right subtree: L, Root, R.

Symmetrical variants are obtained by interchanging Land R. Procedure


33

Symord below traverses a tree in symmetrical order and prints the con-
tent of all nodes and leaves.

proc SYMORD(v) ;
(1) if v is leaf
(2) then print(CONTENT[v])
(3) else SYMORD (LSON [v]) ;
(4) print(CONTENT[v]);
(5) SYMORD (RSON [v] )
fi
end

I. 5. Recursion

Recursive procedure SYMORD traverses a binary tree in symmetrical


order. Before we can estimate time- and space - complexity of SYMORD we
need to take a look at the implemention of recursive procedures in RAM-
or RASP-code. Recursive procedures are realized by means of a stack.
We associate with each call (incarnation, activation) of a procedure
an element of the stack, called activation record. The activation
record contains complete information about the call,

a) the values of the actual parameters,


b) the return address,
c) the local variables.

If a procedure has n parameters and m local variables then the acti-


vation record consists of n + 1 + m storage locations. The i-th cell,
1 ~ i ~ n, contains the value of the i-th actual parameter, the (n+1)-st
cell contains the return address, i.e. the address of the instruction
which follows the procedure call in the calling program, and the
(n+1+j)-th cell contains the j-th local variable. Parameters and local
variables are addressed indirectly via the activation record. More
precisely, if TOP is the address of the storage location immediately
preceeding the activation record then location TOP + i contains the
i-th actual parameter and cell TOP + n + 1 + j contains the j.th local
variable. TOP is best stored in an index register. After completion of
the procedure call control is transfered to the address stored in lo-
cation TOP + n + 1. Also TOP is reduced after completion, i.e. the
34

activation record is deleted from the stack. Parameters and return


address are computed by the calling program, i.e. the first n + 1
cells of an activation record are initialized by the calling program.
We are now ready to give the non-recursive version of SYMORD. Array
K[1 .• ~] is used as the stack

(1')
.
begin co the main program calls
- SYMORD(root)~

(2') TOP .. O~

(3') K[1] .. root~


(4') K[2] .. "HP"
(5 ' ) goto SYMORD ~
(6') HP: Halt~
(7') SYMORD: co here comes the code for SYMORD~ node v is stored in
K[TOP+1] and return address is stored in K[TOP+2]~
(8') if LSON[K[TOP+1]] = RSON[K[TOP+1]] = 0
then £Q K[TOP+1] is a leaf~
print(CONTENT[K[TOP+1]] )~

(10' ) goto FINISH


else £2 call SYMORD(LSON[v])~

(11 ' ) TOP" TOP + 2~


(12' ) K[TOP+1] .. LSON[K[TOP-1]]~
(13' ) K[TOP+2] .. "M1"
(14' ) goto SYMORD~

(15' ) M1 : TOP" TOP - 2~

(16' ) print(CONTENT[K[TOP+1]])~

£2 call SYMORD(RSON[v])~
(17' ) TOP" TOP + 2~
(18' ) K[TOP+1] .. RSON[K[TOP-1]]~
(19' ) K[TOP+2] .. "M2"~

(20' ) goto SYMORD~

(21' ) M2: TOP" TOP - 2~

(22' ) goto FINISH


fi ~
(23') FINISH: goto K[TOP+2]~

end

Call SYMORD(LSON[v]) (line (3) of the recursive program) is simulated


by lines (11') - (15') of the non-recursive program. In (11') storage
space for the activation record is reserved. The activation record is
initialized in lines (12') and (13')~ in (12') the value of the actual
35

parameter and in (13') the return address is stored. In line (14') con-
trol is transfered to SYMORD and the recursive call is started. Upon
completion of the call control is transfered to label M1 (line (15')).
The space for the activation record is freed (line (16')) and execution
of SYMORD is resumed. Analogously, one can associate the other instruc-
tions of the non-recursive program with the instructions of the recur-
sive program.

The program above is practically a RASP-program. Line (23') uses a


TI -instruction. The program can be turned into a RAM program either by
the method described in the proof of 1.3. theorem 3 or more simply by
replacing line (23') by

if K[TOP+2] = "M1"
then goto M1;
if K[TOP+2] = "M2"
then goto M2;
goto HP;

We have described a simplified method for translating recursive pro-


grams into non-recursive ones. The method suffices if global variables
can only come from the main program. This will be the case throughout
this book. In the general case a single register TOP does not suffice;
one has to replace it by a set of registers one for each activation
record which can contain global variables. We refer the reader to a
book on compiler construction for details.

We are now ready to analyse the time complexity of recursive procedures


in the unit cost measure. A constant number of instructions is required
to set up a recursive call, namely to increase TOP, to store the n ac-
tual parameters and the return address. Note that n is fixed and in-
dependent of the input; n can be infered from the program text. Also,
we allow only elementary types in parameter position and hence a single
parameter can be passed in constant time. Upon return from a recursive
procedure TOP has to be decreased. Altogether, the administrative over-
head for a procedure call is bounded by a constant.

The following method for computing the time complexity of recursive


procedures is often useful. We associate with every procedure call the
36

cost of executing the procedure body, inclusive the administrative cost


for initiating further recursive calls but exclusive the time spent
inside recursive calls. Then we sum over all calls and obtain the total
cost in this way. We illustrate this method on procedure SYMORD. Each
line in the body of SYMORD takes constant time. Recall that we only
count the time required to set up the recursive calls in lines (3) and
(5) but do not count the time needed to execute the recursive calls.
Thus one execution of the body of SYMORD takes constant time. SYMORD is
called once for each leaf and node of a binary tree. Thus the total
cost of SYNORD is O(n) where n is the number of leaves and nodes of the
binary tree.

The summation over all calls of a procedure can be done more formally
by means of recursion equations. Let T(v) be the run time of call
SYMORD(v). Then

c1 if v is a leaf
T(v) {
c 2 + T(LSON[v]) + T(RSON[v]) otherwise

for suitable constants c 1 and c 2 • We can now show by induction on the


height of (the tree with root) v that T(v) = c 2 # of nodes in the tree
with root v + c 1 # of leaves in the tree with root v. Although the
induction proof is very simple we include it for didactic purposes.

height (v) 0 Then v is a leaf and we have T(v) = c 1


height (v) > 0 Then v is a node and we have
T(v) c 2 + T(LSON[v]) + T (RSON[v])
c 2 + c 2 #nodes (LSON [v]) + c 1 # leaves (LSON[v]) +
c 2 #nodes(RSON[v]) + c 1 #leaves (RSON[v])
c 2 #leaves(v) + c 1 #nodes (v)

We used #leaves(v) (#nodes(v» to denote the number of leaves (nodes)


in the tree with root v. A more detailed discussion of recursion
equations can be found in II.1.3.
37

I. 6. Order of Growth

In most cases we will not be able to derive exact expressions for the
run time of algorithms; rather we have to be content with order of
growth analysis. We use the following notation.

Definition: Let f: 1N0 '" 1N0 be a function. Then O(f), lI(f) and 6 (f)
denote the following sets of functions:

O(f) {g: IN ... 1N0 ; 3c>0 3no: g (n) ::;; c·f(n) for all n ~ no}
0
lI(f) {g: N - 1N 0 ; 3c>0 3no: g(n) ~ c·f(n) for all n ~ no}
0
6 (f) {g: til - 1N0 ; 3c>0 3no: 1/c.f(n) ::;; g(n) ::;; c· f (n)for all n~ no}
0
[J

We use O-notation in upper bounds, II-notation in lower bounds and 6-


notation whenever we can determine the order of growth exactly.

It is customary, to use the notations above together with the equality


sign instead of the symbols E, c for the relations element in and sub-
set of, i.e. we write n 2 + 5n = ~2 + O(n) = 0(n 2 ) instead of
n 2 + 5n E n 2 + O(n) ~ 0(n 2 ). More precisely, if 0 is an n-ary operation
on functions and A1 , ••• ,An are sets of functions, then o(A 1 , ••• ,An )
denotes the natural extension to sets of functions, e.g.
A1 + A2 = {a 1 + a 2 ; a 1 E A1 , a 2 E A2}. Singleton sets are identified
with their single member. Then expressions ct and e which contain O-ex-
pressions denote sets of functions and ct = e stands for ct ~ e. Equal-
ities, which contain O-expressions, can only be read from left to right.
The terms of a sequence A1 = A2 = ... = ~ represent larger and larger
sets of functions; the bounds become coarser and coarser from left to
right.

I. 7. Secondary Storage

On a few occasions we consider algorithms which use secondary storage.


We make the following assumption. Data is transported in blocks (pages)
between main and secondary memory. A page consists of a fixed (say
2 10 = 1024) number of storage locations. It takes 5000 time units to
transport a page from one memory to the other. This assumption approxi-
mates the behaviour of modern disk memory.
38

I. 8. Exercises

1) Develop a RAM-Program for computing 2 n which runs in O(log n) time


units in the unit cost measure and O(n) time units under the logarith-
k
cost measure. Hint: Let n = L a i 2 i , a i E {O,1}, be the binary re-
i=o
presentation of n. Note that 2 n = ( ••• «2ak)2 2ak-1)2 ..• 2a1)2ao

2) Give a detailed proof of theorem 1.1.1 .. In particular, discuss the


assumption that a RAM-Program does not use cellO. Show, that one can
add one to all addresses dynamically and hence free cellO.

3) Give a detailed proof of theorem 1.1.3 ••

4) Let f: {O,1}* ~ {O,1} be computable in polynomial time on a deter-


ministic RAM under the logarithmic cost measure, and let fn = f I{O,1}n
be the restriction of f to inputs of length n. Show that there is a
boolean circuit (in the sense of V.7.) for fn of size polynomial in n.
(Hint: read the proof of theorem Vr.4.1.).

5) Let f: {a, 1} * ~ {O,1} be computable in polynomial time on a ran-


domized RAM under the logarithmic cost measure with probability € of
error at most 1/4. Let fn = f I{O,1}n' Show that there is a boolean
circuit for fn of size polynomial in n. (Hint: use exercise 4 and
theorem 1.2.1.).

6) Show how to translate conditional and iterative statements into


RAM-code.

7) In doubly linked lists every list element points to its successor


and its predecessor. Do section 1.4.2. for doubly linked lists.

8) A tree is k-ary if every node has exactly k sons. Show that a k-ary
tree with n nodes has exactly k + (k-1) (n-1) leaves.

9) Prove

f(n) = O(f(n»
O(f(n» + O(f(n» O(f(n) )
cO(f(n» =O(f(n»
O(f(n» O(g(n» = O(f(n)g(n»
39

I. 9. Bibliographic Notes

RAMs and RASPs were introduced by Shepherdson/Sturgis (63) and Elgot/


Robinson (64). Our notation follows Hotz (72). The theorems in section
1.1. are taken from Cook/Reckhow (72). The discussion of randomized
algorithms is based on Adleman (78), Reif (82), Yao (77) and Yao (82).
A more detailed account of linear lists can be found in Maurer (74)
and Knuth (68). For a detailed discussion of the implementation of
recursive procedure we reco~mend Gries (71).
II. Sorting

Sorting a set with respect to some ordering is a very frequently occur-


ing problem. IBM estimates that about 25% of total computing time is
spent on sorting in commercial computing centers. The most important
applications of sorting are (according to Knuth (73»:

a) Collecting related things: In an airline reservation system one has


to manipulate a set of pairs consisting of passenger name and flight
number. Suppose that we keep that set in sorted order of passenger name.
Sorting according to flight number then gives us a list of passengers
for each flight.

b) Finding duplicates: Suppose that we are given a list of 1000 persons


and are asked to find out which of them are present in a group of 100

persons. An efficient solution is to create a list of the persons in


the group, sort both lists and then compare them in a sequential scan
through both lists.

c) Sorting makes searching simpler as we will see in chapter III.

We next give a formal definition of the sorting problem. Given is a set


of n objects R1 , •.. ,Rn . Each object Ri consists of a key (name) Si and
some information associated with that name. For example, the objects
might be entries in a German-English dictionary, the keys are German
words, and the information part is gender, English translation,
An important fact is that the keys are drawn from some' linearly ordered
universe U; we use ~ to denote the linear order. In our example, the
ordering relation is the alphabetic order on words. We want to find a
rearrangement R. ,R. , ••• ,R. of the objects such that
1.1 1.2 1. n

S. ~S. ~ ••• ~S .•
1.1 1.2 1. n

Apparently, the information associated with the keys does not play
any role in the sorting process. ~"ie will therefore never mention it in
our algorithms. There is one further remark in order. Frequently, the
information associqted with the keys is much larger than the keys them-
selves. It is then very costly to move an object. Therefore it is bet-
ter to replace the objects by records consisting of the key and a
41

pointer to the object and to sort the set of records obtained in this
way. Sometimes it will also suffice, to only compute the permutation
i 1 ,i 2 , ••• ,i n and to not actually rearrange the set of objects. All
algorithms described below are easily adopted to this modified sorting
problem.

Let us reconsider example a) above. Suppose that we want for each


flight the list of passengers in alphabetic order. Note that we start
with a list of pairs sorted by passenger name. It would then be very
nice if the sorting algorithm would not destroy that order when it re-
arranges the pairs according to flight number because then the passen-
ger lists would be in alphabetic order automatically. Move formally,
we call a sorting algorithm stable if it produces a rearrangement
R. , •.• ,R. such that
~1 ~n

S. S. implies it < it+1


~t ~t+1

for all t. Note that we can always produce a stable rearrangement by


extending the keys to pairs (Si,i) and by uSing the lexicdgraphic order-
ing on these pairs as the linear order.

Sorting algorithmscan be divided into two large groups: the algorithms


in the first group are comparison-based, Le. they make only use of the
fact that the universe is linearly ordered. In these algorithns the only
operation applied to elements of U is the comparison between elements.
We will discuss four algorithms of the first kind: Heapsort which al-
ways runs in time O(n log n), Quicksort which runs in time O(n log n)
on the average and is the algorithm with the smallest average running
time, Mergesort which also runs in time O(n log n) and uses only se-
quential access and finally A-sort (section III. 5.3.2.) which works
particularly well on almost sorted inputs. The algorithms in the first
group are also called general sorting algorithms because they do not
put any additional restriction on the universe. We will also see, that
general sorting algorithms require Q(n log n) comparisons in the worst
case as well as in the average case. Thus all algorithms mentioned
above are optimal up to constant factors. The algorithms in the second
group only work for keys in a restricted domain. We treat sorting reals
and sorting words according ~o lexicographic order.
42

Remark: For this chapter we extend our machine model by two instruc-
tions, which are very helpful in sorting algorithms. One instruction
exchanges the contents of accumulator and some storage cell.

a <--> op and a <--> mop

The second instruction addresses a second general purpose register,


which we denote by a. We allow loads into and stores from a and simple
arithmetic operations, which leave their result in a, e.g.
a - a - op and a - a- mop

Instructions of the second type allow us to compare with a without de-


stroying it. Both type of instructions are available on many machines.

II. 1. General Sorting Methods

II. 1.1 Sorting by Selection, a First Attempt

We begin with a very simple sorting method. Select the largest element
from the input sequence, delete it and add it to the front of the out-
put sequence. The output sequence is empty initially. Repeat this proc-
ess until the input sequence is exhausted. ive formulate the complete
algorithm in our high level programming language first and then trans-
late it into machine code. The input sequence is given by array S[1 .• n].

(1) j - n;
(2) while j > 1
do co S[j+1 .. n] contains the output sequence in increasing order,
S[1 .. j] contains the remainder of the input sequence;
(3) k - j; max - j; S - S[j];
(4) while k > 1
do co we search for the maximal elelment of S[1 .. j]; S
is always a largest element of S[k .. j];
(5) k - k - 1;
(6) i f S[k] > S
(7) then max - k; S - S[k] fi
od;
(8) S[max] - S[j]; S[j] - S;
(9) j - j - 1
od;
43

Next we translate into machine code. We use the following storage as-
signment. Index register Y1 holds j-1, Y2 holds k-1 and index register
Y3 holds max-1. n is stored in location 0, S is stored in a and array
S[1.. nl is stored in locations m+1, .•• ,m+n. i'1e assume n> 1. In the
right column the number of executions of each instruction is given.

o
1
} j n

2 k j n -
3 Y3 Y1 max j n -
4
-a p (m+ Hy 3 ) S S[maxl n -
5 Y2 Y2- 1 k k-1 A
-
6 a a - p(m+1+Y 2 ) A
7 if a ~ 0 then goto 10 } line (6)
A
8 Y2 max k B
9 p(m+1+Y 3 ) S S[maxl B
10 if Y2 > 0 then goto 5 line (4) A
11 a -- p(m+1+Y1 ) } n -
12 line (8)
p(m+Y 3 +1) CI. n -
13 Y1 - Y1 - 1 j - j-1 n -
14 if Y1 > 0 then goto 2 line (2) n -

Lines 5,6,7,10 are executed for j n, n-1, ... ,2 and k = j-1, ..• ,1.
Hence A = n(n-1)/2. Furthermore B A. Thus the run time is
~

~ 3·1 + 10· (n-1) + 5·A + 3.B = 2.5 n 2 + 7.5 n - 7 + 3B ~ 4 n 2 + 6 n - 7


time units in the unit cost measure. Average case run time is slightly
better. We compute it under the assumption that the keys are pairwise
different and that all n! permutations of keys S1"",Sn are equally
likely. The first assumption is not crucial but it simplifies calcula-
tions.

In each execution of the body of the outer loop we exchange Smax with
Sj' Since there are j different possibilities for max, this step trans-
forms j possible arrangements of keys S1""Sj into one arrangement.
Hence after the exchange all possible permutations of keys S1'" Sj_1
are equally likely. Therefore we always have a random permutation of
keys S1"",Sj during the sorting process. Sequence S1"",Sj is
scanned from right to left. Instruction 8 is executed whenever a new
maximum is found. For example, if 4 5 3 1 2 is sequence S1"",Sj (we
assume w.l.o.g. that (S1"",Sj} = (1, .•. ,j}; this convention facili-
44

tates the discussion), then the maximum changes twice: from 2 to 3 and
then to 5. Key Sj is equal to i, 1 ~ i ~ j, with probability 1/j. If
Sj = j then the maximum is found. If Sj = i < j then we may delete
elements 1, ••• ,i-1 from the sequence. They certainly do not change the
maximum. Thus we are left with (j-1)-(i-1) = j-i keys out ofS1 "",Sj_1'
The maximum changes once plus whatever times it will change in the re-
maining sequence. This gives the following recursion for a j the ex-
spected number of changes of the maximum

a1 0
j-1
a. 1/j L (1 + a j _i ) for j > 1
J i=1

Multiplying by j gives

j-1
j·a. j-1 + L ai
J i=1

and similarly for j+1


j
(j+1)a j + 1 j + L ai
i=1

Subtraction yields

(j+1)a j + 1 - j aj

or

a j +1 a j + 1/(j+1)

Thus j
a. L 1/ i
J i=2

j
where Hj = L
1/i is the j-th harmonic number (cf. appendix). We have
i=1
thus shown that lines (8) and (9) are executed a. times on the average
Jo
when the outer loop is executed with j = joe Hence
45

n n
B k a J. k H. - n (n+1)H n - 2n (cf. appendix)
j=2 j=1 J

~ (n+1)ln n - (n-1)

since Hn ~ 1 + ln n (cf. appendix).

Average case running time of our algorithm is 2.5 n 2 + 3(n+1) ln n +


4.5 n 4 = 0(n 2 ). Worst case and average running time are quadratic.
It is also easy to see that the algorithm uses exactly n(n-1)/2 com-
parisons between keys.

II. 1.2 Sorting by Selection: Heapsort

Is the algorithm described in the preceeding section good? Can we im-


prove upon the method for finding the maximum? The answer to the second
question is no, at least, if we restrict ourselves to comparison-based
algorithms. In comparison-based algorithms there is no operation other
than the comparison of two elements which is applicable to elements of
the universe from which the keys are drawn.

Theorem 1: Any comparison-based algorithm needs at least n-1 c'ompari-


sons to find the maximum of n elements.

Proof: Interpret a comparison S~ < S.? as a match between S. and S .•


• J ~ J
If S. < S. then SJ' is the winner and if S. > S. then S. is the winner.
~ J ~ J ~
If an algorithm uses less than n-1 matches (comparisons) then there
are at least two players (keys) which are unbeaten at the end of the
tournament. Both players could still be best (the maximum), a contra-
diction. []

Theorem 1 implies that we have to look for a different sorting method


if we want to improve upon the quadratic running time of the naive
algorithm. Consider that algorithm on input 4 5 3 2 1. We compare 2
with 1, 2 with 3, 3 with 5 and finally 5 with 4. We can summarize our
knowledge at the end of the first maximum selection in
46

, here 5, means that 5 is larger than 3. Next we exchange 5 and 2 and


3
obtain 4 2 3 1. In the second iteration we compare 1 with 3, 3 with 2,
3 with 4 and obtain.

Two of these comparisons were unnecessary. We knew al-


ready from the first iteration that 3 is larger than
1 and 2. Let us take a more global look:
At the end of the first iteration we have a tree-like structure with
the following property: Whenever one considers a path through that tree
then the labels along that path are monotonically decreasing. This is
also called the heap property.

After removing the 5 we obtain:

4 It suffices now to compare 4 and 3. This gives us that 4


3,
2
'1 is larger than 3 and the second selection of a maximum
is completed. Let us consider another example, the se-
quence 1 2 3 4 5. We obtain at the end of the first iteration. After
removing 5 we have 4 uncorrelated elements, i.e. we have
5 not saved any information from the first iteration to

/1\\
1 234
the second. We can see from these examples that the
trees which we build should have small fan-out. In this
way only little information is lost when a maximum is
removed. Let us consider one more example, the sequence 2 10 3 5 1 7 9
6 4 8. The "ideal" tree has the form

2 Unfortunately, the labelling does not satisfy the heap


/\
10 3
property yet. We can install the heap property in a
bottom-up process. In the following tree the three bot-
/\ /\
5 1 7 9
tom levels of the tree already satisfy the heap proper-

\1
ty but the root label does not satisfy it yet.
6/

2 We sink the 2 to its proper position by interchanging


/ \9
10
it with the larger of its sons and obtain:

/\ /\
6 8 7 3
1\5 1/
4
47

10 In this tree the 2 is still not larger than its two sons

2/\ and so we have to interchange it again with the larger


of its sons (the 8). We obtain:
/\ /\
687 3
/\ I
4 5 1

10 a tree having the heap property. So the maximum is the


/\ root label. We remove the maximum and obtain

; \ i 1\ 7 3
/\ I
4 5 1

How should we restore the heap property? We might com-


;'\9 pare the 8 and the 9 and move up the 9. Next we compare
the 7 and the 3 and obtain:
( \ 27/\3
/ \
451
I

We can now remove the 9 and repeat the process. This


gives us

/>
5
11
\6/\7

Although this approach leads to an O(n log n) sorting method there is


one problem with it. After a few iterations the tree looses its per-
fect shape. There is another approach which avoids this problem. After
removal of the 10 we take the 1, the label of the rightmost leaf on
the bottom level, and move it to the root. Next we sink the 1 as de-
scribed above. This method produces the following sequence of trees

Removal Removal
/9" of 9 8" of 8 /7""
8 7 > 6/ 7 > 6 4

6
/\
2 1
/\3 /\ 1\
5 2 1 3 5
/ \ 2 11\3
4
/\5 4
/
1
Removal
of 7
48

Removal
2 3 5 of 6 6
1 <---
1
/ <---
1
/\2 <----
3/ "'4 <:---
5
/\4
1
/ \2 /\
3 2
I
1

In this way we always keep the tree an almost complete binary tree. All
leaves are on two adjacent levels, all levels except the bottom level
are complete, and the leaves on the bottom level are as far to the left
as possible. Trees of this form can be stored in very compact form:
Number the nodes starting at the root (with number 1) according to in-
creasing depth and for fixed depth from left to right. Then the sons
of node k are numbered 2k and 2k+1 and the father of node k is numbered
lk/2 J (LXJ is the largest integer ~ x). Thus we can store the tree in
a single array and save the space for pointers.

Definition: An array S[1 •• n] satisfies the heap property if

for 2 ~ k ~ n. The array is a heap starting at i, 1 ~ i ~ n, if

Notice that every array S[1 .• n] is a heap starting at Ln/2J + 1.


Tree
2 corresponds to array 2,10,9,5,8,7,3,6,4,1 and is a
1/ "-9
/ \8
heap starting at position 2. We give next the com-
/\. plete program for Heapsort; we assume n ~ 2.
5 7 3

6
/ \4 1/

(1) i +- l n/ 2 J + 1; r +- n;
(2) while r ~ 2 do
begin ~ either r = n and then S[1 .. n] is a heap starting at i
(build up phase) or i=1 and the n-r largest elements are stored
in increasing order in S[r+1], •.• ,S[n] (selection phase).
49

(3) i f J/, > 1


~ ~ we are building the heap and add element S[J/,-1]
(4) J/, .... J/, - 1; j .... J/,
else £2 we are in the selection phase. S[1] is the maximum of
S[1], ••• ,S[r]. We exchange S[1] and S[r] and have to restore
the heap property on S[1 •• r-1].
(5) exchange S[1] and S[r]; r .... r - 1; j .... 1 fi;
(6) S .... S[j];
(7) while 2j ~ r do
begin £2 we sink S[j] by interchanging it repeatedly with the
larger of its sons.
(8) k ..... 2j;
(9) if k < r and S[k] < S[k+1] then k .... k + 1;
{ 10) i f S < S[k]
(11 ) then S[j] S [k]; j .... k
( 12) else goto E
end
(13) E: S[j] ... S;
end

Line 10 is executed in each iteration of the inner loop and the inner
loop is entered at least once in each iteration of the outer loop.
Hence total running time is proportional to the number of comparisons
in line (10). We count the number of comparisons. For simplicity, let
n = 2 k _1.

Build-up Phase: The tree has 2i nodes of depth i, 0 ~ i < k. In the


build-up phase we add to the heap the nodes of depth k-2, then the nodes
of depth k-3, •••• When we add a node at level i then it can sink down
to level k-1 for a cost of 2 comparisons per level. Thus the total cost
of the build-up phase is bounded by
k-2
L 2(k-1-i)2 i = 2k + 1-2(k+1)
i=O
(cf. appendix, formula S1).

selection phase: In the selection phase we repeatedly remove the root


and bring up element S[r]. This element can then sink down all the way
to the bottom level of the tree. More precisely, if an element of
depth i is moved up then restoring the heap property can cost us up to
50

2i comparisons. Thus the total number of comparisons in the selection


phase is at most

k-1
2· E i 2i
i=O

Altogether, Heapsort uses at most 2k(2 k -1)-2(2 k -1) = 2n 10g(n+1)-2n


comparisons. For n * 2k_1 counting is slightly more complicated.

Theorem 2: Heapsort sorts n elements in at most 2n 10g(n+1)-2n compari-


sons and time O(n log n).

Compiling into RAM-Code gives a run time of ~ 20n 10g(n+1)-n-7 time


units in the worst case. Average run time of Heapsort is only slightly
better because of the following two reasons. We put new elements into
the root and sink them to their proper position. Since most nodes of a
binary tree are close to the leaves most elements will sink almost down
to the leaves. Furthermore, in the selection phase we sink elements
which we get from a leaf and hence tend to be small. A complete
average case analysis of Heapsort still needs to be written.

II. 1.3 Sorting by Partitioning: Quicksort

Quicksort is an example for a very powerful problem solving method:


divide and conquer. A problem is split into several smaller parts (di-
vide) which are then solved using the same algorithm recursively (con-
quer). Finally the answer is put together from the answers to the sub-
problems. In the case of Quicksort this means: Choose an element from
sequence S1, ... ,Sn' say S1' and partition the sequence into two parts.
The first subsequence consists of all S. with S.
1
< S1 and no S.J with
1
S. > S1 and the second subsequence consists of all S. with S. > S1 and
) J J
no Si with Si < S1. The partitioning algorithm stores the first se-
quence in positions 1 through k-1 of an array, S1 in position k, and
the second sequence in positions k+1, ••. ,n. Then the same algorithm is
applied recursively to the two subsequences. Putting the sorted subse-
quences and the partitioning element S1 together to a single sorted se-
quence is trivial. Nothing has to be done. One could think of splitting
the sequence into three parts; the third part consisting of all Si = S1'
In general, this is not worth the additional effort (cf. exercise 8).
51

We take next a closer look at the partitioning phase. A good solution


encloses array S[1 •. n] with two additional elements S[O] and S[n+1]
such that S[O] ~ Sri] ~ S[n+1] for all i and uses two pointers with
starting values 1 and n+1. Pointers i and k have the following meaning:
the first subproblem consists of S[2], ..• ,S[i], the second subproblem
consists of S[k], ... ,S[n], and elements S[i+1], ••. ,S[k-1] still
have to be distributed. We increase i until we find Sri] ~ S[1] and we
decrease S[k] until S[k] ~ S[l]. Note that no test for "index out of
bounds" is required because of the addition of elements S[O] and S[n+1].
Two cases can arise. If k > i then we exchange S[k] and Sri] and repeat
the process. If k ~ i we are done. (it is easy to see that either k = 1
(if Sri] = S[1]) or k = i-1 (if Sri] *
S [1] in this case). Interchang-
ing S[k] and S[1] finishes partioning.

procedure Quicksort(£,r);
co Quicksort(~,r) sorts the subarray S[£], ••. ,S[r] into increas-
ing order;
(1)
(2 )
begin i
while i < k do
£; k - r + 1 ; S - S [£] ;

( 3) begin re:eeat i i + until Sri] ~ S;


(4 ) reEeat k k - until S[k] ~ S;
(5) if k > i then exchange S[k] and S [iJ
end;
(6) exchange S[£] and S[k];
(7) if £ < k-1 then Quicksort(£,k-1);
(8) if k+1 < r then Quicksort(k+1,r)
end

A remark on correctness of the algorithm is in order. We assume in


lines (3) and (4) the existence of keys S[£-1] and S[k+1] with
S[£-1] ~ Sri] ~ S[k+1] for all i with £ s i ~ r. Existence of these
keys is ensured for call Quicksort(1,n) by adding S[O] and S[n+1]
with the required properties, for recursive calls it is immediate from
the description of the algorithm. Since we only have S[£-1] s Sri] s
S[r+1] we have to test for ~ and ~ in lines (3) and (4) in order to
save the test for index out of bounds.

Worst case behaviour of Quicksort is easily determinded. Consider


lines (1) through (6) for fixed values of £ and r, say £ = 1 and r = n.
In line (3) we compare and increase i, in line (4) we compare and de-
52

crease k. Before entering the loop in line (2) we have k - i


r - t + = n, after termination of the loop we have k - i o or
k - i 1. Hence k and i are changed for a total of n or n + 1 times
and n or n + 1 comparisons are made. Actual run time of lines (2) to
(5) is O(number of comparisons) = O(n). The cost of lines (1) and
(6) - (8) is 0(1) per call of Quicksort. Since there are s n - calls
altogether including the call in the main program (exercise 6 the
total cost of lines (1) and (6) - (8) summed over all calls is O(n).

Let us return to the maximal number QS(n) of key comparisons which are
needed on an array of n elements. We have

Q5(O) Q5(l) o
Q5(n) s n + 1 + max {QS(k-l) + Q5(n-k); 1 s k s nl

It is easy to show by induction that Q5(n) s (n+l) (n+2)/2 - 3. This


bound is sharp as can be seen from the example 1,2, ... ,n. Here the
partitioning phase splits off exactly one element and therefore sub-
problems of size n,n-l,n-2, ... ,2 have to be solved. This requires
(n+l) + n + (n-l) + •.. + 3 comparisons which sums exactly to the bound
given above. Quicksort's worst case behaviour is quadratic.

Average case behaviour is much better. We analyse it under the assump-


tion that keys are pairwise distinct and that all permutations of the
keys are equally likely. We may then assume w.l.o.g. that the keys are
the integers 1, ... ,n. Key Sl is equal to k with probability lin,
1 s k s n. Then subproblems of size k - 1 and n - k have to be solved
recursively and these subproblems are again random sequences, i.e. they
satisfy the probability assumption set forth above. This can be seen as
follows. If 51 = k then array 5 looks as follows just prior to execu-
tion of line (6):

Here i l , ... ,i k _ l is a permutation of integers 1, .. ,k-l and jk+l, .•. ,jn


is a permutation of integers k+l, ... ,n. How did the array look like
before the partitioning step? If t interchanges occured in line (5)
then there are t positions in the left subproblem, i.e. among array
indices 2, ... ,k, and t positions in the right subproblem, i.e. among
k+l, ... ,n, such that the entries in these positions were interchanged
53

pairwise, namely the leftmost selected entry in the left subproblem


with the rightmost selected entry in the right subproblem, . . . . Thus
there are exactly

arrays before partitioning which produce the array above by the parti-
tioning process. The important fact to observe is that this expression
only depends on k but not on the particular permutations i 1 , •.. ,i k _ 1
and jk+1, ... ,jn' Thus all permutations are equally likely, and hence the
subproblems of size k - 1 and n - k are again random. Let QSav(n) be the
expected number of comparisons on an input of size n. Then

and
n
QS (n)= 1/n L
av
k=1

n-1
n+1 + 2/n L QSav(k) for n 2: 2
k=O

We solve this recurrence by the method already used in II.1 .1 .. Multi-


plication by n gives us

n-1
n QSav(n) = n(n+1) + 2' L QSav(k) for n 2: 2
k=O

Subtracting from the equality for n + 1 instead of n, yields

QS av ( n+ 1 ) = 2 + n+2
n+1 OS
.- av ()
n

This recurrence is of the form

2 and c.1 (i+1)/i for i > 1 and has solution


54

n+1 n+1
L ( II CJ,)b i
i=1 j=i+1

as is easily verified by induction. Thus

n n+1
L i+1 2
i=2

= 2 (n+1) (H n + 1 - 3/2) ::;;;2 (n+1) R-n(n+1)

where Hn+1 is the (n+1)-th harmonic number (cf. appendix). Let us re-
turn to run time. We argued above, that run time of the partitioning
phase is proportional to the number of comparisons and that the total
cost of all other operations is O(n). Thus

Theorem 3: Quicksort sorts n elements with at most (n 2 + 3n - 4)/2 key


comparisons and run time O(n 2 ) in the worst case. It uses
: ; ; 2(n+1) R-n(n+1) comparisons and time O(n log n) on the average.

Translating into RAM-Code as described in I.4 produces a program which


sorts n numbers in expected time::;;; 13(n+1) R-n(n+1) + 29n - 33 ~
9(n+1) log(n+1) + 29n - 33. (exercise 7 ). Quicksort has quadratic
worst case behaviour; the worst case behaviour occurs on the completely
sorted sequence. Also almost sorted sequences, which occur frequently
in practice, are unfavourable to Quicksort. There is an interesting way
out of this dilemma : randomized Quicksort. We change the algorithm by
replacing line (1) by

( 1a) beg in i .. R- ; k - r + 1;
(1b) j .. a random element of {O, ••• ,r-R-};
(1c) interchange S[R-] and S[R-+j];
(1d) S .. S[R-];

What does that do for us? Let II be any permutation of numbers 1, ••• ,n
and let QSran(II) be the expected number of comparisons in randomized
Quicksort applied to sequence n(1),n(2), ••• ,n(n). In lines (1a) - (1d)
we choose a random element of II as the partitioning element, i.e.
S = S[h] with probability 1/n for 1 ::;;; h ::;;; n. Then subproblems II1 and n 2
55

of size S[h] - 1 and n - S[h] respectively have to be solved recursive-


ly. Of course, IT1 and IT2 depend on IT and h (= t+j). We write IT1 (IT,h)
and IT 2 (IT,h) in order to make the dependency explicit. Then

n
QSran (IT) 1/n r (n+1 + QSran (IT 1 (IT,h» + QSran (IT 2 (IT,h»)
h=1

It is now trivial to prove that QSran(IT) = QSav(n) where n is the


number of elements in permutation IT (use induction on n). Hence
QSran(IT) ~ 2(n+1) tn(n+1) for any permutation IT of n elements, i.e. ran-
domized Quicksort sorts any fixed sequence in expected time O(n log n) •
The reader should think for a moment about the meaning of this sentence.
Standard Quicksort has average running time O(n log n). When deriving
this result we postulated a distribution on the set of inputs, and the
user of Quicksort has to behave according to that postulate if he wants
to observe small run times. If the user has a preference for nearly
sorted sequences he should better keep away from standard Quicksort.
Not so far randomized Quicksort. Expected run time is O(n log n) on
every single problem instance (and worst case running time is O(n 2 ) on
every single problem instance). There are no bad inputs for randomized
Quicksort, randomized Quicksort behaves the same on all input sequences.

It is worthwhile, to consider divide and conquer strategies in more de-


tail at this point. Let us assume, that a problem of size n is split
into a(n) problems of size ben) and that the cost of dividing into sub-
problems and pasting together the answers is fen). Then we obtain the
following recurrence for T(n), the run time on a problem of size n.

T(n) fen) for ~ n < b- 1 (1)


T(n) a(n) T(b(n» + fen) for n ~ b- 1 (1)

Here we assumed that the recursion stops as soon as we arrive at a prob-


lem of size < b- 1 (1). We solve the recurrence for T(n) in a two step
process. In the first step we solve the "simpler" homogeneous recur-
rence

hen) for ~ n < b- 1 (1)


h (n) a(n) h(b(n» for n ~ b- 1 (1)
56

In all our applications the solution of the homogeneous recurrence will


be very easy to obtain explicitely. Setting R(n) = T(n)!h(n) the re-
currence for T(n) transforms into

R(n) f(n) for 1 S n < b- 1 (1)


and
R(n) h (n) a(n) h(b(n» R(b(n» + f(n) for n~ b- 1 (1)
or
R(n) R(b(n» + f(n)!h(n)

Thus R(n) can be computed by a simple sUl:'luation. With g(n) f(n)!h(n)


we have R(n) = g(n) + q(b(n») +

Theorem 4: Let a,b,f: [1,00) ~ iR+, b strictly increasing and b(n) < n
for all n. Then the recurrence

T(n) f (n) for S n < b- 1 (1)


T (n) a(n) T(b(n» + f(n) for n ~b-1(1)

has solution

rd(n)
T(n) h(n) L g(b(i) (n»
i=o

where

rd(n) = min{d; b(d) (n) < b- 1 (1)}


h (n) for S n < b -1 (1 )
h(n) a(n) h(b(n» for n ~ b- 1 (1)

and

g(n) f(n)!h(n)

Proof: By the discussion above. IJ

Theorem 4 can be visualized as follows. Define the notion of a re-


currence tree by induction on n. If n < b- 1 (1) then the recurrence tree
consists of a single leaf labelled f(1). If n ~ b- 1 (1) then the tree for
n consists of a root labelled f(n) and a(n) subtrees, each being a re-
currence tree for b(n). Then rd(n) is the depth of this tree and h(n)
is the number of leaves of this tree. More generally, the number of
leaves below a node of depth d is h(b(d) (n». T(n) is the sum of the
57

labels of all nodes and leaves of the tree. We can determine T(n) by
summing the labels by depth. A node of depth d has label f(b(d) (n».
If we distribute that label over all leaves below the node then each
leaf receives a portion f(b(d) (n))/h(b(d) (n» = g(b(d) (n». Thus

rd(n)
T(n) hen) 2: g(b(d)(n».
d=o

We can now classify the solutions of the recurrence according to the


growth of function g.

Corollary 5: Under the assumptions of theorem 4 we have

a) T (n) a(h(n» i f g(n) a (q -rd (n) ) for some q >

b) T(n) a(h(n» i f g(n) a (rd (n)p) for some p < -1


c) T(n) a (h (n) log rd(n» i f g (n) a(1/rd(n) )

d) T(n) a (h (n) (rd (n) ) p+ 1 ) i f g(n) a(rd(n)P) for some p > -1

e) T (n) r2(h(n) qrd(n) ) i f g(n) = r2 (qrd(n» for some q > 1

f) T(n) G(f(n» i f g (n) = G (qrd(n» for some q > 1.

Proof: Let n = b(rd(n» (n). Then we can rewrite the conclusion of


o
theorem 4 as

rd(n)
T (n) hen) 2: g(b (i) (n»
i=o

rd(n)
h (n) 2: (b(-rd(n)+i) (n »
g . 0
i=o

rd(n)
h (n) 2: g(b (-i) (n »
i=o
o

a) From g(n) = a(q-rd(n» and hence g(b(-i) (n » a(q-i) we conclude


o
rd (n)
-i
T(n) a(h(n) 2: q ) a(h(n»
i=o

b,c and d) From g(n) = a(rd(n)P) and hence g(b(-i) (n »


o
conclude
58

rd(n}
T(n} O(h(n} LiP}
i=o

O(h(n}} if P < -1
{O(h(n} log rd(n}} if p -1
O(h(n} rd(n}p+1} i f p > -1

e} From g(n} S"l(qrd(n}} and hence g(b (-i) (n )} S"l(qi} we conclude


0

rd(n}
T(n} S"l(h(n} L qi}
i=o
= S"l(h(n} qrd(n}}

f} As in part e} we conclude

rd(n}
T(n} e(h(n} L qi}
i=o

e(h(n}}qrd(n} e(h(n} g(n}}

e(f(n» c

Again it is very helpful to visualize corollary 5 in terms of recurrence


trees. In cases a} and b} of corollary 5 the cost of the leaves domi-
nates, in case f} the cost in the root dominates and in case d}, p = 0
the cost is the same on all levels of the tree. We close with a brief
discussion of a frequently occuring special case: a(n} = a and ben} =
nib for all n.

Corollary 6: Let a,b € IR+, b > 1, and let f: [1,~] ~ R+. Then recurrence

T(n} fen} if :s; n < b


T(n} a T(n/b} + fen} if n ~ b
has solution
Llogb n J
T(n} = i f (n/b i )
L a
i=o

In particular,
59

10gb a
O(n ) i f fen)
10gb a
O(n (10g b n)p+1) p > -1
10gb a 10gb a {
T(n) O(n log log n) i f fen) e(n (10gb n)P)and p =-1
10gb a
O(n ) p < -1

if fen) = e(n P ) with p > 10gb a

Proof: Using the notation of theorem 4 and corollary 5 we have a(n) a,


~ogb n J 10gb n
ben) = nib, rd(n)=Llogb n J and hen) = a O(a) =
10gb a
O(2(log n) (log a)/log b) = O(n ). Thus

Llogb n J Llogb n J • Llogb n -iJ


T(n) a r f (n/b 1 ) /a
i=o

Llog n J •
r a 1 f(n/b i )
i=o

Next note that fen) O(nP ) for some P < 10gb a implies g(n) =
O(q-rd(n)) for some q > 1 and hence T(n) = O(h(n)). Also, if
10gb a
fen) e(n (10g b n)p) then g(n) = O«logb n)p) = O(rd(n)P). Thus
T(n) is as given by corollary 5, cases b) - d). Finally case f) handles
fen) = e(nP ) with P > 10gb a. 0

II. 1.4 Sorting by Merging

Quicksort's bad worst case behaviour stems from the fact that the size
of the subproblems created by partitioning is badly controlled. Corol-
lary 6 tells us that a = b = 2 would produce an efficient method. How
can we achieve the splitting into two subproblems of size n/2 each?
There is a simple answer: Take the first half of the input sequence and
sort it, take the second half of the input sequence and sort it. Then
merge the two sorted subsequences to a single sorted sequence. These
considerations lead to the follow algorithm.
60

procedure Mergesort(S}:
begin let n = lSI: split S into two subsequences S1 and S2 of
length rn/ 2, and Ln/2J respectively:
. Mergesort (S 1 ) :
Mergesort(S2} :
suppose that the first recursive call produces sequence
X 1 S; x 2 S; s; x rn / 2" and the second call produces
Y1 S; Y2 S; s; Y
i.. n / 2 J;
merge the two sequences into a single sorted sequence

end

Let us take a closer look at the merge algorithm. An obvious approach


is to repeatedly compare the front elements of the sequences, to remove
the smaller one and to add it to the end of the z-sequence. Thus

i + 1: j + 1: k + 1:

while i s; r n/2' and j s; Ln / 2J do


begin if x.~ < Yi
then zk Xi: i i + 1: k k +
else zk + Yj: j j + 1: k k +
end:
i f i s; rn/2'
then while i s; r n/2' do begin zk i + 1: k k + end
----- Xi: i
else while j s; Ln / 2J do begin zk Yj: j j + 1: k k + end

This algorithm merges two sequences with at most rn/2' + Ln/2J -


n - 1 comparisons and total run time 8(n}. Note that at least one
element is added to the z-sequence without a comparis0n. This is opti-
mal.

Theorem 7: Every comparison-based algorithm for combining two sorted


sequences x 1 s; x 2 s; ••• s; x rn/ 2,and Y1 s; Y2 s; .,. s; YLn/2Jinto a single
sor~ed sequence z1 s; z2 s; ••• S; zn needs n - 1 comparisons in the worst

case.

Proof: We choose the x- and y-sequence such that the elements are pair-
wise different and such that the following relations between the ele-
61

ments hold: x 1 < Y1 < x 2 < Y2 < ..• < X ln / 2j < Y ln/2 j « x rn / 2,). Element
x rn/ 2' only exists if.n is odd. Let us assume that some algorithm pro-
duces the correct z-sequence and uses less than n - 1 comparisons in
doing so. Then it has not compared a pair xi' Yi or Yi' x i + 1 • Let us
assume the former case, i.e. it has not compared xi with Yi for some i,
1 ~ i ~ n/2. Then let us consider the algorithm on an input where the
following relations hold: x 1 < Y1 < x 2 < ... < Yi-1 < Yi < xi < x i +1 <
•••• All comparisons which are made by the algorithm have the same
outcome on the original and the modified input and hence the algorithm
produces the same z-sequence on both inputs, a contradiction. c

We will next compute the exact number of comparisons which Mergesort


uses on an input of length n in the worst case. We use M(n) to denote
that number. Apparently

M(1) 0 and
M( n) n - 1 + M( rn/ 2') + M( l n/ 2 j) if n > 1

We use induction on n to show

This is correct for n 1. So let n > 1.

Case 1: n * 2k + 1. Then rlog rn/2"


therefore

M(n)

rlog n'
n + n (rlog n' - 1) - 2 +

n • rlog n' - 2 rlog n' + 1 •

Case 2: n rlog n' - 2 and


therefore
62

1) - 2
fl og n' - 1 + 1
M(n)

n • r, 2 flog n' + 2 flog n' - 2 + 1


log n - Ln/2J -

n •

We introduced Mergesort by way of a recursive program. It is easy to


replace recursion by iteration in the case of Mergesort. Split the in-
put sequence into n sequences of length 1. A sequence of length 1 is
sorted. Then we pair the sequences of length 1 and merge them. This
gives us Ln/2J sorted sequences of length 2 and maybe one sequence of
length 1. Then we merge the sequences of length 2 into sequences of
length 4, and so on. It is clear that the run time of this algorithm is
proportional to the number of comparisons.

flog n'
Theorem 8: Mergesort sorts n elements with at most nflog n' - 2 +1
comparisons and run time 8(n log n) .

Translating into RAM-Code results in a run time of 12n log n + 40n +


97 log n + 29 in the worst case. (Exercise 10).

Sorting by merging accesses data in a purely sequential manner. Hence


it is very appropriate for sorting with secondary memory, such as disks
and tapes. In this context the following problem is of interest. Very
often we do not start with sorted sequences of length one but are given
n sorted sequences S1""'Sn of length w1 , ••. ,wn respectively. The prob-
lem is to find the optimal order of merging these sequences into a
single sequence. Here we assume that it costs x + y time units to merge
a sequence of length x with a sequence of length y. Any merging pattern
can be represented as a binary tree with n leaves. The n leaves repre-
sent the n initial sequences and the n - internal nodes represent the
sequences obtained by merging.

Tree S9 represents the following merging pattern:


S8 S6 - Merge(S1 ,S3)

S6 S7 - Merge (S 6 ' S 4 )
S2 S5 8 8 - Merge(8 2 'S5)
83 8 9 - Merge (8 7 ,8 8 )
S1
63

Definition: Let T be a binary tree with n leaves v" •.. ,vn,let CONT:
leaves of T - {w" ••• ,wn } be a bijection and let d i be the depth of
leavevi . Then

C08T(T)

is called the cost of tree T with respect to labelling CONT. c

This definition requires a little bit of explanation. Tree T is a merg-


ing pattern, the leaves of T are labelled by the n initial sequences,
respectively their lengths (weights). What is the cost of merging the
n sequences according to pattern T? Note that in our example above se-
quence 8, is merged three times into larger sequences, namely first
with 8 3 , then as a part of 8 6 with 8 4 and then as a part of 8 7 with 8 8 •
Also three is the depth of the leaf labelled 8,. In general, a leaf v
of depth d is merged d times into larger sequences for a total cost of
d CONT[v]. Thus the cost of a merging pattern T is as given in the def-
inition above. We want to find the merging pattern of minimal cost.

Definition: Tree T with labelling CONT is optimal if Cost(T) ~ Cost(T')


for any other tree T' and labelling CONT'.

Theorem 9: If 0 ~ w, ~ w2 ~ ... ~ wn then an optimal tree T and label-


ling CONT can be found in linear time.

Proof: We construct tree T in a bottom~up fashion. We start with a set


V = {v" ... ,vn } of n leaves and labelling CONT(Vi ) = wi for 1 ~ i S n
and an empty set I of internal nodes and set k to zero; k counts the
number of internal nodes constructed so far.

while k < n-'


do select x 1 ,x 2 E I U V with the two smallest values of CONT; ties are
broken arbitrarily; construct a new node x with CONT(x) =
CONT(X,) + CONT(X 2 ) and add x to I; k - k+1;
delete x, and x 2 from I U V
od

Before we prove correctness and analyse run time we illustrate the


algorithm on an example. Let n = 5 and {w 1 ' •.• ,ws } = {',2,4,4,4}. We
start with 5 leaves of weight ',2,4,4,4. In the first step we combine
64

Let Topt with labelling CONT opt be an optimal tree. Let {Y1""'Y n } be
the set of leaves of Topt Assume w.l.o.g. that CONT opt (Yi) wi for
1 ~ i ~ n. Let d~pt
J_
be the depth of leaf y.1 in tree Top t'

Lemma 1: If w1' < w. then d~Pt ~ d~pt for all i,j.


J 1 J

Proof: Assume otherwise, say w1' < w. and d~pt < d~Pt for some i and j.
J 1 J
If we interchange the labels of leaves Yi and Yj then we obtain a tree
with cost

Cost(T t) - d~Pt w. + d~pt w - d~pt w + d~pt


op 1 1 J i J j 1 Wj

Cost(T t) - (w J' - w.) (d~Pt


op 1 J

a contradiction. o

Lemma 2: There is an optimal tree in which the leaves with content w1


and w2 are brothers.

Proof: Let Y be a node of maximal depth in T t and let y. and y. be its


op 1 J
sons. Then Yi and Yj are leaves. Assume w.l.o.g. that CONTopt (Y i ) ~
CONT t (y.). From lemma 1 we infer that either CONT (y.)
w1 or =
0P J 1
d i ~ d 1 and hence d i = d 1 by the choice of y. In either case we may ex-
change leaves Y1 and Yi without affecting cost. This shows that there
is an optimal tree such that Y1 is a son of y. Similarly, we infer from
lemma 1 that either CONT(Yj) = w2 or d j ~ d 2 and hence d j = d 2 . In
65

either case we may exchange leaves Y2 and Yj without affecting cost. In


this way we obtain an optimal tree in which Y1 and Y2 are brothers.
c

Lemma 3: The algorithm above constructs an optimal tree.

Proof: (by induction on n). The claim is obvious for n ~ 2. So let us


assume that n ~ 3 and let Talg be the tree constructed by our algorithm
for weights w1 ~ w2 ~ ~ wn • The algorithm combines weights w1 and

w2 first and constructs a node of weight (content) w1 + w2 • Let T~lg be


the tree constructed by our algorithm for set {w 1 + w2 ,w 3 ,w 4 ' ••• ,wn }
of weights. Then

because Talg can be ob.tained from T~lg by replacing a leaf of weight


w1 + w2 by a node with two leaf sons of weight w1 and w2 respectively.
Also T~lg is optimal for the set of n - 1 weights w1 + w2 ,w 3 , ••• ,wn
by induction hypothesis.

Let T t be an optimal tree satisfying lemma 2, i.e. the leaves with


op
content w1 and w2 are brothers in Topt • Let T' be the tree obtained
from Topt by replacing leaves w1 and w 2 and their father by a single
leaf of weight w1 + w2 • Then

Cost (T opt ) Cost(T') + w1 + w 2

~ Cost(T~lg) + w1 + w2

Cost (Talg )

since Cost(T') ~ Cost(T~lg) by induction hypothesis. c

It remains to analyse the run time of the algorithm. The crucial ob-
servation is:

Lemma 4: Let z1,z2, ••• ,zn_1 be the nodes created by the algorithm in
order. Then CONT[z1] ~ CONT[z2] ~ ••• ~ CONT[Zn_1]. Furhtermore, we
always have V = {vi, ••• ,vn }, I = {Zj, ••• ,zk} for some i ~ n+1,
j ~ k+1 ~ n when entering the body of the loop.

Proof: (by induction on k). The claim is certainly true when k O. In


66

each iteration of the loop we increase k by one and i + j by two. Also


CONT[zk+1] ~ CONT[zk] is immediately obvious from the construction.
c

Lemma 4 suggests a linear time implementation. We keep the elements of


V and I in two separate sets both ordered according to CONT. Since
w1 ~ ••• ~ wn a queue will do for V and since CONT[zl] ~ ••• ~
CONT[zn_1] a queue will do for I. It is then easy to select
x 1 ,x 2 E I U V with the two smallest values of CONT by comparing the
front elements of the queues. Also x 1 ,x 2 can be deleted in time 0(1)
and the newly created node can be added to the I-queue in constant time.
c

Theorem 9 can be generalized to non-binary trees.

II. 1.5 Comparing Different Algorithms

We saw four sorting methods so far: maximum selection, Heapsort, Quick-


sort, and Mergesort. We see one more in section III.5.3.2.: A-sort. The
following table summarizes our knowledge.

Single Maximum
selection Heapsort Quicksort M:!rgesort A-Sort

# of c:onp3risons
worst case n2/2 2nlogn n2/2 n log n O(n log F/n)
average case n2/2 1':12nlogn 1.44n:bg n n log n O(n log F/n)
nm tine
worst case 2.5 n2 2onlogn 0(n2 ) 12 log n O(n log F/n)
average case 2.5 n2 ~20 n log n 9nlogn 12nlogn O(n log F/n)
storage re- n + const n + const n+logn 2 n + const 5 n
quirement + const

access random sequen- randan


tial

stable no no no yes yes

F denotes the number of inversions in the input sequence; 0 ~ F ~

n(n-1)/2 (cf. III.5.3.2. for details).

Access: Heapsort, Quicksort and A-sort require random access, Mergesort


67

accesses the keys in a purely sequential manner. Therefore Mergesort


is well suited for usage with secondary storage which allows only se-
quential access (e.g. tapes).

storage Requirement: Heapsort needs on top of the storage required for


the input sequence space for a few pointers. Quicksort also needs space
for a pushdown store which holds the arguments of pending recursive
calls. Maximal stack height is n/2, namely if k = r - 2 always and
therefore the size of the subproblem which has to be solved in line (7)
is only two smaller than the size of the original problem. Maximal
stack height can be kept to log n by a slight modification of the pro-
gram: always solve the smaller subproblem first, i.e. replace lines (7)
and (8) by:

if k ~(R. + r)/2
then i f R. < k-1 then Quicksort(R.,k-1) fi~
if k + 1 < r then Quicksort(k + 1, r) fi
else i f k + < r then Quicksort(k + 1, r) fi~
i f R. < k-1 then Quicksort(R.,k-1) fi
fi

This modification has the following effect. The size of the subproblem
which is solved first has at most 1/2 the size of the original problem.
Therefore there are never more than log n recursive calls pending.
Mergesort requires two arrays of length n and space for some additional
pointers. A-sort is based on (a,b)-trees (cf. III.S.2. and III.S.3.).
For a = 2 and b = 3 a node of an (a,b)-tree requires 5 storage loca-
tions and may contain only one key. Hence A-sort requires up to Sn
storage locations.

Average asymptotic run time: The table contains the dominating terms of
the bounds on run time derived above. The relation of the run times of
Quicksort: Mergesort: Heapsort is 1: 1.33: 2.22 which is typical for
many computers. Note however, that the worst case run time of Mergesort
and Heapsort is not much larger than their expected run time. The re-
lative efficiency of Quicksort is based on the following facts: All
comparisons in the partitioning phase are made with the same element
and therefore this element can be kept in a special register. Also an
exchange of keys is required only after every fourth comparison on the
average, after every second in Heapsort and after every comparison in
68

Mergesort. However, Heapsort compares twice as often as Mergesort does.


For small n, the relations somewhat change. 8imple maximum selection is
better than Quicksort for n ~ 22. Therefore Quicksort may be improved
by terminating recursion for some n > 2 and switching to maximum selec-
tion for small n (exercise 11). A-sort is inferior to all other me-
thods with respect to average and worst case run time. However, A-sort
has one major advantage. It runs fast on nearly sorted inputs, i.e. if
F is small, say F = O{n log n), then A-sort runs in time O{n log log n).
This is in marked contrast to the other methods. Heapsort's and Merge-
sort's behaviour hardly depends on the statistical properties of the
input and Quicksort even runs slower on nearly sorted inputs.

II. 1.6 Lower Bounds

In this section we prove a lower bound on the number of comparisons


required for sorting and related problems. We will first show an
n{n log n) lower bound on the average and worst case complexity of
general sorting algorithms. We will then extend this lower bound to
randomized general sorting algorithms and to decision tree algorithms
allowing comparisons of rational functions of the inputs.

General sorting algorithms are comparison based, i.e. the only opera-
tion applicable to elements of the universe from which the keys are
drawn is the comparison between two elements with outcome ~ or >. In
particular, the pair of keys compared at any moment of time depends on-
lyon the outcome of previous comparisons and nothing else. For pur-
poses of illustration let us consider sorting by simple maximum selec-
tion on sequence 8 1 ,8 2 ,8 3 , The first comparison is 8 2 : 8 3 , If 8 3 > 8 2
then 8 3 is compared with 8 1 next, if 8 3 ~ 8 2 then 8 2 is compared with
8 1 , next, •••• We can illustrate the complete sorting algorithm by a
tree, a decision tree.
69

Node i j denotes a comparison between S. and S .. The edge to the


1. J
right son corresponds to Si > Sj' the edge to the left corresponds to
Si ::; Sj.

Definition: A decision tree is a binary tree whose nodes have labels of


the form Si Sj. The two outgoing edges are labelled::; and >. a

Let S1' •.• 'Sn be elements of universe U. The computation of decision


tree T on input S1' •.. 'Sn is defined in a natural way. We start in the
root of the tree. Suppose now that we reached node v which is labelled
S • S .. We then compare S. with S. and proceed to one of the sons of v
1. J 1. J
depending on whether S. ::; S. or S. > S .. The leaves of a decision tree
1. J 1. J
represent the different outcomes of the algorithm.

DefiEition: Let T be a decision tree. T solves the sorting problem of


size n if there is a labelling of the leaves of T by permutations of
{1, ..• ,n} such that for every input S1' ... 'Sn E U: if the leaf reached
on S1' ... 'Sn is labelled by 0 then So(1) ::; So(2) ::; ••• ::; So(n). a

'··le can now define the worst case and average case complexity of the
sorting problem. For a decision tree T and permutation 0 let ~T be the
o
depth of the leaf which is reached on input S1, ... ,Sn with

So(1) < S 0(2) < < S o (n) . Define

S (n) min max Q,T


0 0
T

A(n) min 1/n! L ~T


0
T 0

where T ranges over all decision trees for sorting n elements and 0
ranges over all permutations of n elements. ~; is the number of compar-
isons used on input 0 by decision tree T. Thus S(n) is the minimal
worst case complexity of any algorithm and A(n) is the minimal average
case complexity of any algorithm. We prove lower bounds on S(n) and
A(n) .

k
Suppose S(n) ::; k. A tree of depth::; k has at most 2 leaves. A decision
tree for sorting n elements has at least n! leaves. Thus
2 S (n) :2: n!
or
S(n) :2: rlogn !'
70

since S(n) is an integer. Stirling's approximation for n! gives us

log n! (n+1/2) log n - n/tn 2 + 0(1)


n log n - 1.43 n + O(log n)

An upper bound for S(n) comes from the analysis of sorting algorithms.
In particular, we infer from the analysis of Mergesort

rlog n'
S(n) ::; n rlog n' - 2 + 1
and hence

lim S(n)/n log n


n->=

We have thus determined the exact asymptotic worst case complexity of


sorting. The result derived above is often called the information-
theoretic bound. Any sorting algorithm has to distinguish n! possibili-
ties, and thus has to gain log n! bits of information. One comparison
gives at most 1 bit of information. The bound follows.

We turn to A(n) next. We give a different interpretation of 1/n! L t T


1T
1T
first. Let b 1 ,b 2 , ••. be the leaves of T. Define

1/n! if leaf b i is reached on some input


{ sequence

o othervlise

Then 1/n! L t T = L a. depth(b.) and hence 1/n! L t T is equal to the


1T.~ ~ 1T
1T ~ 1T
weighted path length of tree T with respect to distribution a 1 ,a 2 ,a 3 ..•
(cf. 111.4. for a detailed discussion of weighted path length). We show
in 111.4. in a more general context that

L
1T
t; 1/n! ~ H(1/n!, •.. ,1/n!)

L 1/n! log n! log n!


1T

for any tree T. Here H is the entropy of the distribution (cf. 111.4.).

Theorem 10: Every decision tree algorithm for sorting n elements needs
~ rlog n!' comparisons in the worst case and ~ log n! comparisons on
the average.
71

Theorem 10 can be used to prove lo,'1er bounds on other problems then


sorting. The element uniqueness problem is defined as follows. Given n
elements S1, ... ,Sn in U one has to decide whether Si ~ Sj for i ~ j.

Theorem 11: Every decision tree algorithm for the element uniqueness
problem of size n needs at least log n! comparisons in the worst case.

Proof: Let T be a decision tree for the element uniqueness problem of


size n, i.e. the nodes of T are labelled by comparisons Si : Sj and the
leaves are labelled yes or no. On input (S1, ••• ,Sn) E Un a leaf labelled
yes is reached iff Si ~ Sj for i ~ j. We will show that one can use T
to sort.

For permutation 'TT of n elements let v('TT) be the leaf reached on an in-
put (S1' .. '. ,Sn) E Un with S'TT(1) < S'TT(2) < ... < S'TT(n). Note that this
leaf is well-defined because the computation on any input
(S1, .•• ,Sn) E Un with S'TT(1) < S'TT(2) < ••. < S'TT(n) will end in the same
leaf.

Claim: v('TT) * v(p) if 'TT * P ('TT,p permutations).

Proof: Assume other\'1ise, i.e. there are permutations 'TT and p such that
v('TT) = v(p). Note that leaf v('TT) is labelled yes. We will now construct
an input (S1, ..• ,Sn) such that the computation on input (S1, ... ,Sn)
ends in leaf v('TT), vet
.'
S.]. = S.J for some i ~ J'. This is a contradiction •
(S1, .•• ,Sn) is constructed as follows. Let w 1 , •.• ,w t be the nodes on
the path to leaf v('TT). Consider partial order P(v('TT» on (S1, •.. ,Sn)
defined as follows. For k, 1 ~ k ~ t: if wk is labelled S. : S. and the
]. J
~ - edge (> - edge) is taken from wk to wk + 1 then Si < Sj (Si > Sj) in
partial order p(v('TT». Then P(v('TT» is the smallest partial order (with
respect to set inclusion) satisfying these constraints. In particular,
if (R 1 , ••. ,Rn ) E un is such that R cr (1) < R cr (2) < .•• < Rcr(n) for
cr E {'TT,p} then (R 1 , ..• ,Rn ) satisfies partial order P(v('TT». Hence
P(v('TT» is not a linear order and therefore there are a and b, a ~ b,
such that Sa,Sb are not related in partial order P(v('TT». Let
(S1, •.• ,Sn) E un be such that (S1, ..• ,Sn) satisfies partial order
p(v('TT» and Sa = Sb. Then the computation on input (S1, ••. ,Sn) ends in
leaf v('TT) and hence has result yes, a contradiction. 0
72

Can a randomized sorting algoritl4~, i.e. an algorithm which uses random


choices in order to determine which comparison to make next, be any
faster? After all, we saw that Quicksort I s quadratic ,..orst case be-
haviour vanishes when we switch to randomized Quicksort. The answer is
no. A randomized comparison-based algorithm can be represented by a
random decision tree. In a random decision tree there are two types of
nodes. The first type of node is the ordinary comparison node; the
second type is a coin tossing node. It has two outgoing edges labelled
° and 1 which are taken with probability 1/2 each. For the sake of
simplicity we restrict attention to finite random decision trees, i.e.
we assume that the number of coin tosses on inputs of size n is bounded
by ken). The notion "a random decision tree solves the sorting problem
of size nil is defined exactly as above. Note however, that the leaf
reached not only depends on the input but also on the sequence
s E {O,1}k(n) of outcomes of coin tosses. For any permutation TI and
sequence s E {O,1}k(n) let Ji,T be the depth of the leaf reached on
TI,S
sequence s of coin tosses and input sequence S1' ••• 'Sn where
STI(1) < STI(2) < ••• < STI(n). Define

min max 1/2 ken) L Ji,T


Sran(n) TI,S
T TI sE {a, 1} ken)

and

ken) Ji,T ]
Aran(n) min 1/ n ! L[1/2 L TI,S
T TI sE {a, rf(n)

where T ranges over all random decision trees which solve the sorting
problem of size nand TI ranges over all permutations of n elements.
Aran (Sran) is the minimal average (worst) case complexity of any
randomized comparison-based sorting algorithm. We can now use the argu-
ment outlined at the end of section 1.2. to show that randomization
cannot improve the conplexity of sorting below log n!. We have

~ min 1/n! L 1/2 k (n) L


T TI SE{O,1}k(n)
73

min 1/2 ken)


~
~ L 1/n! L £~
IT,S
T sE{O,1}k(n) IT

~ min 1/2 k (n) L A(n)


T sE{O,1}k(n)

since for every fixed sequence s of coin tosses random decision tree T
defines an ordinary decision tree

~ A(n)

Thus randomization cannot improve expected running time below log n!

We will next strengthen our basic lower bound in a different direction.


Suppose that the inputs are not taken from an arbitrary ordered universe
but from the set of real numbers. Reals cannot only be compared but can
also be added, multiplied, . . • . This leads to the concept of rational
decision trees.

Definition: A rational decision tree for inputs S1""'Sn is a binary


tree whose nodes are labelled by expressions P(S1"",Sn) : q(S1"",Sn)
where p and q are rational functions, whose edges are labelled by ~ and
>, and whose leaves are labelled by rational functions r(S1"",Sn) of
S1'···'Sn·

Rational decision trees compute functions f : ~n ~ IR in an obvious way.


Let S1' ••. 'Sn E ~n. Computation starts in the root. Suppose that compu-
tation has reached node v which is labelled P(S1,··"Sn) : Q(S1, .. "Sn).
We evaluate rational functions p and q and proceed to the appropriate
son of v depending on the outcome of the comparison. If the computation
reaches a leaf labelled by rational function r(S1, .•• ,Sn) then r is
evaluated and the value of r is the result of the computation.

Theorem 12: Let f : ~n ~ ~ be a function and let T be a rational deci-


sion tree which computes f. Let w1 , ... ,TVq be pairwise disjoint subsets
of of non-zero measure and let r 1 , ... ,r q be pairwise different ration-
~

al functions. If f1w. = r i for 1 ~ i ~ q then rational decision tree T


l
has depth at least log q.

Proof: Let T be a rational decision tree which computes f. For v a leaf


74

of T let Dv = {(S1, ••• ,Sn) € ~n; the computation on input (S1, ••• ,Sn)
ends in leaf v}. Then {Dv ; v leaf of T} is a partition of Rn and hence

\..J
v leaf of T
(D
v
n Wi)

for every i, 1 ~ i ~ q. Since Wi has non-zero measure there must be a


leaf v(i) such that DV(i) n Wi has non-zero measure. Note that T has a
finite number of leaves. Let r(v(i» be the rational function which
labels leaf v(i). Then functions r(v(i» and r i agree on set DV(i) n Wi.
Since DV(i) n Wi has non-zero measure we must have that functions
r(v(i» and r i are identical. Hence v(i) * v(j) for i * j and T must
have at least q leaves. Thus the depth of T is at least log q. 0

We give two applications of theorem 12. The first application is to


. n . r1 r2
sort~ng. For (x 1 ' ••• ,x n ) € R def~ne f(x 1 ,···,x n ) = x 1 + x2 +
+ xn n where r i = I {j; Xj < xi} I is the rank of xi. We call f the rank
function. For ~ a permutation of n elements let W~ = {(x 1 ' ••• ,x n ) € IRn;
x~(1) < x~(2) < ••• <x'lf(n)}· Then W~ has non-zero measure, flw~ is a
polynomial and flw = f
p
for ~ hv p *
p. Hence the depth of any rational

decision tree for the rank function is at least log n!

Theorem 13: Any rational decision tree for the rank function of n argu-
ments has depth at least log n!

The second application is to searching. For (y,x 1 , ••• ,x n ) € IR n + 1 define


f(y,x 1 , ••• ,x n ) = I {j; Xj < y} I. We call f the searching function. For
n+1
k, 0 ~ k ~ n, let wk = {(y,x 1 , ••• ,xn ) € ~ ; exactly k xj's are
smaller than y}. Then wk has non-zero measure and flw k. Thus flw
k k
is a rational function and flW flw for k * *
2. We have
k 2

Theorem 14: Any rational decision tree for the searching function of
size n has depth at least log(n+1).

We will see in chapter I I I that log(n+1) is also an upper bound to the


complexity of the searching function. Further applications of theorem 12
can be found in the exercises. Unfortunately, theorem 12 is not strong
enough for the element uniqueness problem. Note that there is a rational
decision tree of depth one which decides the element uniqueness problem,
75

namely IT (x. - x.) =0 ? This shows that there are problems which
1~i<j~n 1. J
are difficult in the restricted model of decision trees but become
simple if tests between rational functions are allowed and no charge
is made forcomputing those functions. Note however that the best
algorithm known for computing the product IT (xi - x j ) requires
1~i<j~n
n(nlog n) multiplications and divisions. Hence, if we charge for tests
and algebraic operations then an n(nlog n) lower bound for the element
uniqueness problem is conceivable. We will use the remainder of the
section to prove such a lower bound. We start by fixing the model of
computation.

Definition: An algebraic computation tree for inputs S1' .•. 'Sn is a


binary tree T with a function that assigns
a) to each leaf an output yes or no
b) to each vertex v with exactly one son (= simple node) an assign-
ment (statement) of the form
Y(v) ~ Y(v 1 ) op Y(v 2 ) , Y(v) ~ c op Y(v 2 ) , or Y(v) ~ IY(v 1 )

where op E {+,-,x,/}, vi is a simple node and a proper ancestor of v in

tree Tor Y(v i ) E {S1' ... 'Sn}' and c E JR


c) to each vertex of v with exactly two sons (= branching node) a
comparison of the form
Y(v 1 ) 2: 0, Y(v 1 ) >0, orY(v 1 ) =0

where v 1 is a simple node and a proper ancestor of v or

Y(v 1 ) E {S1, ... ,Sn}. o

Algebraic computation trees compute functions f: JRn ~ {yes,no} in an


obvious way. Given an input S = (S1' ... ,Sn) E JRn the program traverses
a path peS) in the tree. In simple nodes an arithmetical operation is
performed and the value of the operation is assigned to the variable
associated with the simple node. In branching nodes the value of a
variable is tested and the computation proceeds to the appropriate
son. We require that no computation leads to a division by zero or to
taking the square root of a negative number. The cost of an algebraic
computation tree is its depth, the complexity of (the membership problem
of) a set V ~ JRn is the minimum cost of any algebraic computation
tree which computes the characteristic function of V. The lower bounds
on the cost of algebraic computation trees are based on the following
fact from algebraic topology.
76

Fact: Let q1, ... ,qM be polynomials in N variables of degree at most d.


Let V == JRN be defined by
q1(x1'···'~) = 0, ,qM(x 1 ,···,xN) = °
Then the number of components of V is at most d(2d - 1)N-1.
Remark: A proof of this can be found in J. Milnor: On the betti numbers
of real algebraic varieties, Proc. AMS 15 (1964), 275-280, and is far
beyond the scope of this book. We restrict ourselves to a short informal
discussion. Two points x and x' of V belong to the same component if
there is a line running inside V and connecting them, i.e. if there is
a continous function h: [0,1] ~ V with h(O) = x and h(1) = x'. The
components of V are the equivalence classes under this relation.

The fact above becomes particularly simple if N = 1. In this case it


is equivalent to the fact that a polynomial of degree d in one variable
has at most d real roots. Consider the case N = 2 and d = 2 next. Then
q1(x 1 ,x 2 ) ° defines an ellipse (parabola, or hyperbola) and so do
Q2,q3'·· • The crucial observation is now that Q1 (x 1 ,x 2 ) = 0,
Q2(x 1 ,x 2 ) ° defines a set of at most 6 points, i.e. six zero-
= 0, .•. , QM(x 1 ,x 2 ) =
dimensional sets. All further equations Q3(x 1 ,x 2 ) °
can only weed out some of these points and cannot increase the number
of components.
By analogy the truth of the fact is now conceivable for larger degree
and larger number of variables as well. The set defined by
Q1 (x 1 '· .. ,xN) = ° has at most d components, each of which has dimension
N - 1. Intersecting this set with the set Q2(x 1 , ... ,x N) = yields at °
most d (2d - 1) components each of which has diraension N - 2. Iterating
in this way we arrive at d(2d - 1)N-1 components of dimension ° each
defined by polynomials Q1, ... ,QN. Considering more polynomials weeds
out some of these points but does not increase the number of components.

We close with the warning that the argument above is at most a hint
towards a proof. o

We are now ready for the lower bound. We use #V to denote the number of
components of set V.

Theorem 15: Let T be an algebraic computation for inputs S1, ... ,Sn
which decides the membership problem for V == JRn , and let h be the
depth of T. Then
77

a) max (#V, #(mn _ V)) ~ 2 h 3 h +n

b) h ~ (log max(#V,#(Rn - V)) - nlog 3)/10g 6

Proof: Part b) follows from part a) by taking logarithms. It remains to


prove part a). Since tree T has depth h it has at most 2h leaves. If w
is a leaf of T let D (w) ~ mn be the set of inputs S for which the
computation ends in leaf w. We claim that #D(w) ~ 3h +n . Note first that
this claim implies part a) since there are at most 2h leaves wand each
leaf satisfies #D(w) ~ 3 h +n • Thus #V ~ 2 h 3 h +n and similarly
#(Rn _ V) ~ 2h 3 h +n •
It remains to prove #D(w) ~ 3h + n for every leaf w. In order to do so we
characterize D(w) by a set of polynomial equations and inequalities of
degree at most 2. Let P be the path from the root to leaf w. We traverse
down the path P and set up a system r of equalities and inequalities
as follows. Let v be a node on path P.
If v is a simple node then
operation equation
Y (v) Y (v 1 ) ± Y(v 2 ) Y(v) Y (v 1) ± Y(v 2 )
Y (v) Y(v 2 )
Y(v 1 ) Y (v) Y(v 1 ) Y(v 2 )
Y(v) Y (v 1 ) / Y(v 2 ) Y(v 1 )= Y(v) Y(v 2 )
2
Y (v) +-v'Y(v 1 ) Y(v 1 )= Y(v)
and if v is a branching node with a test
Y(v 1 ) > 0 Y(v 1 ) ~ 0 Y(v 1 ) =0
then we add this (in-)equality to r if the positive outcome is taken on
path P and we add
-Y(v 1 ) ~ 0 -Y(v 1 ) > 0
Y(v) Y(v 1 ) - 1 = 0
otherwise. Note that in the last case Y(v) is a new variable which is
not used in any assignment. Also note that the equation
Y(v) Y(v 1 ) - 1 =0 has a solution iff Y(v 1 ) * o.

The system r involves variables S1, ••. ,Sn' Y(v 1 ), •.. ,Y(v r ) for some
integer r. Also r contains exactly r equalities and some number s of
inequalities. Clearly r + s ~ h since each node on P adds one equality
' 1 'lty. Let W ~ m
or lnequa n+r e
b th e set 0 f so l '
utlons to t h e sys t em r
Then the projection of W onto the first n coordinates is D(w). Since
the projection function is continous we conclude that #D(v) ~ #W and
i t therefore suffices to show #W ~ 3h +n •

What have we obtained at this point? The set W is defined by a set of


r equalities and s inequalities. Each equality or inequality is given
78

by a polynomial of degree at most 2 in n + r variables which we call


x"""xn + r for simplicity from now on, i.e. we have a system
P, (x, , •.. , x n + r ) 0, Pr(x"""xn + r ) 0
q, (x, , ••• , x n + r ) > 0, , qm(x" ••. ,xn + r ) > 0,
qm+'(x" .•• ,x n + r ) ~ 0, , qs (x" ••• , x n +r ) ~ 0
where each Pi,qj has degree at most 2.

In order to apply the fact above we transform this system into a set of
equalities in a higher dimensional space. Let t = #W and let P"""Pt
be points in the different components of W. Let
E = min {qj(Pi) ~ , ~ j ~ m, 1 ~ i ~ t}
Then E O. Let WE be defined by the system
~

P1 (x, , •.. , x n +r ) 0, Pr(x 1 , ••• ,xn + r ) 0


q1 (x 1 '··· 'xn +r ) ;:: E, , qm(x 1 , ••• ,x +
n r ) ~ E
qm+1(x" •.• ,xn + r ) ~ 0, ••• , qs(x 1 , ••• ,xn + r ) ;:: 0

Then WE =Wand Pi E WE for all i. Hence #W ~ #W E.


It therefore suffices to show #W E ~ 3n +h

2
xn+r+m + E
2 2
qm+'(x" •.. ,x n + r ) x n + r +m+" .•• , qs(x" •.• ,xn + r ) = xn+r+s
where xn+r+" .•• ,xn + r +$ are new variables. Then WE is the projection of
Z onto the first n+r coordinates and hence #WE ~ #Z. Furthermore, Z is
defined by a system of polynomial equations of degree at most two in
n + r + s ~ n + h variables. Hence
#Z ~ 2(4 - 1)n+h-1 ~ 3n +h
by the fact above. CJ

We close this section with three applications of Theorem '5.

Theorem '6: The complexity of the element uniqueness problem in the


model of algebraic computation is Q(nlog n) •

Proof: Let V c: lRn be defined by n (x.~ - x j ) * O. Then *V ;:: n! as


1~i<j~n

we will now argue. For x = (x 1 ' •.. , xn) E lRn, x. * x. for i * j, let (J
~ ]
79

be the order type of x, i.e. cr is a permutation with x cr (1) < x cr (2) <
••• < xcr(n). Then it is easy to see that if x, x E lRn have different
order types then any line connecting them must go through a point with
two equal coordinates, i.e. a point outside V, and hence x and x'
belong to different components of V. This proves #V ~ n! Since
log n! = Q (nlog n) the proof is completed by an application of
theorem 15 . [J

Our second application is the convex hull problem (cf. section VIII.2):
Given n points in the plane, does their convex hull have n vertices?

Theorem 17: The complexity of the convex hull problem in the model of
algebraic decision trees is Q(nlog n).

Proof: Let V = {(x 1 'Y1, ••• ,xn 'Yn); the convex hull of point
set {(xi'Yi); 1 ~ i ~ n} has n vertices} =
lR2n. As in the proof of
theorem 16 we assign an order type to every element of V. Let (x 1 'Y1' ••
•• ,xn'Yn) E V, and let p be any point in the interior of the convex
hull of point set {(xi' Yi); 1 ~ i ~ n}. Then the order type of this
tuple is the circular ordering of the points around p. Note that
there are (n - 1)! different order types and that any line in lR 2n
connecting tuples of different order types must go through a point out-
side V. Hence #V ~ (n - 1)! and the theorem follows from theorem 15. [J

Our last application is the computation of the elementary symmetric


functions: Given x 1 , ••• ,xn E lR, compute the elementary symmetric
functions PO(x 1 ,··· ,xn ) ,P1 (x 1 '··· ,xn ),··· 'Pn (x 1 '··· ,xn )·

Here Pj(x 1 ,··.,xn ) =. (-i1)j 1:. x.


1.1
x.
1.2
. .• x.
1. j
. It is a well known
1. 1 < 2< ••• <1. j
fact from algebra that the elementary symmetric functions are the
coefficients of the interpolation polynomial through points (x 1 ,0), •.
n
•• , (xn,O), (0, (-1) x 1 ·• .xn ).

Theorem 18: The complexity of computing the elementary symmetric


functions is Q(nlog n) in the model of algebraic computation trees.

Proof: Let a i = Pi(1,2, •.. ,n) , 1 ~ i ~ n. An algorithm that computes


P1 (x 1 ,···,xn ),···,Pn(x 1 ,···,xn ) can be used to test a i = Pi(x 1 , .•• ,xn ),
1 ~ i ~ n, in n more steps. Since this is true iff {x 1 ' ..• ,xn } = {1, ... ,n}
80

(This is a direct consequence of the uniqueness of the interpolation


polynomial) it suffices to show that #V = n! where V = {(x 1 ' ••• ,xn );
{x 1 ' ••• ,xn } {1, ••• ,n}}. A proof that #V = n! can be given along the
lines of the proof of theorem 15. 0

Theorems 16, 17, and 18 show the strength of theorem 15. It can be used
to prove lower bounds for a great variety of algorithmic problems. We
should also note that theorem 15 is not strong enough to imply lower
bounds on the complexity of RAM computations because indirect addressing
is a "non-algebraic" operation ( a lower bound on the complexity of RAM
Qomputaion will be shown in section II.3) and that is not strong enough
to imply lower bounds for computations over the integers when integer
division belongs to the instruction repertoire.

II. 2. Sorting by Distribution

II. 2.1 Sorting Words

Let ~ be a finite alphabet of size m and let ~ be a linear order on ~.

We may assume w.l.o.g. that ~ = {1,2, ••• ,m} with the usual ordering re-
lation. The ordering on ~ is extended to an ordering on the words over
~ as usual.

Definition: Let x = x 1 ••. x k and y = Y1 "'Yt be words over ~, i.e.


xi'Yj E ~. Then x is smaller than y in the alphabetic ordering (denoted
x < y) if there is an i, 0 ~ i ~ k such that x. = y. for 1 ~ j ~ i and
J J
either i =k < t or i < k, i < t and x i + 1 < Yi+1' 0

The definition of alphabetic ordering conforms ~'7ith every day usage,


e.g. we have x = ABC < AD = Y because x 1 = Y1 and x 2 < Y2'

We treat the following problem in this section: Given n words x 1 ,x 2 , •.• ,


xn over alphabet ~ = {1, ••• ,m} sort them according to alphabetic order.

There are many different ways of storing words. A popular method stores
all words in a cornmon storage area called string space. The characters
of any word are stored in consecutive storage locations. Each string
variable then consists of a pointer into the string space and a loca-
tion containing the current length of the word. The figure below shows
an example for x 1= ABD, x 2 = DBA and x 3 = Q.
81

~1
x1

2
)
x B D D B A

x3

The basic idea of bucketsort is most easily explained when we consider


a special case first: all words x 1 , ••• ,x n have length 1, i.e. the input
consists of n numbers between and m. Bucketsort starts with m empty
buckets. Then we process word by word, throwing xi into the xi_th
bucket. Finally, we step through the buckets in order and collect the
words in sorted order. This description of Bucketsort is fairly poetic
in style; let us fill in some implementation details next. Buckets are
linear lists, the heads of the lists are stored in array K[1 •• m].
Initially, we have to create m empty lists. This is easily done in time
Oem) by initializing array K. In order to process xi we have to access
K[x i ] and to insert xi into the list with head K[x i ]. This can be done
in time 0(1) if we insert xi at the front end of the list or at the
back end of the list. In the latter case K[xi] must also contain a
pointer to the end of the list. Thus we can distribute n words in time
O(n). Finally we have to collect the buckets. We step through array
K[1 •• m] and concatenate the front of the (j+1)-st list with the end of
the j-th list. This takes time Oem), if array K also contains pointers
to the back ends of the lists, and time O(n+m) otherwise. Note that the
total length of all m lists is n. In either case total running time is
o (n+m) • We have to discuss one more detail before we proceed. Should we
add xi to the front or to the rear end of the xi_th list? If we always
add to the rear, then the order of elements xi,x j with xi = x j is un-
changed, i.e. bucketsort is stable. This will be important for what
follows.

We proceed to a slightly more difficult case next. The xi,s, 1 ~ i ~ n,


i
are proper words and all of them have equal length, say k. Then x
i i i with x~
x 1 x 2 ••• E L There are two ways of extending our basic
~ J
algorithm to the more general case. In the first approach we sort
according to the first letter first. This divides our set of words into
m groups, some of which may be empty. Then we sort each group seperately
according to the second character, ••• until each group consists of a
82

single word only. This approach has a serious disadvantage. Groups


become smaller and smaller, but the complexity of bucketsort is at
least the size of the alphabet, i.e. the overhead may be large for
small group size. It is shown in exercise 18 that total running time of
this approach may be as large as n(n·k·m). In the second approach one
sorts according to the last letter first. After having done so we sort
the entire list of n words, which is sorted according to the last
letter, according to the next to last letter. Here comes the crucial
observation. The words are sorted according to the last two letters
now, because bucketsort is stable. Next we sort according to the
(k-2)-th letter, and so on. The second approach requires k passes over
the set of n words, each pass having a cost of O(n+m) time units. Thus
total running time is O(k(n+m».

Can we improve upon this? Let us consider an example with m = 4, n = 5


and k = 3. The 5 words are: 123, 124, 223, 324, 321. The first pass
yields:

bucket one 321 and hence the input sequence for the
bucket two second pass is 321, 123, 223, 124, 324.
bucket three: 123, 223 The second pass yields:
bucket four : 124, 324

bucket one and hence the input sequence for the third
bucket two 321, 123, pass is 321, 123, 223, 124, 324. The third
223, 124, 324 pass yields:
bucket three:
bucket four :

bucket one 123, 124 and hence the final result sequence is
bucket two 223 123, 124, 223, 321, 324.
bucket three: 321, 324
bucket four :

Note that we collected a total of 3·4 = 12 buckets, but only 7 buckets


where non-empty altogether. It would improve running time if we knew
ahead of time which buckets to collect in each pass. Let us assume that
s. buckets are non-empty in the j-th pass, 1 ~ j ~ k. If we could avoid
J
looking at empty buckets then the cost of the j-th pass were only
O(s. + n). Since s. ~ n, the cost of a pass would be only O(n) instead
J J
of O(n + ro).
83

There is a very simple method for determining which buckets are non-
empty in the j-th pass, i.e. which letters occur in the j-th position.
Create set {(j,X~)' 1 ~ j ~ k, 1 ~ i ~ n} of size n·k and sort it by
bucketsort according to the second component and then according to the
first. Then the j-th bucket contains all characters which appear in the
j-th position in sorted order. The cost of the first pass is O(n·k + ro),
the cost of the second pass is O(n·k + k). Total cost is thus O(nk + m).

Before we give a complete algorithm for bucketsort we discuss the ex-


iii i
tension to words of arbitrary length. Let x = xl x 2 ... X 2 .'
1
1 ~ i ~ n; 2i is the length of xi' We basically proceed as above, how-
ever we have to make sure that xi has to be considered for the first
time when we sort according to the 2 i -th letter. This leads to the
following algorithm. Let L = r 2i ~ n

1) Determine the length of x i , 1 ~ i ~ n, and create pairs (2 i , pOinter


to xi). This takes time O(L).

2) Sort the pairs (2 i , pointer to xi) by bucketsort according to the


first component. Then the k-th bucket contains all xi with 2. = k, i.e.
1
all these strings are contained in a linear list. Call this list
length[k]. The cost of step 2) is O(n + L) because L buckets certainly
suffice.

3) Create L pairs (j,x~), 1 ~ i ~ n, 1 ~ j ~ 2. and sort them according


J 1
to the second and then according to the first component. Let Nonempty[j],
1 ~ j ~ 2max = max(2 1 , .•. ,2 n ) be the j-th bucket after the second pass.
Nonempty[j] contains all letters which appear in the j-th position in
sorted order. Delete all duplicates from Nonempty[j]. The cost of step
3 is O(L + m) + O( L + 2max) = O(L + m).

i
4) We finally sort words x by distribution. All lists in the following
program are used as queues; the head of each list contains a pointer to
the last element. Also x is a string variable and x. is the j-th letter
J
of string x.
84

(1) W - empty queue;


(2 ) for k from 1 to m do S[k] - empty queue od;
(3 ) for j from R. to 1
max -
(4 ) do add length[j] to the front of Wand call the new queue W;
(5) ~vhile W * !25
(6) do let x be the first element of W; delete x from W;
(7 ) add x to the end of S[x.];
J
od
(8) while Nonempty[j] * !25
(9 ) do let k be the first element of Nonempty[j];
(10) delete k from Nonempty[j];
( 11) add S[k] to the end of IV;
( 1 2) set S[k] to the empty queue;
od
od

Correctness of this algorithm is immediate from the preceding discus-


sion. Line (2) costs Oem) time units, a single execution of any other
line has a cost of 0(1). Note that only a pointer to string x is moved
in line (7). Lines (3) and (4) are executed R. times. In lines (5),
max .
(6) and (7) we operate exactly R.. times on string Xl. Hence the total
1
cost of these lines is O(L). We associate the cost of a single execu-
tion of lines (9) to (12) with the first element of S[k]; k as in line
(9). In this way we associate at most O(R..) time units with xi,
1
1 ~ i ~ n, and hence the total cost of lines (8) - (12) is O(L). Al-
together we have shown that total cost of steps (4) - (12) is Oem + L).

Theorem 1: Bucketsort sorts n words of total length L over an alphabet


of size m in time Oem + L).

II. 2.2 Sorting Reals by Distribution

We briefly describe distribution sort applied to real numbers. For


simplicity, we assume that we are given a sequence Xi' 1 ~ i ~ n, of
reals from the interval [0,1]. We use the following very simple al-
gorithm, called Hybridsort. a is some fixed real and k is equal to an.

1) Create k empty buckets. Put Xi into bucket rkx; for 1 ~ i ~ n.


85

2) Apply Heapsort to every bucket and concatenate the buckets.

The correctness of this algorithm is obvious.

Theorem 2: a) worst case running time of Hybridsort is O(n log n) .

b) If the xi's are drawn independently from a uniform distribution over


the interval [0,1], then Hybridsort has expected runninq time O(n).

Proof: a) Running time of the first ohase is clearly O(n). Let us as-
sume that ti elements end UD in the i-th bucket, 1 ~ i ~ k. Then the
cost of the second phase is 0(2: t. log til Itlhere O·log 0 = 0 and
1
i
L t. = n. But 2: t. log t. ~ 2: ti log n = n log n.
1 1 1
i i

b) Let Bi be the random variable represent ina the number of elements in


the i-th bucket after pass 1. Then prob(B i = h) = (~) (1/k)h(1-1/k)n-h
since any single Xj is in the i-th bucket with probability 1/k. Ex-
pected running time of nhase 2 is

h
k· 2:
h=2

h
:s; k· 2:
h=2

k(n(n-1)/k 2 + n/k)

n-2 n-1
since h 2 (~) (h (h-1) + h) (~) n(n-1) (h-2) + n(h-1)

O(n)

since k an Cl

II. 3. Lower Bounds on Sorting, Revisited

In section II.1.6. we proved an ~(n log n) lower bound on the average


and ,vorst case complexity of sorting. However, in II. 2.2. we showed an
O(n) upper bound on the average case complexity of sorting reals. What
86

went wrong? An upper bound which is smaller than the corresponding


lower bound? The answer is that we have to keep the models of computa-
tion in mind for which we proved the bounds.The lower bound of 11.1.6
was shown for rational decision trees. In rational decision trees we
can compare rational functions of the inputs at every step. Hvbridsort
uses a larger set of priTIitives; in particular it uses division and
rounding and it uses indirect addressing. Note that indices into arrays
are computed as functions of the inputs. Also the upper bound on
running time is expected case and not worst case. It is open whether
any variant of Hybridsort can sort numbers in linear worst case time.
However, it can be shown that any RA'~ (in the sense of 1.1.) which
operates on natural nuwbers and has basic operations +, ~ (subtraction
in ~o)' • in addition to the comparison operator ~ requires time
~(n log n) in the unit cost measure for sorting in the worst case. This
is even true for coin tossing rums (in the sense of 1.2.). It is open
whether the result stays true if division is also a basic operation.

Before y,le state the precise result we briefly recall the RAN model. It
is convenient to use indirect addressing instead of index registers as
the means for address calculations. We saw in 1.1. that this does not
affect running time by more than a constant; however it makes the proof
more readable. The basic operations are (i, k E IN):

a. +- i, a .... p (i) ,a .... p(p(i»

p(i) .... a ,p(p(i» .... a

a .... a op p (i) , where op E f +, • , ~ }

goto k

if p(i) > a then ~ k1 else goto k2 fi

a .... random

r x - y if x <:: Y
Here x y and
~
10 if x < y

a .... random assigns 0 or 1 to a y,li th probability 1/2 each. A RRAH pro-


gram is a sequence of instructions nQmbered starting at 1. The labels
in the goto instructions refer to this numbering.
87

Definition: Let A be an A solves the sorting problem of size n


~1.

if for all x = (x 1 ' •.. ,x n ) EIR n : if A is started with xi in location


i, 1 ~ i ~ n, and 0 in the accumulator and all locations j, j > n, and
~ x n (2) ~ ... ~ xn(n) then A
if n is a permutation such that x n (1)
stops and xn(i) is in location i, 1 ~ i ~ n, when A stops.

Theo.!:em 1: Let A be any RRAH which solves the sortin~ ),roblem of size
n. Then there is an x E ~n such that the exnected running time of A on
x is at least loC! n!, i.e. the worst case running time of A. is at least
log n!.

Proof: Let A be any P.Rl\.1·~ 'vhich solves the sorting problem of size nand
stops on all inDuts x E Rn and all sequences of coin tosses in at most
t steps. Here t is some integer. The proof is by reduction to the deci-
sion tree model studied in section II.1.6 .. The first step is to re-
place all instructions of the form a - a ~ p(i) by the equivalent
sequence if p(i) ~ a then a - 0 else a - a - p(i) fi. After the modifi-
cation A uses only true sUbtractions. In the secone. step ,ve associate
with ?rogram A a (maybe infinite) decision tree T(A) by unfolding. T(A)
is a binarv tree whose nodes are labelled by instructions anc tests and
some of \vhose edges are labelled by 0 or 1. Hore precisely, let A con-
sist of m instructions. Then Ti(A), 1 ~ i ~ m+1 is defined by

(1) Tm+1 (A) a single leaf

(2) if line i of A is instruction a - i, a - p(i), a - p(p(i)),


p(i) - a, p(p(i)) - a.ora - a op p(i) then Ti(A) consists of a root
labelled by that instruction with a single son. The single subtree is
Ti 1(A).

(3) if line i is goto k then Ti(A) is equal to Tk(A).

(4) if line i is if p(i) > a then goto k1 else go to k2 fi then

Ti (A)

(5) if line i is a - random then


88

Ti + 1 (A)

Finally T(A) = T1 (A). Tree T(A) simulates ~~M A in an obvious way; in


coin tossing nodes the two outgoing edges are taken with equal proba-
bility. Tree T(A) might be infinite but because A stops on every input
x E Rn within t steps no node of depth> 2t is ever reached in any
computation. Therefore we may prune T(A) at depth 2t.

In the third step we associate with every edge e of the decision tree
a set {Pe,i' i E ~o} of polynomials in indeterminates x1 , ••• ,X n • The
intended meaning of 0-- e,~. (x) is the content of location i (the accumula-
tor for i = 0) if the input is x E IRn and control has reached edge e.
Polynomials Pe,i are defined inductively by induction on the depth of
e. Polynomials p e, ~. will not have the intended meanina - for all
- inputs
x but only for a sufficiently large set of nice inputs as made precise
below. If p and q are !1olynomials we write p::q to denote the fact that-
p and q define the same rational function. The inductive definition is
started by:

If e is the (conceptual) edge entering the root then

if 1 ~ i ~ n
Pe,i(X)
othen·Tise

For the induction step let e be an edge leaving node v, let d be the
edge into v and let ins (v) be the label of node v.

(1) if ins (v) is p(i) > a or coin toss then p e,~. = Pd . for all i
,~
~ 0

(2) if ins (v) is a - a op p(i), op E {+,-,.} then

if j = 0
{ Pd,o op Pd,i
Pd,j otherwise
89

(3) if ins (v) is a ~ i then

i if j = 0
{ otherwise

(4) if ins(v) is a ~ p(i) or a ~ p(p(k» and

Pd,k =i for some i E No then

if j = 0

otherwise

(5) *
if ins (v) is a ~ p (p (k» and Pd,k i for all i E IN O then let w be
the closest ancestor (i.e. an ancestor of maximal depth) of v such that
the label of w is p(p(£'» ~ a for some £, EN and P f ,£, = Pd,k where f is
the edge entering w. If w does exist then

if j = 0

otherwise

and if w does not exist then

if j = 0

otherwise

(6) if ins(v) is p(i) ~ a or p(p(k» ~ a and Pd,k - i for some i E IN o


then

if j = i

otherwise

(7) if ins (v) is p(p(k» ~ a and Pd,k $ i for all i E INo then
Pd . for all j.
, J

We will next derive a sufficient condition for the "correctness" of the


intended meaning of polynomials P .• Let I = {1, ... ,n} U {j; there is
e, J
some instruction with address j in T(A) or Pe,i =
j for some edge e and
i E No}. Note that I is finite since for every edge e there are only
90

finitely many (at most n + depth of e) i's with Pe,i '" O. This is
easily seen by induction on the depth of e. Let QA' a set of polynomials,
be defined by QA = I U {p.. e, J..; e is edge of T(A) and i ~ O}. QA is a
fini te set of polynomials by the renark above. A point x E IRn is
admissible if p(x) * q(x) for any p,g E QA with P '" q.

Lemma 1: If x E ~n is admissible for QA then all p . 's have their in-


- e, J
tended meaning for all edges e and all j E I, i.e. p . (x) is the
e,]
content of location j if the input is x and control reaches e for all
j E 1.

Proof: The proof is by induction on the depth of e. The claim is clear-


ly true for the edge entering the root. So let us consider the case
that edge e emanates from node v. Let d be the edge entering v. The
induction step is by case analysis paralleling the definition of p e,]"
The induction step is easy in cases (1), (2), (4) and (6) and there-
fore left to the reader. The two remaining cases are cases (5) and (7).

Case (5): Let w,f and ~ be defined as above. Let us consider the case
that w exists first. Let h = Pf,~(x) = Pd,k(x). Then Pf,o(x) was
stored in location h by instruction ins(w). It remains to be shown that
location h was not written into on the path from w to v. Let z be any
node on that path excluding v and w. If ins(z) is not a store instruc-
tion then there is nothing to show. So let us assume that ins(z) is
either p(i) + a or p(p(i» + a. In the former case we have i *h
Pd,k(x) since i E I ~ QA' x is admissible for QA' and Pd,k is not con-
stant, in the latter case we have Pg,i(x) * h = Pf,~(x), where g is the
edge entering z, since Pg,i E QA and x is admissible for QA' In either
case ins(z) does not write into location z.

If w does not exist then one proves in the same way that nothing was
ever written in location h = Pd,k(x) before control reaches edge e.

Case (7): Then ins(v) is p(p(k» + a and Pd,k '" i for all i E mo' Hence
Pd,k(x) I since x is admissible for QA and I ~ QA' Thus the content
~
of locations with addresses in I is not changed by ins (v) . D

Let 1Tbe a permutation of {1,2, ... ,n}. x E /R n is of order type 1T if


x 1T (1) < x 1T (2) < ... < x 1T (n)' Let P = I {1T; there is x EIRn of order
91

type TI which is admissible for QA} I. We show below that p = n! Let x(TI)
be admissible for QA of order type TI. Execution of T(A) on input x(TI)
ends in some leaf with ingoing edge e; of course, the leaf depends on
sequence s E {O,1}2t of coin tosses used in the computation. We have
Pe,i(x(TI)) xTI(i)(TI) for all i
E {1, ..• ,n}. Since X1 ' ... 'Xn E QA and
x(TI) is admissible for QA this is only possible if Pv,i = XTI(i) for all
i E {1, .•. ,n}. Thus for every sequence s E {O,1}2t of coin tosses at
least n! different leaves are reachable one for each order type. Let
d(TI,s) be the number of nodes of outdegree 2 on the path from the root
to the leaf which is reached on input x(TI) when sequense s of coin
tosses is used. Then

1/n! L d(TI,s) ~ log n!


TI
2t
(compare the proof of ILlo6., Theorem 10) for every s E {o,1} and
hence

1/22t L (1 In! L d(TI,s)) ~ log n!


sE {a, 1} 2t TI

or
1/n! L (1/2 2t L d(TI,s)) ~ log n!
TI sE {a, 1} 2t

Thus there must be some TI such that

1/22t L d(TI,s) ~ log n!


sE{O,1}2t

,i.e. the expected running time of A on input x(TI) is at least


log n! ~ n log n - 2n.

It remains to prove that p = n!. QA is a finite set of polynomials. x


is admissible for QA if pix) *
q(x) for any pair p,q E QA with p q, *
i.e. if R(x) *
0 where RA = n{p-q; p,q E QA' P q}. RA is a single *
polynomial. It therefore suffices to prove lemma 2.

Lemma 2: Let R *0 be a polynomial of degree m in variables {X 1 , ... ,X n }


and let TI be any permutation of {1, ... ,n}. Then there is an
x E {1, .•. ,n+m}n of order type TI with R(x) * o.
92

Proof: Since R(X n (1)' .•. 'X n (n)) is again a polynomial of degree m it
suffices to prove the claim for n being the identity. This is done by
induction on n. For n = 1 the claim follows from the fact that a
univariate polynomial of degree m has at most m zeroes. For the in-
duction step let

s
R(X) L R i (X 1 , ••• ,xn _ 1 ) X~
i=o

where R $ O. Let r be the degree of Rs. Then r + s ~ m. By induction


s . n-1
hypothesis there 1S some x E {1, ..• ,r+n-1} , x 1 < x 2 < •.• < x n - 1
with Rs(x) o. *
Choose xn E {r+n, ... ,n+r+s} such that the s-th degree
polynomial

in X is non-zero. 00
n

Similar lower bounds can be shown for related problems, e.g. the nearest
neighbour problem (exercise 20) and the problem of searching an ordered
table (exercise 21). It is open whether theorem 1 stays true if integer
division is added as an additional primitive operation. It should be
noted however that one can sort in linear time (in the unit cost model)
if bitwise boolean operations (componentwise negation and componentwise
AND of register contents, which are imagined to be binary representa-
tions of numbers) and integer division are additional primitives.

Theorem 2: RM~s with integer division and bitwise boolean operations


can sort n numbers in time O(n) in the unit cost model.

Proof: The idea of the proof is to exploit the parallelism provided by


bitwise boolean operations and to use integer division for cutting large
numbers into pieces. The details are as follows.

Let x 1 ,x 2 , ..• ,x n be integers. We first find the maximum, say x m' com-
pute x v X- (bitwise) and add 1. This produces 10 k where k is the
m m
length of the binary representation of x • Note that 10 k is the binary
m
representation of 2k+1.
93

We shall compute the rank of every xi' i.e. compare each xi with all
Xj and count how many are smaller than it. Note that if we have

A X.
~

B o Xj 0

indicator

in registers A and B, with xi and Xj in matching positions, then regard-


less to the rest of registers A and B, C = A - B will contain a 1 at
the indicated position iff xi 2: x ..
J

So, to sort, we obtain in a single register n copies of


1 xn 11 x n - 1 11 x n - 2 ... 1 xl 1 concatenated to each other, and
(0 xn O)n (0 x n _ 1 O)n •.. (0 xl O)n in another with the length of all
xi's padded out to k with leading zeroes. This can be done in time O(n)
as follows. We show the construction for (0 xn O)n (0 x n - 1 O)n .•.
(0 xl O)n. Note first that we have 2k+l available and therefore can
compute a := 2(k+2)n in time O(n). Next note that
n
b:= L x. 2(k+2)n(i-l)+1 has binary representation.
i=l ~

o ... 0 x 0 o ... 0 x 1 0 o ... 0 xl 0


~ ~ ~

(k+2) n bits (k+2)n bits (k+2)n bits

and can be computed in time O(n) given a, x 1 ' ... ,x n • Finally observe,
n-l
that L b 2(k+2)i is the desired result.
i=o

At this point, a single subtraction yields all comparisons. An AND with


2
bit string (10 k+l ) n , wh~ch
. can be constructed in time O(n), retrieves
all the indicator bits. More precisely, we have a bitstring of length
(k+2)n 2 such that bit (k+2)n (j-l) + (k+2)i is one iff xi 2: Xj and
all other bits are zero. We cut this bit string into pieces of length
(k+2)n by repeatedly dividing it by 2(k+2)n and sum all the pieces.
This yields

o ... 0 rank(x 2 ) o ... 0 rank (xl) o ... 0

~ ~ ~
(k+2) bits (k+2) bits (k+l) bits
94

The ranks are now easily retrieved and the sort is completed in time
O(n) • c

II. 4. The Linear Median Algorithm

Selection is a problem which is related to but simpler than sorting. We


are given a sequence S1, ••• ,Sn of pairwise distinct elements and an in-
teger i, 1 S i S n, and want to find the i-th smallest element of the
sequence, i.e. an Sj such that there are i-1 keys S~ with S~ < Sj and
n-i keys S~ with S~ > Sj. For i = n/2 such a key is called median. Of
course, selection can be reduced to sorting. We might first sort
sequence S1' ••• 'Sn and then find the i-th smallest element by a single
scan of the sorted sequence. This results in an O(n log n) algorithm.
However, there is a linear time solution. We describe a simple, linear
expected time solution (procedure Find) first and then extend it to a
linear worst case time solution (procedure Select).

Procedure Find is based on the partitioning algorithm used in Quicksort.


We choose some element of the sequence, say S1' as partitioning element
and then divide the sequence into the elements smaller than S1 and the
elements larger than S1. We then call Find recursively on the appropri-
ate subsequence.

(1) procedure Find(M,i);


co finds the i-th smallest element of set M;
(2) S +- some element of H;
(3) M1 +- {m E H; m < S} ;
(4) M2 +- {m E !II; m > S};
(5) ~ Ir1 1 I of
(6) < i - 1 Find (H 2 , i - IM11 - 1);
(7) i - return S;
(8) > i - Find(M 1 , i)
(9) esac
(10) end

When set M is stored in an array then lines (2) - (4) of Find are best
implemented by lines (2) - (6) of Quicksort. Then a call of Find has
cost O(IMI + the time spent in the recursive call). The worst case
running time of Find is clearly o(n 2 ). Consider the case i = 1 and
95

IM11 = IMI - 1 always. Expected running time of algorithm Find is


linear as we show next. We use the same randomness assumption as for
the analysis of Quicksort, namely the elements of M are pairwise dis-
tinct and each permutation of the elements of M is equally likely. In
particular, this implies that element S chosen in line (2) is the k-th
largest element of H with probability 1/IMI. It also implies that both
subproblems M1 and M2 again satisfy the randomness assumption (cf. the
analysis of Quicksort). Let T(n,i) be the expected running time of
Find(M,i) where IMI = n and let T(n) = max T(n,i).
i

We have T(1) c for some constant c and

i-1 n
T(n,i) ~ cn + 1/n[ L T(n-k, i-k) + L T (k-1, i) 1
k=1 k=i+1

since the partitioning process takes time cn and the recursive call
takes expected time T(n--k,i-k) if k = IH11 + 1 < i and time T(k-1,i)
if k = IM11 + 1 > i. Thus

i-1 n-1
T(n) ~ cn + 1/n max[ L T(n-k) + L T(k) 1
i k=1 k=i

We show T(n) ~ 4cn by induction on n. This is clearly true for n 1.


For n > 1 we have

n-1 n-1
T(n) ~ cn + 1/n max[ L4ck + L 4ckl
i k=n-i+1 k=i

~ cn + 4c/n max[n(n-1) - (n-i) (n-i+1)/2 - i(i-1)/21


i

~ 4cn

since the expression in square brackets is maximal for i (n+1)/2


(note that the expression is symmetric in i and n-i+1) and then has
value n(n-1) - n(n-1)/4 ~ 3n 2 /4. We have thus shown.

Theorem 1: Algorithm Find has linear expected running time.


96

The expected linearity of Find stems from the fact that the expected
size of the subproblem to be solved is only a fraction of the size of
the original problem. However, the worst case running time of Find is
quadratic because the size of the subproblem might be only one smaller
than the size of the original problem. If one wants a linear worst case
algorithm one has to choose the partitioning element more carefully. A
first approach is to take a reasonable size sample of M, say of size
IMI/s, and to take the median of the sample as partitioning element.
However, this idea is not good enough yet because the sample might
consist of small elements only. A better way of choosing the sample is
to divide M into small groups of say S elements each and to make the
sample the set of medians of the groups. Then it is guaranteed that a
fair fraction of elements are smaller (larger) than the partitioning
element. This leads to the following algorithm.

(1) proc Select(M,i);


£Q finds the i-th smallest element of set M;
(2) n - IMI;
(3) if n ~ 100 then sort M and find the i-th smallest element directly
else
(4) divide M in rn/ S' subsets M1 , •.• ,Mr n /S' of S elements each (the
last subset may contain less than S elements);
(S) sort M.; 1 ~ j ~ rn/S';
J
(6) let mj be the median of Mj ;
(7) call select({m1 , ••• ,m rn / S'}' r n/10') and determine m, the median
of the medians;
(8) let M1 = {m E M; m < m} and M2 {m E M; m ~ m};
(9) i f i ~ I M1 I
(10) then select(M 1 ,i)
(11) else select(M2 ,i - IM1 I)
fi
fi
end

It is very helpful to illustrate algorithm Select pictorially. In line


(4) M is divided into groups of S elements each and the median of each
group is determined in lines (S) and (6). At this point we have n/S
linear orders of S elements each. Next we find m,
the median of the
medians. Assume w.l.o.g. that m1 , .•• ,mn / 10 < m and m ~ mn/10+1, ..• ,mn/S.
This may be represented by the following diagram.
97

r.- -.'
I

• I

I
...: J mn/S

where each of the groups is represented by a vertical line of S ele-


ments, largest element at the top. (Note that all elements in the solid
rectangle are smaller than ill and hence belong to Ml and that all points
in the dashed rectangle are at least as large as m and hence belong to
M2 . Each rectangle contains 3n/l0 points, provided that 10 divides n.

Lemma 1: IMl I , I M2 ~ ~ 8nl 11 .

Proof: Almost immediate from the discussion above. Note that


IMll + IM21 = n and that IMl I, IM21 ~ 3n/l0 if 10 divides n. If 10 does
not divide n then IM11, IM21 ~ 3n/ll for n ~ 100. Details are left to
the reader. o

Let T(n) be the maximal running time of algorithm Select on any set M
of n elements and any i.

Lemma 2: There are constants a,b such that

T(n) ~ a·n for n ~ 100


T(n) ~ T(21n/loo) + T(8n/ll) + b·n for n ~ 100.

Proof: The claim is obvious for n ~ 100. So let us assume n ~ 100.


Select is called twice within the body of Select, once for a set of
rn/S' ~ 21n/loo elements and once for a set of size at most 8n/l1.
Furthermore, the total cost of Select outside recursive calls is clear-
ly O(n). o

Theorem 2: Algorithm Select works in linear time.

Proof: We sho"7 T(n) ~ c·n where c max(a,1100b/69) by induction on n.


98

For n ~ 100 there is nothing to show. For n > 100 we have

T(n) ~ T(21n/100) + T(8n/11) + bn


~ c 21n/100 + c 8n/11 + bn ~ cn

by definition of c. o

II. 5. Exercises

1) Let S[nl and P[1 .• nl be two arrays. Let p[1l, ••. ,P[nl be a permuta-
tion of the integers 1, .•. ,n. Describe an algorithm which rearranges S
as given by P, i.e. Safter[il = Sbefore[P[ill.

2) Write a Rru~-program for Heapsort and analyse it.

3) Is there a sequence of n numbers which forces Heapsort to use


2n(10g(n+1)-1) comparisons?

4) When discussing Heapsort we first derived a method which does not


keep the heap balanced. Analyse this variant of Heapsort. In particular,
treat the following questions. Is it possible to store the tree without
explicite father-son pointers? storage requirement of the method?
Number of comparisons? Running time on a RAM?

5) Discuss Heapsort based on ternary trees.

6) Procedure Quicksort is called at most n-1 times on a problem of size


n (use induction). Conclude, that the expected number of calls in
lines (7) and (8) are n/2-1 each. Also show that line (5) is executed
at most n/4 times on the average.

7) Translate Quicksort into RAM-code and analyse it. (Use exercise 6).

8) Do you recommend to modify Quicksort such that a separate list is


built for the elements Si with Si = S1? Assume that every element Si
occurs exactly k times in the initial sequence. At what value of k does
it payoff to partition into three sequences?

9) Solve the following recurrences:


99

a) 3/2
n log n for :s; n < 10
T{n) { In T{/n) + n 3/2
log n for n 2: 10

b) f{n) for :s; n < 100


T{n) { 2T{n/2) + f (n) for n 2: 100

Use f{n) n, f{n) n log n, f{n) n 3/ 2

c) In for :s; n < 10


T{n) { log n T{log log n) + In for n 2: 10

10) Write a RASP-program for Mergesort and analyse it.

11) Modify Quicksort such that sequences of length at most M are sorted
by repeatedly searching for the maximum. What is the best value for M.
(Compare the proof of theorem V.4.2.). Running time?

12) Would you recommend to use the linear median algorithm of section
11.4. in the partitioning phase of Quicksort?

13) Prove theorem 9 (of section 11.1.4.) for ternary trees.

14) Let T be any binary tree with n leaves. Interpret the tree as a
merging pattern and assume that all initial sequences have length 1. In
section 111.5.3.3., theorem 14 we give an algorithm which merges two
sequences of length x and y in time O{log{x+ y )). Show that the total
y
cost of merge pattern T is O{n log n).

15) Does theorem 11.1.6. 12 stay true if we allow exponentiation as an


additional operation?

n
16) For (x 1 ' .•• ,x n ) E R let f{x 1 , .•• ,x n ) = min{i; xi 2: Xj for all j}
be the maximum function. Use theorem 120f section II.1.6. to prove a
log n lower bound on the depth of rational decision trees for the
maximum function. Can you achieve depth O{log n)?

if x < 0
17) For n E~, x E IR let f{x) if 0 :s; x :s; n
if x > n
100

be the floor-function restricted to interval [0 •.• n]. Use theorem 12 to


prove a lower bound on the complexity of the floor function. Does theo-
rem12 stay true if the floor-function is added as an additional opera-
tion?

i
18) Let x , 1 $ i $ n, be words of length k over alphabet
L = {1, ••. ,m}. Discuss the following variant of bucketsort. In phase 1
the input set is divided into m groups according to the first letter.
Then the algorithm is applied recursively to each group. Show that the
worst case running time of this method is Q(n m k). Why does the German
postal service use this method to distribute letters?

19) Use Bucketsort to sort n integers in the range [o ••• n k ], k fixed,


in worst case time O(n) •

20) A program solves the nearest neighbour problem of size n if for all
inputs (x 1 , •.. ,x n 'Y1' ... 'Yn) the first n outputs produced by the pro-
gram are (x i1 ' ... 'x in ) where for all ~: i~ E {i; IXi-y~1 $ IXj-y~1 for
all j}. Show an n log n lower bound for the nearest neighbour problem
in the PRru~-model of section II.1.6. (Hint: for ~ a permutation of
{1, ••• ,n} say that (x 1 , .•• ,x n 'Y1' .•. 'Yn) is of order type ~ if for all
i,j: Ix (O)-Yo I
~ ~ ~
< Ixo-yo
J ~
I. Modify lemma 1 in the proof of theorem 1).

21) A program solves the searching problem of size n if for all inputs
(x 1 ,.·.,xn 'y) with x 1 < x 2 < ••• < xn it computes the rank of y, i.e.
it outputs I {i, xi < y} I. Prove an Q(log n) lower bound in the PRAM-
model of section II.1.6 ••

II. 6. Bibliographic Notes

Heapsort is by Williams (64) and Floyd (64). Hoare (62) developed


Quicksort and procedure Find. Sorting by merging and distribution was
already known to von Neumann and dates back to methods used on mechani-
cal sorters. Bucketsort as described here is due to Aho/Hopcroft/
Ullmann (74). Hybridsort is by Meijer/Akl (80). The treatment of re-
currences is based on Bentley/Haken/Saxe (80). Theorem 9 (of section
II.1.) is by Huffmann (52), the linear time implementation was described
by van Leeuwen (76). The sections on lower bounds are based on A.
Schmidt(82) (theorems 12-14 of II. 1.6) and Hong (79) (theorems 12-14 of II. 1.6
and theorem 1 of II. 3.), Paul/Simon (80) (theorems 1 and 2 of II. 3.),
and Ben-Or (83) (theorems 15 - 18 of II. 1.6). Weaker versions of
theorems 17 - 18 were obtained previously by Yao (81) and Strassen (73)
respectively. Finally, the linear time median algorithm is taken from
Blum/Floyd/Pratt/Rivest/Tarjan (72).
III. Sets

Many algorithms manipulate sets. We consider some typical examples.


A compiler uses a symbol table to keep track of the identifiers which
are used in the program. An identifier together with relevant infor-
mation (e.g. type, scope, address, ••• ) is entered into the symbol-
table when its declaration is processed by the compiler. Applied
occurences of the same identifier refer to the defining occurence;
the compiler has to access the symboltacle and to look up the rele-
vant information. More abstractly, a compiler deals with a set ST of
objects consisting of a name (key) and associated information. Two
kinds of operations are performed on the set ST. New objects (x,I)
are added to set ST, i.e. ST is replaced by ST U {(x,I)}, and the
objects are accessed via their key, i.e. given an identifier x we
want to find I such that (x,I) E ST. In most prograro~ing languages
identifiers are strings of letters and digits of some bounded length,
say at most length 6. Then the number of possible identifiers is
(26 + 10)6 ~ 109 ; in every program only a small subset of the set of
all possible identifiers is used. Set ST is small compared to the
very large universe of all possible identifiers.

A second example is the author catalogue of a library. The name of


the author is the key, the associated information are titles of books,
their locations on the shelf, ..•• This example exhibits all charac-
teristica of the problem above; however, at least one additional oper-
ation is performed on the set: print a library catalogue in ascending
lexicographic order.

Let us consider a third example: the set of accounts in a bank. The


account number is the key, the associated information is the holder
of the account, the balance, etc. Typical operations are Access,
Insert, Delete, List in ascending order; i.e. the same operations as
in our previous example. However, there is one major difference to
the previous examples: the size of the universe. A bank might have
5 • 10 5 different accounts and use account numbers with 6 decimal
digits, i.e. there are 106 possible account numbers and half of them
are actually used. The universe of possible keys and the set of keys
used are of about the same size. Graph algorithms (chapter IV) also
provide us with plenty of examples for this phenomenon.
103

We treat the case of drastic size difference between the universe and
the set stored first (sections 1 to 7) and discuss the case of equal
size later (section 8). The major difference between the solutions is
based on the fact that accessing an information via a key is a diffi-
cult problem in the first case, but can be made trivial in the second
case by the use of an array.

Sets consist of objects. An object is typically a pair consisting of


key (name) and information associated with the key. As in chapter II
we will concentrate on the key part and identify object and key.

Let S cUbe the subset of a universe U. We consider the following


operations:

Name of operation effect


Access (x,S) or if xES
Member(x,S) then the information associated with x
else a message, that x is not element
of S
Insert(x,S) S +- S u {x}
Delete(x,S) S +- S - {x}

Operations Insert und Delete change set S, i;e. the old version of set
S is destroyed by the operations. Operation names Access and Member are
used interchangeable; we will always use Member when the particular
application only requires yes/no answers.

For the following operations we assume in addition, that (U,~) is


linearly ordered.

Ord(k,S) the k-th element of the linear arrange-


ment of set S
List(S) a list of the elements of set S in ascen-
ding order.

Additional operations will be considered in later sections.

We know already one data structure which supports all operations men-
tioned above, the linear list of section 1.3.2 . . A set S={x 1 , ... ,x n }
1~

is represented as a list, whose i-th element is xi. All operations


above can be realized by a single traversal of the list and hence take
time O(n) in the worst case.

In this chapter we study data structures which are considerably more


efficient than linear lists. These data structures can be divided in
two large groups: comparison based methods (sections 3 to 7) and meth-
ods based on representation (sections 1 and 2). The former methods
only use comparisons (~, <, =,> ,~) between elements to gain informa-
tion, the latter methods use the representation of keys as strings
over some alphabet to gain information. Search trees and hashing are
typical representatives of the two classes.

III. 1. Digital Search Trees

III. 1.1 TRIES

One of the most simple ways to structure a file is to use the digital
representation of its elements; e.g. we may represent S = {121, 102,
211, 120, 210, 212} by the following TRIE

102 120 121 210 211 212

The general situation is as follows: the universe U consists of all


strings of length t over some alphabet of say k elements, i.e.
U = {O, ••. , k-1} t • A set S =
U is represented as the k-ary tree
consisting of all prefixes of elements of S. An implementation which
immediately comes to mind is to use an array of length k for every in-
ternal node of the tree. (We will see a different implementation in
section6.~. ~operations Access, Insert and Delete are very fastand
are very simple to program; in particular, if the reverse of all ele-
105

ments of S are stored (in our example this would be set {121, 201, 112,
021,012, 212}), then the following program will realize operation
Access (x)

v +- root;
y +- Xi
do t times (i,y) +- (y mod k, y div k)i
v +- i-th son of v
od;
if x CONTENT [v] then "yes" else "no".

This program takes time OCt) = O(logkN) where N = lUI. Unfortunately,


the space requirement of a TRIE as described above can be horrendous:
O(no't·k). For each element of set S, lSI = n, we might have to store
an entire path of t nodes, all of which have degree one and use up
space O(k).

There is a very simple method to reduce storage requirement to O(n·k).


We only store internal nodes which are at least binary. Since a TRIE
for a set S of size n has n leaves there will be at most n-1 internal
nodes of degree 2 or more. Chains of internal nodes of degree 1 are
replaced by a single number, the number of nodes in the chain. In our
example we obtain:
106

Here internal nodes are drawn as arrays of length 3. On the pointers


from fathers to sons the numbers indicate the increase in depth, i.e.
1 + the length of the eliminated chain of nodes of degree one. In our
example the 2 on the pointer from the root to the son with name b indi-
cates that after branching on the first digit in the root we have to
branch on the third (1 + 2) digit in the son. The algorithrr~ for
Access, Insert und Delete become slightly more complicated for com-
pressed TRIES but still run in time O(~).

Theorem 1: A compressed TRIE supports operations Access, Insert and


Delete with time bound O(logkN), where N is the size of the universe
and k is the branching factor of the TRIE. A set S of n elements re-
quires space O(k·n).

Proof: by the discussion above. c

Note that TRIES exhibit an interesting time space trade-off. Choosing


k large will make TRIES faster but more space consuming, choosing k
small will make TRIES slower but less space consuming. For static sets,
i.e. only operation Access is supported, we describe a further com-
pression technique below.

A disturbing fact about TRIES is that the worst case running time de-
pends on the size of the universe rather than the size of the set
stored. We will next show that the average case behaviour of TRIES is
O(logkn)~ i.e. average access time is logarithmic in the size of the

set stored. We use the following probability assumption:

Every subset S ~ U, lSI = n, is equally likely.

Theorem 2: Let E(d n ) be the expected depth of a k-ary compressed


TRIE for a set of n elements. Then

Proof: Let qd be the probability that the TRIE has depth d or more.
Then E(d ) = L qd. Let S = {x 1 , .• ,x } C U = {O, ••• ,k-1} be a subset
~
n d>1 n -
of U of size n7 The compressed TRIE for S has depth less than d if the
function trunc d _ 1 which maps an element of U into its first d-1 digits
is injective on S. Furthermore, trunc d _ 1 is an injective mapping on
107

set S iff {trunc d _ 1 (x), xES} is a subset of size n of {O, •• ,k_1}d-1.


d-1
Thus there are exactly (k ).k(~-(d-1»·n subsets S of size n of U
n
such that trunc d _ 1 is injective on S. Hence

n-1
1 - n (1_i/k d - 1 )
i=O

Next note that

n-1
Hn(1-i/k d - 1 )
n-1
n (1_i/k d - 1 ) i=O
e
i=O

J ~n (1-x/k d-1 ) dx
n

<': eO

The inequality follows from the fact that f(x) = ~n(1-x/kd-1) is a de-
i+1
creasing function in x and hence f(i) <': f f(x)dx. The last equality
i
can be seen by evaluating the integral using the substitution
x = k d - 1 (1-t). Hence

since eX - 1 <': x and hence 1 - eX ~ - x. Let c 2 r log k n'. Then


108

c
E (dn ) L qd + L qd
q=l d2':c+l

$ c + L n 2 /k d
d2':c

$ 2 r log k n' + (n 2 /k c ). L k- d
d2':O

$ 2 rl ogk n' + 1/ (1-1 /k) o

Theorem 2 shows that the expected depth of a random TRIE is at most


2 logk n + 0(1) and so the expected ACCESS-, INSERT- and DELETE-time
isO{(log n)/(log k». Space requirement is O(nok). Parameter k, the
basis of the digital representation, allows us to trade between space
and time.

III. 1.2 STATIC TRIES or Compressing Sparse Tables

In this section we show that the space requirement can be drastically


reduced for static TRIES without an increase in access time. Static
TRIES only support operation ACCESS. The reduction is done in two
steps. In the first step we describe a general overlay technique for
compressing large sparse tables. This technique is not only applica-
ble to TRIES but also to other areas where large sparse tables arise,
e.g. parsing tables. The first step reduces space requirement to
O(n log log n). In a second step we reduce the space requirement fur-
ther to O(n) by packing several numbers into one storage location.

A TRIE for a set of n elements requires space O(kon). There are at


most n-l internal nodes each of which requires storage for an array
of k elements. Of the (n-1)·k possible outgoing pointers at most 2n-2
will be non-nil, because the TRIE has n leaves and at most n-2 inter-
nal nodes unequal the root. This suggests to use an overlay technique
to reduce storage requirement (An alternative approach is discussed
in section 2. 3) •
109

In our example, we might use an array of length 10

0 2 3 4 5 6 7 8 9

I 1 1
I
1
I
1
I 11
I 11 I 12
I 12
I I
11
I
v v v v v v v v v
210 211 212 120 121 a b 102 c

to store all four arrays of length 3. The root node starts at loca-
tion 4, node a starts at 7, node b starts at 0 and c starts at loca-
tion 3. This information is stored in an additional table
a b c root

7 o 3 4

Suppose now that we search for 121. We follow the 1-st pointer out of
the root node, i.e. the pointer in location 4 + 1 of the large array.
This brings us to node a. Ne follow the 2-nd pointer out of a, i.e.
the pointer in location 7 + 2 of the big array which brings us to node
c, •..• It is also instructive to perform an unsuccessful search, say
to search for 012. Ne follow the O-th pointer out of the root, i.e.
the pointer in location 4 + O. This brings us to a leaf with content
121 *012. So 012 is not member of the set.

Ne will now describe one particular compression technique in more de-


tail. Let A be a r by s 0 - 1 matrix with exactly m entries equal to
one. Ne want to find small row displacements rd(i), 0 ~ i ~ q - 1,
such that A[i,j] = 1 = A[i' ,j'] and (i,j) *
(i',j') implies rd(i) + j
* rd(i') + j' for all pairs (i,j) and (i',j'), i.e. if we store the
i-th row of matrix A beginning at position rd(i) of a one-dimensional
array e[o .. ] then no two ones will collide. In our example the O's
correspond to the nil pointers and the 1's correspond to the non-nil
pointers. One method for computing the row displacements is the first-
fit decreasing method.

1) Sort the rows in nonincreasing order according to the number of


ones in the row, i.e. the row with the maximal number of ones
comes first.
2) Set rd(O) = O. For i ~ 1 choose rd(i) ~ 0 minimal such that no
collision with the previously placed rows 0 to i - 1 occurs.
110

In our example step 1 could produce the following matrix.

o 2 3 4 5 6 7 8 9
b: 1 1 1
c: 1 1 0
root: 0 1 1
a: 1 0 1

In step 2 we choose rd(b) = 0, rd(c) 3, rd(root) 4 and rd(a) = 7.


These choices are illustrated by the second matrix.

The first fit decreasing method produces small row displacements if


the ones of matrix A are evenly distributed across the matrix.

Theorem 3: Let m(~) be the total number of ones in rows of A which


contain ~ + 1 or more ones. Ifm(~) ~ m/(~+1) for all ~ then the first-
fit decreasing method produces row displacements rd(i) ~ m for
o ~ i ~ r - 1 in time O(romos).

Proof: Consider a row with exactly ~ ones. When that row is placed in
step 2 only rows with ~ ~ ones have been placed and hence the array C
can contain at most m(~-1) ones. Each such one can block at most ~

possible choices for the row displacement. Since ~·m(~-1) ~ m by as-


sumption we can always find rd(i) ~ m for all i, 0 ~ i ~ r-1.

It remains to prove the time bound. In time O(r·s) we compute the number
of ones in each row. Bucket sort will then sort the rows according to the
number of ones in time O(r+m). Finally, in order to compute rd(i) one
has to try up to m candidates. Testing one candidate takes time O(s).
We obtain a total of O(r·s + r+m + r·m·s) = O(r·m·s) time units. D

The hypothesis of theorem 3, the harmonic decay property, puts a severe


restriction on the distribution of ones in matrix A. We have m(1) ~ m/2
and thus at least half of the ones have to lie in rows with exactly
one entry equal to one. Also m(/m) < m/lm = /m and hence no row of A
can contain 1m or more ones. t1hat can we do if A does not have the
harmonic decay property? We try to find column displacements cd(j),
o ~ j ~ s-1, such that matrix B obtained from matrix A by displacing
columns has the harmonic decay property. Then we apply the previously
described compression technique to matrix B.
111

In our example we might choose cd(O) = 0, cd(1) = cd(2) 1 and obtain


the following 5 by 3 matrix B. We can now choose

o 2

o 1 o 2

1 1 1 cd 0

2 0 1 0

3 1 1 1

4 0 1

row displacements according to the first fit decreasing method. Note


that step 1 of that algorithm reorders the rows of B into order 1, 3,
0, 2, 4. Step 2 of that algorithm chooses rd(1) = 0, rd(3) = 3,
rd(O) 6, rd(2) 6 and rd(4) 6

o 2 3 4 5 6 7 8

o 1 0 0

1 1 1

2 0 1 0

3 1 1 1

4 0 0 1

and hence matrix C is the following array of length 9


o 2 3 4 5 6 7 8 9

The important fact to remember is that all ones of matrix A are mapped
on distinct ones of matrix C, namely A[i,j] = 1 implies A[i,j] =
= B[i + cd[j],j] = C[rd[i + cd[j]] + j]. The question remains how to
choose the column displacements? We will use the first fit method.
112

Let mj be the number of ones in columns O, ••. ,j of matrix A. We choose


cd(O), cd(1), •.. in that order. Suppose we have chosen cd(O), ... ,
cd(j-1) and applied these displacements to the first j columns of matrix
A. Let B. 1 be the matrix obtained in that way and let m. 1 (~) be the
J- J-
number of ones in rows of B j _ 1 with ~ + 1 or more ones. We want that
B = Bs - 1 has the harmonic decay property, i.e.

ms - 1 (0 ~ m/ (H1) for all ~ 2: 0

In order to ensure the harmonic decay property after all colunm dis-
placements have been chosen we enforce a more stringent restriction
during the selection process, i.e. we enforce

where f will be chosen later. The boundary conditions for fare


f(~,m 1) 2: ~ + 1 and f(O,m.) ~ m/m .. The former condition ensures the
s- J J
harmonic decay property at the end of the construction, the latter con-
dition makes sure that we can choose cd(O) = 0 and that the requirement
can be satisfied for ~ = O. Note that mj(o) = mj for all j and
mo(~) = 0 for ~ > o.

We use the first fit method to choose the column displacements: Choose
cd(O) O. For j > 0 choose cd(j) 2: 0 minimal such that
mj(~) ~ m/f(~,mj) for all ~ 2: O.

We need an upper bound on the values cd(j) obtained in that way. We ask
the following question: Consider a fixed ~ 2: 1. How many choices of
cd(j) may be blocked because of violation of requirement ~ : mj (~) ~

m/f(~,mj)? If a particular choice, say k, of cd(j) is blocked then

where mj(~) is computed using displacement k for the j-th column. Since
requirement ~ was satisfied after choosing cd(j-1) we also have

mj _ 1 (~) ~ m/ f ( ~ , mj -1 )
and hence

mJ. ( ~ ) - m. 1 (~)
J-
> m/ f ( ~ , mJ.) - m/ f ( ~ , mJ-
. 1)'
113

Let q = m/f(~,m.)
]
- m/f(~,m.
]-
1). We can interpret q as follows: In ma-
trix B j the number of ones in rows with ~ ~ + 1 ones is at least q
more than in matrix B.] - 1. We can count these q ones in a different way.
There are at least q/(~+1)pairs (a row of B.] - 1 with ~ ~ ones, a one in
column j) which are aligned when column displacement cd(j) = k is cho-
sen. Note that any such pair contributes either 1 (if the row of B j _ 1
has ~ ~ + 1 ones) or ~ + 1 (if the row of B.] - 1 has exactly ~ ones) to
q. Since the number of rows of B.] - 1 with ~ ~ ones is bounded by
m.] - 1 (~-1)/~ ~ m/~.f(l-1,m.
]-
1) and since the j-th column of A contains
exactly m.] - m.] - 1 ones the number of such pairs is bounded by

p : = (m.] -m ]. - 1)· m/ ( l· f (l-1 ,m·] - 1)).

Hence there are at most p/[q/(~+1)] possible choices k for cd(j) which
are blocked because of violation of requirement ~, ~ ~ 1. Hence the
total number of blocked values is bounded by

~o (H1)·(m. - m. 1)·m
] J-
BV

where ~O = min{~; m/f(~,mj_1) < ~}. Note that there are no rows of
B j _ 1 with ~ ~O ones and hence p (as defined above) will be 0 for ~ > ~O.

Hence we can we can always choose cd(j) such that 0 ~ cd(j) ~ BV.

It remains to derive a bound on BV. We rewrite the expression for BV


as follows:

(m. - m. 1) f (~,m.] - 1)
BV 2+1 ] ]-
~ (f(~,m. 1)/f(~,m.)-1) f(~-1,mj_1)
]- ]

This expression involves only quotients of f and therefore we set


g(~,m. )
f (~, T:l j ) 2 ] for some function g to be chosen later. 1'1e obtain

~o
2+1
(m j - mj _ 1 ) g (~,Iaj_1) -g (~-1 ,m j _ 1 )
BV L 2
~=1
~ g(~,m'_1)-g(~,miJ
(2] -'-1)

~O (m j - m,] - 1)
~ L
~+1
-~-
(g (~,m, 1) g(~,mj)) ·~n 2
. 2]-
g(l,m. 1)-9(~-1,m. 1)
1-
~=1 ]-
114

since 2 x -l 2 x·tn 2. Next we note that the two differences involve on-
ly one argument of g. This suggests to set g(t,m j ) = h(t)·k(m j ) for
functions hand k to be chosen later. The upper bound for BV simpli-
fies to

(m j - mj _ l ) ·2(h(O-h(t-l».k(m j _ l )
.Hl
t h(t) (k(m j _ l ) k(mj»tn 2

This sum will further simplify if we choose hand k to be linear func-


tions, say h(t) = t and k(rn j ) = (2-m j /m) ~ 2. Then

£0 (m j - m. 1)
Hl J- 22
BV ~ L
t t· (m/m m. 1 /m) . tn 2
t=l J-

to to to
~ L (4/ln 2)m. (Hl)/t 2 (4 ·m/ £n 2) ( L l/t + L 1/ £ 2)
t=l t=l £=1

~ (4·m/tn 2) (tn to + 1 + n 2 /6)

to
since L l/t ~ 1 + tn to (cf. appendix) and L 1/t 2 n 2 /6
9,=1 9,21

~ 4·m·log £0 + 15.3 m

Finally notice that f(9"m.) = 29,· (2-m j /m) 2 29, and therefore 9,0 ~ log m.
9, J 0
Also f(9"m s _ l ) = 2 2 9,+ 1 for all £ and f(O,m j ) = 2 = 1 ~ m/m j for
all j and so f satisfies the boundary conditions. Thus we can always
find cd(j) such that 0 ~ cd(j) ~ 4·m·loglog m + 15.3·m.

Theorem 4: Given a matrix A[O .. r-l, O .. s-l] with m nonzero entries one
can find colurnn displacements cd(j), 0 ~ j ~ s-l, such that
o ~ cd(j) ~ 4·m.loglog m + 15.3m and such that matrix B obtained from A
using those displacements has the harmonic decay property. The column
displacements can be found in time Oeser + m.loglog rn)2).

Proof: The bound on the column displacements follows from the discus-
sion above. The time bound can be seen as follows. For every row of B.
J
we keep a count on the n~mber of ones in the row and we keep the num-
115

bers mj(i) and mj • In order to find cd(j+1) we have to test up to


4·m·loglog m + O(m) possible values. For each candidate we have to up-
date the m.(i) 's in time O(r + m·loglog m) and to test for violation
J
of requirement ~, 1 ~ ~ ~ ~O' in time O(~O) = O(log m). Hence the to-
tal time spent on computing the column displacements is
o (s· (r+m.loglog m) 2) . 0

Let us put theorems 3 and 4 together. Given a matrix A[0 .• r-1, 0 .. s-1]
with m nonzero entries, theorem 4 gives us column displacements cd(j),
o ~ j < s, and a matrix B such that

A[i,j] *0 implies B[i+cd(j) ,j] A[i,j]

B has s columns and r' ~ r + 4·m·loglog m + 15.3·m rows. Of course, B


has at most m rows with at least one nonzero entry. Next we apply theo--
rem 3 and obtain row displacements rd(i), 0 ~ i < r' and a one-dimen-
sional matrix C such that

B[h,j] * 0 implies C[rd(h)+j] B[h,j]

or in other words

A[i,j] * 0 implies C[rd(i+cd(j»+j] A[i,j] .

Since B has only m nonzero entries there are at most m different h's
such that rd(h) * o. Furthermore, array C has length at most m + s
since rd(h) ~ m for all h.

So far, we obtained the following reduction in space: C uses m + s


storage locations, cd uses s storage locations and rd uses
r' ~ r + 4·m·loglog m + 15.3·m storage locations.

Let us apply our compression technique to a TRIE for a set of n ele-


ments with branching factor k ~ n; k = n will give the best result with
respect to access time. We can view the array representation of the
internal nodes as an r, r ~ n - 1, by s, s = k, array with ~ 2n - 2
non-nil entries. Compression gives us a matrix C with O(k + n) = O(n)
locations, a set of k = O(n) column displacements and a set of
O(n·loglog n) row displacements. So total space requirement is
O(n·loglog n).
116

The entries of arrays rd, cd and C are numbers in the range 0 to O(n),
i.e. bitstrings of length ~ log n + 0(1). As we observed above, array
rd has ~ c n loglog n entries for some constant c all but 2n of which
are zero. We will next describe a compression of vector rd based on
the following assumption: A storage location can hold several numbers
if their total length is less than log n.

Let i o ' i 1 , ••• , i t - 1 , t ~ 2 n - 2, be the indices of the nonzero ele-


ments of vector rd. We compress vector rd into a vector crd of length
t by storing only the nonzero entries, i.e. crd[~] = rd[i~] for
o ~ ~ ~ t - 1. It remains to describe a way of finding ~ given i~.

Let d = Lloglog n J • We divide vector rd into c·n·loglog n/d ~ 2'c'n


blocks of length d each. For each block we write down the minimum ~

such that i~ lies in that block, if any such ~ exists. This defines a
vector base of length 2.c·n. For any other element of a block we store
the offset with respect to ~ in a two-dimensional array offset, i.e.

I
min {~; i~ div d v} v
base[v]

- 1 otherwise

for 0

offset[v,j]
~ v < 2·c·n and

I - ~ base [v] if v.d + j i9, for some 9,

- 1 otherwise

for 0 ~ j < d.

Then rd[h] = 0 iff offset [h div d, h mod d] = - 1 and rd [h] * 0 im-


plies rd[h] = crd[base[h div d] + offset[h div d, h mod d]].

For any fixed v, offset[v, ] is a list of d numbers in the range


- 1, .•. , d - 1. We combine these numbers into a single number off [v]

d-1
by off[v] L (offset[v,j] + 1)(d + 1)j
j=O
117

Then 0 ~ off[v] ~ (d + 1)d ~ n and thus off[v] fits into a single stor-
age location. Also

offset[v,j] = ((off[v] div(d+1)j) mod(d+1)) - 1

and so offset[v,j] can be computed in time 0(1) from off[v] and a table
of the ~rs of d + 1. Altogether we decreased the space requirement to
O(n), namely O(n) each for arrays crd, base and off, and increased
access time only by a constant factor.

We illustrate these definitions by an example, d 3,


i2 = 5 and i3 11.

rd: [0 1 0 11 0 1 I0 0 0 10 0 1
Then

crd: rd ( 1) Ird (3) rd (5) I


rd ( 11 ) I
base: o -1 3

offset:
-1 0 -1

0 -1 1 and off: 33

-1 -1 ~1 o
-1 -1 0 16

Note that off[ll = (1 + offset[1,0]) '4 0 + (1 + offset[1,1]) '4 1 +


+ (1 + offset[1,2]).4 2 = 1 . 4 0 + 0 . 4 1 + 2 4 2 = 33.

Theorem 5: Let 8 c U, 181 = n and lUI = N. Then a n-ary TRIE supports


operation Access in time O(logn N) worst case and 0(1) expected case.
The TRIE can be stored in O(n) storaqe locations (of O(log n) bits each).

Proof: The time bound follows from theorems 1 and 2. The space bound
follows from the preceding discussion. o
118

We will improve upon theorem 5 in section 111.2.3. on perfect hashing


and show how to obtain 0(1) access time in the worst case. We included
theorem 5 because the compression technique used to prove theorem 5 is
of general interest. In particular, it compresses large spa~se tables
without seriously degrading access time. Note that an access to array A
is replaced by an access to three arrays rd, cd and c and only a few
additions, at least as long as we are willing to tolerate the use of
O(n log log n) storage locations.

III. 2. Hashing
The ingredients of hashing are very simple: an array T[0 •• m-1], the
hash table, and a function h U ~ [0 .• m-1], the hash function. U is
the universe; we will assume U [0 .• N-1] throughout this section. The
basic idea is to store a set S as follows: xES is stored in T[h(x)].
Then an access is an extremely simple operation: compute h(x) and look
up T[h(x)].
Suppose m = 5, S = {03, 15, 22, 24} c [0 .• 99] and h(x) x mod 5. Then
the hash table looks as follows:

o 15

2 22

3 3

4 24

There is one immediate problem with this basic idea: what to do if


h(x) = h(y) for some x, yES, x *
y. Such an event is called a colli-
sion. There are two main methods for dealing with collisions: chaining
and open adressing.

III. 2.1 Hashing with Chaining

The hash table T is an array of linear lists. A set S c U is represented


as m linear lists. The i-th list contains all elements xES with
h(x) = i.
119

The following figure shows the representation of set S = {1,3,4,7,10,


17,21} in a table of length m = 3. We use hash function h(x) =x mod 3.

0 3
II 21 It-II
II 4 II 7 II 10 IHI
2 17
H
Operation Access(x,S) is realized by the followinq oroqram:
1) compute h (x)
2) search for element x in list T[h(x)]

Operations Insert(x,S) and Delete(x,S) are implemented similarly. We


only have to add x to or delete x from list T[h(x)]. The time complexi-
ty of hashing with chaining is easy to determine: the time to evaluate
hash function h plus the time to search through list T[h(x)]. We as-
sume in this section that h can be evaluated in constant time and
therefore define the cost of an operation referring to key x as
0(1 + 0h(x,S» where S is the set of stored elements and

, and

if hex) = h(y) and x *y


0h(x,y) = {1
o otherwise.

The worst case complexity of hashing is easily determined. The worst


case occurs when the hash function h restricted to set S is a constant,
i.e. h(x) = iO for all xES. Then hashing deteriorates to searching
through a linear list~ anyone of the three operations costs O(ISI)
time units.

Theorem 1: The time complexity (in the worst case) of operations


Access(x,S), Insert(x,S) and Delete(x,S) is O(ISI).

Average case behaviour is much better. We analyse the complexity of a


sequence of n insertions, deletions and accesses starting with an empty
120

table, i.e. of a sequence OP1 (x 1 ),···, OPn(xn ), where OPk E{Insert,


Delete, Access} and ~ E U, under the following probability assumptions
(we will discuss these assumptions later).

1) Hash function h : U ~ [0 ••• m-1] distributes the universe uniformly


over the interval [0 ••• m-1], i.e. for all i, i' E [0 ••• m-1] :
Ih- 1 (i)1 = Ih- 1 (i')I.

2) All elements of U are equally likely as argument of anyone of the


operations in the sequence, i.e. the argument of the k-th operation
of the sequence is equal to a fixed x E U with probability 1 I I U I •

Our two assumptions imply that value h(~) o~ the hash function on
the argument of the k-th operation is uniformely distributed in
[0 ••• m-1], i.e. prob(h(xk ) = i) = 11m for all k E [1 ••• n] and
i E [0 ••• m-1].

Theorem 2: Under the assumptions above, a sequence of n insertions, de-


letions and access-operations takes time 0((1 + BI2)n) where B = n/m
is the (maximal) load factor of the table.

Proof: We will first compute the expected cost of the (k+1)-st oper-
ation. Assume that h(xk + 1 ) = i, i.e. the (k+1)-st operation accesses
the i-th list. Let prob(tk(i) = j) be the probability that the i-th
list has length j after the k-th operation. Then

L prob(tk(i) j) (1+j)
j2:0

is the expected cost of the (k+1)-st operation. Next note that

prob(tk(i) = j) ~ (~) (1/m)j(1-1/m)k-j (with equality if the first k


operations are insertions) and hence

k . k-·
~ 1 + L (j) (11m) ] (1-1/m) J. j
j2:0

1 + (kim) L
j 2:1

1 + kim
121

Thus the total expected cost of n operations is

n n
L EC k O( L (1+(k-1)/m))
k=1 k=1

0(1 + Bn/2) o

We will next discuss the probability assumptions used in the analysis


of hashing. The first assumption is easily satisfied. Hash function h
distributes the universe U uniformly over the hash table. Suppose
U = [0 .•. N-1], and miN. Then h(x) = x mod m will satisfy the first re-
quirement (division method). If m does not divide N but N is much
larger than m then the division method almost satisfies assumption 1);
theorem 2 stays true.

The second assumption is more critical because it postulates a certain


behaviour of the user of the hash function. In general, the exact con-
ditions of latter use are not known when the hash function is designed
and therefore one has to be very careful about applying theorem 2. We
discuss one particular application now and come back to the general
problem in the sections on perfect and universal hashing.

Symboltabels in compilers are often realized by hash tabels. Identifiers


are strings over the alphabet {A,B,C, ... }, i.e. U = {A,B,C, ... }*. The
usage of identifiers is definitely not uniformly distributed over U.
Identifiers 11, 12, 13, J1, ... are very popular and XYZ is not. We can
use this nonuniformity to obtain even better behaviour than predicted
by theorem 2. Inside a computer identifiers are represented as bit-
strings; usually 8 bits (a byte) is used to represent one character.
In other words, we assign a number num(C) E [0 ... 255] to each character
of the alphabet and interpret a string Cr Cr _ 1 ... CO as a number in base
r .
256, namely . L num(C.)· 256~ ..; moreover, consecutive numbers are usually
~=O ~
assigned to Characters 1,2,3, . . . . Then strings 10, 11, 12, and XO, X1,
X2 lead to arithmetic progressions of the form a + i and b + i respec-
tively where i = 0,1,2, ..• and 2561(a-b). Because identifiers of the
form 10, 11, 12, and XO, X1, X2 are used so frequently, we want

h(a + i) * h(b + j) for 0 ~ i,j ~ 9 and 2561 (a-b)


122

i.e. if hex) = x mod m then we want

(b - a)+(j - i) *0 mod m

Since 2561(b - a) we should choose m such that m does not divide numbers
of the form 256· C + d where I dis; 9. In this way one can obtain even
better practical performance than predicted by theorem 2.

load factor
0.5 0.6 0.7 0.8 0.9
access
time

experiment 1 .19 1 .25 1. 28 1. 34 1.38

theory 1. 25 1 .30 1. 35 1.40 1. 45

(the expected behaviour of hashing (Lum (1971».

Assumption 2) is not the only problem with hashing as we described it.


The expected behaviour of hashing depends on the load factor B = n/m.
An operation can be executed in time 0(1) if B is bounded by a constant.
This implies that either one has to choose m large enough to begin
with or one has to increase (decrease) the size of the hash table from
time to time. The first solution increases storage requirement, which
in many environments also implies an increased running time. If the hash
table is too large to be stored in main storage, then a small load fac-
tor will increase the number of page faults.

In the second case we can use a sequence TO' T 1 , T 2 , .•• of hash tables
of size m, 2m, 4m, •.• respectively. Also, for each i we have a hash
function hi. We start with hash table TO. Suppose now, that we use
hash table Ti and the load factor reaches 1 or 1/4. In the first case,
we move to hash table T i + 1 by storing all 2im elements which are pres-
ent in Ti in table Ti + 1 • On the average, this will cost 0(2 i m) time
units. Also, the load factor of table T i + 1 is 1/2 and therefore we can
i+1 .
execute at least (1/4)·2 ·M = (1/2) .2 l .m operations until the next
restructuring is required. In the second case, we move to hash table
Ti _ 1 by storing all (1/4) .2 i ·m elements which are pr~sent in Ti in
table T.l - 1. On the average, this will cost 0«1/4) ·2 l ·m) time units.
Also, the load factor of table Ti - 1 is 1/2 and therefore we can execute
123

at least (1/4) ·2 i - 1 .m operations without any further restructuring. In


either case, the cost of restructuring is twice the number of subse-
quent operations which can be performed without further restructuring.
Hence we can distribute (conceptually) the cost of restructuring to
the operations following it but preceding the next restructuring proc-
ess. In this way we will assign cost 0(1) to each operation and so the
average cost of an operation is still 0(1). Also the load factor is al-
ways at least 1/4 (except when table TO is in use) .

We continue this~sectian with a remark on operations Ord(k,S) and List(S).


Since the elements of set S are completely scattered over the
hash table T both operations cannot be realized at reasonable cost. One
of the main applications of operation List(S) is batching of requests.
Suppose that we want to perform n1 operations Access, Insert, Delete on
set S. Instead of performing n 1 single operations it is often better to
sort the requests by the key referred to and to ~erform all requests by
a single sweep of set S. If set S is stored in a hash table we may still
use this method. We apply the hash function to the requests and sort the
requests by the hashed key. Then we process all requests during a sin-
gle scan through the hash table.

We close this section with a second look at the worst case behaviour
of hashing and discuss the expected worst case behaviour of hashing
with chaining. Suppose that a set of n elements is stored in the hash
table. Then max 0h(x,S) is the worst case cost of an operation when set
xEU
S is stored. We want to compute the expected value of the worst case
cost under the assumption that S is a rand8m subset of the universe.
More precisely, we assume that S = {x 1 ' •.. ,x n } and that
prob(h(x k ) = i) = 1/m for all k E [1 .•• n] and i E [0 •.• m-1]. The very
same assumption underlies theorem 2.

Theorem 3: Under the assumption above, the expected worst case cost of
hashing with chaining is O«log n)/log log n) provided that S = n/m $ 1.

Proof: Let t(i) be the number of elements of S which are stored in the
i-th list. Then prob(t(i) :::: j) $ (t;l)(1/m)j. Also
J

m-1
prob «max t(i)) :::: j) $ ~ prob(t(i) :::: j)
i i=o
124

'-1
5 n(n/m)] (1/j!)

Thus the expected worst case cost EloVe, i.e. the expected lenth of the
longest chain, is

Ewe ~ prob «max l?, (i) ) 2': j)


j2':1 i

, -1
5 ~ min(1, n(n/m)] (1/j!»
j 2':1

Let jo = min (j; n(n/m)j-1 (1/j)! 5 1} 5 min (j; n 5 j!} since n/m 5 1.
From j! 2': (j/2)j/2 we conclude jo = O«log n)/log log n). Thus

jo j-j
Ewe 5 ~ 1 + r 1/j 0
j=1 j>jo 0

O«log n)/log log n). o

III. 2.2 Hashing with Open Addressing

Each element x E U defines a sequence h(x,i), i 0, 1, 2, •.. of table


positions. This sequence of positions is searched through whenever an
operation referring to key x is performed.

A very popular method for defining function h(x,i) is to use the linear
combination of two hash functions h1 and h 2 :

h (x, i) = [h 1 (x) + i h2 (x)] mod m

We illustrate this method by an example; let m = 7, h1 (x) = x mod 7


and h2 (x) = 1+(x mod 4) . If we insert 3, 17, 6, 9, 15, 1 3, 10 in that
order, we obtain
0
1
h(3,i) (3 + 4i) mod 7, i 0 works
2
h(17,i) (3 + 2i) mod 7, i works 3
4
h(6,1) (6 + 3i) mod 7, i 0 works
5
h(9,i) (2 + 2i) mod 7, i 0 works 6
125

h(15,i) (1 + 4i) mod 7, i o works


h(13,i) (6 + 2i) mod 7, i 4 works
h(10,i) (3 + 3i) mod 7, i 5 works

Hashing with open addressing does not require any additional space.
However, its performance becomes poorly when the load factor is nearly
one and it does not support deletion.

We analyse the expected cost of an operation Insert(x) into a table


with load factor B = n/m under the following assumption: Sequence
h(x,i), i = 0, 1, ... , m-1 is a random permutation of the set
{a, .•. , m-1}. The cost of operation Insert(x) is 1 + min {i; T[h(x,i)]
is not occupied}.

Theorem 4: The expected cost of an Insert into a table with load fac-
tor B = n/m is (m+1)/(m-n+1) ~ 1/(1-B) provided that n/m < 1.

Proof: Let C(n,m) be the expected cost of an Insert into a table with
m positions, n of which are occupied. Let qj (n,m) be the probability
that table positions h(x,a) , •.. , h(x,j-1) are occupied. Then
qo(n,m)= 1, qj(n,m) = [n/m]·[(n-1)/(m-1)]. .. [(n-(j-1»/(m-(j-1)] and

n
C(n,m) L (q, (n,m) - gJ'+1 (n,m» (j+1)
j=oJ

n
L qJ' (n,m) - (n+1)qn+1 (n,m)
j=a

n
L gJ' (n,m) •
j=a

The expression
- for q,
-J (n,m) can be J'ustified as follows. Position h(x,a)
is occupied in n out of m cases. If h(x,a) is occupied then position
h(x,1) is occupied in n-1 out of m-1 cases (note that h(x,1) * h(x,O», ...
We prove C(n,m) = (m+1)/(m-n+1) by induction on m and for fixed m by
induction on n. Note first that C(a,m) = qa(a,m) = 1. Next note that
qj (n,m) = (n/m) ·qj-1 (n-1 ,m-1) for j ~ 1. Hence
126

n
C(n,m) L qJ' (n,m)
j=O

n-1
1 + (n/m)· L q, (n-1 ,m-1)
j=O J

1 + (n/m)·C(n-1,m-1)

1 + (n/m) ·m/(m-n+1)

(m+1)/(m-n+1) o

The expected cost of a successful Access operation is now easy to de-


termine. Suppose that set S is stored. When Access(x), xES, is exe-
cuted we step through sequence h(x,O), h(x,1), .•• until we find an i
with T[h(x,i)] = x. Of course, the very same i determined the cost of
inserting element xES in the first place. Hence the expected cost of
a successful search in a table with n elements is

n-1 n-1
L C(i,m) L m+1
n i=O n i=O (m-i+1)

m+1 m-n+1
m+1
n
[ L 1/j - L 1/j]
j=1 j=1

~ (1/B).tn[(m+1)/(m-n+1)]

~ (1/ B) • tn 1/ ( 1- B)

Theorem 5: The expected cost of a successful search in a table with


load factor B = n/m is O«1/B)tn(1/(1-B»).

Proof: By the discussion above. o

Theorems 4 and 5 state that Insert and Access time will go up steeply
as B approaches 1, and
127

B 0.5 0.7 0.9 0.95 0.99 0.999

1/(1-8) 2 3.3 10 20 100 1000

( 1 /8) Q,n ( 1- 8 ) 1 .38 1. 70 2.55 3.15 4.65 6.9

that open addressing works fine as long as 8 is bounded away from one,
say 8 ::; 0.9.

III. 2.3 Perfect Hashing

We based our analysis of the expected performance of hashing with


chaining on two assumptions, the second of which is very critical. It
postulates uniformity on the key space, an assumption which is almost
always violated. However, we saw in section 2.1. that it is possible to
tune the hash function according to the bias which is present in the
key space. In this section we will consider the ultimate form of tun-
ing. Set S is known when hash function h is chosen, h is chosen such
that it operates injectively on S.

Definition: a) A function h : [0 .•• N-1] ~ [0 •.• m-1] is a perfect hash


function for S c [0 ••• N-1] if h(x) * h(y) for all x,y E S, x * y.
b) A set H of functions h : [0 .•• N-1] ~ [0 ..• m-1] is called
(N,m,n) - perfect (or perfect for short) if for every S c [0 .•• N-1],
lSI = n, there is h E H such that h is perfect for S. Q

Of course, every set S has a perfect hash function. In our example of


the beginning of section 2 we can take h(x) = (last digit of x) mod 4.
The most interesting questions concerning perfect hash functions are:

a) How large are the programs for perfect hash functions, i.e. is there
always a short program computing a perfect hash function?

b) How hard is it to find a perfect hash function given S, m and N?

c) How hard is it to evaluate perfect hash functions?

In this section we will essentially answer all three questions


completely. We first have to give a more precise definition of
program size. The size of a program is just
128

the length of the program written as a string over some finite alpha-
bet. We prove upper bounds on program size by exp1icite1y exhibiting
programs of a certain length. We prove lower bounds on program length
by deriving a lower bound on the number of different programs required
and then using the fact that the number of words (and hence programs)
of length ~ L over an alphabet of size c is ~ c L + 1 /(c_1).

Theorem 6: Let N,m,n E IN and let H be a (N,m,n) - perfect class of


hash functions. Then

a) IHI

b) IHI ~ log N/1og m

c) There is at least one S ~ [O ••• N-1], lSI = n, such that the length
of the shortest program computing a perfect hash function for S is

n(n-1) n(n-1)
max (2m fu 2 2N )/,n 2 (1 - ~,
n-1) 1 og 1 og N - 1 og 1 og m)/1 og c - 1 ,

here c is the size of the alphabet used for coding programs.

Proof: a) There are (~) different subsets of [O ••• N-1] of size n. It


therefore suffices to show that any fixed function h : [O ••• N-1] ~

[O ••• m-1] is perfect for at most (N/m)n. (m) different subsets


n -1
S ~ [O ••• N-1], lSI = n. If h is perfect for S then Ih (i) n SI ~ 1
for all i E [O •.. m-1]. Hence the number of sets S such that h is per-
fect for S is bounded by

Ih- 1 (i )1
n

This expression is maximal if Ih- 1 (i) I N/m for all i E [O ••• m-1] and
its value is equal to (N/m)n.(m) in this case.
n

b) Let H = {h 1 , ••• , h t }. We construct Ui ~ U, 0 ~ i ~ t, such that for


every S ~ u, Is n Uil ~ 2, functions h 1 , .•• , hi are not perfect for S.
Then we must have IUtl ~ 1. Let Uo = U and

for i < t
129

-1 -1
where j is such that lUi n h i + 1 (j) I ~ lUi n h i + 1 (t) I for every

t E [O ••• m-1]. Then IU i + 1 1 ~ IUil/m and hence IU i + 1 1 ~ N/mi+1. Also


functions h 1 , ••• , h'+1 are constant on Ui + 1 and hence IUtl ~ 1. Thus
t 1
1 ~ N/m or t ~ log N/log m.

c) Let LBa and LBb be the lower bounds for IHI proven in parts a) and
b). Since there are at most c L+ 1 different programs of length ~ Land
different functions require different programs we conclude that there
is at least one S c [O ••• N-1], lSI = n, such that the shortest proqram
computing a perfect hash function for S has length
max(log LBa, log LBb)/log c - 1. But

log LBb log log N - log log m

and
N .•• (N-n+1) .mn
log ~~~~~~~~--
log LBa
Nn m· " . (m-n+1)

n-1 N ,n-1 ,
log [n ~/ n m-1]
i=O N i=O m

n-1 n-1
= [ L tn(1-i/N) - L tn(1-i/m)]/tn 2
i=O i=O

n-1 n-1
~ [(1 - n-l). L (i/N) + L (i/m)]/tn 2
N i=O i=O

since tn(1-i/m) ~ - i/m and hence tn(1-i/m) ~ i/m and tn(1-i/N) ~

- (i/N) (1- (n-1) /N) for 0 ~ i ~ n-1 (cf. appendix)

~ n' (n-1)/2m·tn 2 - n· (n-1)· (1-(n-1)/N)/(2.N.tn 2) 0

Informally, we can state part c) of theorem 6 as follows. The length


of the shortest program for a perfect hash function is at least
[(S/(2 tn 2»·n + log log N]/log c, i.e. there is an initial cost
log log N due to the size of the universe and there is an incremental
cost of S/ (2 tn 2) bits per element stored. The incremental cost de-
pends on the load factor B = n/m.
130

How good is that lower bound? We give our answer in two steps. We will
first show by a non-constructive argument that the lower bound is al-
most achievable (theorems 7 and 8). Unfortunately, the programs con-
structed in theorem 8 are extremely inefficient, i.e. theorem 8 settles
question a) concerning the program size of perfect hash functions but
does not give convincing answers to questions b) and c). In a second
step we will then derive answers for questions b) and c) •

Theorem 7: Let N, m, n E IN. If

then there is a (N,m,n) - perfect class H with IHI t.

Proof: We may represent any class H = (h l , ••. , h t } by a N by t matrix


M(H) = (hol (x»O< <N-l l<o<t
_x_, _l_ with entries in [O ••. m-l], i.e. the i-th
column of matrix M(H) is the table of function values for hi. Converse-
ly, every N by t matrix M is the representation of a class H of hash
functions. There are mN • t matrices of dimension N by t with entries in
[0 •.. m-l ].

We want to derive an upper bound on the number of non-perfect matrices,


i.e. matrices which correspond to non-perfect classes of hash functions.
If H does not contain a perfect hash function for S = (xl < x 2 <... <xJ,
then the submatrix of M(H) given by rows Xl' x 2 ' ..• , xn cannot have a
column with n different values. Hence the columns of that submatrix can
be chosen out of mn - m(m-l) ..• (m-n+l) possibilities (namely, the num-
ber of functions from n points into a set of m elements minus the num-
ber of injective functions), and hence the number of such submatrices
is bounded by [mn - m(m-l) .•. (m-n+l)]t. Recall that the submatrix has
t columns. Since S can be chosen in (N) different ways, the number of
n
non-perfect matrices is bounded by

(N) [mn _ m(m-l) .•. (m-n+l)]t m(N-n).t


n

Note that the rows corresponding to elements not in S may be filled ar-
bitrarily. Thus there is a perfect class H, IHI = t, if
131

(~) [mn _ m(m-1) •.• (m-n+1)]t m(N-n)·t < mN·t

or

or

t ~ (~n(N»/(_ ~n(1 - m(m-1) ••• (m-n+1)/mn »


n

n-1
8ince ~n(N) ~ n'~n N, - ~n(1 - m(m-1) ••• (m-n+1)/mn ) ~ n ( 1-i/m)
n
i=O
n-1
L ~n(1-i/m)
n-1 n
i=O
e and L ~n(1-i/m) ~ f ~n(1-x/m)dx =
i=O 0
m[ (1-n/m) (1-~n(1-n/m) )-1] ~ m[ (1-n/m) (1+n/m)-1] = n2/m there will be a
perfect class H with IHI = t provided that

2
t ~ n' (~n N) • en /m [J

Theorem 7 gives us an upper bound on the cardinality of perfect clas-


ses of hash functionsj it does not yet give us an upper bound on pro-
gram size. The upper bound on program size is given by the next theo-
rem.

Theorem 8: Let N,m,n E IN. For every 8 c [0 ..• N-1], 181 n, there is
a program of length

0(n 2 /m + log log N + 1)

which computes a perfect hash function h [0 •.• N-1] .... [0 ..• m-1] for 8.

Proof: We will explicitely describe a program. The program implements


the proof of theorem 7 j it has essentially 4 lines:

(1) k r~n N' written in binarYj


r 2/ '
(2) t n.k'e n m written in binary;

(3) i some number between 1 and t depending on 8 written in binary;

(4) search through all 2k by t matrices with entries in [0 •.• m-1] until
a (N,m,n) - perfect matrix is found; use the i-th column of that
matrix as the table of th~ hash function for 8j
132

The correctness of this program is immediate from theorem 7 ; by theo-


rem 7 there is a 2k by t perfect matrix and hence we will find it in
step (4). One column of that matrix describes a perfect hash function
for S, say the i-tho We set i to the appropriate value in line (3).

The length of this program is log log N + 0(1) for line (1), log n +
log log N + n2/m + 0(1) for lines (2) and (3) and 0(1) for line (4).
Note that the length of the text for line (4) is independent of N, t
and m. This proves the claim. o

Theorems 6 and 8 characterize the program size of perfect hash functions;


upper and lower bounds are of the same order of magnitude. Unfortunate-
ly the program constructed in theorem 8 is completely useless. It runs
extremely slow and it uses an immense amount of work space. Therefore,
we have to look for constructive upper bounds if we also want to get
some insight on questions b) and c).

Our constructive upper bounds are based on a detailed investigation of


the division method for hashing. More precisely, we consider hash func-
tions of the form

x - « kx) mod N) mod m

where k, 1 ~ k < N, is a multiplier, N is the size of the universe and


m is the size of the hash table. The following lemma is crucial.

Lemma 9: Let N be a prime, let S c [0 •• • N-1], IS I n. For every k,


1 ~ k < N, and mEN let

b~1 I {x E S; «kx) mod N) mod m i} I

for 0 ~ i < m.

m-1 k
a) For every m there is a k such that L (b.)2 ~ n + 2n(n-1)/m. More-
l
i=o
over, such a k can be found in time O(nN).

m-1
b) For every m, a k satisfying L (b~)2
1
~ n + 4n(n-1)/m can be found
i=o
in random time O(n).
133

Proof: a) For k, 1 ~ k < N, let hk(x) = «kx) mod N) mod m be the hash
function defined by multiplier k. Then

N-1 m-1 N-1 m-1


L ( L (b~)2 -n) L (r I {x E S; hk (x)
k=1 i=o ~ k=1 i=o

N-1 m-1
r r I ((x,y); x,y E S, x * y, hk(x) i} I
k=1 i=o

r I {k; hk(x)
x,yES
x*y

Next note that hk(x) = hk(y) iff [(kx) mod N - (ky) mod N] mod m = O.
We are asking for the number of solutions k with 1 ~ k < N.
Since k ~ (kx)mod N is a permutation of {1, ••• ,N - 1} we may assume
w.l.o.g. that x = 1 and hence y * 1. Thus

N-1
L lSI r I{k; h k (1)
k=1 yES,y*1

Consider a fixed y and let gy(k) = k - (ky)mod N. We need to count the


number of k with ~ k < Nand gy(k) mod m = O. Note first that

-N + 2 ~ gy(k) ~ N - 2.
We can therefore rewrite the sum above as

L (N-2) /mJ
lSI L I{k; gy(k) :I: im} I
i=1

We show I{k; gy(k) = :I: im}1 ~ 2. Let k 1 ,k 2 E {1, ••• ,N-1} be such that
gy(k 1 ) a g y (k 2 ) where a E {-1, +1}. Then

k1 - (k 1y)mod N = a(k 2 - (k 2y)mod N)


or
k1 - ak 2 = (k 1y)mod N - (ak 2y)mod N
and hence
134

Since y * 1 and N prime this implies (k 1 - ak 2 )mod N o.


and hence k1 = k2 or k1 = N - k 2 • Hence

N-1 m-1 L (N-2/mJ


L (L (b~) 2 - n)-::::; IS I • L 2
k=1 i=O ~ i=O

::::; 2n(n-1) (N-2) 1m

Thus there is at least one k such that

m-1
L (b~)2::::; n + 2n(n-1)/m.
i=O ~

Finally note that k can be found by exhaustive search in time O(Nn).

N-1 m-1
b) In part a) we have shown that L (L (b~) 2 - n) ::::; 2n (n-1) (N-2) 1m.
k=1 i=o ~
m-1
Since L (b~)2 - n ~ 0 for all k we conclude that we must have
~
i=o
m-1
L (b~) 2 - n ::::; 4 (n-1) nlm for at least fifty percent of the k' s between
~
i=o
1 and N-1. Thus the expected number of tries needed to find a k with
m-1
L (b~)
~
2 - n ::::; 4 n(n-1) 1m is at most two. Testing a particular k for
i=o
that property takes time O(n). [J

We will make use of lemma 9 in two particular cases:


m = nand m ~ n 2 •

Corollary 10: Let N be a prime and let S c [O ••• N-1], lSI n. Let b~~

be defined as in lemma 9 •
135

m-1
a) If n = m then a k satisfying L (b~)
1.
2 < 3 n can be found in time
i=o
m-1
O(nN) deterministically, and a k satisfying L (b~)
1.
2 < 4 n can be found
i=o
in random time O(n).

b) If m = 1 + n(n-1) (m = 2n(n-1) + 1) then a k such that


x ~ «kx)mod N)mod m operates injectively on S can be determined deter-
ministically in time O(nN) (in random time O(n».

Proof: a) follows immediately from lemma 9 by substituting m n. For


part b) we observe first that substituting m = 1 + n(n-1)
(m =2n(n-1) + 1 respectively) into lemma 9a (9b resp.) shows the
existence of a k, 1 ~ k < N, such that L(b~)2 < n + 2. Next note that
. 1.
k 1. k
b~1. E IN
0
for all i and that L b i = n. Thus b i ~ 2 for some i implies
i
L (b ~) 2 ~ n + 2, a contradiction. We conclude that b~ ~ 1 for all i
i 1. 1. '
1..e. the hash function induced by k operates injectively on S. o

Corollary 10 can be interpreted as follows. If m > n(n-1)then the


general division method directly provides us with a perfect hash func-
tion. Of course, nobody wants to work with a load factor as small as 1 In.
However, part a) of corollary 10 suggests a method to improve upon the
load factor by using a two step hashing function. In the first step we
partition set S into n subsets S., 0 ~ i < n, such that LIS. 12 < 3 n as
1. 1.
described in part a) of corollary 10. In the second step we apply part
b) to every subset. The details are spelled out in

Theorem 11: Let N be a prime and let S = [0 •.. N-1], lSI n.

a) A perfect hash function h : S ~ [0 ••• m-1], m = 3n, with 0(1} evalu-


uation time and 0 (n log N) program size can be constructed in time O(nN).

b) A perfect hash function h : S ~ [0 ••. m-1], m = 4 n, with 0(1) evalu-


ation time and O(n log N) program size can be constructed in random
time O(n).

Proof: a) By corollary 10 a) there is a k, 1 ~ k < N, such that


n-1
L {x E S; «kx)mod N)mod n = i}. Moreover, k
i=o
136

can be found in time O(nN). Let b i = lSi' and let c i = 1 +bi (b i -1)
For every i, 0 ~ i < n, there is ki' 1 ~ ki < N, such that
x - «kix)mod N)mod c i operates injectively on Si by corollary 10 b).
Moreover, k i can be determined in time O(biN) .

The following program computes an injective function from S into


n-1
[ O .•• m-1 ] where m = L c i = n + (L b~ - L b 1.) < n + 3n-n = 3n
i=o i 1 i

(1) i «kx) mod N) mod n


(2) j «k. x) mod N) mod
1
i-1
(3) output L c9, + j
9,=0

The size of this program is O(n log N)i namely, O(log N) bits each for
i-1
integers k, k i and L C9,l 0 ~ i < n - 1. The running time is clearly
9,=0
0(1) in the unit cost measure. Finally, the time to find the program is
bounded by O(nN + L b. N) = O(nN).
i 1

b) The proof of part b) is very similar to the proof of part a). Note
n-1
first that a k with L IS. ,2 < 4n can be found in random time O(n).
i=o 1

Also, ki's such that x ~ «kix)mod N)mod (2b i (b i -1) + 1) operates in-
jectively on Si can be found in random time L O(b.) = o (n). Putting
i 1
these functions together as described above yields an injective func-
n-1
tion from S into [0 ... m-1] where m = L (2b. (b.-1) + 1) =L b~ < 4n o
i=o 1 1 i 1

Theorem 11 provides us with very efficient perfect hash functions. After


all, evaluating the hash functions constructed in the proof of theorem 9
requires only two multiplications and four divisions. However, the pro-
grams are hard to find, at least deterministically, and they are very
large. Let us take a closer look. The method devised in part a) of the-
orem 11 requires a hash table of size 3n and storage space for 2n in-
tegers in the range 1 ... N. Thus a total of 5n storage locations are
needed. The situation is even worse for the hash functions constructed
by probabilistic methods. They require a total of 6n storage locations,
4n for the hash table and 2n for the program. We will improve upon both
methods in the sequel and cut down the storage requirement for the
hash function to O(n log n + log log N) bits.
137

The key to the improvement is another variant of the division method


which we will use to reduce the size of the universe. More precisely,
we will show that for every 8 ~ [0 ... N-1] there is p = 0(n 2 2n N) such
that x - x mod p operates injectively on 8. We can then apply theorems
10 and 11 to set 8' = {x mod p; x E 8}. 8ince the members of 8' have
size 0(n 2 2n N) this will reduce the space requirement considerably.

Theorem 12: Let 8 = {Xl < x 2 < ... < x n } ~ [0 .• N-l].


a) There is a prime p = 0(n 2 2n N) such that x. mod p * x. mod p for
1 J
i * j.

b) A number p satisfying p = o(n 2 2n N) and x. mod p * x. mod p for


1 J
i * j can be found in time O(n·log n· (log n + log log N)) by a prob-
abilistic algorithm, and in time 0(n 3 log N log n) deterministically.

Proof: a) let d ij = Xj - x. for 1


1
$ i < j $ n. Then Xl mod p* x. modp
J
2
iff d .. * 0 mod p. Let D n d .. $ N (n ) . He need to find a bound on
1J i<j 1J
the size of the smallest prime which does not divide D.

Claim 1: Let m E IN. Then m has at most 0(2n m/2n 2n m) different


prime divisors.

Proof: Let m have q different prime divisors and let Pl' P2' P3' ...
be the list of primes in increasing order. Then

q
L 2n i
i=l
e

Hence there is a constant c such that q $ c(2n m)/2n 2n m. D

We infer from claim 1 that D has at most c(2n D)/(2n 2n D) different


prime divisors. Hence at least half of the 2·c(2n D)/(2n 2n D) smallest
P rimes will not divide D and hence not divide any d 1J
... The prime num-
ber theorem gives us a bound on the size of this prime.
138

Fact: There is d E IR such that Pq ~ d q ~n q for all q ~ 1; Pq is the


q-th smallest prime.

Proof: Cf. I. Niven/H.S. Zuckermann: Introduction to the Theory of


Numbers, Vol. 2, theorem 8.2. o

We infer from this fact that at least half of the primes


p ~ d(2·c ~n D/~n ~n D) ~n(2·c ~n D/~n ~n D) = O(~n D) = 0(n 2 ~n N)
satisfy part a).

b) We proved in part a) that there is a constant a such that at least


half of the primes p ~ a n 2 ~n N will not divide D and hence satisfy a).
Furthermore, the prime number theorem tells us that there are at least
b·(a n 2 ~n N)/~n(a n 2 ~n N) primes less than a n 2 ~n N for some constant
b > o. These observations suggest a probabilistic algorithm for finding
a number p (not necessarily prime) satisfying P ~ a n 2 ~n N and Xi mod p *
Xj mod p for i * j. We select a number p ~ a n 2 ~n N at random
and check whether Xi mod p *
Xj mod p for i *
j in time O(n log n) by
sorting the numbers Xi mod p, 1 ~ i ~ n. If p does not work then we try
again, •••• It remains to derive a bound on the expected number of
unsuccessful attempts. Note first that a random number p ~a n 2 ~n N is
a prime with probability n(1/~n(a n 2 ~n N» and that a random prime
satisfies a) with probability ~ 1/2. Hence a random number p ~ a n 2 ~nN
leads to a mapping x ~ x mod p which is injective on S with probability
n(1/~n( a n 2 ~n N»; therefore the expected number of unsuccessful at-
tempts is O(~n(a n 2 ~n N». Since each attempt costs O(n log n) time
units the total expected cost is O(n log n(log n + loglog N».

Deterministically, we search through numbers p = 0(n 2 ~n N) exhaustive-


ly. This will cost at most 0(n 3 log n log N) time units. DO

We close this section by combining theorems 10, 11 and 12.

Theorem 13: Let S c [0 .•. N-1], lSI = n. There is a program P of size


O(n log n + log log N) bits and evaluation time 0(1) which computes a
perfect hash function from S into [0 .•. m-1], m = 3n. P can be found
in random time 0(n 3 + n log n log log N) •
139

Proof: Let 8 c [0 ••• N-1], 181 n. By theorem 12a) there is a prime


p = 0 (n 2 log;) such that h 1 : x .... x mod p operate"s injectively on 8.
Moreover, p can be found in random time O(n log n(log n + log log N».
Let 8 1 = h1 (8) :: [0 •.• p-1]. By theorem 1ob) there is k, ~ k ~ p,

such that h 2 : x - ((kx)mod p)mod n 2 operates injectively on h1 (8).


Moreover, k can be found in random time 0 (n). Let 8 2 = h2 (8 1 ) :: [0 ••• n 2-1].
By theorem 11a) there is an injective function h3: 8 2 .... [0 ... m-1],
m = 3n/with evaluation time 0(1) snd program size O(n log n). More-
over, h3 can be found in time 0(n 3 ) deterministically.

h = h3 0 h2 0 h1 is the desired hash function. A program for h can be


found in time 0(n 3 + n log n log log N) by a probabilistic algorithm.
The program has size O(log p + log P + n log n) = O(n log n + log log N)
bits. Moreover, it can be evaluated in time 0(1). 0

Theorem 13 essentially settles all questions about perfect hashing.


The program constructed in the proof of theorem 13 has almost minimal
size, namely O(n log n + log log N) bits instead of O(n + log log N)
bits, they achieve a load factor S = n/m exceeding 1/3, they are not
too hard to find, and they are quite efficient. More precisely, evalu-
ation requires one division of numbers of length O(log N), a multiplica-
tion and two divisions on numbers of length O(log n + log log N), and
two multiplications and four divisions on numbers of length O(log n) •

III. 2.4 Universal Hashing

Universal hashing is a method to deal with the basic problem of hashing:


its linear worst case behaviour. We saw in section 2. 1. that hashing
provides us with 0(1) expected access time and O(n) worst case access
time. The average was taken over all sets 8:: [0 •.• N-1], 181 n. In
other words, a fixed hash function h : [0 .•. N-1] .... [0 .•• m-1] works well
for a random subset S :: u, but there are also some very "bad" inputs
for h. Thus it is always very risky to use hashing when the actual dis-
tribution of the inputs is not known to the designer of the hash func-
tion. It is always conceivable, that the actual distribution favours
worst case inputs and hence will lead to large average access times.

Universal hashing is a way out of this dilemma. We work with an entire


cla$H of hash functions instead of a single hash function; the specific
140

hash function in use is selected randomly from the collection H. If H


is chosen properly, i.e. for every subset S c U almost all h E H dis-
tribute S fairly evenly over the hash table, then this will lead to
small expected access time for every set S. Note that the average is
now taken over the functions in class H, i.e. the randomization is
done by the algorithm itself not by the user: the algorithm controls
the dices.

Let us reconsider the symbol table example. At the beginning of each


compiler run the compiler chooses a random element h E H. It will use
hash functionh for the next compilation. In this way the time needed
to compile any fixed program will vary over different runs of the com-
piler, but the time spent on manipulating the symbol table will have
small mean.

What properties should the collection H of hash functions have? For


any pair x,y E U, x'*' y, a random element h E H should lead to collision,
i.e. h(x) = h(y), with fairly small probability.

Defini tion: Let c E IF, N, m E IN. A collection


H c {h; h : [0 ..• N-1] ... [0 ... m-1]} is c-universal, if for all
x,y E [0 •.. N-1 ], x '*' y

I {h; h E Hand h(x) h(y)} I ::; c . IHI/m o

A collection H is c-universal if only a fraction c/m of the functions


in H lead to collision on any pair x,y E [0 •.. N-1]. It is not obvious
that universal classes of hash functions exist. We exhibit an almost
1-universal class in theorem 14; in exercise 6 it is shown that there
are no c-universal classes for c < 1 - miN. Thus theorem 14is almost
optimal in that respect.

Theorem 14: Let m, N E IN and let N be a prime. Then

{h a, b; h a, b (x) [(ax + b) mod N] mod m, a,b E [0 .•. N-1]}

is a c-universal class, where c [ r N / m'/(N/m) ] 2.


141

Proof: Note first that iH11


2
N . Let x,y E [0 ••• N-1], x * y. We have
to show that

If h a, b(x) = h a, bey) then there are q E [0 ••• m-1] and


r,s E [0 ••• r N/ m'-1] such that

ax + b q + rm mod N
ay + b q + sm mod N

Since ~N is a field (N is a prime) there is exactly one solution


in a,b of these equations for each choice of q,r and m. Hence

I {(a,b); h a, b(x)

and therefore class H1 is c-universal. o

Universal class H1 has size N2 , i.e. O(log N) bits are required to


specify a function of the class. A random element of H1 may be selected
by choosing two random numbers a,b in the range 0 .•• N-1. In theorem 17
we exhibit a smaller universal class; O(log m + log log N) bits suf-
fice to specify a member of that class. We will also show that this is
best possible.

We analyse the expected behavior of universal hashing under the fol-


lowing assumptions:

1) The hash function h is chosen at random from some c-universal


class H, i.e. each h E H is chosen with probability 1/IHI.
2) Hashing with chaining is used.

Theorem 15: Let c E IR and let H be a c-universal class of hash func-


tions.

a) Let S c [0 ••• N-1], IS I = n and let x E [0 ••• N-1]. Then

:$ {1 + cn/m if x ~ S
E (1 + 0h(x,S»/IHI
hEH 1 + c(n-1)/m if xES
142

b) The expected cost of an Access, Insert or Delete operation is


0(1 + cB), where B = n/m is the load factor.

c) The expected cost of a sequence of n Access, Insert and Delete


operations starting with an empty table is 0((1 + cB/2)n) where
B = n/m is the (maximal) load factor.

Proof: a)

L (1 + 0h(x,S» IHI + L L °h(x,y), by definition of 0h


hEH hEH yES

IHI + L L °h(x,y), reordering


yES hEH

:s; IHI + L c IHI/m , since °h(x,x) = 0


yES- {x} andH is c-universal

(1 + c·n/m) if x ~ S
:s; (HI
IHI (1 + c· (n-1)/m) i f x E S

b) immediate from part a)

c) immediate from part b) and the observation that the expected cost of
the i-th operation in the sequence is 0(1 + c·i/m). c

Theorem15, c reads the same as theorem 2 (except for the factor c).
However, there is a major difference between the two theorems. They are
derived under completely different assumptions. In theorem 2 each sub-
set S =Ur lSI = n, was assumed to be equally likely, in theorem 15, c
each element h E H is assumed to be equally likely. So universal hash-
ing gives exactly the same performance as standard hashing, but the
dices are now controlled by the algorithm not by the user.

For every fixed set S =


U, a random element h E H will distribute S
fairly evenly over the hash table, i.e. almost all functions h E H
work well for S and only very few will give us bad performance on any
fixed set S. Theorem 16 gives us a bound on the probability of bad per-
formance.
143

Theorem 16: Let c E IR and let H be a c-uni versal class. Let


S ~ [0 ••• N-1], lSI n and x E [0 .•• N-1]. Let V be the expected value
of 0h(x,S), i.e. V (L 0h(x,S»/IHI. Then the probability that
hEH
0h(x,S) ~ t·V is less than 1/t.

Proof: Let H' = {hEH; 0h(x,S) ~ t·V}. Then

~ t·jl·IH'I/IHI since 0h(x,S) ~ t·jl for hEH'

and hence IH' I ~ IHI/t [J

We infer from theorem 16 that the probability that the performance is


more than t times the expected performance is at most 1/t. Much better
bounds can often be obtained for specific universal classes; cf exer-
cise 7 where a 1-universal class with an 0(1/t 2 ) bound is described.
We close this section with an estimate of the size of universal classes
of hash functions.

Theorem 17: a) Let H c {hi h [0 •.• N-1] ~ [0 •.• m-1]} be a c-universal


class. Then

and hence log I H I = rl (log m + log log N - log c).

b) Let N,m E IN, N ~ m. Then there is a 8-universal class


H2 c {hi h . [0 .•• N-1] ~ [0 ... m-1]} of hash functions with

log IH21 O(log m + log log N)

Proof: a) Let H = {h 1 , ••• ,h t }. As in the proof of theorem 6, a) we


construct a sequence 00 = [0 .•• N-1], 01' 02' ••. such ~hat h 1 , •.• ,h i
are constant functions on 0i and 10il ~ IOi_1 I/m ~ N/ml. Let
to = rl ogmN' - 1. Then 10toi > 1. Let x,y E Uto' x * y. Then
144

to S I (hEH; h(x) = h(y)} I S c· IHI/m

since H is c-universal. Thus IHI >


- m· (rlogmN' - 1)/c.

b) Let N,m E ~ and let t be minimal such that t·~n Pt ~ m'~n N. Here
Pt denotes the t-th prime. Then t = O(m ~n N). Let

where

x mod p~

and

gc,d(Z) = [(cz + d) mod P2t] mod m.

2
Then IH21 t'P2t and hence log IH21 = O(log t) = O(log m + log log N)
since log P2t = O(log t) by the prime number theorem. It remains to
show that H2 is 8 -universal.

Let x,y E [O .•. N-1], x * y, be arbitrary. We have to show that

[c(y mod p~) + d] mod P2t mod m

Thus there have to exist q E [0 ... m-1] and r,s E [0 . . . r p2t / m' -1] such
that

q + r·m

[c(y mod p~) + d] mod P2t = q + s·m

We have to count the number of triples (c,d,~) which solve this pair
of equations. We count the solutions in two groups. The first group
contains all solutions (c,d,~) with x mod p~ *y mod p~ and the second
145

group contains all solutions (c,d,~) with x mod p~ = y mod p£.

Group 1: Of course, there are at most t different £'s such that


x mod P£ *
Y mod p£. For each such £ and any choice of q,r and s there
is exactly one pair c,d which solves our equations. This follows from
the fact that ~p is a field. Hence the number of solutions in group
2t
one is bounded by

t m( r P2t I m1) 2 :-:; t m(1 + P2t/m)


2

Group 2: Let L ={£; t < £ :-:; 2t and x mod P£ = Y mod p£} and let
ILl
p = n {p£; £ E L} . Then P ;:: Pt . Also P divides x - y and hence P :-:; N.
Thus ILl :-:; (£n N)/£n Pt :-:; tim by definition of t.

Consider any fixed £ ELand any choice of q, rand s. If r * s then


there is no pair (c,d) solving our pair of equations. If r = s then
there are exactly P2t pairs (c,d) solving our pair of equations. Hence
the number of solutions in group two is at most

Altogether, we have shown that the number of solutions (c,d,£) is


2
bounded by 2(1 + E) IH21/m where E = m/p2t :-:; 1. (Note that P2t :-:; m
would imply t £n Pt < P2t £n P2t :-:; m £n m :-:; m £n N, a contradiction to
the definition of t). Hence H2 is 8-universal. o

III. 2.5 Extendible Hashing

Our treatment of hashing in sections 2.1. to 2.4. was based on the


assumption that main memory is large enough to completely contain the
hash table. In this section we discuss application of hashing to se-
condary storage. We assume that secondary storage is divided into
buckets (pages) of size b; i.e. each bucket can hold up to b elements
of universe u.

Again, we start with a hash function h u ~ {O,1}k where k is some


146

integer. h is assumed to be injective. For d, 0 ~ d ~ k, we use hd to


denote the function which ma~s x E U onto the first d digits of hex),
i.e. hd : U - {0,1}d and hd(x) is a prefix of hex) for all x E U. Let
S ~ u, lsI = n, be a subset of U. The depth deS) of S with respect to
bucket size b and hash function h is defined as

deS) = min{d; I {x E S; hd(x) = a} I ~ b for all a E {O,1}d}

In other words, if we use a TRIE to partition h(S) into subsets of size


at most b then this TRIE has depth deS) •

Extendible hashing uses a table T[0 ••• 2 d (S) - 1], called the directory,
and some number of buckets to store set S. More precisely, the entries
of table T are pointers to buckets. If x is an element of S then the
bucket containing x can be found as follows.

(1) Compute hd(s)(x) ahd interpret it as the binary representation of an


integer, say i, in the range 0 ••• 2 d (S) - 1.

(2) Use this integer to index directory T; pointer T[i] points to the
bucket containing x.

Example: Let h(S) {OOOO, 0000, 0100, 1100} and let b 2. Then
deS) = 2.

00
F 0000, 0001

P
01
0100
10

11
E 1100 CJ

As one can see from the example, we allow entries of T to point to the
same bucket. However, we require that sharing of buckets must conform
to the buddy principle. More precisely, if r < deS), a E {O,1}r,
a 1 ,a 2 E {0,1}
d(S)-r
, a1 *
a 2 and T[aa 1 ] = T[aa 2 ] then T[aa 1 ] = T[aa 3 ]
d(S)-r . deS)
for all a 3 E {0,1} • In other words, 1f we represent {0,1} as
a TRIE then the table entries sharing a bucket form a subtree of the
TRIE. Finally, if B is a bucket and 2 d (s)-r table entries point to B then
147

r is the local depth of B. In our example the local depth of buckets


is shown in their left upper corner.

The insertion algorithm for extendible hashing is quite simple. Suppose


that we want to insert x E U. We first compute bucket B which should
contain x. If B is not full, i.e. B contains less than b keys, then we
insert x into B and are done. If B is full, say B contains x 1 , ••• ,xb ,
then additional work is required. Let r be the local depth of page B
and let B' be a new page. If r = deS) then we double the size of di-
rectory T, i.e. we increase deS) by 1, create a directory T' of size
2 d (S)+1 and initialize T'. Note that initializing T' essentially means
to make two copies of T and to merge them. At this point we have
r < deS) in either case, i.e. if r < deS) initially or if r = deS) and
directory size was doubled. We finish the insertion by setting the
local depth of Band B' to r + 1 and by inserting x1' ••• '~' x into B
or B' whatever is appropriate. Note that this might cause B or B' to
overflow (in some rare case). In this case we go through the routine
once more.

Example (continued): Suppose that we want to insert x with hex) 0010.


It will cause the first bucket to overflow. We obtain

000 p1 0001, 0000 IP 0010


001

010

011

100
PI 0100

101

110

111 fJJ 1100 []

The deletion algorithm is also quite simple. Suppose that we want to


delete x from S. We first determine bucket B containing x and delete x
from B. Let B' be the buddy of B, i.e. if r is the local depth of Band
a E {0,1}r-1 and z E {0,1} are such that all directory entries T[aza11,
a 1 E {0,1}d(S)-r, point to B then B' is the buddy of B if all entries
148

-
T[aza d ( S )and
-r-
1 ], a 1 E {0,1} z 1 - z, point to B'. Note that B' does
not necessarily exist. If B' does exist and Band B' contain together
at most b keys then we merge Band B' to a single bucket of local depth
r - 1. In addition, if r = d(S) and Band B' were the only buckets of
depth d(S) then we half the size of the directory. This completes the
description of the deletion algorithm.

What can we say about the behaviour of extendible hashing? What are the
relevant quantities? We have seen already that an Access operation
requires only two accesses to secondary memory. This is also true for
an Insert, except in the case that a bucket overflows. In this case we
have to obtain a new bucket, a third acces&,and to distribute the ele-
ments of the bucket to be split over the new buckets. In rare cases we
will also have to double the directory. These remarks show that the
time complexity of extendible hashing is very good. The space complexity
requires further investigation. The two main questions are: What is the
size of directory T? How many buckets are used? First of all, as for all
hashing schemes worst case behaviour can be very, very bad. So let us
discuss expected behaviour. The analysis is based on the following
assumption. We have k = =, i.e. hash function h maps U into bit strings
of infinite length. Furthermore, h(x) is uniformly distributed in in-
terval [0,1]. Note that h(x) can be interpreted as the binary represen-
tation of a real number. A discussion of expected behaviour is particu-
larly relevant in view of our treatment of universal hashing. Note that
the behaviour of extendible hashing heavily depends on the hash function
in use and that universal hashing teaches us how to choose good hash
functions. Unfortunately, a complete analysis of the expected behaviour
of extendible hashing is quite involved and far beyond the scope of the
book.

Theorem 18: a) The expected number of buckets required to store a set


of n elements is approximately nib ~n 2.

b) The expected size of the directory for a set of n elements is ap-


proximately (e/b ~n 2)n 1+ 1 / b •

Proof: A complete analysis of extendible hashing can be found in


Flajolet/Steyaert (82). The exact formula for the expected size of the
directory is
149

Q( (1 + 1 /b) log n) n 1+1/b (1 + 0 (1 ) )

where Q is a periodic function given by Q(z) -2ik'ITZ


L gke with
k~O

go (-1 /b £.n 2) [ (b + 1 ) ! ]1 /b r (-1 /b)

and

gk (-1/b £.n 2) [(b+1)!]1/b- Ak r(A k - 1/b) where

r(z) is the gamma function. Q is periodic with mean value go; go is


numerically close to e/b £.n 2. In part b) of theorem 18 we only quoted
the leading term of the exact formula for expected directory size. More-
over, we replaced Q by its mean value. An approximate and simpler anal-
ysis of extendible hashing is contained in A. Yao (1980). 0

We finish this section with a discussion of theorem 18. Part a) states


that the expected number of buckets is n/(b £.n 2); in other words the
expected number of elements per bucket is b £.n 2 ~ 0.69 b. Expected
storage utilization is 69 %. This result is not too surprising. After
all, buckets can contain between 0 and b keys. Once a bucket overflows
it is split into two buckets. The size of the two parts is a random
variable; however, it is very likely that each of the two buckets
receives about 50 % of the elements. We should thus expect that the
expected number of elements per bucket is somewhere between 0 and b
with a small inclination towards b.

Part b) is more surprising. Expected directory size is non-linear in


the number of elements stored. The following table lists expected di-
rectory size for various choices of band n.

10 5 0
b n 10 6 10 8 10

2 6.2 · 10 57 1.96 · 10 86 1.96 · 1010 811 1.96 · 1010 1014


10 1 .2 · 10 3 1 .5 · 1010 6 2.4 · 8 3 .9 · 10 10
50 9.8 · 10 3 1.0 · 4 1.1
· 10106 1.2 ·
00 4.4
· 10 4.5
· 10 4.7 · 4.9
· 10 8
150

We can see from. this table that the non-linear growth is clearly per-
ceptible for small b, say b 10, and that directory size exceeds the
~

size of the file even for moderate n, say n = 10 6 . If b is larger, say


b ~ 100, then the non-linearity is hardly noticible for practical
values of n, say n ~ 10 10 Moreover, the size of the directory will be
only about 5 % of the size of the file.

Why does directory size grow non-linearly in the size of the file? In the
case b = 1 this is not too hard to see and follows from the birthday
paradox. If b is 1 then directory size doubles whenever two elements of
S hash to the same entry of the directory (have the same birthday). If
directory size is m (the year has m days) and the size of 8 is n then
the probability p that no two elements of 8 hash to the same entry
n,m
of the directory is

p
n,m
= m(m-1) •.• Un -n+1) /mn

n-1
IT (1 - i/m)
i=o

n-1
L 9,n( 1-i/m)
i=o
e

n-1
- L i/m
i=o
~ e ~ e

Thus P ~ 1/e if n exceeds 1m. In other words, a directory of size


n,m
m suffices for a set of n = 1m elements with probability less than
- 1/e. 80 directory size must grow non-linearly in file size and
should in fact be quadratic in file size.
151

III. 3. Searching Ordered Sets

We will now turn to comparison based methods for searching. We assume


that U is linearly ordered and denote the linear ordering by ~. The
assumption of U being linearly ordered is no real restriction; there
is always an ordering on the internal representations of the elements
of U. The basis for all comparison-based methods is the following al-
gorithm for searching ordered arrays. Let S = {x 1 < x 2 < ... < x n } be
stored in array S[1 •• n], i.e. S[i] = xi' and let a E U. In order to
decide a E S, we compare a with some table element and then progeed
with either the lower or the upper part of the table.

(1) low _ 1; high - n;


(2) next - an integer in [low •• high];
(3) while a * S[next] and high> low
(4) do if a < S[next]
(5) then high - next - 1
(6) else low - next + 1 fi;
(7) next - an integer in [low •• high]
(8) od;
(9) if a = S[next] then "successful" else "unsuccessful";

Various algorithms can be obtained from this scheme by replacing lines


(2) and (7) by specific strategies for choosing next. Linear search is
obtained by next - low, binary search by next - r{low + high)/2' and
r a-S[low-1] . '
interpolation search by next - (low-1) + S[high+1]-S[low-1] (h1gh-low+1)
We discuss these strategies in greater detail below.

The correctness of the program is independent of the particular choice


made in line (2) and (7). This can be seen from the fact that the fol-
lowing predicate P is an invariant of the body of the while-loop:
{a E S * a E {S[low], ••• , S[high]}) and ({low ~ high) * low ~ next~higl:»

P is certainly true before execution of the while-loop. If the loop


body is entered then a * S[next] and hence either a < S[next] or
a > S[next]. If a < S[next] then certainly a { {S[next], ••• , S[high]}
and hence a E S implies a E {S [low],••• , S [next - 1]}. The case
a > S[next] isrreated similarly. Also a number in [low •• high] is as-
signed to next in line (7) provided that low ~ high.
152

Thus when the while-loop terminates we have P and «a = S[next]) or


high ~ low). If a = S[next] then the search is successful. Suppose now
that a * S[next]. Since P holds we know that a E S implies
a E {S[low], ••. , S[high]}. If high < low then certainly a ( S. If
high = low then next = high by P and hence a ( S. In either case the
search is unsuccessful.

Finally, the program terminates because high - low is decreased by at


least one in each execution of the loop body.

III. 3.1. Binary Search and Search Trees

Binary search is obtained by replacing lines (2) and (7) by next


- r(low + high)/2'. It is very helpful to illustrate the behaviour of
the algorithm by a binary tree. We do so for n = 6. In this tree node
S[4] represents a comparison with S[4].

If a < S[4] then we go left, if a > S[4] then we go right, if a = S[4]


then we are done. We start the search by comparing a and S[4]. If
a > S[4] then a can only be equal to S[5] or S[6]. Next we compare a
and S[6], .••• We can also see from this picture that an unsuccessful
search gives us information about the rank of a in S.

Since the value of high - low + 1 is halved in each iteration of the


loop, the loop body is executed at most log n times. Thus an operation
Access(a,S) takes time O(log lSI). Operations Ord(k,S) and Sequ(S) are
trivial in this structure, however Insert and Delete cannot be done
efficiently. An Insert would require to move part of the array, a costly
process. An elegant way out is to represent the tree above explicitely
by pointers and not implicitely by an array. Then operations Insert and
Delete can also be executed fast as we will see shortly. This leads to
the following definition.
153

Definition: A binary search tree for set S = {x 1 < x 2 < ... < xnl is a
binary tree with n nodes {v1, ••. ,vnl. The nodes are labelled with the
elements of S, i.e. there is an injective mapping CONTENT:
{v1, •.• ,vnl S. The labelling preserves the order, i.e. if vi(v j ) is
a node in the left (right) subtree of the tree with root v k then
CONTENT[Vi ] < CONTENT[vk ] < CONTENT[V j ].

An equivalent definition is as follows: a traversal of a search tree


for S in symmetric order reproduces the order on S. We will mostly iden-
tify nodes with their labellings, i.e. instead of speaking of node v
with label x with speak of node x and write ® or simply x. Node x cor-
responds to the test: if a < x then go to the left son else if a = x
then terminate search else go to the right son fi fi. The n + 1 leaves
represent unsuccessful access operations. It is not necessary to store
leaves explicitely. Each leaf represents one of the n + 1 open inter-
vals of U generated by the elements of S. We draw the leaf correspond-
ing to interval xi < a < x i + 1 as \(x i ,x i + 1 )1 .

In the text we simply speak about leaf (x i ,x i + 1 ). Leaf ( ,x1 ) represents


all a E U with a < x 1 • Sometimes we will write (x O'x 1 ) instead of
( ,x 1 ). A similar remark applies to leaf (xn ' ). So let T be a binary
search tree for set S. Then the following piece of code realizes oper-
ation Access(a,S).

v ..... root of Ti
while v is a node and a * CONTENT[v]
do if a < CONTENT[v]
154

then v LSON[v]
else v RSON[v]
fi
od

If this algorithm terminates in node v then a = CONTENT[v]. Otherwise


it terminates in a leaf, say (x i ,x i + 1 ). Then xi < a < x i + 1 • Oper-
ation Insert(a,S) is now very easy to implement. We only have to replace
leaf (x i ,x i + 1 ) by the tree

Deletion is slightly more difficult. A search for a yields node v with


content a. We have to distinguish two cases.

Case 1: At least one son of v is a leaf, say the left. Then we replace
v by its right son and delete v and its left son from the tree.

Case 2: No son of v is a leaf. Let w be the rightmost node in the left


subtree of v. Node w can be found by following the left pointer out of
v and then always the right pointer until a leaf is hit. We replace
CONTENT [v] by CONTENT[w] and delete w as described in case 1. Note that
w's right son is a leaf.

The following figure illustrates both cases. The node with content 4 is

-A
deleted, leaves are not drawn.
155

Operations Access, Insert and Delete essentially consist of a single


pass down the tree followed by some local updating. Updating takes
time 0(1) and hence the total cost is O(h(T)), where h(T) is the height
of tree T. Operation Sequ(S) is equivalent to the traversal of tree T
in symmetric order. We have already seen (see I.4.) that tree trav-
ersal takes time O(rSI). Finally, we show how to realize operation
Ord(k,S) in time O(h(T)) by extending the data structure slightly. We
store in each node the number of elements stored in the left subtree.
These numbers are easily updated during insertions and deletions. With
the use of these numbers Ord(k,S) takes time O(h(T)).

The considerations above show that the hejght of the search tree
plays a crucial role for the efficiency of the basic set operations.
We will see in III.5. that h(T) = O(log lSI) can be achieved by the use
of various balanced tree schemes. In the exercises it is shown that the
average height of a randomly grown tree is O(log n).

III. 3.2 Interpolation Search

Interpolation search is obtained by replacing lines (2) and (7) by

( +r a - S [low-.1 ] ,
next - low-1) S[high+1] _ S[low-1] • (high-low+1)

It is assumed that positions S[O] and S[n+1] are added and filled with
artificial elements. The worst case complexity of interpolation search
is clearly O(n); consider the case that S[O] = 0, S[n+1] = 1,
a = 1/(n+1) and S ~ (O,a). Then next = low always and interpolation
search deteriorates to linear search. Average case behaviour is
much better. Average access time is O(log log n) under the assumption
that keys x 1 , ••• ,xn are drawn independently from a uniform distribution
over the open interval (xO ,xn + 1 ). An exact analysis of interpolation
search is beyond the scope of this book. However, we discuss a variant
of interpolation search, which also has O(log log n) expected behaviour:
quadratic binary search.

Binary search has access time O(log n) because it consists of a single


scanning of a path in a complete binary tree of depth log n. If we
could do binary search on the paths of the tree then we would obtain
log log n access time. So let us consider the question, whether there
156

is a fast (at least on the average) way to find the node on the path of
search which is halfway down the tree, i.e. the node on the path of
search which has depth 1/2 log n. There are 21/2 log n = In of these
nodes and they are In apart in the array representation of the tree.
Let us make an initial guess by interpolating and then search through
these nodes by linear search. Note that each step of the linear search
jumps over In elements of S and hence as we will see shortly only 0(1)
steps are required on the average. Thus an expected cost of 0(1) has
reduced the size of the set from n to In (or in other words determined
the first half of the path of search) and hence total expected search
time is O(log log n).

The precise algorithm for Access(a,S) is as follows. Let low = 1,


high = n and let next = r p •n ' be defined as above; here
p = (a-xO)/(xn + 1-xO). If a > S[next] then compare a with S[next + In],
S[next + 2/n], ••• until an i is found with a ~ S[next + (i-1)./n].
This will use up i comparisons. If a < S[next] then we proceed analo-
gously. In any case, the subtable of size In thus found is then
searched by applying the same method recursively.

We must determine the expected number C of comparisons required to de-


termine the subtable of size In. Let Pi be the probability that i or
more comparisons are required to find the subtable. Then

C L i(p~-P~+1)
i~1 ~ ~

It remains to estimate Pi. Note first that P1 = P2 = 1 since two com-


parisons are always required. So let i > 2. If i or more comparisons are
needed then
lactual rank of a - next I ~ (i-2)·/n

where actual rank of a denotes the number of xj's smaller than a. Hence

Pi ~ Prob (Iactual rank of a - next I ~ (i-2) In)

We use Chebyshev's inequality (cf. W. Feller, An Introduction to Prob-


abtility Theory, and its Applications, John wiley, New York 1968) to
derive a bound on Pi:
157

for a random variable X with mean ~ and variance cr 2

Let random variable X be the number of xj's smaller than a. Recall,


that we assume that x 1 , ... ,xn are drawn independently from a uniform
distribution over (x O'xn +1 ). Then, since the Xi are independent and
since p = (a-x o )/(x n + 1 -xO) is the probability that anyone of them is
less than a, the probability that exactly j out of n are less then a is
n j n-j
(j)p (l-p) • Thus the expected number of keys less than a, i.e. the
expected rank of a is

n
n J' n-J'
~ r j ( , ) p (l-p) pn
j=O J

with variance

2 n 2 n' n-J'
cr r (j-~) (,)pJ (l-p) p. (l-p) . n
j=O J

Thus

Pi S Prob ( I actual rank of a - p.nl 2: (i-2)./n)

S p. (1-p)n/«i-2)/n)2

s p. (1-p)/(i-2)2

S 1/ (4· (i-2)2)

since p(l-p) s 1/4 for 0 s p s 1. Substituting into our expression for


C yields

C s 2 + r 1/(4(i-2)2)
i2:3

Finally, let T(n) be the average number of comparisons used in search-


ing a random table of n keys for a. Since the subtables of size In are
again random, we have
158

T(n) ~ C + T(/n) for n ~ 3

and T(1) ~ 1, T(2) ~ 2 and thus

T(n) ~ 2 + C·log log n for n ~ 2

as is easily verified by induction on n.

Theorem 1: The expected cost of quadratic binary search is O(log log~.

The worst case access time of quadratic binary search is O(/n). Note
that the maximal number of comparisons used is n 1 / 2 + n 1 / 4 + n 1 / 8 + •••
= O(/n ). This worst case behaviour can be reduced to O(log n) without
sacrificing the O(log log n) expected behaviour as follows. Instead of
using linear search to determine the i with S[next + (i-2) ./n] < a
~ S[next + (i-1)./n] with i comparisons we use exponential + binary
search (cf. III. -4.2., theorem 10) for a cost of only O(log i) compari-
sons. Since log i ~ i the expected behaviour stays the same. However,
the maximal number of comparisons is now log n 1 / 2 + log n 1 / 4 + log n 1 / 8
+ ... = (1/2 + 1/4 + 1/8 + ... ) log n = log n. Thus worst case behav-
iour is O(log n) if exponential + binary search is used.

III. 4. Weighted Trees

In this section we consider operation Access applied to weighted sets


S. We associate a weight (access probability) with each element of S.
Large weight indicates that the element is important and accessed fre-
quently; it is desirable that these elements are high in the tree and
can therefore be accessed fast.

Definition: Let S = {x 1 < x 2 < ... < x } and let B. (a.) be the proba-
n ~ J
bility of operation Access (a,S) where a = x. (x. < a < x. 1) for
~ J J+
1 ~ i ~ n(O ~ j ~ 0, a. ~ 0 and ~B. + La. = 1. The
n). Then B. ~
J ~ ~ J
(2n + 1)-tuple (aO,B1,a1, ... ,Bn,an) is called access (probability)
distribution.
159

Let T be a search tree for set 5, let b~ be the depth of node xi and
].

let a~ be the depth of leaf (x j ,X j + 1 ). Consider a search for element a


J
of the universe. If a = xi then we compare a with b~ ].
+ 1 elements in

the tree, if Xj < a < x j + 1 then we compare a with a3 elements in the


tree. Hence

TnT n T
p = l: Si (1 + b.) + l: 0. a
i=l ]. j=O j j

is the average number of comparisons in a search. pT is called (normal-


T
ized) weighted path length of tree T. We take P as our basic measure
for the efficiency of operation Access; the actual search time is pro-
portional to pT. We will mostly supJDcress index T if tree T can be in-
ferred from the context. The following figure shows a search tree for
set 5 = {x 1 ,x 2 ,x 3 ,x 4 } with (o.O,Sl, ... ,S4,o.4) = (1/6, 1/24,0, 1/8, 0,
1/8,1/8,0,5/12)

In this tree, b 1 = 1, b 2 = 2, b 3 = 0, b 4 = 1, a o = a 3 = a 4 = 2 and


a 1 = a 2 = 3. Weighted path length P is equal to 2. There is no search
tree for set 5 with smaller weighted path length; the tree shown above
is optimal with respect to the given access distribution.

III. 4.1 Optimum Weighted Trees, Dymamic Programming and Pattern


Matching

We associated with every search tree for set 5 a single real number,
its weighted path length. We can therefore ask for the tree with the
minimal weighted path length. This tree will then also optimize average
access time.

Definition: Let 5
160

••• ,Bn,a n ) be an access distribution. Tree T is an optimum binary search


tree for set S if its weighted path length is minimal among all search
trees for set S. We use Topt to denote an optimum binary search tree
and P opt to denote its weighted path length.

Theorem 1: An optimum binary search tree for set S and distribution


(a O ,6 1 , ..• ,B n ,a n ) can be constructed in time 0{n 2 ) and space 0{n 2 ).

Proof: We use dynamic programming, i.e. we will construct in a system-


atic way optimal solutions for increasingly larger subproblems. In our
case this means the construction of optimum search trees for all pairs,
triples, ••• of adjacent nodes. A search tree for set S has nodes
x1' •.•
~n and leaves {xO 'x 1 ), •.• , (x n 'xn + 1 ). A subtree might have nodes
xi,···,x j and leaves (x i - 1 ,x i ) , ••• , (x j ,X j + 1 ) with 1 ~ i, j ~ n,
i ~ j + 1. Such a subtree is a search tree for set {x., •.. ,x.} with
~ J
respect to the universe (x i _ 1 ,x j + 1 ). The access probabilities are given
by the conditional probabilities

and

We use T ~J
.. to denote an optimum
_ _ binary_ search
_ tree for set {x.,
~
••• ,x.}
J
with access distribution (a. 1,B., ••• ,B.,d.). Let P .. be the weighted
~- ~ J J ~J
path length of Tij and let r ij be the index of the root of T ij , i.e.
xm with m = r ij is the root of T ij •

Lemma 1: a) Pi ,i-1 0

b) wij P ij wij + min (w.~,m- 1 P.~,m- 1 + wm,J


+1 . Pm+1 ,J.) for i ~ j
i~m~j

Proof: a) T i ,i-1 consists of a single leaf which has depth zero. Thus
P i ,i-1 = O.

b) Let T .. be an optimum tree for set {x., ..• ,x.}. Then Tij has weighted
~J ~ J
path length P .. and root x with m = r ... Let To (T ) be the left (right)
~J m ~J N r
subtree of T .. with weighted path length Po (P ). Since
~J N r
161

T .. Tt
b k 1J 1 + bk for i ~ k ~ m - 1

T ..
b 1J 0
m
T .. T
b k 1J 1 + b r for m + 1 ~ k ~ j
k

and analogously for the leaf weights we have Wij P ij = wij + wi ,m-1 P t
+ wm+ 1 ,j P r T t is a search tree for set x i , .•• ,xm_ 1 and therefore
P t ~ P i ,m-1. We must have Po = P. 1 because otherwise we could replace
7v 1,m-
T t by T i ,m-1 and obtain a tree with smaller weighted path length. This
proves b). [J

Lemma 1 suggests a way for computing all values w .. P ... Initialization


1J 1J
is given in part a) and the iterative step is given in part b). In the
complete program below we use P. . to denote w.. P ..•
1J 1J 1J

(1) for i from 0 to n

(2) do Vl i + 1 ,i eli; P i + 1 ,i - 0 od;

(3) for k from 0 to n -

(4) do for i from 1 to n - k

(5) do j i + k;

(6) wij Wi ,j-1 + Bj + C!j;


(7) let m, i ~ m ~ j, be such that P.1,m- 1 + Pm+ 1 ,J. is minimal;
in case of ties choose the largest such m

(8)

(9) Pij - wij + Pi ,m-1 + Pm+ 1 ,j


(10) od
( 11) od

The program above is a direct implementation of the recursion formula


in lemma 1. After termination the optimum search tree is given implic-
itly by the array r ij . Node xm with m = r 1 ,n is the root of the search
tree. The root of the left subtree is x k with k = r 1 ,m-1' . . • • It is
easy to see that the search tree can be explicitly constructed in time
O(n) from array r ij .

So let us consider the complexity of the algorithm above. The program


162

uses three arrays P .. , w .. and r .. and hence has space complexity 0(n 2 ).
~]~] ~]

We turn next to the time complexity. Note first that one execution of
lines (5), (6), (8), (9) takes time 0(1) and one execution of line (7)
takes time 0(j-i+1) = 0(k+1) for fixed i and k. Thus the total running
time is

n-1 n-k
:L :L 0(k+1)
k=O i=1

This falls short of the 0(n 2 ) bound promised in the theorem. Before we
sketch an improvement we illustrate the algorithm on the example from
the beginning of III.4 .• Arrays P ij , wij ' 1 ~ i ~ 5, 0 ~ j ~ 4 and r ij ,
1 ~ i ~ 4, 1 ~ j ~ 4 are given below:

5 11 24 5 8 14

24P
o 3 12 48]
31
24w
o 3 9 24]
19
o 6 22 o 6 16
o 13 3 13
o 10

2
2 3
r =
3

We learn one important fact from this example: Matrix r is monotone in


each row and column, i.e. r ~,]-
. . 1 ~ r ~,]
. . ~ r'+
~,]
1 . for all i,j. We post-
pone the proof of this fact for a while (cf. lemma 3 below). The mono-
tonicity of r has an important consequence; we may change line (7), the
search for r .. , into
~]

let m, r ~,]-
.. 1 ~ m ~ r'+
~ 1 , ]. be such •..

without affecting the correctness of the algorithm. However, the change


does have a dramatic effect on the running time. It is now

n-1 n-k
O(:L :L (1+r i + 1 ,i+k - r i ,i+k-1»
k=O i=1
163

n-l
O( L (n-k + r -k - r 1 k»
k=O n,n,

n-l
o (L n)
k=O

This proves theorem 1.

We still have to justify the monotonicity of r. We will do so in a more


general context: Dynamic programming with quadrangle inequalities.

Let w(i,j) E IR for 1 ~ i < j ~ n and let c(i,j) be defined by

c (i, i) 0

c(i,j) w(i,j) + min (c(i,k-1) + c(k,j» for i < j


i<k~j

Optimum binary search trees are a special case of these recursion equa-
tions: take w(i,j) = wi + 1 ,j = a i + Si+l + ... + Sj + aji then
c(i,j) = Pi+l,j.

The algorithm given in the proof of theorem 1 also allows us to compute


c(i,j), 1 ~ i < j ~ n, in time o(n 3 ). There is however a faster way to
compute c(i,j) if function w(i,j) satisfies the quadrangle inequality
(QI)

w(i,j) + w(i',j') ::; w(i',j) + w(i,j') for i ~ i' < j ~ j'

Theorem 2: If w satisfies QI and is monotone with respect to set in-


clusion of intervals, i.e. w(i,j') ::; w(~,j) if i ~ i' < j ~ j', then
function c as defined above can be computed in time o(n 2 )

Remark: Before we give a proof of theorem 2 we apply it to optimum


binary search trees. Function w(i,j) = w.+ 1 . is obviously monotone and
1 , J
satisfies QI, in fact with equality.

Proof of theorem 2: Theorem 2 is proven by establishing the following


two lemmas.
164

Lemma 2: If w satisfies QI and is monotone then function c defined


above also satisfies QI, i.e. c(i,j) + c(i',j') ~ c(i,j') + c(i',j)
for i ~ i' ~ j ~ j'.
We use ck(i,j) to denote w(i,j) + c(i,k-1) + c(k,j) and we define
K(i,j) = max {k; ck(i,j) = c(i,j)} for i < j. Also K(i,i) = i. Then
K(i,j) is the largest index where the minimum is achieved in the defi-
nition of c(i,j). Then

Lemma 3: If c satisfies QI then K is monotone, i.e.

K(i,j) ~ K(i,j+1) ::;; K(i+1,j+1) for i ~ j

Lemma 3 is the key for improving the running time of dynamic program-
ming to O(n 2 ) as we have seen above. It remains to prove lemmas 2 and 3.

Proof of lemma 2: We use induction on the "length" 9- j'-i of the


quadrangle inequality for c(QIc)

c(i,j) + c(i',j') ~ c(i,j') + c(i',j) for i ~ i' ~ j ~ j'

This inequality is trivially true if i = i' or j = j ' . This proves Qlc


for 9- ~ 1. For the induction step we have to distinguish two cases:
i' = j or i' < j

Case 1: i < i' = j < j ' . In this case QIc reduces to

c(i,j) + c(j,j') ~ c(i,j')

, an (inverse) triangle inequality. Let k K (i, j , ). "I'iTe distinguish two


symmetric subcases: k ~ j or k ~ j.

Case 1.1: k ~ j. We have c(i,j') = w(i,j') + c(i,k-1) + c(k,j') and


therefore

c (i, j) + C (j , j ') ~ w (i, j) + C (i, k-1) + c (k, j) + C (j , j , )


(deL of c(i,j»
~ w(i,j') + c(i,k-1) + c(k,j) + c(j,j')
(monotonicity of w)
~ w(i,j') + c(i,k-1) + c(k,j')
(triangle inequality for k ~ j ~ j')
165

:5 c(i,j')

Case 1.2: k ~ j. This is symmetric to case 1.1 and left to the reader.

Case 2: i < i' < j' < j. Let y = K(i' ,j) and z = K(i,j'). Again we
have to distinguish two symmetric cases z:5 y or z ~ y. We only treat
the case z :5 y. Note first that z :5 y :5 j by definition of y and i < z
by definition of z. We have

c(i' ,j') + c(i,j) c y (i' , j , ) +c z (i, j)

w (i' ,j , ) +c (i' ,y-1 ) +c (y, j , ) +w (i, j) +c (i, z-1 ) +c (z, j)

:5 w(i,j') +w(i' ,j) +c (i' ,y-1) +c (i,z-1) +c (z,j) +c (y, j')

,by QI for w

:5 w (i , j , ) +w (i' ,j) +c (i ' ,y-1 ) +c (i, z -1 ) +c (y , j ) +c (z , j , )

,by the induction hypothesis, i.e. QI for c, applied to z :5 Y :5 j :5 j'

c (i, j , ) +c ( i ' ,j)

,by definition of y and z. This completes the induction step and thus
proves lemma 2. o

Proof of lemma 3: Lemma 3 is trivially true when i j, and so we only


have to consider i < j. We will only prove K(i,j) :5 K(i,j+1). Recall
that K(i,j) is the largest index where the minimum is assumed in the
definition of c(i,j). It therefore suffices to show

[ c k ' (i, j) :5 c k ( i, j) 1 * [c k ' (i, j + 1) :5 c k (i, j + 1 ) 1

for all i < k :5 k' :5 j, i.e. if K(i,j) prefers k' over k then so does
K(i,j+1). In fact, we will show the stronger inequality

or equivalently

c k (i, j ) + c k ' (i, j + 1) :5 c k ' (i, j) + c k (i , j + 1 )


166

or equivalently by expanding all four terms using their definition

c(k,j) + c(k' ,j+1) ::; c(k' ,j) + c(k,j+l)

However, this is simply the QI for c at k ::; k' ::; j ::; j+l. DD

Dynamic programming is a very versatile problem solving method. The


reader finds many applications in exercises 10 - 12 and in sections
V.2. and VI.6.1 •• Dynamic programming is closely related to problem
solving by backtracking. We illustrate the connection with two examples:
optimum binary search trees and simulating 2-way deterministic pushdown
automata on randOm access machines.

A call OST(l,n) of the following recursive procedure computes the cost


of an ~ptimum ~earch .!ree.

(1) real function OST(i,j : integer);


OST computes the weighted path length of an optimum
tree for xi' ••. ,x j •
(2) i f i = j +
(3) then OST .... 0
(4) else OST .... 00;
(5) for k from i to j
(6) do OST .... min(OST, wij + OST(i,k-l) + OST(k+l,j))
(7) od
(8) fi
(9) end

The running time of procedure OST is exponential. If T(n) is the time


required by OST to find the optimum cost of a tree for a set of n ele-
n-l n-l
ments then T(n) = O(n) + L (T(i) + T(n-i-1) ) = O(n) + 2 L T(i) .
i=o i=o
Subtracting the equations for T(n+l) and T(n) yields T(n+l) - T(n)
0(1) + 2 T(n) and hence T(n+l) = 0(1) + 3 T(n). This shows that T(n)
grows exponentially.

Of course, the exponential running time of OST stems from the fact that
subproblems OST(i,j) are solved repeatedly. It is therefore a good idea
to introduce a global table P[i,j] and to record the values computed by
OST in this table. This leads to
167

(1 ' ) real function OST(i,j integer) ;


(2' ) i f P[i,j] is defined
(3' ) then OST ..... P[i,j]
(4 ' ) else i f i j +
(5' ) then OST 0
(6 ' ) else OST co'I

(7' ) for k from i to j


(8' ) do OST ..... min(OST,w .. + OST(i,k-1) + OST(k+1, j))
1J
(9 ' ) od
(10' ) fi;
(11 ' ) P[i,j] ..... OST
( 1 2 ' ) fi
( 1 3 ' ) end

Note that lines (4') - (11') are executed at most once for every pair
(i,j), i + 1 $ j. Hence the total time spent in lines (4') - (11') of
OST is O(n 3 ). Also note that the total number of calls of OST is O(n 3 )
since lines (4') - (11') are executed at most once for every pair (i,j).
Thus the total time spent in lines (1') - (3') and (12') - (13') of OST
is also o(n 3 ).

We can see from this example that tabulating function values in ex-
haustive search algorithms can have a dramatic effect on running time.
In fact, the revised program above is essentially our dynamic pro-
gramming algorithm. The only additional idea required for the dynamic
programming algorithm is the observation that recursion can be replaced
by iteratioJ;L.

We describe one more application of this approach. A two-way determin-


istic pushdown automaton consists of a finite set of states, an input
tape with a two-way reading head and a pushdown store

$ a1 a2 a. an ¢
1

U
[COntrOl J --+
168

Formally, a 20POA is a 7-tuple (S,A,B,F,go'C,o) consisting of a finite


set S of states, an input alphabet A, a pushdown alphabet B, a set F c S
of accepting states, a start state go E S, initial pushdown sy~bol

C E B and a transition function 0 : S x (A U {$, ¢}) x B - S x ({E} U B2)


x {-l,n.

On input a 1 a 2 ••. an E A* the machine is started in state go with


$ a 1 ••• an ¢ on its input tape, its reading head on a 1 and with C in
the pushdown store. The machine then operates as given by o. More pre-
sicely, if the machine is in state g E S, reads a E A U {$,¢}, has SO,
S E B*, 0 E B, in its pushdown store and o(g,a,O) = (g',a,~) then the
new state is g', the new content of the pushdown store is Sa and the
input head is moved by ~. Note that a E {E} U B2. If a = E then the
move is called a pop move, if a E B2 then the move is called a push
move. A 20POA is not allowed to leave the portion of the input tape
delimited by $ and ¢, i.e. o( ,$, ) = ( , , + 1) and o( ,¢, ) =
( , , - 1). A 20POA halts if it empties its pushdown store. It accepts
if it halts in an accepting state.

Example: We describe a 20POA M which does pattern matching, i.e. it


accepts all strings a 1 ••• am # b 1 ••• b n , ai,b j E {O,l} such that
there is a j with a i = b j + i - 1 for 1 ~ i ~ m. In other words, M decides
whether pattern a 1 ••• am occurs in text b 1 ••• b n • Machine M operates
as follows.

(1) move the head to the right endmarker ¢ and then move left and store
b n ,b n _ 1 , ••. ,b 1 in the pushdown store; b 1 is at the top of the push-
down store. Position the input head on a 1 •

(2) while the symbol under the input head and the top pushdown symbol
agree
do move the input head to the right and delete one symbol from
the pushdown store
od

(3) if the symbol under the input head is #


then empty the pushdown store and accept fi

(4) if the top symbol on the pushdown store is C (the special symbol)
then empty the pushdown store and reject fi
100

(5) Move the input head to a 1 • While moving left push all symbols
scanned onto the pushdown store
(6) Remove one symbol from the pushdown store and go to (2).

The correctness of this machine follows from the following observation.


Before step (2) the input head is on a 1 and the pushdown store contains
b j b j +1 b n with b j being at the top. If in step (2) we move the in-
*
put head to a i + 1 then a h = b j +h - 1 for 1 ~ h ~ i and a i + 1 bj+i' Next
observe, that i = m implies that we found an occurrence of the pattern
and that j + i = n + 1 implies that the text is too short to contain an
occurrence of the pattern. In step (5) we push b,+, J 1-
l ' b,+, 2, ••• ,b,
J 1- J
in that order onto the pushdown store. Thus restoring the initial con-
figuration. In (6) we remove b j from the stack and then search for an
occurrence of the pattern starting at b j + 1 • c

Of course, a 2DPDA can be directly implemented on a RAM. The disadvan-


tage of this approach is that the running time might be quite large. In
our example, the worst case running time of the 2DPDA and hence the RAM
is O(m·n). We can do a lot better.

Theorem 3: If a language L is accepted by a 2DPDA then there is RAM


which accepts L in linear time.

Proof: We will first define a recursive procedure which accepts Land


then improve its running time by tabulating function values.

Let M = (S,A,B,F,qo'C,o) be a 2DPDA and let a 1 a 2 .•• an E A* be an in-


put. A triple (q,D,i) with q E S, DEB and 0 ~ i ~ n + 1 is called a
surface configuration of Mi here i denotes the position of the input
head on the input tape. Note that the number of surface configurations
on input a 1 ••• an is ISI·IBI (n+2) = O(n). Define partial function
term: S x B x [O ••• n+1] ~ S x [O ••• n+1] by term(q,D,i) = (p,j) if M
started in configuration (q,D,i) will eventually empty its pushdown
store and is in state p and input position j in this case.

Next note that term(qo,C,1) = (p,j) for some p E F iff M accepts


a 1 a 2 ••• an' It thus suffices to compute term. The following (in-
efficient) recursive procedure TERM computes term
170

(1) function TERM(q,D,i)


(2) if o(q,D,a i ) = (p,E,ll)
(3) then TERM - (p,i+ll)
(4) else let o(q,D,a i ) = (p,GH,ll) where G, H E Bi
(5) (r,j) - TERM(p,H,i+ll) i
(6) TERM - TERM(r,G,j)
(7) fi
(8) end

The correctness of this program is almost immediate. Procedure TERM


certainly computes term if line (3) applies. If lines (4) - (6) apply
then the computation out of configuration (q,D,i) starts with a push
move. When the pushdown store has length 1 for the next time, the ma-
chine is in state r and scans position j (line 5). The content of the
pushdown store is G at this point. Therefore term is correctly computed
in line 6. The running time of this program is equal to the running
time of the underlying 2DPDA. As in our previous example we observe
that TERM may be called repeatedly for the same argQment. This suggests
to tabulate function values in a table which we call TE. In table TE we
store terminators which were already computed and we store * in order
to indicate that a call of TERM was initiated but not yet completed.
Initially, all entries of TE are undefined. We obtain

(1') function TERM(q,D,i)


(2') if TE[q,D,i] = *
(3') then halt and reject because the 2DPDA is in an infinite 100Pi
(4') fi;
(5') if TE[q,D,i] is defined
(6') then TERM - TE[q,D,i]
(7' ) else TE[q,D,i] - *;
(8' ) if o(q,D,a i ) = (p,E,ll)
(9' ) then TERM - TE[q,D,i] - (p,i+ll)
(10' ) else let o(q,D,a i ) = (p,GH,ll) where G,H E B;
(11 ' ) (r,j) - TERM(p,H,i+ll)i
(12' ) TERM - TE[q,D,i] - TERM(r,G,j)
(13') fi
(14') fi
(15') end
171

Claim: a) The total running time of call TERM(qo,C,1) is O(n).

b) A call TERM(qo,C,1) correctly computes term(qo,C,1).

Proof: a) Recall that the number of surface configurations is O(n).


Observe next, that lines (7') - (13') are executed at most once for
each surface configuration. Hence the total time spent in lines (7') -
(13') is O(n) and the total number of calls of TERM is O(n). Thus the
total time spent in lines (1') - (6'), (14') - (15') of TERM is also
O(n). This shows that the total running time is O(n).

b) Observe first that if term(q,D,i) returns pair (r,j) then


term(q,D,i) =(r,j). It remains to consider the case that the simula-
tion stops in line (3'). This can only be the case if there is a call
TERM(q',D',i') which (indirectly) initiates call TERM(q',D',i') before
its own completion. In this case we detected an infinite loop in the
computation of M. cc

Theorem 3 has a very pleasant consequence. Pattern matching can be done


in linear time on a RAM. Of course, the algorithm obtained by applying
theorem 3 to the 2DPDA described in the exercise above is quite involved
and will be hard to understand intuitively. We therefore give an alter-
nate simple linear time algorithm for pattern matching next.

Let a 1 •.• an be a pattern and let b 1 b 2 .•. b m be a text, ai,b j E {O,1}.


We want to find all occurrences of the pattern in the text. Define
f : [1 ••• n] ~ [O ••• n], the failure function for the pattern, by

f(i) max{h < ii a i - k = a h - k for 0 ~ k < h}

The significance of function f is as follows. Suppose that we started


to match the pattern at position j of the text and succeeded up to
position i of the pattern, i . e. a 1 = b j + 1- 1 for 1 ~ 1 ~ i and a i + 1 * bj+i.
At this point we can slide the pattern to the right and start

b j b j +1 b j +i-1 bj+i
II
a1 a2 ai *
a i +1

a 1 •••• • ah ah+1
172

matching at some later position in text b. If we move the pattern to


Lhe right such that a h is below b j + i - 1 then a match can only succeed if
we have a i - k = a h - k for 0 ~ k < h. Thus the only sensible values for h
to try are f(i), f(f(i)), We obtain the following algorithm. In
this algorithm we that we added a special symbol a n + 1 to the
ass~e

pattern which does not match any symbol in the text.

(1) i .... O;j .... O;


(2) while j ~ m
(3) do b j - i + 1 ••• b j and (9, > i implies a 1 •.• a t *
b j - H1 . . . b j )
(4 ) i f ai+1 = b j +1
(5) then i .... i + 1; j .... j + 1
(6 ) else i f i = n then report match starting at b j - n + 1 fi;
(7) if i 0
(8 ) then j + j + 1
(9) else i f(i)
(10) fi
( 11 ) fi
( 1 2) od

Lemma 4: The program above determines all occurences of pattern


p = a 1 ••• a n in text b 1 •.. b m in time O(m).

Proof: In order to prove correctness it suffices to verify the loop


invariant. It is certainly true initially, i.e. if i = j = o. So assume
the invariant is true before executing the loop body. If a i + 1 = b j + 1
then the invariant trivially holds after execution of the body, if
a i +1 *
b j + 1 and i = 0 then it also holds trivially and if i > 0 then it
holds by definition of f.

The bound on the running time is shown as follows. In each iteration


either line (5), line (8) or line (9) is executed. Lines (5) and (8)
increase j and are therefore together executed exactly m + times. In
line (9) the value of i is decreased since f(i) < i. Since i is only
increased in line (5) and i ~ 0 always we conclude that line (9) is
executed at most m + 1 times. IJ

Lemma 4 shows that pattern matching requires linear time if failure


function f is available. Fortunately, f can be computed in time O(n).
173

In fact, the same algorithm can be used because f is the result of


matching the pattern against itself.

i - O~ j - 1~ f(1) - O~
while j :5 n
do -a a and (i <
a 1 ••· a i - j-i+1··· j
R, < ]' implies a 1 ···a.~ *
a.]-R, +1 ..• a ].)
+1 = a j +1
if a i
then f(j+1) - i + 1~ i j + 1
else if i = 0
then f (j+1) O~ j j + 1
~ i - f(i)
fi

od

Lemma 5: The program above computes failure function f in time O(n).

[]
Proof: Similar to the proof of lemma 4.
We sUIlll1iarize in
Theorem 4: All occurrences of pattern a 1 .•. a n in string b 1 ••• b n can be
found in linear time O(n + m).

Proof: Immediate from lemmas 4 and 5. []

The dynamic programming algorithm for optimum binary search trees has
quadratic space and time requirement. It can therefore only be used for
small or medium size n. In the next section we will discuss algorithms
which construct nearly optimal binary search trees in linear time. Note
that giving up optimality is really not that bad because the access
probabilities are usually only known approximatively anyhow. There is
one further advantage of nearly optimal trees. We will be able to bound
the cost of every single access operation and not only expected cost.
Recall that average and worst case behaviour can differ by large
amounts, e.g. in Quicksort~ a similar situation could arise here.

We will not be able to relate weighted path length of optimum trees and
nearly optimal trees directly. Rather we compare both of them to
an independent yardstick, the entropy of the access distribution.
174

Definition: Let (Y 1 , ••• ,Y n ) be a discrete probability distribution, i.e.


Yi ;:: 0 and I:y i = 1. Then
n
I: Yi log Yi
i=1

is called the entropy of the distribution. We use the convention


O·log 0 = o. [J

Some basic properties of the entropy function can be found in the ap-
pendix. In the sequel we consider a fixed search tree T for set
S = {x 1 ' ••• ,x n } and access distribution (cx O,S1, ••• ,Sn'cx n ). We use H to
denote the entropy of the distribution, i.e. H = H(CX O,S1, ••• ,Sn'cx n )
and we use bi(a j ) for the depth of node xi (leaf (x j ,X j + 1 » for
1 :5 i :5 n (0:5 j :5 n). P is the weighted path length of T. We will prove
lower bounds on the search times in tree T. These lower bounds are in-
dependent of the structure of T; in particular, they are valid for
the optimum tree. The proofs follow classical proofs of the noiseless
coding theorem.

Lemma 6: Let c E IR with 0 :5 c < 1. Let

Bi «1_C)/2)b i c , 1 :5 i :5 n
a.
(Xj «1-c)/2) J ,0 :5 j :5 n

Then Bi , (Xj ;:: 0 and I:Bi + I:a j


bility distribution.

Proof: (By induction on n). If n = 0 then a O = 0 and hence (Xo = 1. So


assume n > O. Let x k be the root of T, T~(Tr) the left (right) subtree
of T. Let bi(bi), 1 :5 i :5 k-1 (k+1 :5 i :5 n) be the depth of xi in tree
T~(Tr). Define aj and aj analogously. Then

for :5 i :5 k-1
b.J. for i k
for k+1 :5 i :5 n

and
175

={
a '. + 1 for 0 S; j S; k-1
J
aj
a'! + 1 for k S; j S; n
J

Also by induction hypothesis


k-1 b '. k-1 a '.
l
s£ L «1-c)/2) c + L «1-c)/2) J = 1
i=1 j=O
An analogous statement holds for T r . Furthermore, Sk c. Thus

LfL +
i l
La.
j J
= «1-c)/2)Sn + c + «1-c)/2)Sr = 1
Yv
IJ

Theorem 5: (Lower Bound on weighted path length). Let B LSi. Then

a) max {(H-dB)/10g(2+2- d ); d E: IR} S; P


b) H S; P + B[log e - 1 + log (P/B) 1

where we used the notation as defined above.

Proof: a) Define Si and a j as in lemma 6. Then

b. + 1 1 + (log S. - log c)/log c


l l

(log a.) flog c


J
where c = (1-c)/2. An application of property 3) of the entropy func-
tion (cf. appendix) yields (note that log c < 0)
P LSi (b i +1) + La. a j
J
B (1 - log c/log c) + (1/10g c) [LS. log 'Bi + La. log ajl
l J
~ B (1 - log c/log c) - (1/10g c) ·H

(H - B 10g(c/c))/10g(1/c)

Setting d = log(c/c) and observing that c/c = 2c/(1-c) is a surjective


mapping from 0 S; c < 1 onto the reals finishes the proof of part a).

b) Unfortunately, there is no closed form expression for the value of


d which maximizes the left side of a). Numerical methods have to be
used to compute d max in every single application. A good approximation
for d max is d = 10g(P/2B). It yields

H S; P.log(2+2- d ) + dB

P 10g(2+2B/P) + B 10g(P/2B)

S; P(1+(B/P)10g e) + B(log P/B-1)


176

since log x ~ (x-1) log e


= P + B(log e - 1 + log P/B) [J

Special case d = 0 is also useful in some occasions. It yields


P ~ H/log 3. We will next turn to the behavior of single access opera-
tions. Theorem Sa reads in expanded form
-d -d
L~i[(-log ~i-d)/log(2+2 ») + Laj[-LOg a j /log (2+2 »)

~ L~i[(bi+1») + Laj[a j )
We show that the inequality above is almost true componentwise for the
expressions in square bracketsi more precisely, for h E JR, h> 0
define

and

Then
L ~o L ao ~ 2
-h ,
iENh J. + jELh J

i.e. for a set of leaves and nodes, whose total weight exceeds 1 - 2
-h ,
theorem Sa "almost" holds componentwise. "Almost" has to be interpret-
ed as: up to the additive factor -h/log(2 + 2- d ). The proof of this
claim goes as follows. Let d = log(c/c) with c = (1 - c)/2 and
- -d-
o ~ c < 1. Then d = log c - log c and log(2 + 2 ) = log(1/c). A simple
computation shows that the definitions of Nh and Lh are equivalent to

Hi 2- h Si} and
Nh ~i ~

{ji ao 2- h U }
Lh J
~ j

where Si and Uj are defined as in lemma 6. Thus

LSi + La 0

J
~ L Si + Lao ~ 2h[ L i3 + Lao)
i
iENh J°EL h J iENh J°EL h J
We summarize in

Theorem 6: (Lower Bounds for single access operations). Let c,h E JR


with 0 ~ c < 1 and h > O. Define Si' a j as in lemma 6 and let

Nh {ii ~i ~ 2- h Si}

and
177

Lh {j; 0.. ~ 2-h -o. j }


J
Then
L ~\ + L 0.. ~ 2- h c
iENh jEL h J

We give an explicit example for theorems 5 and 6 at the end of section


III.4.2.

III. 4.2 Nearly Optimal Binary Search Trees

In binary search (cf. 111.3.1.) we always compare the argument of the


access operation with the middle element of the remaining array and
hence exclude at least half of the set in every step of the search. We
deal now with the more general situation that elements have different
weights (probabilities). We should therefore try to exclude in every
step one half of the elements in probability. Let us consider the
example from the beginning of 111.4. and let us draw the distribution
on the unit line.

o 1/4 1/2
Point 1/2 lies wibhin a Si or an o. j • In the first case we should choose
xi as the root of the search tree, in the second case we should either
choose Xj if 1/2 lies in the left half of o. j or x j + 1 if 1/2 lies in the
right half of o. j • In our example we choose x3 as the root. This also
fixes the right subtree. For the left subtree we still have the choice
of choosing either x 1 or x 2 as the root.

Method 1: The restriction of our access distribution to set {x 1 ,x 2} is


given by (1/6 W, 1/24 W, 0, 1/8 W, 0) where W = (1/6 + 1/24 + 1/8)-1
We proceed as described above and look for the middle of this distribu-
tion. In this way we will choose x 1 as the root of the left subtree.
Method 1 is analysed in exercise 20.
178

Method 2: We proceed by strict bisection, i.e. we choose the root of


the left subtree by considering reference point 1/4. Point 1/4 is con-
tained in S2 and therefore x 2 is chosen as the root of the left subtree.
In this way the following tree with weighted path length P BB = 50/24 is
constructed.

We now describe method 2 in more detail. Let

for 1 :::; i :::; n

Then a call construct-tree(O,n,O,1) constructs a search tree according


to method 2.

procedure construct-tree(i,j,cut,£);

comment we assume that the actual parameters of any call of construct-


tree satisfy the following conditions.

(1) i and j are integers with 0 :::; i < j :::; n,


(2) £ is an integer with £ ~ 1,
£-1 -p
(3) cut Lp=1 Xp2 with xp E {O,1} for all p,
(4) cut :::; s. :::; s. :::; cut + 2-£+1.
l J

A call construct-tree (i,j, ,) will construct a binary search tree for


nodes i + 1, .•• , j and leaves i, .•. , j ;

if i + 1 = j (Case A)

then return tree


179

else
determine k such that

(5) i < k :;; j

(6) k i + or s :;; cut + 2- t


k-1
(7) k

comment k exists because the actual parameters are supposed to satisfy


condition (4);

if k = i + 1 (Case B)
then return

construct-tree(i+1,j,cut+2- t ,t+1)

if k j (Case C)
then return

construct-tree(i,j-1,cut,t+1)

if i + 1 < k < j (Case 0)


then return fi

-t
construct-tree(i,k-1,cut,t+1) construct-tree(k,j,cut+2 ,t+1)
fi

end
180

Theorem 7: Let b i be the depth of node xi and let a j be the depth of


leaf (x j ,X j + 1 ) in tree TBB constructed by construct-tree (O,n,O,1) . Then

Proof: vle state several simple facts.

Fact 1: If the actual parameters of a call construct-tree(i,j,cut,~)

satisfy conditions (1) to (4) and i + 1 f j, then a k satisfying condi-


tions (5) to (7) exists and the actual parameters of the recursive calls
of construct-tree initiated by this call again satisfy conditions (1) to
(4) •

Proof: Assume that the parameters satisfy conditions (1) to (4) and
-£+1
that i + 1 f j. In particular, cut $ s. $ cut + 2 • Suppose, that
J _~ _~
there is no k,i < k $ j, with sk-1 $ cut + 2 and sk 2 cut + 2 '. Then
either for all k,i < k $ j,sk < cut + 2-~ or for all k,i < k $ j,
-~
sk_1 > cut + 2 In the first case k j satisfies (6) and (7), in the
second case k i + 1 satisfies (6) and (7). This shows that k alvlays
exists. It remains to show that the parameters of the recursive calls
satisfy again (1) and (4). This follows immediately from the fact that
-~
k satisfies (5) to (7) and that i + 1 f j and hence sk 2 cut + 2 in
-~
Case Band sk-1 $ cut + 2 in Case C. D

Fact 2: The actual parameters of every call of construct-tree satisfy


conditions (1) to (4) (if the arguments of the top-level call do) .

Proof: The proof is by induction, Fact 1 and the observation that the
actual parameters of the top-level call construct-tree (O,n,O,1) satis-
fy (1) to (4). D

We say that node h(leaf h resp.) is constructed by the call construct-


tree(i,j,cut,~) if h = j(h = i or h = j) and Case A is taken or if
h = i + 1 (h i) and Case B is taken or if h = j(h = j) and Case C is
taken or if h = k and Case D is taken. Let b i be the depth of node i
and let a. be the depth of leaf j in the tree returned by the call con-
J
struct-tree (O,n,O, 1) .
181

Fact 3: If node h Qeaf hl is constructed by the call construct-tree


(i,j,cut,£), then b h + 1 = £(a h = £).

Proof: The proof is by induction on £. D

Fact 4: If node h(leaf h) is constructed by the call construct-tree


..
( 1,],CU t ,~0) , t h en Sh <_ 2-£+1 (Nh
~ <_ 2-£+2).

Proof: The actual parameters of the call satisfy condition (4) by fact
2. Thus

- S.
1

~ Sh(resp. a h /2). D

-b -a +2
We infer from facts 3 and 4, Sh ~ 2 hand a h ~ 2 h Taking
logarithms and observing that b h and a h are integers proves the
theorem. D

TheoreITs 6 and 7 together give fairly detailed information about the


tree constructed by procedure construct-tree. In particular, we have

for most nodes and leaves of tree TBB . Substituting the bounds on b i
and a j given in theorem 7 into the definition of weighted path length
we obtain

Theorem 8: Let P BB be the weighted path length of the tree constructed


by construct-tree. Then

and further

Theorem 9: Let P BB be the weighted path length of the tree constructed


by construct-tree for distribution (a O ,S1' ... ,Sn,a n ) and let P opt be
182

the weighted path length of an optimum tree. Then (B = LSi)

a) max { H-dB ,. d E \R} <_ P < H + 1 + 'a.


-< P BB-
log (2+2 d ) opt
L.
J"

Proof: a) follows immediately from theorem 5a and 8 and b) follows


immediately from theorem 5b and 8. c

Theorem 9 can be interpreted in two ways. On the one hand it shows that
the weighted path length P BB of tree TBB is always very close to the
optimum and hence TBB is a good search tree. Essentially, part b) shows

On the other hand, it provides us with a small interval containing P op t


as well as P BB • This interval is easily computable from the distribu-
tion and affords us with a simple a-priori estimate of the behaviour of
search trees. This estimate can be used in the decision whether to use
weighted trees or not. The bounds given in theorems 5 - 9 are sharp (cf.
exercises 18,19).

Let us illustrate our bounds by an example. There is extensive litera-


ture about word frequencies in natural languages. In English, the prob-
ability of oc~e of the i-th most frequent word (cf. E.S. Schwartz,
JACM 10 (1963), 413 - 439) is approximately

where c = 1/L (1/i) 1.12


i~1

A simple calculation yields

In the light of theorem 9 we would therefore expect that the weighted


path length of an optimum binary search tree for all English words is
about 10.2 and certainly no larger than 11.2. This was also observed in
experiments. Gotlieb/Walker took a text of 10 6 words and counted word
frequencies. Then they constructed (nearly) optimal binary search trees
183

for the N most common words, N = 10, 100, 1 000, 10 000, 100 000. Let
P N be the weighted path length of the tree constructed for the N most
common words. Then PN ~ 11 for N ~ 00 as the figure (due to Gotlieb/
Walker) below suggests. This is in good agreement with theorem 9.
PN logn

11

log 500 log 10 5 log N


We will now turn to the time complexity of recursive procedure con-
struct-tree. Let T(n) be the maximal running time required by
construct-tree for a tree with n nodes, i. e. n = j - i. If n 1, then
the body of construct-tree requires constant time. Hence

T(1) = c1

for some constant c 1 . If n > 1 then k has to be determined and some


recursive calls have to be initiated. Let Ts(n,m) be the time required
to find k, where m = k - i. We determine Ts(n,m) below when we specify
a concrete algorithm for finding k. Construct-tree is called once or
twice recursively within the body. In Case D the first call constructs
a tree with k - i m - 1 nodes and the second call constructs a
tree with j - k n - m nodes. Hence

T(n) ~ max [T(m-1) + T(n-m) + Ts(n,m) + c 2 ]


m

Constant c 2 measures the cost of parameter passing, • . . • If we define


T(O) = 0 then the inequality above also holds true in cases Band C of
construct-tree where only one recursive call is started. With the con-
vention T s (1,m) = 0 and c = max(c 1 ,c 2 ) we can further simplify our in-
equality and obtain

T(O) 0
184

T(n) 5 max [T(m-1) + T(n-m) + TS(n,m) + cl


15m5n

We discuss two methods for finding k.


Binary Search: We first try r = L(i + 1 + j)/2 J • If sr ~ cut + 2
then k 5 r, otherwise k ~ r. We iterate as described in 111.3.1. and
find k in log n steps. Thus Ts(n,m) 5 d·log n for some constant d, and
we obtain

T(O) 0

T(n) 5 max [T(m-1) + T(n-m) + c + d log nl


15rn5n

We infer T(n) O(n log n), cf. section 11.3 .. Conversely,

n
T(n) ~ T(n-1) + d·log n + c ~ d· L log i r/(n log n)
i=1

Theorern10: If the search for k in procedure construct-tree is imple-


mented by binary search, then T(n) = 8 (n log n).

Exponential and Binary Search: The running time of procedure construct-


tree with binary search is r/(n log n) since we use up log(j-i) time
units even if k ~ i + 1 or k ~ j, i.e. even if the size of the problem
to be solved is reduced only by a small amount. If we want to improve
upon the O(n log n) time bound we have to use a search algorithm which
finds k fast if k is close to the extremes. A first attempt is to use
linear search and to start the search simultaneously at both ends. How-
ever, this is not good enough. If k = (i + 1 + j)/2 then this method
will use 8(j-i) steps to find k and again we obtain an O(n log n)
algorithm (exercise 21). So, how can we do better? We should start
searching from the end but not in unit steps:

(1) Compare sr with cut + 2-£ for r = L(i + 1 + j)/2 J • If


sr ~ cut + 2-£ then k E {i + 1, .•. ,r}, if sr 5 cut + 2-£ then
k E {r, ••. , j}. We assume for the sequel that k E {i + 1, ••. ,r} .
Step 1 has constant cost, say d 1 •

(2) Find the smallest t, t 0,1,2, ..• , such that s ~ cut + 2-£.
i+2 t
185

Let to be that value of t. We can find to in time d 2 (t O + 1) for


t -1 to t
some constant d 2 • Then i + 2 0 < k S i + 2 , i.e. 2 0 ~
t -1
k - i = m > 2 0 and hence log m > to - 1. Thus the cost of step
2 is bounded by d 2 (2 + log m).

(3) Determine the exact value of k by binary search on the interval


t -1 to t t -1
i + 2 0 + 1, ••• , i + 2 • This takes d 3 (log(2 0 - 2 0 ) + 1)
= d 3t o < d 3 (1 + log m) time units for some constant d 3 •

Exponential (step 2) and binary search (step 3) allows us to find k


in S d(1 + log m) time units provided that i < k S Ji + 1 + j)j2 J •

Here m =k - i and d is a constant. Similarly, k can be found in


S d(1 + log(n - m +1» time units if L(i + 1 + j)j2 J < k. Thus
Ts(n,m) = d(1 + log min(m,n - m + 1» and we obtain the following re-
currence relations for the worst case running time of construct-tree.

T(O) 0

T(n) max [T(m-1) + T(n-m) + d( 1 + log min(m,n-m+1» + cl


1SmSn

Theorem 11: If the search for k in procedure construct-tree is imple-


mented by exponential and binary search, then T(n) = O(n) .

Proof: We show by induction on n:

T(n) S (2d + c)n - d log(n + 1)

This is certainly true for n O. For n > 0 we have

T(n) S max [T(m-1) + T(n-m) + d(log min(m,n-m+1» + d + cl


1SmSn

max [T(m-1) + T(n-m) + d log m + d + cl


1SmS(n+1)j2

by the symmetry of the expression in square brackets in m - 1 and


n - m. Next we apply the induction hypothesis and obtain
186

~ max [(2d+c) (m-1+n-m)-d (log m + log(n-m+1» + d log m + (d+c)]


1~m~(n+1)/2

(2d+c)n + max [-d(1 + log(n-m+1)]


1~~(n+1 )/2

The expression in square brackets is always negative and is maximal for


m = (n + 1)/2. Thus

T(n) ~ (2d + c)n - d(1 + log(n + 1)/2)

(2d + c)n - d log(n + 1) IJ

Let us summarize. Construct-tree constructs trees which are nearly op-


timal with respect to average (theorem 9) as well as with respect to
single search times (theorems 6 and 7). Construct-tree can be made to
run in linear time (theorem 11) . We conclude this section by exemplify-
ing theorems 8 to 9 on the example from the beginning of section III.4.
We start with theorem 9, which concerns average search times. We havp.
H F<:1 2.27, ~Si[log 1/S' J + ~or.. Llog 1/or.. J F<:1 2.04, ~S. F<:1 0.29, ~OI.. F<:1 0.71.
~ J J ~ - J
d 1 .05 maximizes the left hand side of 9 a and yields 1. 50 ~ Popt ~
2.0 ~ 2.04 = PBB ~ 3.75. Of course, the additive constants play an al-
most dominating role in our bounds for that small value of H. We
have seen in the application to an English dictionary that the esti-
mates are much better for large values of H.

We will now turn to theorems 6 and 7 about the behaviour of single


searches:

name of node
or leaf
depth in
Topt
depth in probability -
L log PJ Bi , 01..
J
for
'13B c = 1/2

x1 2 1/24 4 1/32
x2 2 1/8 3 1/8

x3 0 0 1/8 3 1/2
x4 0 00 1/8
,x 2 ) 2 3 1/6 2 1/64
(x 1 ,x 2 ) 3 3 0 00 1/64
187

(x 2 'x 3 ) 3 2 o 00 1/16

(x 3 ,x 4 ) 2 2 1/8 3 1/16

(x 4 ' ) 2 2 5/12 1/16

We can see from this table that the upper bounds given by theorem 7
exceed the actual values by 1 or 2. If we apply theorem 6 with c = 1/2
and h = 2 then N2 {3,4} and L2 {1,2} and

1/8 :::; 1/4

Hence nodes and leaves with total probability ~ 7/8 satisfy


theorem Sa componentwise (cf. the discussion preceding theorem 6).

III. 5. Balanced Trees:

We return to the discussion started in III.3.1.: Realizing operations


Access, Insert and Delete by binary trees. We saw in section III.3.1.
that the height of the tree plays a crucial role.

We consider only unweighted sets in this section, i.e. we are only in-
terested in the size of the sets involved. In other words, if T is a
search tree for set S = {x 1 < x 2 < .•• < xn} then we assume uniform access
probabilities, i.e. Si = 1/n and a j = O. As above, we use b i to denote
the depth of node xi in T.

p = r• (1/n) (b.1. + 1)
1.

is called the average (internal) path length of T. Theorems Sb and 6 of


the previous section give log n =H :::; P + log P + 0.44 and
height(T) ~ log n - 1. The second inequality is obtained by taking the
limit h - 0 in theorem 6. Somewhat better bounds can be obtained by
direct computation.

Theorem 1: Let T be a binary search tree for set S

a) P ~ Llog(n+1)J - 1

b) height(T) ~ rlog (n+1)'


188

Proof: Since T is a binary tree, there are at most 2i nodes of depth i


k i k+1
(i ~ 0), and hence at most L 2 = 2 -1 nodes of depth :5 k. Thus in a
i=O
tree with n nodes there must be at least one node of depth k where
2k+1 _ 1 ~ n. This proves b) since height(T) = max {depth (v) + 1;
v node of T} .

Apparently, a tree T with n nodes has minimal average path length, if


there is 1 node of depth 0, 2 nodes of depth 1, .•• ,2 k nodes of depth k,
k+1
and n - 2 + 1 nodes of depth k + 1. Here k = Llog(n+1)J - 1. Thus

k
P ~ 1/n( L (H1)2 i + (k+2) (n_2 k + 1 + 1))
i=O

1/n[k.2k + 1 + 1 + (k+2) (n_2 k + 1 + 1)]

~ Llog(n+1) J - 1 []

Theorem 1 shows that logarithmic behaviour is the best we can expect


from binary search trees in the worst case as well as in the average
case. Also, logarithmic behaviour is easy to obtain as long as we re-
strict ourselves to access operations. This is even true in the case
of weighted sets as we saw in 111.4. Insertions and deletions create
new problems; the naive insertion and deletion algorithms of 111.3.1
can create extremely unbalanced trees and thus lead to intolerable
search times. Inserting x 1 , •.. ,x n with x 1 < x 2 < ... < xn into an initial-
ly empty tree creates a tree with average path length (n+1)/2. Thus
tree search deteriorates to linear search. Extreme deterioration is not
very probable in the case of random

~
insertions (exercise 9). Deterioration
can be avoided completely if the
.... ..... tree is rebalanced after every in-
..... ..... sertion or deletion. We will see
..... later that rebalancing can be re-
.....
~ stricted to local changes of the
tree structure along the path from
the root to the inserted or deleted node. In this way, rebalancing time
is at most proportional to search time and hence total cost is still
logarithmic.
189

All known classes of balanced trees can be divided into two groups:
weight-balanced and height-balanced trees. In weight-balanced trees one
balances the number of nodes in the subtrees, in height-balanced trees
one balances the height of the subtrees. We will discuss one representa-
tive of each group in the text and mention some more in the exercises.

III. 5.1 Weight-Balanced Trees

For this section a is a fixed real, 1/4 < a ~ 1 - 12/2. The bounds on a
will become clear lateron.

Definition: a) Let T be a binary tree with left subtree T t and right


subtree Tr • Then

p(T) = ITtl/ITI = 1 - ITrl/ITI

is called the root balance of T. Here ITI denotes the number of leaves
of tree T.

b) Tree T is of bounded balance a, if for every subtree T' of T:

a ~ p(T') ~ 1 - a

c) BB[a] is the set of all trees of bounded balance a. o

In the following tree (leaves are not shown)

the subtrees with root u (v,w,x) have root balance 1/2 (2/3,2/5,5/14).
The tree is in BB[a] for a ~ 1/3.
190

Trees of bounded balance have logarithmic depth and logarithmic aver-


age path length.

Theorem 2: Let T € BB[a] be a tree with n nodes. Then

a) P ~ (1 + 1/n)log(n + 1)/H(a, 1 - a) - 1

where H(a, 1 - a) = - a log a - (1 - a)log(1 - a)

b) height(T) ~ 1 + (log(n + 1) - 1)/log(1/(1 - a»


Proof: a) For this proof it is easier to work with P= n·P = L (b i + 1).
We show P ~ (n + 1)log(n + 1)/H(a, 1 - a) - n by induction on n. P is
often called total (internal) path length of T. For n = 1 we have P = 1.
Since 0 ~ H(a, 1 - a) ~ 1 this proves the claim for n = 1. So let us
assume n > 1. T has a left (right) subtree with t(r) nodes and path
length Pt (P r ). Then n = t + r + 1 and P = Pt + Pr + n (cf. the proof
of lemma 1 in III.4.1.) and a ~ (t + 1)/(n + 1) ~ 1 - a. Applying the
induction hypothesis yields

1
~ H(a,1-a) [(Hl) log (H1) + (r+l) log (r+1)] + 1

n+1 t+1 t+1 r+1 r+1


H(a,1-a) [log (n+1) + n+1 log n+1 + n+1 log n+1] + 1

H (H1 r+1)
(n+1) log (n+1) + 1 _ (n+1). n+1' n+1
H(a,1-a) H(a,1-a)

~ H(a,1-a) (n+l) log (n+1) - n,

since H(x, 1 - x) is monotonically increasing in x for 0 ~ x ~ 1/2

b) Let T E BB[a] be a tree with n nodes, let k = height(T), and let


v O ,v 1 , .•• ,vk _ 1be a path from the root to a node v k _ 1 of depth k-1. Let
wi be the number of leaves in the subtree with root vi' 0 ~ i ~ k - 1.
Then
2 ~ wk - 1 and
191

for 0 :0:; i < k-1

since T is of bounded balance a, and therefore

2 < w < (1 a)k-1 w = (1-a) k-1 (1+n)


- k-1 - - 0

Taking logarithms finishes the proof. o

For a ~ 1 - 12/2 ~ 0.2928 theorem 2 reads

P :0:; 1.15(1+1/n) log (n+1) - 1 and

height(T) :0:; 2 log (n+1) - 1

A comparison with theorem 1 shows that the average search time in


trees in BB[1-/2/2] is at most 15 % and that the maximal search time is
at most by a factor of 2 above the optimum.

Operations Access, Insert and Delete are performed as described in


111.3.1. However, insertions and deletions can move the root balance of
some nodes on the path of search outside the permissib~ range [a,1-a].
There are two transformations for remeding such a situation: rotation
and double rotation. In the following figures nodes are drawn as circles
and subtrees are drawn as triangles. The root-balances are given beside
each node. The figures shmv transformations "to the left". The symmetri-
cal variants also exist.

rotation
192


double rotation

The root balances of the transformed trees can be computed from the old
balances P1' P2 (and P3) as given in the figure. We verify this claim
for the rotation and leave the double rotation to the reader. Let a,b,c
be the number of leaves in the subtrees shown. Then

a/(a+b+c) and P2 b/(b+c)

Since

a + b P1 (a+b+c) + P2 (b+c)

P1 (a+b+c) + P2 «a+b+c) - a))

= ( P1 + P2 (1-P 1 )) (a+b+c)

the root-balance of node x after the rotation is given by

and the root-balance of node y is given by

(a+b)/(a+b+c) = (p 1 + P2 (1-P 1 )).

Let us consider operation Insert first. Suppose that node a is added to


the tree. Let v O ,v 1 , ••. ,vk = a be the path from the root to node a. Op-

o
eration Insert(a) described in 111.3.1 creates the following subtree

cJi-itJ
wi th root-balance 1/2. I'le will now walk back the path to-
wards the root and rebalance all nodes on this path. So let
193

us assume that we reached node vi and that the root balances of all
proper descendants of vi are in the range [a,1-a]. Then 0 ~ i ~ k-1.
If the root-balance of node vi is still in the range [a,1-a] then we
can move on to node v i - 1 . If it is outside the range [a,1-a] we have to
rebalance as described in the following lemma.

Lemma 1: For all a E {1/4,1-/2/2] there are constants d E [a,1-a] and


o ~ 0 (if a < 1-/2/2 then 0 > 0) such that for T a binary tree with
subtrees T~ and Tr and
(1) T~ and Tr are in BB[a]
(2) IT~I/ITI < a and either
(2.1) IT~I/{ITI-1) ~ a (i.e. an insertion into the right subtree
of T occured) or
(2.2) (IT~I+1)/{ITI+1) ~ a (i.e. a deletion from the left subtree
occured) •
(3) P2 is the root balance of Tr
we have
(i) if P2 ~ d then a rotation rebalances the tree, more precisely Y1'
Y2 E [(1+0) a, 1 - {1+0)a] where Y1'Y2 are as shown in the figure de-
scribing rotation.
(ii) if P2 > d then a double rotation rebalances the tree, more precisely
Y1 'Y 2 'Y 3 E [{1+0)a,1-{1+0)a] where Y1 'Y 2 'Y 3 are as shown in the figure
describing double rotation.

Proof: A complete proof is very tedious and unelegant. It can be found


in Blum/Mehlhorn. In that paper one can also find expressions for 0
and d as a function of a. In order to give the reader an impression of
the proof, we verify some parts of the claim for a = 3/11, d = 6/10
and 0 0.05. Let us consider case (i), i.e. P 2 ~ 6/10 and a rotation
=
is applied. We will only verify Y1 E [(1+0) a, 1 - {1+o)a] and leave
the remaining cases to the reader. Note first that Y1 = P1 + {1-P 1 )P 2
is an increasing function of P1 and P2 . Hence

78/110 - (1+1/15)3/11 ~1 - 1.05 a

It remains to prove a lower bound on Y1. From IT~I/{ITI-1) ~ a or


(IT~I+1)/{ITI+1) ~ a and IT~I ~ 1 one concludes P1 = IT~I/ITI ~ a/{2-a)
and hence
1M

Y1 ~ a/{2-a) + (1 - a/{2-a».a

= 81/208 ~ 1.05 a o

Lemma 1 implies that a BB[a]-tree can be rebalanced after an insertion


by means of rotations and double rotations. The transformations are re-
stricted to the nodes on the path from the root to the inserted element.
Thus height(T) = O(log lSI) transformations suffice; each transforma-
tion has a cost of 0(1).

We still have to clarify two small points: how to find the path from
the inserted element back to the root and how to determine whether a
node is out of balance. The path back to the root is easy to find. Note
that we traversed that very path when we searched for the leaf where
the new element had to be inserted. We only have to store the nodes of
this path in a stack; unstacking will lead us back to the root. This
solves the first problem. In order to solve the second problem we store
in each node v of the tree not only its content, the pointers to the
left and right son, but also its size, i.e. the number of leaves in the
subtree with root v. So the format of a node is

CONTENT LSON RSON SIZE

The root balance of a node is then easily computed. Also the SIZE field
is easily updated when we walk back the path of search to the root.

We summarize: An operation Insert(a,S) takes time O(log lSi). This is


also true for operation Delete(a,S). Delete(a,S) removes one node and
one leaf from the tree as described in III. 3.1. (The node removed is
not necessarily the node with content a). Let vO, •.• ,vk be the path
from the root Vo to the father v k of the removed node. We walk back to
the root along this path and rebalance the tree as described above.

Theorem 3: Let a E (1/4, 1-/2/2]. Then operations Access(a,S),


Insert(a,S), Delete(a,S), Min(S), Deletemin(S) and Ord(k,S) take time
O(log lSi) in BB[a]-trees. Also operation Sequ(S) takes time O(ISI).

Proof: The discussion preceding the theorem treats operations Access,


195

Insert and Delete. The minimum of S can be found by always following


left pointers starting at the root; once found the minimum can also be
deleted in time O(log lSI). Operation Ord(k,S) is realized as described
in III. 3.1 and Sequ(S) as in I.5. 0

We argued that at most height(T) transformations are required to rebal-


ance a tree in BB[a] after an insertion or deletion. It is easy to find
examples where one actually has to use that many transformations. Take
a tree where all nodes have balance a and perform one insertion (at the
proper place). Then all nodes on the path of search will move out of
the range [a,1-a] and have to be rebalanced. Note however, that this
will move the root balances of all nodes involved in the rebalancing
operations into the interval [(1+o)a, 1 - (1+o)a] where 0 > 0 if
a E (1/4, 1-/2/2). Therefore these nodes will not go out of balance for
the near future. This observation leads to

Theorem 4: Let a E (1/4, 1-/2/2). Then there is a constant c such that


the total number of rotations and double rotations required to process
an arbitrary sequence of m insertions and deletions into the initially
empty BB[a]-tree is ~ cm.

Proof: Let TO be the BB[a]-tree which consists of a single leaf and no


node. The sequence of m insertions and deletions gives rise to a sequence
of trees T 1 , ••. ,Tm, where T j + 1 comes from T j by an insertion or deletion
and subsequent rebalancing. We need some more notation.

A transaction is either an insertion or deletion. A transaction goes


through a node v if v is on the path from the root to the node to be
inserted or deleted. A node v takes part in a single rotation (double
rotation) if it is one of the two (three) nodes explicitely shown in
the figure defining the transformation. Furthermore, nodes retain their
identity as shown in that figure, i.e. if a rotation to the left is
applied to a subtree with root x, then node x has subtrees with weights a
and b respectively after the rotation. Note also that nodes are created
by insertions and then have balance 1/2 and nodes are destroyed by de-
letions. Finally, a node v causes a single rotation (double rotation)
if v is node x in the figure defining the transformations, i.e. v is a
node which went out of balance.

With every node v we associate accounts: The transaction accounmTAi(v)


196

and the balancing operation accounts BOi(V), 0 ~ i < All accounts


have initial value zero.

The j-th transaction, ~ j ~ m, has the following effect on the ac-


counts of node v:

a) If the transaction does not go through v then all accounts of v re-


main unchanged.

b) If the transaction does go through v then let w be the number of


leaves in the subtree of T. 1 with root v. Let i be such that
J-
(1/(1-a»i ~ w < (1/(1_a»i+1. Note that w ~ 2 and hence i ~ 1. We add
one to transaction accounts ~Ai-1 (v), TAi(V). TA i + 1 (v). If v causes a
rebalancinq operation then we also add one to BO. (v) .
~

Lemma 2: For every node v and every i


is as in lemma 1.

Proof: We show how to count ao/(1-a)i increments of TAi(v) for every


increment of BOi(V). Suppose BOi(V) is increased at the j-th transac-
tion, i.e. the j-th transaction goes through v and moves v out of bounds.
Let w be the number of leaves in the subtree of T. 1 with root v. Then
J-
1/(1-a)i ~ w < 1/(1_a)i+1.

Let k < j be such that: v took part in a rebalancing operation at the


k-th transaction or the k-th transaction created v and v did not take
part in a rebalancing operation after the k-th and before the j-th
transaction. In either case we have p(v) = t'/w' E [(1+o)a,1 - (1+o)a]
in Tk . Here t' (w') is the number of leaves in the left subtree of v
(in the tree with root v) in Tk . Since v causes a rebalancing operation
at the j-th transaction we have p(v) = t/w f [a,1-a], say p(v) < a
after the j-th transaction but before rebalancing v. We use t to denote
the number of leaves in the left subtree of v in that tree.

Node v did not take part in rebalancing operations between the k-th and
the j-th transaction. But its balance changed from t'/w' to t/w and
hence many transactions went through v. Suppose that a insertions and b
deletions went through v. Then w = w' + a - band t ~ t' - b.
197

Claim: a + b ~ oaw

Proof: Assume otherwise, i.e. a + b < oaw. Then


(1+o)a ~ t'/w' ~ (t+b)/(w-a+b) ~ w-o;;~2b ~ (t+oaw)/(w+oaw)
~ (aw+oaw)/(w+oaw) < (1+o)a, a contradiction. Note that c
(t+b)/(w-oaw+2b) is increasing in b.

We have thus shown that at least oaw ~ oa/(1-a)i transactions went


through v between the k-th and the j-th transaction. During the last
oaw of these transactions the weight (number of leaves in the subtree
with root v) of v was at least w - oaw ~ 1/(1-a) i-1 and at most
w + oaw < 1/(1_a)i+1. Hence all these transactions were counted on
TAi(V). c

Lemma 3: For all i

Proof: Let vO, ••. ,'vk be the rebalancing path for the j-th transaction
and let w~ be the weight of node v~, i.e. the number of leaves in the
tree with root v~. Then w~+1 ~ (1-a)w~ fO:_~ ~ 0. Thus ther~+~re at
most three nodes on the path with 1/(1-a)~ ~ w~ < 1/(1-a) . Hence
at most three is added to ~ TA. (v) for every transaction. c
v ~

It is now easy to complete the proof. ~ ~ BO. (v) is the total number of
~ v ~
single and double rotations required to process the sequence of m trans-
actions. We estimate this sum in two parts: i < k and i ~ k where k is
some integer.

~ ~ BOi(V) ~ ~ ~ ((1-a)i/ oa ) TAi(V), by lemma 2


i~k v i~k v

~ ~ ((1-a)i/ oa ) 3m , by lemma 3
i~k

~ (1_a)k 3m/oa 2

and

~ ~ BOi(v) < (k-1)m


i<k v
198

since there is at most one node v for each transaction such that 00. (v) is
1.
increased by that transaction for any fixed i. Hence the total number
of single and double rotations is bounded by [(k-1)+3(1-a)k/ oa 2]m for
any integer k. o

It is worthwhile to compute constant c of theorem 4 for a concrete


example. For a = 3/11 we have 0 = 0.05 (cf. proof of lemma 1). Choosing
k = 17 yields c = 19.59. Experiments with random insertions suggest
that this is far too crude an estimate; the true value of c is probably
close to one. Nevertheless, theorem 4 establishes the fact that the to-
tal number of rebalancing operations is linear in the number of inser-
tions and deletions. Furthermore, the proof of theorem 4 also shows
that L BOi(v) = O(m (1-a)i); thus rebalancing operations are very rare
v
high up in the tree.

We can use this fact as follows. In chapters VII and VIII we will
frequently augment BB[a]-trees by additional information. In these
augmented trees the cost of a rotation or double rotation will not be
0(1); rather the cost of a rebalancing operation caused by node v will
depend on the current "thickness" of node v, i.e. if node v causes a
rebalancing operation and the subtree with root v has w leaves then
the cost of the rebalancing operation is f(w) time units for some non-
decreasing function f. In many applications we will have f(x) = x or
f(x) = xlog x.

Theorem 5: Let a E (1/4, 1 - /2/2) and let f : JR .... JR be a non-


decreasing function. Suppose that the cost of performing a rotation or
double rotation at node v of a BB[a]-tree is f(th(v» where th(v) is
the number of leaves in the subtree with root v. Then the total cost
of the rebalancing operations required for a sequence of m insertions
and deletions into an initially empty BB[a]-tree is
clog m -i-1 i
O(m • L f( (1-a) ) (1-a) ) where c = 1/log(1-a».
i=1

-i -i-1
Proof: If a node v with (1-a) < th(v) ~ (1-a) causes a rebalancing
operation then the cost of this operation is at most f«1_a)-i-1) time
units since f is non-decreasing. Every such rebalancing operation is
recorded in account BOi(V). Hence the total cost of all rebalancing
operations is
199

2: 2: BOi(V) f « 1-0.) -i-1)


v i
:$; 2: 2: ( (1-0.) i /00.) TAi (v) f « 1-0.) -i-1) by lemma 2
v i
clog m
:$; (3m/oo.) 2: (1-a.)i f«1-a.)-i-1) , by lemma 3
i=1
and the observation that TAi(v) = 0 for i> clog m by lemma 1b. 0

Theorem 5 has some interesting consequences. If f(x) = x a with a < 1


then the total rebalancing cost is Oem) and if f(x) = x(log x)a for
some a ~ 0 then the total rebalancing cost is O(m(log m)a+1). Thus even
if f(x) is fairly large the amortized rebalancing cost (i.e. rebalancing
cost per insertion/deletion) is small. We will use this fact
extensively in chapters VII and VIII.

III. 5.2 Height-Balanced Trees

Height-balanced trees are the second basic type of balanced tree. They
come in many different kinds: AVL-trees,(2,3)-trees,B-trees, HB-trees,
••• and (a,b)-trees which we describe here.

Definition: Let a and b be integers with a ~ 2 and 2a-1 :$; b.


A tree T is an (a,b)-tree if

a) all leaves of T have the same depth


b) all nodes v of T satisfy p(v) :$; b
c) all nodes v except the root satisfy p (v) ~ a
d) the root r of T satisfies p (r) ~ 2.

Here p(v) denotes the number of sons of node v.

(a,b)-trees are known as B-trees if b = 2a-1. In our examples we always


use a 2 and b 4. We have to address the following questions: how to
store a set in an (a,b)-tree, how to store an (a,b)-tree in a computer,
how to search in, insert into and delete from an(a,b)-tree.

Sets are stored in (a,b)-trees in leaf-oriented fashion. This is not


200

compulsory, but more convenient than node-oriented storage which we


used so far. Let S = {x < ••. < x } be a subset of ordered universe U and
1 n
let T be an (a,b)-tree with n leaves. We store S in T as follows.

1) The elements of S are assigned to the leaves of T in increasing or-


der from left to right.

2) To every node v of T we assign p(v)-1 elements k1 (v), ••• ,k p (v)_1(v)


of U such that for all i (1 ~ i ~ p(v» : ki(v) < k i + 1 (v) and for all
leaves w in the i-th subtree of v we have k i _ 1 (v) < CONTENT[w] ~ ki(v).

The following figure shows a (2,4)-tree for set S {1 ,3,7,8,9,1 o} c IN

The most simple method for storing an (a,b)-tree in a computer is to


reserve 2b-1 storage locations for each node of the tree, b to contain
the pointers to the sons and b-1 to contain the keys stored in the node.
In general, some of these storage locations are unused, namely, when-
ever a node has less than b sons. If a node has arity p(v) then a frac-
tion (2p(v)-1)/(2b-1) of the storage locations will be used. Since
p(v) ~ a for all nodes (except the root) at least the fraction
(2a-1)/(2b-1) of the storage locations is used. In (2,4)-trees this
might be as low as 3/7. We will see in section III. 5.3.4 that storage
efficiency is much larger on the average. An alternative implementation
is based on red-black trees and is given at the end of the section.

Searching for an element x in an (a,b)-tree with root r is quite simple.


We search down the tree starting at the root until we reach a leaf. In
each node v, we use the sequence k 1 (v), .•• ,k p (v)_1(v) in order to guide
the search to the proper subtree. In the following program we assume
that kO(v) < x < kp(v) (v) for every element x E U and every node v of T.
201

v _ root of T;
while v is not a leaf
do find i, S i S p(v)-l,
such that k i - 1 (v) < x S ki(x);
v i-th son of v;
od;
if x = CONTENT[v]
then success else failure fi;

The cost of a search in tree T is apparently proportional to


O(b·height(T)); there are height(T) iterations of the while-loop and in
each iteration O(b) steps are required to find the proper subtree. Since
b is a constant we have O(b·height(T)) = O(height(T)) and again the
height of the tree T plays a crucial role.

Lemma 4: Let T be an (a,b)-tree with n leaves and height h. Then

a) 2·a h - 1 S n S b h
b) log n/log b S h S 1 + log(n/2)/log a

Proof: Since each node has at most b sons there are at most b h leaves.
Since the root has at least two sons and every other node has at least
a sons there are at least 2·a h - 1 leaves. This proves ~. Part b) follows
from part a) by taking logarithms. o

We infer from lemma 4 and the discussion preceding it that operation


Access(x,S) takes time O(log lSI). We will now turn to operation
Insert(x,S) .

A search for element x in tree T ends in some leaf w. Let v be the


father of w. If x = CONTENT[w] then we are done. If x * CONTENT[w] then
we proceed as follows:

1) We expand v by giving it an additional son to the right of w (we also


say: we split w), store x and CONTENT[w] in wand the new leaf in appro-
priate order and store min(x, CONTENT[w]) in v at the appropriate posi-
tion, i.e. between the pointers to wand the new leaf.

Example: Insertion of 6 into the tree of the previous example yields


202

2) Adding a new leaf increases the arity of v by 1. If p(v) $ b after


adding the new leaf then we are done. Otherwise we have to split v.
Since splitting can propagate we formulate it as a loop.

while p(v) = b+1


do if VIS father exists
then let y be the father of v
else let y be a new node and make v the only son of y
fi;
let VI be a new node;
expand y, i.e. make VI an additional son of y immediately to
the right of v;
split v, i.e. take the rightmost r(b+1)/2 1 sons and keys
k L (b+1)/2 J +1 (v), ..• ,kb(v) away from v and incorporate them in-
to VI and move key k L (b+1)/2 J (v) from v to y (between the
pOinters to v and VI);
v-y
od

Example continued: Splitting v yields


203

Lemma 5: Let b ~ 2a-1 and a ~ 2. Inserting an element x into an (a,b)-


tree for set 5 takes time O(log 151).

Proof: The search for x takes time O(log 151). Also we store the path
of search in a pushdown store during the search. After adding a new
leaf to hold x we walk back to the root using the pushdown store and
apply some number of splitting operations. If a node v is split it has
b+1 sons. It is split into nodes v and v' with L(b+1)/2 J and r(b+1)/2'
sons respectively. Since b ~ 2a-1 we have L(b+1)/2 J ~ a and since b ~ 3 we
have r(b+1)/2' ~ b and thus v and v' satisfy the arity constraint after
the split. A split takes time Orb) = 0(1) and splits are restricted to
(a final segment) of the path of search. This proves lemma 5. D

Deletions are processed very similarly. Again we search for x, the ele-
ment to be deleted. The search ends in leaf w with father v.

1) If x * CONTENT[w] then we are done. Otherwise, we shrink v by de let-


ing leaf wand one of the keys in v adjacent to the pointer to w (to be
specific, if w is the i-th son of v then we delete k i (v) i f i < p (v)
and k i - 1 (v) i f i = p (v».

Example continued: Deleting 6 yields

2) Shrinking v decreases p (v) by 1. If p (v) is still ~ a then rebalanc-


ing is completed. Othervlise v needs to be rebalanced by either fusing
or sharing. Let y be any brother of v.

while p(v) = a-1 and pry) = a


do let z be the father of v;
fuse v and y, i.e. make all sons of y to sons of v and move all keys
from y to v and delete node y; also move one key (the key
204

between the pointers to y and v) from z to v; (note that this will


shrink z, i.e. decrease the arity of z by one)
if z is root of T
then if p(z) = 1 then delete z fi;
goto completed

v .. Zi

let y be a brother of v
od;
comment we have either p(v) ~ a and rebalancing is completed or
p(v) = a-1 and p(y) > a and rebalancing is completed by sharing;
i f p (v) = a-1
then
comment we assume that y is the right brother of v;
take the lef~~ost son away from y and make it an additional (right-
most) son of v; also move one key (the key between the pointers to v
and y) from z down to v and replace it by the leftmost key of y;
fi.
-,
completed:

Example continued: The tree of the previous example can be either re-
balanced by sharing or fusing depending on the choice of y. If Y is the
left brother of v then fusing yields

If Y is the right brother of v then sharing yields


205

Lemma 6: Let b ~ 2a-1 and a ~ 2. Deleting an element from an (a,b)-


tree for set S takes time O{log lSI).

Proof: The search for x takes time O{log lSI). An (a,b)-tree is rebal-
anced after the removal of a leaf by a sequence of fusings followed by
at most one sharing. Each fusing or sharing takes time O{b) = O(1) and
fusings and sharings are restricted to the path of search. Finally note
that a fusing combines a node with a-1 sons with a node with a sons and
yields a node with 2a-1 ~ b sons. c

We summarize lemmas 4, 5 and 6 in

Theorem 5: Let b ~ 2a-1, a ~ 2. If set S is represented by an (a,b)-


tree then operations Access{x,S), Insert{x,S), De1ete{x,S), Min{S),
De1etemin{S) take time O{log lSI).

Proof: For operations Access, Insert and Delete this is immediate from
lemma 4, 5 and 6. For Min and De1etemin one argues as in theorem 3. c

{a,b)-treesprovide us with many different balanced tree schemes. For


any choice of a ~ 2 and b ~ 2a-1 we get a different class. We will
argue in III.5.3.1 that b ~ 2a is better than b = 2a-1 (= the smallest
permissible value for b) on the basis that amortized rebalancing cost
is much smaller for b ~ 2a. So let us assume for the moment that b = 2a.
What is a good value for a? We will see that the choice of a depends
heavily on the intended usage of the tree. Is the tree kept in main
memory, or is the tree stored on secondary memory? In the later case we
assume that it costs C1 + C2 m time units to transport a segment of m
contiguous storage locations from secondary to main storage. Here C1
and C2 are device dependent constants. We saw in lemma 4 that the
height of an {a,2a)-tree with n leaves is about log n/10g a. Let us
take a closer look at the search algorithm in {a,b)-tree. The loop body
which is executed log n/10g a times consists of two statements: in the
first statement the proper subtree is determined for a cost of c 1 + c 2a,
in the second statement attention is shifted to the son of the current
node for a cost of C1 + C2a. Here C2 = 0 if the tree is in main memory
and C1 + C2a is the cost of moving a node from secondary to main memory
otherwise. Thus total search time is
206

which is minimal for a such that

If the tree is kept in~ain memory then typical values for the con-
stants are c 1 ~ c 2 ~ C1and C2 = 0 and we get a = 2 or a = 3. If the
tree is kept in secondary storage, say on a disk, then typical values
of the constants are c 1 ~ c 2 ~ C2 and C1 ~ 1000 c 1 • Note that C1 is
the latency time and C2 is the time to move one storage location. In
this case we obtain a ~ 100. From this coarse discussion one sees that
in practice one will either use trees with small arity or trees with
fairly large arity.

We close this section with the detailed description of an implementation


of (2,4)-trees by red-black trees. A tree is colored (with colors red
and black) if its edges are colored red and black. If v is a node
we use bd(v) to denote the nun~er of black edges on the path from the
root to v; bd(v) is the £lack ~epth of node v. A red-black tree is a
binary, colored tree satisfying the following three structural
constraints:
1) all leaves have the same black depth,
2) all leaves are attached by black edges,
3) no path from the root to a leaf contains two consecutive red
edges.

In the following diagrams we draw red edges as wiggled lines and


black edges as straight lines.

There is a close relationship between (2,4)-trees and red-black trees.


Let T be a (2,4)-tree. If we replace nodes with three (four) sons by

and

respectively, then we obtain a red-black tree. In the example from the


beginning of the section we obtain:
207

Conversely, if T is a red-black tree and we collapse nodes connected by


red edges then a (2,4)-tree is obtained. Red-black trees allow for a
very efficient and elegant implementation. Each node and leaf is stored
as a record of type node where

~ node record content: U


color : (red, black)
son[O .• 1] : tnode
end

The field content stores an element of the underlying universe, the


field color contains the color of the incoming edge (the color of the
edge into the root is black by default), and fields son[o] and son[1]
contain the pointers to the left and right son respectively. All son-
pointers of leaves are nil.
In the following programs variables root,p,q,r are of type tnode, but
we talk simply about nodes instead of pointers to nodes. A node is
called red (black) if its incoming edge is red (black). The program for
operation Access is particularly simple. For later use we store the
path of search in a pushdown store, more precisely we store pairs (z,d)
where z is a pOinter to a node and d E {O,1} is the direction out of
node z taken in the search. The following program searches for x E U.
208

(1) p +- root;
(2) while pt.son[O] nil * -- a test, whether p is a leaf
(3) do if x ~ pt.content
(4) then push (p,O);
(5) p +- pt.son[O]
(6) else push (p,1);
(7) p +- pt.son[1]
(8) fi
(9) od;
(10) if pt.content = x
(11) then "successful"
(12) else "unsuccessful"
(13) fi

We will next turn to operation Insert. Suppose that we want to insert


x and also suppose that we executed the program above. It terminates in
line (12) with p pointing to a leaf and with the path of search stacked
in a pushdown store. The leaf p is not stacked. We initialize the
insertion algorithm by replacing leaf p by a red node r with sons p
and a new leaf containing x. This is done in lines

(1) to (15) below. We also redirect the pointer from p'S father to the
new node r. If p'S father is black this completes the insertion.

(1) new(q);
(2) qt.color black; qt.son[O]- qt.son[1] - nil;
(3) qt.content +- x;
(4) new (r);
(5) rt.content +- min(x,pt.content);
(6) r t. color +- red;
(7) if x < pt.content
(8) then rt.son[O] +- q; rt.son[1] p
°
+-

(9) else rt.son[1] - q; rt.son +- p


(10) fi;
209

( 11 ) (q,dir2) - pop stack;


(12 ) qt.son[dir2] r;
( 1 3) if qt .color black
( 1 4) then - - "the insertion is completed"
( 15) fi;

If node q (as tested in line (13» is red then we created two


consecutive red edges and therefore destroyed the third structural
constraint. The following program restores the red-black
properties.

(16) (p,dir1) - pop stack

At this point we are in the following situation. Node p is black


(because its son q is red), node q is red and has exactly one red
son, namely r (otherwise, two consecutive red edges would have
existed before the insertion). We will maintain this property as
an invariant of the following loop. In this loop we distinguish
two cases. If both sons of node p are red then we perform a color
flip on the edges incident to p and propagate the "imbalance"
closer to the root. A color flip corres.ponds to a split in (2,4)-
trees. If p has only one red son then we rebalance the tree by
eitiler a rotation (dir1 = dir2) or a double rotation (dir1 '" dir2).
Both subcases correspond to expanding node p in the related (2,4)-
tree and hence terminate the insertion.

(17) while true


(18) do if pLson[l-dirl]Lcolor = red
( 1 9) then p has two red sons and we perform a
color flip

---
(20) pt.son[O].color - pt.son[l].color - black;
( 21) pt.color - red;
(22) if p = root
(23 ) then pt.color - black;
(24) terminate the insertion algorithm;
210

(25)
(26) r +- p;
(27 ) (q,dir2) - pop stack;
(28) if qt.color = black
(29) then terminate the insertion algorithm
(30) fi;
(31) (p,dir1) - pop stack
(32) else if dir1 = dir2
(33) then we rebalance the tree by a rotation

(34) pt.son[dir1] - qt.son[1-dir1];


(35) qt.son[1-dir1] - p;
(36) pt.color - red; qt.color - black;
(37) if p = root
(38) then root - q
(39) else (r,dir2) - pop stack;
( 40) rt.son[dir2] - q
(41) fi
(42) terminate the insertion algorithm
(43) else -- we rebalance the tree.hy a double rotation

(44) pt.son[dir1] rt.son[dir2];


(45) qt.son[dir2] rt.son[dir1];
(46) rt.son[dir1] qi
(47) rt.son[dir2] p;
(48) pt. color .. red; rt.color .. black;
(49) if p = root
211

(50) then root - r


(51) else (p,dir2) - pop stack;
(52 ) pt.son[dir2] - r
(53 ) fi;
(54) terminate the insertion algorithm
(55 ) fi
(56) fi
(57) od

There are several remarks appropriate at this pOint. We mentioned


already that color flips in red-black trees correspond to splits in
(2,4)-tree. What do rotations and double rotations correspond to? They
have no equivalent in (2,4)-trees but correspond to the fact that the
subtrees shown below are not "legal" realizations of nodes with four

sons. If we would replace the third structural constraint by "red


components (=sets of nodes connected by red edges) consist of at most
three nodes" then the subtree above were legal and the rotations and
double rotations were not required. However, the code which realizes
a split would become more cumbersome.

Deletions from red-black trees can be handled by a similar but slightly


longer program. The program is longer because more cases have to be
distinguished. We leave the details to the reader. There is one important
remark to make however. The algorithms for red-black trees as described
above simulate (2,4)-trees in the following sense. Let T be a (2,4)-tree
and let T' be the red-black tree which corresponds to T as described
above. Suppose now that we perform an insertion into (deletion from) T
and the same operation on T'. Let T1 and T 1 ' be the resulting (2,4)-tree
and red-black tree respectively.
Then T 1 ' corresponds to T1 in the sense described above. Also, the
number of color-flips required to process the the operation on T' is the
same as the number of splits required to process the operation on T. We
will use this observation frequently in the sequel without explicitely
212

mentioning it. More precisely, we will derive bounds on the amortized


rebalancing cost in (2,4)-trees in the next section. These bounds hold
also true for red-black trees (if the programs above are used to re-
balance them).

Red-black trees can also be used to implement (a,b)-trees in general.


We only have to replace the third structural constraint by: "red
components have at least a-1 and at most b-1 nodes" (cf. exercise 27).

Finally, we should mention that there are alternative methods for


rebalancing (a,b)-trees, b ~ 2a, and red-black trees after insertions
and deletions. A very useful alternative is top-down rebalancing.
Suppose that we want to process an insertion. As usual, we follow a
path down the tree. However, we also maintain the invariant now that
the current node is not a b-node (a node with b sons). If the current
node is a b-node then we immediately split it. Since the father is not
a b-node (by the invariant) the splitting does not propagate towards
the root. In particular, when the search reaches the leaf level the
new leaf can be added without any problem. The reader should observe
that b ~ 2a is required for this strategy to work because we split b-
nodes instead of (b+1)-nodes now. The reader should also note that the
results presented in section III.5.3.2 below are not true for the top-
down rebalancing strategy. However, similar results can be shown
provided that b ~ 2a + 2 (cf. exercises 29 and 32).
Top-down rebalancing of (a,b)-trees is particularly useful in a parallel
environment. Suppose that we have several processors working on the same
tree. Parallel searches cause no problems but parallel insertions and
deletions do. The reason is that while some process modifies a node,
e.g. in a split, no other process can use that node. In other words,
locking protocols have to be used in order to achieve mutual exclusion.
These locking protocols are fairly simple to design if searches and
rebalancing operations proceed in the same direction (deadlock in a one-
way street is easy to avoid), i.e. if top-down rebalancing is used.
The protocols are harder to design and usually have to lock more nodes
if searches and rebalancing operations proceed in opposite directions
(deadlock in a two-way street is harder to avoid), i.e. if bottom-up
rebalancing is used. We return to the discussion of parallel operations
on (a,b)-trees at the end of section 5.3.2. In section 5.3.2. we prove
a result on the distribution of rebalancing operations on the levels
213

of the tree. In particular, we will show that rebalancing operations


close to the root where locking is particularly harmful are very rare.

III. 5.3 Advanced Topics on (a,b)-Trees

(a,b)-trees are a very versatiJe data structure as we will see now. We


first describe two additional operations on (a,b)-trees, namely Split
and Concatenate, and then apply them to priority queues. In the second
section we study the amortized rebalancing cost of (a,b)-trees under
sequences of insertions and deletions. We use the word amortized to de-
note the fact that the time bounds derived are valid for sequences of
operations. The amortized cost per operation is much smaller than the
worst case cost of a single operation. This analysis leads to finger
trees in the third section. Finally, we introduce fringe analysis, a
method for partially analyzing random (a,b)-trees.

III. 5.3.1 Merqable Priority Queues

We introduce two more operations on sets and show how to implement


them efficiently with (a, b)-trees. We then describe the implementation
of mergable priority queues based on (a,b)-trees.

S3 ..... S1 U S2; operation Concatenate is


only defined if max S1 < min S2.

S2 {x E S1 ; x $ y} and
S3 {x E 51; x > y}

Both operations are destructive, i.e. sets 51 and 52 (set 51 respective-


ly) are destroyed by an application of Concatenate (Split).

Theorem 6: Let a ~ 2 and b ~ 2a-1. If sets 51 and 52 are represented


by (a,b)-trees then operation Concatenate(5 1 ,S2,5 3 ) takes time
O(log max(15 1 I, IS 2 1)) and operation 5plit(S1,y,S4,S5) takes time
o (log I 51 I ) •
214

Proof: We treat Concatenate first. Let S1 and S2 be represented by


(a,b)-trees T1 and T2 of height h1 and h2 respectively. We assume that
the height of a tree and the maximal element of a tree are both stored
in the root. It is easy to see that this assumption does not affect
the time complexity of any of the operations considered so far.

Assume w.l.o.g that h1 ~ h 2 • Let r 2 be the root of T2 and let v be the

node of depth h 1 -h 2 on the right spine of T 1 , i.e. v is reached from


the root of T1 by following h 1 -h 2 times the pointer to the rightmost
son. Fuse v and r 2 and insert the maximal element stored in T1 as the
additional key in the combined node. The combined node has arity at
most 2b. If its arity is not larger than b then we are done. Otherwise
we split it in the middle and proceed as in the case of an insertion.
Splitting may propagate all the way to the root. In any case, the time
complexity of the algorithm is O(lh 1 -h 2 1+ 1) = O(max(h 1 ,h 2 )) =
O(log max(IS 1 1,IS 2 1)). Also note that the resulting tree has height
max(h 1 ,h 2 ) or max(h 1 ,h 2 ) + 1. This finishes description and analysis
of Concatenate.

The algorithm for Split (S1'Y' , ) is slightly more complicated. Let


T1 be an (a,b)-tree for S1. The first thing to do is to search for y
and split all nodes on the path of search at the pointer which leads to
that successor which is also on the path of search. In the example be-
low splitting along the path to leaf 12 yields:
215

The splitting process yields two forests F1 and F 2 , i.e. two sets of
trees. F1 is the set of trees to the left of the path and F2 is the set
of trees to the right of the path. The union of the leaves of F1 gives
8 4 and the union of the leaves of F2 gives 8 5 • We show how to build 8 4
in time O(log 18 1 I). The root of each tree in F1 is a piece of a node
on the path of search. Hence F1 'contains at most h1 = height(T 1 ) trees.
Let D1 , ••• ,D m, m ~ h1' be the trees in F1 from left to right. Then each
Di is an (a,b)-tree except for the fact that the arity of the root
might be only one. Also max Di < min Di + 1 and height(D i ) > height(D i + 1 )
for 1 ~ i < m. Hence we can form a tree for set 8 4 by executing the
following sequence of Concatenates.

Concatenate(Dm_1,Dm,D~_1)

Concatenate(Dm_2,D~_1,D~_2)

It is easy to see that applying Concatenate to (a,b)-trees with the


possible defect of having a root with arity one yields an (a,b)-tree
which might again have that defect. Hence Di is an (a,b)-tree for set
8 4 except for that possible defect. If the root of D; has arity 1 then
we only have to delete it and obtain an (a,b)-tree for 8 4 . It remains
to analyse the running time of this algorithm. The splitting phase is
clearly O(log n). For the build-up phase let h! be the height of D!.
1 m-2 1
Then the complexity of the build-up phase is O( Ih 1-h 1+ L Ih.-h!+11+m).
m- m i=1 1 1

Proof: 8ince Di + 1 is used to form Di+1 we clearly have hi+1 ~ h i + 1 • We


show hi+1 ~ h i + 1 + 1 by induction on i. For i = m-2 we have

since h m < h m- 1 < h m_ 2 and for i < m - 2 we have

,property of Concatenate
216

, since h i + 1 < hi o

m-2
Thus Ih 1 - h I + L Ih. - h~+l I + m
m- m i=l ~ ~

m-2
$ h 1 - h + L (h. - h~+l) + m
m- m i=l ~ ~

m-2
$ h' 1 - h + L (h~ - h~+l) + m
m- m i=l ~ ~

In our example Fl consists of two trees. Concatening them yields

3 5 7

4 7

Concatenate is a very restricted form of set union. General set union


of ordered sets is treated in 111.5.3.3. below.

However, Concatenate is good enough to handle the union question on un-


ordered lists. A very frequent task is the manipulation of priority
queues; we will see an example in section IV.6 on shortest path
algorithms. The name mergable priority queue represents the problem of
manipulating a set of sets under the operations Insert(x,S), Min(S),
Deletemin(S) and Union(Sl,S2,S3). We will add two more operations later.
Note that operation Access is not included in this list. Also note,
that operation Access was the main reason for storing the elements of
a set in sorted order in the leaves of an (a,b)-tree. We give up on that
principle now.

A set S, lSI = n, is represented in an unordered (a,b)-tree T with n


leaves as follows:
217

1) the leaves of T contain the elements of S in some order


2) each node v of T contains the minimal element in the subtree with
root v and a pointer to the leaf containing that element.

Operation Min(S) is trivial in this data structure; it takes time 0(1).


For Deletemin(S) we follow the pointer from the root to the minimal
element and delete it. Then we walk back to the root, rebalance the tree
by fusing and sharing and update the min values and pointers on the way.
Note that the min value and pointer of a node can be found by looking
at all its sons. Thus Deletemin(S) takes time O(a log lsi/log a). We
include factor a because we will see that other operations are propor-
tional to O(log lSI/log a) and because we will exploit that fact in
IV.6. Insert(x,S) is a special case of Union where one of the sets is
a singleton. Finally Union(Sl'S2) reduces to Concatenate and takes
time O(a log(max(IS 1 I ,IS 2 1»/log a). Delete in its pure form cannot be
supported because there is no efficient method for finding an element.
However, a modified form of Delete is still supported. Given a pointer
to a leaf that leaf can be deleted in time O(a loglSI/log a) as de-
scribed for Deletemin above. We call this operation Delete*. Finally we
consider operation Demote* which takes a pointer to a leaf and an ele-
ment x of the universe. Demote* is only applicable if x is smaller than
the element currently stored in the leaf, and changes (demotes) the
content of that leaf to x. Dernote* takes time O(log lSI/log a) because
one only has to walk back to the root and replace all elements on that
path by x if x is smaller. We summarize in:

Theorem 7: Let a ~ 2 and b ~ 2a - 1. If sets are represented by unor-


dered (a,b)-trees then operations Min(S), Deletemin(S), Insert(x,S),
Union(Sl'S2,S3)' Delete*( ,S), Demote*( ,S) take time 0(1),
O(a log lSI/log a), O(a log lSI/log a), O(a log(IS 1 I + IS 2 1)/log a),
O(a log lSI/log a) and O(log lSI/log a) respectively.

III. 5.3.2 Amortized Rebalancing Cost and Sorting Presorted Files

In this section we study the total cost of sequences of insertions and


deletions into (a,b)-trees under the assumption that we start with an
initially empty tree. We will show that the total cost is linear in the
length of the sequence. The proof follows a general paradigm for analys-
ing the cost of sequences of operations, the bank account paradigm,
218

which we saw already in the proof of theorem 4 in III. 5.1 •• We


associate a bank account with the tree ; the balance of that account
measures the balance of the tree. We will then show that adding or
pruning a leaf corresponds to the withdrawal of a fixed amount from
that account and that the rebalancing operations (fusing, sharing and
splitting) correspond to deposits. Using finally the obvious bounds for
the balance of the account, we obtain the result.

Theorem 8: Let b ~ 2a and a ~ 2. Consider an arbitrary sequence of i


insertions and d deletions (n = i+d) into an initially empty (a,b)-tree.
Let SP be the total number of node splittings, F the total number of
node fusings and SH be the total number of node sharings. Then

a) SH ~ d ~ n

b) c
(2c-1)·SP + c·F ~ n + c + a+c-1 (i-d-2)

where c = min(min(2a-1, r(b+1)/2')-a, b-max(2a-1, L(b+1)/2 j ». Note that


c ~ 1 for b ~ 2a and hence SP+F ~ n/c + 1 + (n-2)/a)

Proof: a) Node sharing is executed at most once for each deletion.


Hence SH ~ d.

b) We follow the paradigm outline above.

For a node v (unequal the root) of an (a,b)-tree let the balance b(v)
of v be

b(v) = min(p(r)-a, b - p(v), c)

where c is defined as above. Note that c ~ 1 for b ~ 2a and a ~ 2 and


that p(v') = L(b+1)/2 j and p(v") = r(b+1)/2' implies
b(v') + b(v") ~ 2c-1 and that p(v) = 2a-1 implies b(v) c.
For root r (r will always denote the root in the sequel) the balance is
defined as

b*(r) = min(P(r)-2, b - p(r),c)

Definition: (T,v) is a partially rebalanced (a,b)-tree where v is a


node of T if
219

a) a-1 ~ p(v) ~ b+1 if v *r


~ p(v) ~ b+1 if v = r

b) a ~ p (w) ~ b for all w * v,r


c) 2 ~ per) ~ b if v *r
Let (T,v) be a partially rebalanced (a,b)-tree. Then the balance of T
is defined as the sum of the balance of its nodes

beT) L b(v) + b* (r)


v is node of T
v *r
Fact 1: Let T be an (a,b)-tree. Let T' be obtained from T by adding a
leaf or pruning a leaf. Then beT') ~ b(T)-1.

Proof: obvious. 0

Fact 2: Let (T,v) be a partially rebalanced (a,b)-tree with p(v) b+1.

Splitting v and expanding v's father x generates a tree T' with


beT') ~b(T) + (2c-1).

Proof: Since p(v) = b+1 we have b(v) = b*(v) -1

Case 1: v is not the root of T. Let x be the father of v. v is split


into nodes, v' and v" say, of arity L (b+1) /2 J and r (b+1) /2' respectively,
and the arity of x is increased by one. Hence the balance of x de-
creases by at most one and we have

beT') ~ beT) + b(v') + b(v") - b(v) - 1

Furthermore, b(v) -1 and b(v') + b(v") ~ 2c-1 by the remark above.


This shows

beT') ~ beT) + (2c-1) - (-1) - 1


~ beT) + (2c-1)

Case 2: v is the root of T. Then the father x of v is newly created


and hence has arity 2 after the splitting of v. Hence
220

bIT') ~ bIT) + b(v') + b(v") - b*(v) + b*(x)


~ bIT) + (2c-1) - (-1) + 0 o

Fact 3: Let (T,v) be a partially rebalanced (a,b)-tree with p(v) = a-1


and v *r the root of T. Let y be a brother of v and let x be the
father of v.

a) If ply) = a then let T' be the tree obtained by fusing v and y and
shrinking x. Furthermore, if x is the root and has degree 1 after the
shrinking, then x is deleted. Then bIT') ~ bIT) + c.

b) If ply) > a then let T' be the tree obtained by sharing, i.e. by
taking 1 son away from y and making it a son of v. Then bIT') ~ b(T).

Proof: a) y and v are fused to a node, say w, of arity p(w) 2a-1.


Hence b(w) = b*(w) = c.

Case 1: x is not the root of T. Then the arity of x is decreased by one


and hence the balance of x is decreased by at most one. Hence

bIT') ~ bIT) + (b(w)-b(v)-b(y» - 1


~ bIT) + (c - (-1) - 0) -
~ bIT) + c

Case 2: x is the root of T. If pIx) ~ 3 before the fusing then the ana-
lysis of case 1 applies. Otherwise we have pIx) = 2 and hence b*(x) = 0
before the fusing, and x is deleted after the fusing and w is the new
root. Hence

bIT') bIT) + (b*(w) - b(v) - b(y» - b*(x)


bIT) + c - (-1) - 0 - 0
bIT) + c +

·In either case we have shown bIT') ~ bIT) + c.

b) Taking one son away from y decreases the balance of y by at most one.
Giving v (of arity a-1) an additional son increases b(v) by one. Hence
bIT') ~b(T). 0
221

Fact 4: Let T be an (a,b)-tree with m leaves. Then 0 ~ b(T) ~


c + (m-2) __c_
a+c-1

Proof: For 0 ~ j < c, let mj be the number of interior nodes unequal


the root of degree a+j and let m be the number of interior nodes un-
c c
equal the root of degree at least a+c. Then b(T) ~ c + L m. j since
j=O J
the balance of the root is at most c.
c
Furthermore, 2 + L (a+j)m. ~ m + f m. since the expression on the
j=O J j=O J
right side is equal to the number of edqes (= number of leaves + non-
root nodes) in T and the expression on the left hand side is a lower
bound on that number. Hence

c
L (a+j-1)m. ~ m-2
j=O J

Since

j/(a+j-1) ~ c/(a+c-1) for

we conclude
c
b (T) ~ c + L j·m.
j=O J

c j
~ c + L
a+j-1
(a+j-1) ·m.
j=O J

~ c + (c/ (a+c-1» (m-2) D

In order to finish the banking account paradigm we need to relate depo-


sits, withdrawals and initial and final balance. Since we start with an
empty tree TO' the initial balance b(T O) is O. Next we perform i inser-
tions and d deletions and obtain Tn(n=i+d). Since Tn has i-d leaves we
conclude b(T n ) ~ c + (i-d-2)c/(a+c-1). Also the total withdrawals are
at most n by Fact 1 and the total deposits are at least (2c-1) ·SP + c·F
by facts 2 and 3. Hence

b(T O) + (2c-1) .SP + c·F - n ~ b(T n )


and thus
(2c-1) ·SP + c·F ~ n + c + (i-d-2)c/(a+c-1). D
222

Theorem 8 establishes an 0(1) bound on the amortized rebalancing cost


in (a,b)-trees for b ~ 2a. In that respect it is a companion theorem
to theorem 4 on weight-balanced trees. Let us look at some concrete
values of a and b. For a 2, b = 4 we have c and hence SP+F:::; 3n/2.
For (4,13)-trees we have c = 3 and hence SP + F :::; n/2 + 2/3. We should
also mention that theorem 8 does not hold if b = 2a-1 as can be seen
from the following example; rebalancing always runs all
Insertion of new
rightmost leaf

Deletion of
rightmost leaf

the way to the root. However, theorem 8 is true for b 2a-1 if one
considers insertions only (exercise n) .

Theorem 8 has an interesting application to sorting, more precisely to


sorting presorted files. Let x 1 , ... ,x n be a sequence which has to be
sorted in increasing order. Suppose, that we know that this sequence
is not random, but rather possesses some degree of sortedness. A good
measure for sortedness is number of inversions. Let

n
and F = L i =1 f i . Then 0 :::; F :::; n(n-1)/2, F is called the number of in-
versions of the sequence x 1 ' .. ,x . \life take F as a measure of sortedness;
n 2
F = 0 for a sorted sequence, F ~ n for a completely unsorted sequence
and F « n 2 for a nearly sorted sequence. These remarks are not meant
to be definitions. We can sort sequence x 1 , ... ,x n by insertion sort,
i.e. we start with the sorted sequence xn represented by an (a,b)-tree
and then insert xn-1,xn_2, ••. ,x1 in turn. By theorem 5 this will take
total time O(n log n). Note however, when we have sorted x i + 1 , ... ,x n
already and next insert xi' then xi will be inserted at the fi-th posi-
223

2
tion from the left in that sequence. If F « n , then fi « n for most
i and hence most xis will be inserted near the beginning of the sequence.
What does this mean for the insertion algorithm. It will move down the
left spine (the path to the leftmost leaf), for quite a while and only
depart from it near the leaf-level. It is then cheaper to search for
the pOint of departure from the left spine by moving the spine upwards
from the leftmost leaf. Of course, this requires the existence of son-
to-father pointers on the left spine.

Let us consider the insertion of xi in more detail. We move up the left


spine through nodes v 1 ,v 2 ,v 3 , •.. (v 1 is the father of the leftmost leaf
and v j + 1 is the father of v j } until we hit node Vj with xi ~ k1 (v j ),
i.e. xi has to be inserted into the leftmost subtree of node Vj but not
into the leftmost subtree of node v. l' i.e. either j = 1 or
J-
Xi > k1 (V j _ 1 )· In either case we turn around at Vj and proceed as in an
ordinary (a,b}-tree search. Note that the search for Xi will cost us
O(height(v.)} time units. Since all leaves stored in the subtree rooted
J
at v j _ 2 must have content less than Xi we conclude that fi ~ number of
h(v. 2}-1
leaves in subtree rooted at v. 2 ~ 2·a J- by Lemma 4 and hence
J-

The actual insertion of Xi costs O(si} time units, where si is the


number of splits required after adding a new leaf for Xi. This gives
the following time bound for the insertion sort

n n n
E [O(log f i } + O(si} ] O(n + E log fi + E si}
i=1 i=1 i=1

O(n + n log(F/n}}

since Elog fi = log ITfi and (ITf i ) 1/n ~ (Efi}/n (the geometric mean is
never larger than the arithmetic mean) and since ES i = O(n} by theorem
8. We thus have

Theorem 9: A sequence of n elements and F inversions can be sorted in


time O(n + n log(F/n}}.
224

Proof: By the preceding discussion. c

The sorting algorithm (A-sort) of theorem 9 may be called adaptive. The


more sorted sequence x 1 , ••• ,xn is, the faster the algorithm. For
F = n log n, the running time is O(n log log n). This is in marked con-
trast to all other sorting algorithms, e.g. Heapsort, Quicksort,
Mergesort. In particular, it will be faster than all these other
algorithms provided that F is not too large. A careful non-asymptotic
analYSis of A-sort is beyond the scope of this book; it can be found
in Mehlhorn/Tsakalidis, where is it shown that A-sort is better than
Quicksort for F S o.02.n 1 .57.

Let us return to theorem 8 and its companion theorem 4 on weight-bal-


anced trees. In the proof of theorem 4 we also established that most
rotations and double rotations occur near the leaves. We will now pro-
ceed to show a similar theorem for height - balanced trees. We need some
more notation.

We say that a splitting (fusing, sharing) operation occurs at height h,


if node v which is to be split (which is to be fused with its brother y
or shares a son with its brother y) has height h; the height of a leaf
being O. A splitting (fusing) operation at height h expands (shrinks)
a node at height h+1. An insertion (deletion) of a leaf expands
(shrinks) a node at height 1.

Let (T,v) be a partially rebalanced (a,b)-tree. We define the balance


of tree T at height has:

L b(v) if h is not the height


v node of T of height h of the root
{ b* (r) if h is the height of
the root r of T

where band b* are defined as in the proof of theorem 8.

Theorem 10: Let b ~ 2a and a ~ 2. Consider an arbitrary sequence of i


insertions and d deletions (n = i+d) into an initially empty (a,b)-tree.
Let SPh(Fh,SH h ) be the total number of node splittings (fusings,
sharings) at heighth. Then
225

where c is defined as in theorem 8.

Proof: The first part of the proof parallels the proof of theorem 8.

Fact 1: Let T be an (a,b)-tree. Let T' be obtained from T by adding or


pruning a leaf. Then b 1 (T') ~ b 1 (T)-1 and bh(T') = bh(T) for h > 1.

Fact 2: Let (T,v) be a partially rebalanced (a,b)-tree with p(v) = b+1


and height of v equal h. Splitting v generates a tree T' with
bh(T') ~ bh(T) + 2·c, b h + 1 (T') ~ hh+1 (T) - 1 and b£(T') = b£(T) for
£ * h, h+1.

Fact 3: Let (T,v) be a partially rebalanced (a,b)-tree with p(v) = a-1,


height of v equal h and v * r the root of T. Let y be a brother of v
and let x be the father of v.

a) if p(y)= a then let T' be the tree obtained by fusing v and y and
shrinking x. Furthermore, if x is the root of T and has degree after
the shrinking, then x is deleted. Then bh(T') ~ bh(T) + c + 1,
b h + 1 (T') ~ b h + 1 (T) - 1 and b£(T ' ) = b£(T) for £ * h, h+1.

b) if p(y) > a then let T' be the tree obtained by sharing. Then
b£(T ' ) ~ b£(T) for all £.

The proofs of facts 1 to 3 are very similar to the proof of the corre-
sponding facts in theorem 8 and therefore left to the reader.

Fact 4: Let Tn be the tree obtained after i insertions and d deletions


from TO' the initial tree. Let SP o + Fa := i+d. Then for all h ~ 1

Proof: Facts 1-3 imply that splits (fusings) at height h increase the
balance at height h by 2c(c+1) and decrease the balance at height h+1
by at most 1. o

Since bh(To ) = a for all h (recall that we start with an empty tree) and
2c ~ c+1 (recall that c ~ 1) we conclude from fact 4
2?6

and hence

n/(c+1)h +

Fact 5: For all h ~ 1:

h
L b£ (Tn) (c+1) £ :s; (c+1) (i-d) :s; (c+1)·n
£=1

Proof: Let m.(h) be the number of nodes of height h and degree a+j,
J
o :s; j < c, and let rnc(h) be the number of nodes of height h and degree
at least a+c. Then

c c
(*) L (a+j)mJ.(h):S; L rn. (h-1 )
j=O j=O J
for h ~ 2 since the number of edges ending at height h-1 is equal to the
c
number of edges emanating at height h. Setting L m.(O) := i-d (the nurn-
j=o J
ber of leaves of Tn) the inequality is true for all h ~ 1.

c
L j.rn.(£) and relation (*) we obtain
j=O J

h c
L [(c+1)£ L j rn J. (£) ]
£=1 j=O

:s;
h
L [(c+1) •£{C rn.(£-1) - a L rn.(£) ]
L
C}
£=1 j=O J j=O J

c
(c+1) L m. (0)
j=O J

h c c
+ L (c+1)£[ L m. (£-1) - (c!1) L rn. (£-1)]
£=1 j=O J j=O J
227

h c
- (c+1) ·a· L m. (h)
j=O J

::;; (c+1) (i-d)

since a/(c+1) ~ 1 and L m.(O) = i-d. lJ


j J

Substituting the bound of fact 5 into the bound for SP h + Fh we obtain

With respect to sharing, note that a fusing at height h-1 either com-
pletes rebalancing or is followed by a sharing or fusing at heigth h.

Hence

for h ~ 2 and

putting everything together we obtain

for all h ~ 1 and theorem 10 is proven. lJ

SP h + Fh + SH h is the number of insertions and deletions which require


rebalancing up to height h or higher. Theorem 10 shows that this number
is exponentially decreasing with h (recall c ~ 1). This is very similar
to lemma 2 of 111.5.1. Again note that the proof of theorem 10 relies
heavily on the fact that b ~ 2a. In fact, theorem 10 is not true for
b = 2a-1 as the example following the proof of theorem 8 shows. There
SPh + Fh + SH h = n for all h.

We finish this section with a brief sketch of an application of theorem


10: (a,b)-trees in a parallel environment. Some applications, in par-
ticular real-time data bank applications, call for a very high trans-
action rate. Ve~ high transaction rates can only be supported by con-
228

current tree manipulation, i.e. by many processors working on the same


tree. Concurrent searches cause no problem; however, concurrent in-
sertions/deletions do. Note that the rebalancing operations (splitting,
fusing, sharing) require locking of nodes, i.e. whilst node v is re-
balanced by one process, the other processes cannot use node v and have
to wait if they want to. Also note, that locking node v will (on the
average) block many other processes if v is close to the root and that
it will block (almost) no other processes if v is close to the leaves.
That's exactly the point where theorem 10 comes in. Theorem 10 guaran-
tees that most rebalancing operations occur close to the leaves and
that therefore blocking of processes is no insurmountable problem. We
refer the reader to Bayer/Schkolnik for a detailed discussion.

III. 5.3.3 Finger Trees

In this section we generalize (a,b)-trees to finger trees. We have seen


in the previous section that it is sometimes better to start searches
in an (a,b)-tree at a leaf. This led to A-sort. Finger trees grow out
of that observation and generalize it. Recall that we used (a,b)-trees
to represent ordered lists. A finger into a list is a pointer to an ele-
ment of the list. Fingers may be used to indicate areas of high activity
in the list and we aim for efficient searches in the vicinity of fin-
gers. If the list is represented as the leaves of an (a,b)-tree then a
finger is a pointer to a leaf. (a,b)-trees as they stand do not support
efficient search in the vicinity of fingers. This is due to the fact
that neighboring leaves may be connected only by a very long path. There-
fore we introduce level-linked (a,b)-trees.

In level linked (a,b)-trees all tree edges are made traversible in both
directions (i.e. there are also pointers from sons to fathers); in addi-
tion each node has pOinters to the two neighboring nodes on the same
level The figure on the next page shows a level-linked (2,4)-tree for
list 2, 4, 7, 10, 11, 15, 17, 21, 22, 24.

A finger tree is a level-linked (a,b)-tree with pointers to some of its


leaves, the fingers. Level-linked (a,b)-trees allow very fast searching
in the vicinity of fingers.
229

Lemma 7: Let p be a finger in a level-linked (a,b)-tree T. A search for


a key k which is d keys away from p takes time 0(1+log d) •

Proof: We first check whether k is to the left or right of p, say k is


to the right of p. Then we walk towards the root, say we reached node v.
We check whether k is a descendant of v or v's right neighbour .on the
same level. If not, then we proceed to v's father. Otherwise we turn
around and search for k in the ordinary way.

Suppose that we turn around at node w of height h. Let u be that son of


w which is on the path to the finger p. Then all descendants of u's
right neighbour lie between the finger p and key k. Hence the distance
d is at least a h - 1 and at most 2b h • The time bound follows. 0

Lemma 3: A new leaf can be inserted in a given position of a level-


linked (a,b)-tree in time 0(1+s), where s is the number of splittings
caused by the insertion.

Proof: This is immediate from the description of the insertion algorithm


in 111.5.2 •• Note that it is part of the assumption of lemma 8 that we
start with a pointer to the leaf to be split by the insertion. So no
search is required, only rebalancing.

Lemma 9: A given leaf can be deleted from a level-linked (a,b)-tree in


time 0(1+f), where f is the number of node fusings caused by the de~n.
230

Proof: Immediate from the description of the deletion algorithm.


Again note that it is part of the assumption of lemma 9 that we start
with a pOinter to the leaf which has to be deleted.

Lemma 10: Creation or removal of a finger at a given leaf in a level-


linked (a,b)-tree takes time 8(1).

Proof: Obvious.

We can now appeal to theorem 8 and show that although the search time
in level-linked (a,b)-trees can be greatly reduced by maintaining fin-
gers, it still dominates the total execution time, provided that b ~ 2a.

Theorem 11: Let b ~ 2a and a ~ 2. Then any sequence of searches, finger


creations, finger removals, insertions and deletions starting with an
empty list takes time

O(total cost of searches)

if a level-linked (a,b)-tree is used to represent the list.

Proof: Let n be the length of the sequence. Since every operation has
to be preceded immediately by a search, the total cost for the searches
is ~(n) by lemma 7. On the other hand the total cost for the finger
creations and removals is O(n) by lemma 10 and the total cost of in-
sertions and deletions is O(n) by lemmas 8 and 9 and theorem 8. 0

Theorem 9 on sorting presorted files is a special case of theorem 11.


Theorem 11 can be generalized in two directions. We can start with sev-
eral empty lists and add Concatenate to the set of operations (exercise
33) or we can start with a non-empty list. For the latter generalization
we also need a more general version of theorem 8. We need a bound on
total rebalancing cost even if we start with a non-empty tree.

Let T be any (a,b)-tree. Suppose now that we execute a sequence of in-


sertions and deletions on T. It is intuitively obvious that only nodes
which lie on a path from one of the inserted or deleted leaves to the
root are affected (this is made precise in fact 1) below. We will derive
a bound on the number of such nodes in fact 5. Of course, only these
nodes can change their balance and hence their number gives a bound on
231

the difference of the balance of initial and final tree. An application


of the bank account paradigm will then give us a bound on the number of
splittings, fusings and sharings (Fact 4) .

In order to facilitate the following discussion we introduce the follow-


ing convention: if a leaf is deleted from an (a,b)-tree, it (conceptual-
ly) stays as a phantom. The rebalancing algorithms do not see the phan-
toms, i.e. the arity of nodes is solely determined by the non-phantom
leaves. In the following example phantom leaves are shown as dashed
00xeS.

deletion of
4th leaf
and sharing

\ a phantom

deletion of third
leaf and fusing

insertion of a

.. new third leaf

~
phantoms

insertion of new
4th leaf and splitting

---------.~ ...

Theorem 12: Let b ~ 2a and a ~ 2 and let T be an (a,b)-tree with n


leaves. Suppose that a sequence of s insertions and t deletions is per-
formed and tree T' is obtained. Then tree T' has n + s leaves, t of
which are phantoms. Number the leaves from to n + s from left to right.
Let P1,P2, ... ,Ps+t be the positions of the s + t new leaves and phan-
toms in T', P1 ~ P2 ~ ~ Ps+t' Let SH(SP,F) be the total number of
232

~ings (splittings, fusings) required to process this sequence. Then


s+t
SH + SP + F ~ 9(s+t) + 4(Llog (n+s)J + ! Lloga(P.-P'_1+1)J)
a i=2 ~ ~

Proof: We first introduce a marking process which (conceptually) marks


nodes during the rebalancing process.

Adding a leaf: When a new leaf is added we mark the new leaf and its
father.

Splitting a node: Suppose that node v (v will be marked at this point


and has a marked son) is split into nodes v' and v". Then v'is marked
if it has a marked son, v" is marked if it has a marked son and we mark
the father of v' and v".

Pruning a leaf: We mark the phantom and its father.

Fusing: Suppose that node v (v has a marked son at this point) is fused
with its brother y. Then we mark v and its father.

Sharing: Suppose that node v (v has a marked son at this point) receives
a son from its brother y. Then we mark v and we unmark y (if it was
marked) •

Fact 1: If interior node v is marked then it has a marked son.

Since the only leaves which are marked are the new leaves and the phan-
toms we conclude from Fact 1 that all marked nodes lie on paths from
the new leaves and the phantoms to the root. In fact 5 we derive an up-
per bound on the number of such nodes.

Next we need to define some new concepts: critical and noncritical


splitting operation and marked balance. A splitting of node v is criti-
cal if v's father exists and has arity b. All other splittings are non-
critical. Let SPC be the number of critical splittings and let SPNC be
the number of noncritical splittings and let SH (F) be the number of
sharings (fusings).

Fact 2: SPNC + SH ~ s+t


233

Proof: A sharing or noncritical splitting terminates rebalancing. 0

The marked balance of a tree is the sum of the balances of its marked
nodes, i.e.

mb(T) L b(w) + if root is marked then b* (r)


w marked node of T
w * root of T

where the balance of a node is defined as follows.

-1 i f p (w) a-1, b+1

{ 0 i f pew) b
b(w) 2 i f p (w) 2a-1
i f a ::;:; pew) ::;:; b and p (w) * b, 2a-1

and

-1 i f p (r) +1, b+1

b* (r)
{ 0
2
i f p (r)
i f p (r)
b
2a-1
i f 2 ::;:; p (r) : ;:; b and p (r) * b, 2a-1

Fact 3: Let T' be obtained from T by


a) adding a leaf, then mb(T') ~ mb(T) - 2
b) pruning a leaf, then mb(T') ~ mb(T) - 2
c) noncritical splitting, then mb(T') ~ mb(T)
d) critical splitting, then mb(T') ~ mb(T) + 1
e) fusing, then mb(T') ~ mb(T) + 2
f) sharing, then mb(T') ~ mb(T)

Proof: a) Suppose we add a leaf and expand v. Then v is marked after


adding the leaf and may be marked or not before. Hence

mb(T') mb(T) + b(v after adding leaf) - [b(v before adding leaf)]

where the expression jn square brackets is only present if v is marked


before adding the leaf. In either case it is easy to see that
mb(T') ~ mb(T) - 2.
234

b) Similar to part a) .

c) Suppose we split node v (which is marked at this point) into nodes


v' and v" and expand v's father x. Since the splitting is noncritical
we have p(x) < b before the splitting. Also at least one of v' and v"
will be marked after the splitting, x will be marked after the split-
ting, x may be marked before or not. Hence

rnb(T') :2: rnb(T) + min(b(v'), b(v")) + b(x after splitting) - b(v)


- [b(x before splitting)]

where the expression in square brackets is only present if x was marked


before the splitting. Since min(b(v'), b(v")):2: (obviously
f(b+1)/2' < b) and since the balance of x can decrease by at most two
we conclude

rnb(T') :2: rnb(T) + 1 + 0 - (-1) - 2

d) Argue as in case c) but observe that p(x) b before splitting.


Therefore

rnb(T') :2: rnb(T) + + (-1) - (-1) - [0]


:2: rnb(T) +

e) Suppose that we fuse v and its brother y and shrink their cornmon
father x. If x is the root and has arity 1 after the fusing then x is
deleted. Also v and x are marked after the fusing and at least v is
marked before. y and x may be marked before. Hence

rnb(T') :2: mb(T) + b(v after fusing)


+ b(x after fusing) - b(v before fusing)
- [b(x before fusing)] - [bey before fusing)]
:2: rnb(T) + 2 + (-1) - (-1) - 0
:2: rnb(T) + 2

since the balance of x can decrease by at most one.

f) Suppose that v takes away a son from y. Then v is marked before and
after the sharing, y is not marked after the sharing and may be marked
or not before the sharing. Also the balance of y before the sharing is
at most 2.
235

Hence

mb(T') mb(T) + b(v after sharing) -


b(v before sharing) - [b(y before sharing)]
~ mb(T) + 1 - (-1) - 2
~ mb (T) o

Suppose now that we start with initial tree T (no node marked) and per-
form s insertions and t deletions and obtain Tn (n = s+t).

Fact 4: a) mb(T n ) ~ SPC + 2F - 2(s+t)

b) mb(Tn ) ~ 2·m, where m is the number of marked nodes of Tn.

c) All marked nodes lie on a path from a new leaf or phantom to the root.

d) SPC + F ~ 2(s+t) + 2· (number of nodes on the paths from the new


leaves and phantoms to the root).

Proof: a) Follows immediately from fact 3, b) is immediate from the


definition of marked balance, c) follows from fact 1 and d) is a conse-
quence of a), b) and c). o

It remains to derive a bound on the number of marked nodes in tree Tn.


In Fact 5 we use the name (a,~)-tree for any tree where each interior
node unequal the root has at least a sons and the root has at least
2 sons.

Fact 5: Let T be an(a,~)-tree with N leaves. Let 1 ~ P1 ~ P2 ~ ••• ~

Pr ~ N. Let m be the total number of nodes on paths from the root to


the leaves with positions Pi' 1 ~ i ~ r. Then

r
m ~ 3r + 2(LlogaNJ + L Lloga(Pi-Pi_1 + 1)J)
i=2

Proof: For every node v label the outgoing edges with O, ••• ,p(v)-1 from
left to right.

~(V)-1
236

Then a path from the root to a node corresponds to a word over alphabet
{O,1,2, ••• } in a natural way.

Let Ai be the number of edges labelled 0 on the path from the root to
leaf p., 1 $ i $ r. Since an (a,~)-tree of height h has at least 2'a h - 1
~

leaves, we conclude 0 $ Ai $ 1 + Llog a N/2 J • Furthermore, let ti be the


number of interior nodes on the path from leaf Pi to the root which are
not on the path from leaf Pi-1 to the root. Then
r
m $ 1 + Lloga N/2 J + L ti
i=2

Consider any i ~ 2. Let v be the lowest common node on the paths from
leaves Pi-1 and Pi to the root. Then edge k1 is taken out of v on the
path to Pi-1 and edge k2 > k1 is taken on the path to Pi' Note that the
path from v to leaf Pi-1 as well as to leaf Pi consists of ti + 1 edges.

Proof: The paths from Pi-1 and Pi to the root differ only below node v.
Let s be minimal such that

a) the path from v to Pi-1 has the form k 1 aB with IBI s and a contains
no o.

b) the path from v to Pi has the form k2 olal y for some y with Iyl s.

Note that either B starts with a 0 or y starts with a non-zero and that
Ial + I BI ti .
v
237

o then -1

+ number of zeroes in y
number of zeroes in B
~ Ai - 1 - 1 + (ti-s) + 0 - s

It remains to show that s ~ 1 + Lloga(Pi-Pi_1+1)j. This is certainly


the case if s = o. Suppose now that s > o.

We noted above that either B starts with a zero or y starts with a non-
zero. In the first case consider node w which is reached from v via
k1 a 1, in the second case node w which is reached from v via k2 olal o .
All leaf descendants of w lie properly between Pi-1 and Pi· Further-
s-1 leaf descendants. This
more, w has height s-1 and hence at least a
proves

s-1
a ~ Pi - P i -1 - 1
and hence

s ~ + L10ga(Pi-Pi_1-1)j

~ 1 + Lloga(Pi-Pi_1+1)j D

Using our claim repeatedly, we obtain

r
t.~ - 2 L loga(Pi-Pi_1+1)
i=2

- 3 (r-1)

r r
L ti ~ 3r - 3 + 1 + Lloga N/2 j + 2 L Lloga(Pi-Pi_1+1)j
i=2 i=2

and hence
r
m ~ 3r - 1 + 2 Llog a N/2 j + 2 i~2 Lloga(Pi-Pi_1+1)j

This proves fact 5. D


238

At this point, we can put everything together and obtain a bound on the
number of rebalancing operations.

SH + SP + F ~ SH + SPNC + SPC + F
~ s + t + SPC + F by (Fact 2)
~ 3(s+t) + 2m by (Fact 4d)

whe~~ m is the total number of nodes on the paths from the new leaves
and phantoms to the root in the final tree. Since the final tree is an
(a,~)-tree and has n+s leaves and phantom leaves, we conclude from factS

and hence

s+t
SH + SP + F ~ 9(s+t) + 4(Lloga (n+s)j + L Lloga(Pi-Pi_1+1)j)
i=2

This proves theorem 12. c

Theorem 12 provides us with a bound on total rebalancing cost if we


start with a non-empty (a,b)-tree. We use theorem 12 to generalize
theorem 11 to the case where we start with a non-empty list.

Theorem 13: Let b ~ 2a and a ~ 2. Let L be a sorted list of n elements


represented as a level-linked (a,b)-tree with one finger establishe~.

Then in any sequence of searches, finger creations, insertions and dele-


tions, the total cost of the sequence is

O(log n + total cost of searches)

Proof: Let S be any sequence of searches, finger creations, insertions


and deletions containing exactly s insertions and t deletions. Let
Tfinal be the (a,b)-tree, which represents list L after S is performed.
Assume that we keep deleted elements as phantoms. Let the n+s leaves
(real leaves and phantoms) of T f . 1 be named 1, ••• ,n+s from left to
lna
right. Assign to each leaf p a label ~(p), whose value is the number
of leaves lying strictly to the left of p which were present initially
and which did not become phantoms. These labels lie in the range 0, ••. ,n.
239

Consider the searches in S which lead either to the creation of a new


finger or to the insertion or deletion of an element. Call an element
of L accessed if it is either the source or the destination of such a
search (We regard an inserted item as the destination of the search
which discovers where to insert it). Let P1 < P2 < .•. < P£ be the
accessed items.

We shall consider graphs whose vertex set is a subset of {Pi11 ~ i ~ £}.


We denote an edge joining p.~ < p.J in such a graph by -p.1 - p., and we
define that cost of this edge to be max (rIOg(£(Pj)-£(Pi)+1)1,1). For
each item Pi (except the initially fingered item) let qi be the fingered
item frornwhich the search for Pi was made. Each qi is also in {PiI1~i~ £}

since each finger except the first must be established by a search. Con-
sider the graph G with vertex set f~11 ~ i ~ £} and edge set
{(qi'Pi) 11 ~ i ~ £ and Pi is not the originally fingered item}.

Some constant times the sum of edge costs in G is a lower bound on the
total search cost, since 1£(Pi)-£(qi) 1+1 can only underestimate the ac-
tual distance between qi and Pi when Pi is accessed. We shall describe
a way to modify G, while never increasing its cost, until it becomes

where r 1 < r 2 < ••. < r k are the k = s+t inserted or deleted leaves.
Since the cost of this graph is E max(rlog (£(r i ) - £(r i _ 1 )+1)1,1)
1 <:L::;k
~ k + E log (r. - r i - 1 + 1), the theorem then follows from theorem 12.
1 <i~k ~

The initial graph G is connected, since every accessed item must be


reached from the initially fingered item. We first delete all but £ -
edges from G so as to leave a spanning tree; this only decreases the
cost of G.

Next, we repeat the following step until it is no longer applicable:


let Pi - Pj be an edge of G such that there is an accessed item Pk sat-
isfying p~~ < Pk < p J.. Removing edge p.~ - p.
. J
now divides G into exactly
two connected components. If Pk is in the same connected component as
p., we replace p. - p. by Pk - p.; otherwise, we replace p. - p. by
~ ~ J J ~ J
Pi - Pk· The new graph is still a tree spanning {Pi11 ~ i ~ £} and the
cost has not increased.
Finally, we eliminate each item Pj which is not an inserted or deleted
leaf by transforming Pi - Pj - Pk to Pi - Pk' and. by removing edges
Pj - Pk where there is no other edge incident to Pj. This does not in-
crease cost, and it results in the tree of inserted or deleted items

as desired. c

Finger trees can be used effectively for many basic set operations such
as union, intersection, difference, symmetric difference, ••••

Theorem 14: Let A and B be sets represented as level-linked (a,b)-trees,


b ~ 2a and a ~ 2.

a) Insert(x,A), Access(x,A), Delete(x,A), Concatenate(A,B), Split(x,A)


take logarithmic time.

b) Let n = max(IAI,IBI) and m = min(IAI,IBI). Then A U B, A ~ B, A n B,


n+m
A' B can be constructed in time O(log( m )).

Proof: a) It is easy to see that theorems Sand 6 are true for level-
linked (a, b)-trees.

b) We show how to construct A ~ B = (A - B) U (B - A). Assume w.l.o.g.


IAI ~ IBI. The algorithm is as follows.

(1) establish a finger at the first element of A;


(2) while B not exhausted
(3) do take the next element, say x, of B and search for it in A start-
ing at the finger;
(4) insert x into or delete x from A, whatever is appropriate;
(5) establish a finger at the position of x in A and destroy the
old finger
(6) od

Let P1, ••. ,Pm' m = IBI, be the positions of the elements of B in the
set A U B, let Po = 1. Then the above program takes time
241

m-1
O(m + log(n+m) + ~ 10g(Pi+1 - Pi + 1»
i=O

by theorem 13 and the observation that total search time is bounded by


m-1
~ 10g(P'+1 - Pi + 1).
i=1 ~

This expression is maximized for Pi+1 - Pi = (n+m)/m for all i, and


then has value O(log(n+m) + m log«n+m)/m» = O(m log«n+m)/m»
= O(log( n+m
m ».

In the case of A U B, we only do insertions in line (4). In the case of


A n B, we collect the elements of A n Bin line (4) (there are at most m of
them) and construct a level-linked (a,b)-tree for them afterwards in
time O(m).

Finally we have to consider A' B. If IAI ~ IBI, then we use the pro-
gram above. If IAI < IBI then we scan through A linearly, search for
the elements of A in B as described above (roles of A and B reversed)
and delete the appropriate elements from A. Apparently, the same time
bound holds. c

Note that there are ( n+m


m ) possibilities for B as a subset of A U B.
Hence log (n!m) is also a lower bound on the complexity of union and
symmetric difference.

III. 5.3.4 Fringe Analysis

Fringe analysis is a technique which allows us to treat some aspects of


random (a,b)-trees. Let us first make the notion of random (a,b)-tree
precise. A random (a,b)-tree is grown by random insertions starting
with the empty tree. Let T be an (a,b)-tree with j leaves. An insertion
of a new element into T is random if each of the j leaves of T is
equally likely to be split by the insertion. This can also be phrased
in terms of search trees. Let S be a set with j - 1 elements and let T
be a search tree for S U {~}. Then the elements of S split the universe
into j intervals. The insertion of a new element x is random if x has
equal probability for being in anyone of the j intervals defined
above.
242

We use fringe analysis to derive bounds on n(N), the expected number of


nodes in a random (a,b)-tree with N leaves, i.e. a tree obtained by N
random insertions from an empty tree. Then n(N) (2b-1) is the average
number of storage locations required for a random (a,b)-tree with N
leaves. Since any (a,b)-tree with N "leaves has at least (N-1)/(b-1)
nodes and hence uses at least (2b-1) (N-1)/(b-1) storage locations we
can define seN) := (N-1)/((b-1) n(N» as the storage utilization of
a random (a,b)-tree. We show that seN) ~ 0.69 if b = 2a and a is large.
This is in marked contrast to worst case storage utilization of
(a-1)/(b-1) ~ 0.5.

For T an (a,b)-tree let neT) be the number of nodes of T and let PN(T)
be the probability that T is obtained by N random insertions from the
empty tree. Of course, PN(T) is zero if the nQmber of leaves of T is un-
equal N. Then

n(N) L PN(T) neT)


T

Fringe analysis is based on the fact that most nodes of an (a,b)-tree


are close to the leaves. Therefore a good estimate of n(N) can be ob-
tained by just estimating the number of nodes on the level one above
the leaves.

Let ni(T) be the number of leaves of T which are sons of a node with
exactly i sons, a ~ i ~ b. Then L n l" (T) = ITI, the number of leaves of
i
T. Let

n.l (N) N

Lemma 9: a) Let T be an (a,b)-tree and let r = L n. (T)/i. Then


i l

- 1/(b-1) + (1 + 1/(b-1» r ~ neT) ~ 1 + (1 + 1/(a-1» r

b) Let r(N) = L nl' (N)/i. Then


i
- 1/(b-1) + (1 + 1/(b-1» r(N) ~ n(N) ~ 1 + (1 + 1/(a-1» r(N)

Proof: a) Let m be the number of nodes of T of height 2 or more. Then


243

neT) = m + L n. (T)/i since ni(T)/i is the number of nodes of arity i


i ~
and height 1. Also

0: n{(T)/i-1)/(b-1) ~ m ~ (L n{ (T)/i - 1)/(a-1) + 1


i ~ i ~

since every node of height 2 or more has at most b and at least a sons
(except for the root which has at least two sons) and since there are
exactly L n. (T)/i nodes of height 1 in T. The 1 on the right hand side
. ~

accounts~for the fact that the degree of the root might be as low as 2.

b) immediate from part a) and the definition of n. (N) and n(N) . a


~

We infer from lemma 9 that n(N) is essentially L n. (N) Ii. We determine


. ~

this quantity by setting up recursion equations~for ni(N) and solving


them.

Lemma 10: Let b = 2a and a ~ 2. Then

n (N+1) na (N) + a(nb(N) - na (N) ) /N


a

n a + 1 (N+1) n a + 1 (N) + (a+1) (nb (N) + na (N) - n a + 1 (N»/N

and
n. (N+1) n. (N) + i (n.~- 1 (N) ni(N»/N for a+2 ~ i ~ b
~ ~

Proof: We prove the second equation and leave the two others to the
reader. Let T be an (a,b)-tree with N leaves. Consider a random inser-
tion into T resulting in tree T'. Note that n a + 1 (T') - n a + 1 (T) grows
by a + 1 if the insertion is into a node with either exactly a (proba-
bility na(T)/N) or b (probability nb(T)/N) leaf sons and that
n a + 1 (T') - n a + 1 (T) goes down by a+1 if the insertion is into a node of
height 1 with exactly a+1 sons (probability n a + 1 (T)/N). Thus

n a + 1 (N+1)

- T
Let Q(N) be the column-vector (na(N), •.. , nb (N) ) Then lemma 10 can
be written in matrix form as
244

Q(N+1) (I + 2.N B)Q(N)

where

-(a+1)
a+2 -(a+2)

+b

With q(N) = (1/N) Q(N) this can be rewritten as

q(N+1)= (I + N11 (B-1» q(N)

Note that matrix B-1 is singular since each column sums to zero. We
show below that q(N) converges to q, a right eigenvector of B-1 with
respect to eigenvalue 0, as N goes to infinity. Also Iq(N) - ql = O(N- c )
for some c > O. This is shown in theorem 16.

T
We will next determine q = (qa, ••• ,qb) From (B-I)q o and
I: q. = lim I: ni (N) /N = one concludes
i . J. N.... co i

qa = a/ «a+1) (b+1) (H b -Ha) )


and

for a+1 ~ i ~ b

a
where Ha I: 1/i is the a-th harmonic number.
i=1

(The qi's, a ~ i ~ b, can be found as follows: take qb as an indeter-


minate and solve (B-I)q for qb-1' qb-2' ••• , qa+2' qa' qa+1 in that
order. Then use ~ qi = 1 to determine qb). Thus

1
(a+1) (b+1) +
245

1
(a+1) (b+1) +

since b 2a

Theorem 15: Let b = 2a and a ~ 2, let e;>Oand lets(N) = (N-1)/«b-1)n(N»


be the storage utilization of a random (a,b)-tree with N leaves. Then

Is(N) - tn21 ~ Cia + e;

for some constant C independent of N and a and all sufficiently large N.

Proof: Note first that

N N
- e; ~s(N) ~ - - - - - - - - - - + e;
(b-1) (1+1/(a-1»r(N) (b-1) (1+1/ (b-1 » r (N)

for all sufficiently large N by lemma 9b. Here r(N)/N = ~ qi(N)/i


~ q./i + O(N
-c ) = 1/«b+1) (Hb-H » + O(N -c ) for some constant
~
c > O.
i ~ b a M1
Furthermore Hb-H a ~ 1/i = tn2 + O(1/a) since J (1/x)dx ~
b b i=a+1 a+1
~ 1/i ~ J (1/x)dx.
i=a+1 a

Thus Is(N) - tn21 ~ Cia + e; for all sufficiently large N and some con-
stant C. c

Storage utilization of a random (a, 2a) -tree is thus about tn2 RI 69%.
Fringe analysis can also be used to sharpen theorem 8 on the total re-
balancing cost. The bound in theorem 8 was derived under the pessimistic
assumption that every insertion/deletion decreases the value of the tree
by 1. Fringe analysis provides us with a smaller bound at least if we
restrict attention to random sequences of insertions. It is not hard to
define what we mean by a random deletion; any leaf of the tree is re-
moved with equal probability. However, it seems to be very hard to ex-
tend fringe analysis to random insertions and deletions.
246

We still have to prove convergence of sequence q(N), N = 1,2, •••• The


answer is provided by the following general theorem which is applicable
to fringe analysis problems of other types of trees also.

Theorem 16: Let H (h .. ) 1<' '< be a matrix such that


~J -~,J-m

1) all off-diagonal elements are non-negative and each column of H sums


to zero and

2) there is an i such that for all j there are jo,··.,jk with i jo'
j = jk and h . . > 0 for 0 ~ ~ < k. Then
J~,J~+1

a) Let A1 , ••• ,Am be the eigenvalues of H in decreasing order of real


part. Then A'1 = 0 > Re(A 2 ) > Re(A3) ~ ••• ~ Re(Am)

b) Let q(O) be any non-zero m-vector and define q(N+1) = (I+ N !1H)q(N)
for N ~ O. Then q(N) converges to q a right eigenvector of H with re-
Re A2
spect to eigenvalue 0 and Iq - q(N) I = O(N ).

Proof: a) H is singular since each column of H sums to zero. Thus 0 is


an eigenvalue of H. Furthermore, all eigenvalues of H are contained in
the union of the disks with center h .. and radius L Ih .. 1, j = 1,2,
JJ hj ~J
••• ,m. This is the well-known Gerschgorin criterion (cf. Stoer/
Bulirsch: Numerische Mathematik II, page 77). Thus all eigenvalues of
H have non-positive real part.

It remains to show that 0 is an eigenvalue of multiplicity one. This is


the case iff the linear term in the characteristic polynomial of H (i.e.
det(H-AI)) is non-null. The coefficient of the linear term is L det H .. ,
i ~~
where Hii is obtained from H by deleting the i-th row and column.
Application of the Gerschgorin criterion to Hii shows that all eigen-
values of Hii have non-positive real part. Since det Hii = E 1 .··E m_ 1

r
where E 1 , •.• ,E m_ 1 are the eigenvalues of Hii , we infer that either
m-1
det(H ii ) = 0 or sign (det Hii ) = (-1) • Thus det Hii = 0 iff
det Hii = 0 for all i.

We will next show that det Hii * 0 where i satisfies assumption 2) of


the theorem. Assume otherwise. Let u = (u1, ••• ,ui_1,ui+1, ••• ,um) be a
left eigenvector of Hii with respect to eigenvalue O. Let u t be a com-
247

ponent of maximal absolute value in u and let I = {j;lujl = lutl} =


{1, ••• ,m} - {iL Since if-I and I * ¢ there must be j E I, k f- I,
such that h kj > 0 by assumption 2. We may assume w.l.o.g. that u j > O.
Thus

::; u. L h tj + (Iukl/u j - 1 ) h kj ),
J t
since lutl ::;u. and h tj 2: 0 for .Q, j
J *
< 0
since L h.Q,' I uk I/u j < 1 and h kj > O. Hence u is not left
0,
.Q, J
eigenvector of H .. with respect to eigenvalue o.
1.1.

n
b) Let fn(x) n (1 + x/j) and let f(x) lim fn(x). Then
j=1 n-> =
f(O) = fn(O) 1. Also

Claim: I fn (x) I ::; C n Re x for some C depending on x.


n n
Proof: Note first that If (x) I = n 11 + x/jl = exp( L tn 11 + x/jl).
n j=1 j=1
Next note that

11 + x/ jl 2 11 + Re(x/j) 12 + IIm(x/j) 12

::; I 1 + Re (x/ j) I 2 (1 + c I 1m (x/j) I 2)

for some constant c and all j 2: jo (c and jo depend on x). Taking


square roots and substituting into the expression for Ifn(x) I yields

n
exp( L .Q,n 11 + x/jl + L (tn(1 + Re(x/j» +
j::;jo j=jo
tn ( (1 + c I 1m (x/j) I 2) 1/2)

for some constant C depending on x since tn(1 + Re(x/j» ::; Re(x)/j and
tn«1 + c IIm(x/j)1 2 )1/2)::; (c/2) IIm(x)1 2 /j:2. 0
248

Let q(O) be some m-vector and let q(N+1) = (I + n+1 H) q(N) for N ~ o.
Then q(N) = fn(H)q(O) where fn(H) n (I ~ J
1
H). We consider matrix
1::;j::;n
fn(H) in more detail.

Let J = THT- 1 ( Jo
1.. . 0) JK
be the Jordan matrix corresponding to H;

J 1 , •• ·,Jk are the blocks of the Jordan matrix. We have J 1 (0), i.e.
~ is a one by one matrix whose only entry is zero. Also

with Re At < O. Then

T- 1 f n (J)T as is easily verified. Also

f (J )
n 1 f (J )
n 2

We have (cf. Gantmacher, Matrices, chapter V, example 2)

(v t -1 )
f(2) (A ) fn (At)
n t
21 v t1

where v t is the multiplicity of At and f~h) is the h-th derivative of


f • The reader can easily verify this identity (for every polynomial f )
n n
by induction on the degree. Hence f n (J 1 ) = (1), the one by one matrix
whose only entry is one and

_(e:1'1~~~... e:1,Vt(n))
. e: (n)
f ( In ) - • •
n N
o • •

vt,V t
249

where S.1., J' = O(nRe A


2). Thus q(N) converges to q = T- 1 f(J)T q(O) as N
goes to infinity. Here f(J) is a matrix with a one in position (1,1)
and all other entries equal to zero. Also H·q = (T- 1 JT) (T- 1 f(J)Tq(0» =
T-' J f(J) T q(O) = T-' 0 T q(O) where 0 is the all zero matrix. Hence
H q = 0, i.e. q is right eigenvector of H with respect to eigenvalue o.
Finally, Iq(N) - ql = O(n Re 1.. 2 ). c

III. 6. Dynamic Weighted Trees

In this section we will combine some of the results of section III.4.


on weighted trees and section III.5. on dynamic trees and treat dynamic
weighted trees. The szenario is as follows: We are given a set
S = {x" ••• ,xn }, x, < x 2 < ... < x n ' of n elements and weights wi E IN,
1 ~ i ~ n. In section 4 we saw how to build good static trees for
weighted set S, i.e. we showed how to support operation Access in log-
arithmic time. More precisely, a search for xi had essentially cost
= w, + w 2 + ••• + wn is the total weight of set S.
O(log W/W i ) where W
Section 5 was devoted to dynamic unweighted sets, i.e. we showed how to
realize operations Insert, Delete, Access, Concatenate and Split on un-
weighted sets in logarithmic time. We will now combine both approaches
and show how to do Insert, Delete, Access, Concatenate and Split on
weighted sets. What kind of behaviour can we expect in view of the
results of section 4? The cost of an Access to an element of weight w
in a set of total weight W can certainly be no cheaper than O(log W/w) •
Similarly, deleting an element of weight w or splitting at an element
of wight w can be no cheaper than accessing and therefore must have cost
~(log W/w). Demotion (decrease the weight by some 8 > 0) can be no
cheaper than accessing the "demoted element" and therefore must have
cost ~(log W/(w-8». Promotion (increase the weight by some 8 > 0) can
be no cheaper than accessing the element in the "promoted" tree and
therefore must have cost ~(log(W+8)/w). An Insert might have to add a

leaf between leaves of minimum weight. It is therefore reasonable to


expect that an Insert requires time ~(log(W+w); in fact we will be able
to achieve a slightly better bound, namely O(log(W+w) /min(w' ,w,w"»
where w' and w" are the weights of the two neighbors of the new node.
Finally, a Concatenate operation jOins two trees of weight W1 and W2
respectively. We might hope to do Concatenates in time 0(log(W,+w 2 )/
min(W"W 2 »· However, we will not be able to achieve that bound (note
2W

that even in the unweighted case the cost of a join is related to the
height difference of the operand trees which is in general not related
to the log of the weight ratio (cf. exercises 28 and 38) and therefore
will only show a bound of O(log(W 1+W 2 )/w) where w is the weight of the
rightmost element of the first tree.

The main result of this section is that these time bounds are in fact
achievable. How can we proceed? How can we generalize weight-balanced
or height-balanced trees in order to cope with elements of different
weights? A first idea is to balance weights and cardinalities of sets
in weight-balanced trees (cf. the generalization of binary search from
unweighted to weighted sets in 4.1.) or to let the height of a leaf
depend on the weight of the leaf in height-balanced trees, e.g. to
set the height of a leaf of weight w to Llog wJ • The following example
shows that this idea does not work in its pure form. Consider a set of
three elements of weight 1, n, and 1 respectively.

In a weight-balanced binary tree the root will have balance 1/(n+2)


which can be arbitrarily close to O. In a height-balanced tree we have
three leaves of height log 1, log n and log 1 respectively, i.e. the
height of brother nodes can differ by arbitrary amounts.

Three approaches have been considered to the remedy the situation. In


the historically first approach one gives up the concept that each
element xES is represented by a single leaf. Rather, one splits the
weight of heavy elements into smaller pieces so as to maintain the
balancing criterion. In our example we might represent object x 2 E S
by leaves of weight 2,2,4, ••• ,n/4,n/4, ••• ,4,2,2 and obtain a balanced
tree in this way. Only one of these leaves, namely one of the large
pieces of weight
251

~
~rrJ ~
\

leaves representing
x2 E S

n/4, "really" represents x 2 and searches for x 2 are directed to that


leaf, all other leaves are only there to maintain the fiction of a
fully balanced tree· The details of this approach can be found in
section 6.2.
The historically second approach which can be found in S.W. Bent, D.O.
Sleator, R.E. Tarjan: Biased 2-3 Trees, 21 st FOCS, 1980, 248-254,
th
or H. Guting, H.P. Kriegel: Dynamic k-dimensional search, 5 GI-
Conference on Theoretical Computer Science, LNCS 104,135-145, starts
from the observation that unbalanced nodes need only occur close to
leaves. This can be seen as follows. Suppose that we want to store
elements with weights w1 , ..• ,w n in the leaves of a binary tree. Let i
be such that w 1 + ••• + wi - 1 :::; W/2 :::;w 1 + ••• + wi where W = w1 + ••• +
wn ' If either w 1 + ••• + wi - 1 ;::: W/3 or w1 + ••• + wi:::; 2W/3 then we can
construct a tree with root balance in interval [1/3, 2/3]. Otherwise,
we must have wi ;::: W/3 and 1 < i < n or wi ;::: 2W/3 and i = 1 or i = n.
In either case, one of the following trees is a good search tree; it

a tree for
a tree for a tree for
w1 ' .•• ,w i - 1 wi"" ,w n - 1
w2 "" ,wn

has an unbalanced root and all non-trivial subtrees have weight at most
W/3. Thus logarithmic search time is guaranteed and unbalanced nodes
only occur near leaves. A similar statement can be made if we look at
height-balanced trees. In their paper on biased trees Bent/Sleator/
Tarjan show that this property can be maintained dynamically and that
the time bounds stated above can be achieved by biased trees.
252

The historically third approach is discussed in section 6.1.2. It is


based on the idea of self-organizing data structures and definitely the
most elegant solution.

This section is organized as follows. In section 6.1. we discuss self-


organizing data structures and their amortized and average case
behavior. Section 6.1.1. is devoted to self-organizing linear lists
and 6.1.2. to self-organizing trees. In section 6.2. we describe D-trees
and in section 6.3. we discuss an application of dynamic weighted trees
to multi-dimensional searching.

III. 6.1 Self-Organizing Data Structures and their Amortized and


Average Case Analysis

In this section we discuss self-organizing data structures, more


precisely self-organizing linear lists and trees. The idea of self-
organization is quite simple. Suppose that we have a data-structure for
set S = {x 1 ' .•. ,x n }. Whenever we access an element of S, say xi' then
we move xi closer to the entry point of the data structure. This will
make subsequent accesses to xi cheaper. In this way the elements of S
compete for the "good" places in the data structure and high-frequency
elements are more likely to be there. Note however, that we do not main-
tain any explicite frequency counts or weights~ rather, we hope that the
data structure self-organizes to a good data structure.

Since no global information is kept in a self-organizing data structure


the worst case behavior of a single operation can always be horrible.
However, the average and the amortized behavior may be good. For an
average case analysis we need to have probabilities for the various
operations. The data structure then leads to a Markov chain whose st~tes
are the different incarnations of the data structure. We can then use
probability theory to compute the stationary probabilities of the
various states and use these probabilities to derive bounds on the
expected behavior of the data structure. In section 6.1.1 we will
carry out an average case analysis of self-organizing linear lists.

Amortized analysis is the worst case analysis of an algorithm for a


(worst-case) sequence of operations, i.e. the goal of amortized analysis
is to derive an upper bound on the cost of a sequence of operations.
253

We have seen several examples of amortized analysis already, most


notably (a,b)-trees and BB[a]-trees. There are many more examples to
come.

In the analysis of (a,b)-trees we used the bank account paradigm. For


the application of the paradigm in this section we need to discuss its
principles in more detail. Consider a sequence OP1, ••• ,OPm of operations
leading us from an initial data structure Do to a final data structure
Dm·

Do - - - -•• D1 ---_I ....

Suppose also that we have a function bal: {Do ,D 1 , ..• } ~ lR from the set
of possible data structures into the set of reals. If D is a data
structure then we call bal(D) the balance of the account of the
structure. A unit of balance represents the ability to pay for 0(1)
units of computing time. We define the amortized cost of operation OPi
by

(x)

where ti is the actual execution time of operation OPi.

Example: In our analysis of (2,4)-trees (section 5.3.2 with a = 2,


b = 4) we used the following account:
bal(T) I{ v; v is a node of T and has exactly three sons} I •
The actual cost of adding a leaf is + s where s is the number of node
splittings caused by adding the leaf. If adding a leaf to tree T causes
s nodes to split and yields tree T' then bal(T') - bal(T) ~ -(s-1)
since there are at least (s-1) additional nodes in T' with exactly three
sons. Hence the amortized cost of adding a leaf is at most
1 + s - ( s- 1) = 2. []

Summing the defining equation of amortized cost over all operations


yields

m
L a i + bal(Do ) - bal(Dm )
i=1
i.e. the total actual cost of the sequence of operations is equal to
254

the total amortized cost plus the net decrease in balance between
initial and final configuration. We will mostly use the concept of
amortization as follows. Suppose that we have defined the intended cost
iC i of operation OPi by some means; e.g. in dynamic weighted trees the
intended cost of an access operation to an element of weight w in a set
of total weight W is log W/w. We will then try to find an account for
the data structure, i.e. a function bal, such that the amortized cost
of every operation is bounded by the intended cost, i.e.

Then

m m
L t.::::; L iC i + bal(D o ) - bal(Dm) ,
i=1 1. i=1

i.e. total actual cost is bounded by total intended cost plus the net
decrease in balance. Amortization is a means of cost sharing between
operations. Operations which do not require their intended cost, i.e.
ti ::::; ic i , pay for the cost of operations which exceed their intended
cost, i.e. ti > ic i • The sharing between the costs is made by the
account associated with the data structure, i.e. an operation deposits
«or withdraws) iC i - ti units into (from) the account in order to cover
the cost difference between intended and actual time bound.

In most cases of amortized analysis, we have either bal(D) ~ 0


(positive account) or bal(D) ::::; 0 (negative account) for all D.

In the case of a Eositive account we have

m m
L t. ::::; L ic. + bal(D o )
1. 1.
i=1 i=1

,i.e. actual cost is bounded by intended cost plus initial balance. The
interpretation of a positive account is particularly simple. We start
with an initial investment of bal(D o ) units. Using this initial
investment and the units provided by the intended costs of the
operations we can also cover the actual cost. In other words, we use the
account to have operations pay for the cost of later operations which
might overrun their intended cost.

ExamEle: An example of a positive account is provided by our analysis


of BB[a]-trees, cf. theorems 4 and 5 of section 5.1.
255

Let 1/4 < a < 1 - /272 and let 0 > 0 be defined as in lemma 1 of section
5.1. For a binary tree T let

bal(T) = L max (0, a + 0 - p(v), p(v) - (1 - a - 0»/0

where p(v) is the root balance of node v and the summation is over all
nodes of tree T. We claim that the amortized cost of adding or deleting
a leaf is 0(1) (this follows from the fact that adding a leaf below a
node of thickness th(v) can change its root balance by at most 1/th(v)
and that the amortized cost of a rotation or double rotation is zero
(this follows from the fact that a node v which causes a rebalancing
operation, i.e. p(v) < a or p(v) > 1-a, contributes at least one to
bal(T) and does not contribute anything after the rotation). Hence the
total number of rotations and double rotations is bounded by the order
of the number of insertions and deletions; cf. theorem 4 of section 5.1.
o
In the case of a negative account we have

m m
L t. ~ L iC i - bal(Dm)
i=1 l i=1

i.e. actual cost is bounded by intended cost plus final debt. In the
case of a negative account we use bal(D m) to keep track of the cost
overrun, i.e.lbal(Dm) I measures the overrun of actual cost over intended
cost. In other words, we use the account to have later operations pay
for the cost of preceding operations, and we use bal(Dm) to keep track
of the final dept.

Example: An example of a negative account is provided by our analysis


of (a,b)-trees in section 5.3.2. and by the proof of fact 5 in section
5.3.3. which bounds the number of nodes on the paths from the root to
the leaves with position Pi' 0 ~ i ~ r, in an (a,oo)-tree with N leaves,
Po ~ P1 ~ o •. ~ Pro We let Di be the path from the root to position Pi'
- bal(D i ) to be the number of edges labelled 0 on path Di (bal(D i ) is
called Ai in the proof of fact 5), ti to be the number of nodes on
path Di which do not lie on Di - 1 (called ~i in the proof of fact 5),
and iC i 2 Lloga(Pi - Pi-1 + 1)J + 3. Then

as was shown in the proof of fact 5. o


256

III. 6.1.1 Self-Organizing Linear Lists

Self-organizing linear search is quite simple. Let S {x 1 ' ... ,x n }. We


=

consider operations Access(x), where xES is assumed, Insert(x), where


x ~ S is assumed, and Delete (x) , where xES is assumed. We always
organize S as a linear list which may be realized as either an array or
a linked list. We use pos(i) to denote the position of element xi in
the list. We assume that the cost of operations Access(x i ) and Delete
(xi) is pos(i) and that the cost of operation Insert(x) is lSI + 1.

There are many strategies for self-organizing linear search. Two very
popular strategies are the Move-to-Front and the Transposition rule.

Move-to-Front Rule (MFR): Operations Access (x) and Insert(x) make x the
first element of the list and leave the order of the remaining elements
unchanged; operation Delete (x) removes x from the list.

TransposiTion Rule (TR): Operation Access (x) interchanges x with the


element preceding x in the list, Insert(x) makes x the next to last
element and Delete (x) removes x from the list.

Example: We give an example for the Move-to-Front Rule.


Insert(2) Access(3) Delete(1)
134 .2134 .3214 -324

The cost of this sequence is 4 + 3 + 3 = 10.

Our first goal of this section is to prove that no algorithm can do


significantly better that MFR in an amortized sense. We will derive this
result in three steps. In the first step we will compare MFR with the
frequency decreasing strategy and motivate the account used in the third
step. In the second step we define the general concept of an algorithm
for maintainig linear lists and its cost and in the third step we will
actually derive the result.

For the first step we will restrict ourselves to sequences of access


operations only. Let s be such a sequence and let k. 1 $ i $ n be the
1,

number of accesses to element xi in sequence s. We may assume w.l.o.g.


that k1 2 k2 2 ... 2 k n . In the frequency decreasing rule (FDR) we
organize S as list x 1 ,x 2 , ... ,x n and never change this arrangement. The
257

cost of processing list s under the PD-rule is clearly


n
CpDR (s) L ik i . We will show that the cost C~WR is at most twice
i=1
that much.

Lemma 1: Let C~R(s) be the cost of processing sequence s under the


~-rule starting with initial list x 1 ,x 2 ' ..• ,x n .
Then C~R(s) ~ 2C pDR (s) - m where m is the length of sequence s.

i
Proof: Let t j , 1 ~ j ~ k i , be the cost of the j-th access to element xi
under the move-to-front rule. We are going to derive a bound on
n k. i n
ik. L ( Ll(t. i)) •
L
i=l
l i=l j=l J
i
Consider an arbitrary pair i,j. If t. > i then there must have been at
i J
least tj - i accesses to elements ~, h > i, between the (j-l)-th and
the j-th access to element xi (the o-th access is the initial con-
figuration). Hence

k. i
Ll (t J. - i) ~ k i + 1 + ... + k n
j=1
for all i, 1 ~ i ~ n, and therefore
n
CMPR(s) - CpDR(s) ~ L (k i + 1 + ... + k n )
i=l
n
L (i-J)k. CpDR (s) - m o
i=J l

There is another way of interpreting the proof of lemma 1 which leads


to an account- to be used later. We argued above that if t~ > i then there
J
were at least t~ - i accesses . . . • This suggests to charge the "excess
cost" of t~ - i of the j-th access to xi to the accesses to elements
x h ' h > i, between the (j-1)-th and the j-th access to xi' i.e.

to charge the excess cost to those x h ' h > i, which are in front of xi
when item xi is accessed for the j-th time. In other words, whenever
we access x h then we charge an extra h-1 time units to this access and
use these time units to pay for the excess cost of accesses to elements
xi' i < h. In this way, the amortized cost of accessing x h is 2h - 1.
258

We can formalize this idea by using an account with balance


n
L I{ xh~ h > i and x h is in front of xi in the current list }I
i=1
This completes the first step.

In the second step we need to define the general concept of an algorithm


for maintaining linear lists and define the running time of such an
algorithm. We assume that ail algorithms work as follows. To access an
element, the list is scanned from the front until the element is located.
The cost of accessing element x is the position of x in the list. In OJ:'-
der to insert x the element x is added to the rear end of the list,
and in order to delete x the element is removed from the list. The cost
of an insert is the length of the sequence after the insert and the
cost of deleting x is the position of x. Finally, an algorithm has the
possibility for rearranging the list at any time. After operations
Access (x) and Insert(x) we allow x to be moved closer to the front of
the list. Such an exchange is called a free exchange and has no cost.
Any other exchange of a pair of consecutive items is called a paid
exchange and has a cost of one. Note that the MF-rule and the TR-rule
use only free exchanges. We are now ready for the main theorem of this
section.

Theorem 1: Let s be an arbitrary sequence of Access, Insert, and Delete


operations starting with the empty list and let A be an arbitrary
algorithm. Let CA(s) be the cost of algorithm A on sequence s not
counting paid exchanges, let XA(s) be the number of paid exchanges, and
let m be the length of sequence s. Then
CMFR(s) ~ 2 CA(s) + XA(s) - FA(S) - m

Proof: We use the bank account paradigm. Let s' be a prefix of sand
let LMFR and LA be the sequences obtained by processing s' under
algorithm MFR and A respectively. Assume w.l.o.g. that LA = (x 1 x 2 ••• x n ).
We define our account by
n
bal(LMFR ) =,L I{xh ; h>i and x h is in front of xi in LMFR } I
1=1
n
=L I{x.; h>i and x. is behind x h in LMFR } I
11=1 1 1
259

Note that the balance of LMFR is defined with respect to the numbering
of elements defined by list LA' If we want to emphasize this dependency
we write bal(~R,LA) instead of bal(L MFR ).

Let Op be the operation following s' in sequence s. Since an Insert can be


viewed as an Access to a fictitious element xn+1 we may assume w.l.o.g.
that Op is either Access(x i ) for some i, 1 ~ i ~ n + 1, or Delete(x i )
for some i. Let t be the position of element xi in list LMFR . Then the
cost of operation Op is t under the MF-rule and i under algorithm A.
Note that algorithm A changes list LA only in a trivial way when
processing Op (either by adding xi at the end or by deleting xi)' We
count the effect of the free and paid exchange performed by algorithm
A seperately. We have the following claim:

Claim: a) The amortized cost of operation Op is at most 2i - 1 where i


is its cost under algorithm A.
b) The amortized cost of a free exchange of algorithm A is -1.
c) The amortized cost of a paid exchange of algorithm A is at
most +1.

Proof: a) Let bal' = bal(LMFR , LA) and bal = bal(~FR,LA) where the
prime denotes the lists after performing operation Op. Since the actual
cost of Op is t its amortized cost is t + bal' - bal. It therefore
suffices to show that t + bal' - bal ~ 2i - 1.
Let k be the number of items x h with h > i and x h is in front of xi
in LMFR • Then k + (i-1) ~ t - 1 and hence k ~ t - i.

If operation Op accesses element xi then bal' - bal ~ - k + (i-1)


since there are k items x h with h > i and x h is in front of xi in LMFR
but not in LMFR and since there are at most i - i t e m s Xj with
j < i and xi is in front of Xj in LMFR but not in LMFR • This proves
bal' - bal ~ - k + (i-1) ~ 2i - 1 - t if Op accessses element xi'
If operation Op deletes element xi then the same argument shows that
bal' - bal =- k ~ i - t.

In either case we conclude that t + bal' - bal ~ 2i - 1.

b) and c). Note first that the actual cost of a free or paid exchange
of algorithm A is zero since no action of algorithm MFR is involved.
260

Also, a free exchange decreases the balance of list LMFR by one and a
paid exchange can increase the balance by at most one. 0

We can now finish the proof by observing that the balance of the initial
list is zero, that we deal with a positive account, and by appealing to
the bank account paradigm. Hence

Theorem 1 is a fairly strong statement about the quality of the move-


to-front rule: no conceivable algorithm, not even an algorithm which
has advance knowledge about the entire sequence of requests, can beat
the MF-rule by more than a factor of two. No such result is true for the
transposition rule. Consider the following sequence: We first insert
x 1 ,x 2 , ... ,x n in that order; this generates sequence x 2 ... x n x 1 under the
transposition rule. We now alternately access x 1 and x n ' The cost of
this sequence of requests is ~(n2 + (m-n)n) under the TR-rule. However,
the cost under the MF-rule is only O(n 2 + m) which is smaller by an
arbitrary factor.
It is also interesting to consider theorem 1 in the case where the
initial lists are non-empty. Suppose that we process sequence sand
start with initial lists LMFR and LA of n items each respectively.
Then

2
- m + n

2
by the proof of theorem 1 and since bal(L MFR , LA) ~ n
This inequality can be interpreted as follows. The MF-rule needs O(u ~ )
time units in order to make up for the unfavorable initial configuration;
after that its cost is at most twice the cost of algorithm A.

For the remainder of this section we turn to expected case behavior.


We do so for two reasons:
- we want to demonstrate the use of Markov chains for the average
case analysis of algorithms,
- we want to show that the MF-rule and the TR-rule have very good
expected case behavior. The behavior of the TR-rule is discussed in
exercise 44.

For the expected case analysis we consider only sequences of Access


261

operations. Let S = {x" ••• ,xn } and let Bi be the probability of an


Access to element xi' , ~ i ~ n. We assume w.l.o.g. that
B, ~ S2 ~ ••• ~ Sn. The frequency decreasing rule arranges S as list
n
x,x 2 •• ·xn and has expected access time P FDR i:' iSi. We use the
letter P instead of C to emphasize that we discuss expected behavior
from now on. The expected access time of the frequency decreasing rule
is easily seen to be optimal. Consider a sequence ••• xjx i •.• in which
x. is directly in front of x. and j > i. Exchanging this pair of elements
J 1
changes the expected access time by Sj - Si' a non-positive amount. This
shows that the expected access time of the FD-rule is optimal.

For the analya~s of the MF and the TR rules we use Markov chains. The
following diagram illustrates the transposition rule for a set of three
elements. The diagram has 6 = 3! states

In this diagram '23 denotes linear list x,x 2 x 3 • If x3 is accessed


(probability S3) then list x,x2x3 is changed into list x,x3x2. The
transposition rule is analysed in exercise 44.

The move-to-front rule also induces a Markov chain with n! states. The
states correspond to the n! linear arrangements of set S, i.e.
permutation n represents a linear list where xi is at position n{i).
Furthermore, there is a transition from state n to state n if there is
an i such that p{i) =" p{j) = n{j) + , for j such that n{j) < n{i)
and p{j) = n{j) otherwise~ This transition has probability Si. It is
easy to see that this Markov chain is irreducible and aperiodic and
therefore stationary probabilities Yn exist. Yn is the asymptotic
(limiting) probability that the chain is in state n, i.e. that xi is
at position n{i) for , ~ i ~ n. Then
262

is the asymptotic expected search time under the move-to-front rule.

Lemma 2: Let o(j,i) be the asymptotic probability that x. is in front


J
of x .• Then
1

a) L Si(1 + L o(j,i»
i j*i

b) o(j,i)

Proof: a) Let p. = L Y 'JT(i). Then PMFR


1 'JT 'JT
position of element xi. Furthermore,

Pi L Y'JT 'JT(i)
'JT

L Y'JT ( 1 + I {j; 'JT(j) <'JT(i)}I)


'JT

1 + L L {Y'JT; 'JT ( j ) < 'JT (il}


j"'i

1 + L o(j,i)
j*i

since L{Y'JT; 'JT(j) < 'JT(i)} is the asymptotic probability that Xj is in

front of x ..
1

b) Xj is in front of xi asymptotically if there is a k such that the


last k + 1 accesses are an access to x. followed by k accesses to
J
elements different than Xj and xi. Hence

o lj ,i) S. L (1 - (S. + S.»k


J k~o 1 J

S/(1 - (1 - (Si + Sj}})

S/(Si + Sj) o
263

a) PMFR 1 + 2

b) PMFR 5 2.PFDR - 1

Proof: a) We have

PMFR L Bi (1 + L o(j,i» by lerruna 2a


i j,H

L Bi (1 + L B/(B i + Bj » by lerruna 2b
i jH

1 + L Bi B/(B i + Bj )
j,.i

1 + 2 L B{ BJ./(B{ + BJ.)
j<i ~ ~

b) Since B./(B. + BJ.) $ 1 we infer from part a)


J ~

5 1 + 2 L Bi(i - 1) 2 PFDR - 1 Cl
i

Theorem 2 gives a closed form expression for PMFR which is readily


evaluated for particular distributions B (exercise 45) and usually
shows that the expected cost of the MF-rule is only a few percent
above the optimum. Theorem 2 also shows that P MFR is never more than
twice the optimum, a result which can also be obtained as a direct
consequence of lerruna 1. In exercise 44, the expected behavior of the
transposition rule is investigated and it is shown that it is never
worse than the expected behavior of the move-to-front rule. Thus the
TR-rule exemplifies a drastic difference between expected and amortized
behavior. The former is very good the latter is very bad.

III. 6.1.2 Splay Trees

Splay trees are a particular kind of self-organizing tree structure


which provide us with a very elegant solution to the weighted
dictionary problem.
2~

Let U be an ordered set and let w: U ~ llio be a weight function. We


use splay trees for the representation of subsets of U. More specifi-
cally, splay trees support the following operations. We use x to
denote an arbitrary element of U and T to denote trees. Splay trees use
node-oriented storage organization, i.e. items are stored in all nodes.

Access (x,T) : if item x is in tree T then return a pointer to its


location, otherwise return nil

Insert(x,T): insert x into tree T and return the resulting tree (i.e. a
pointer to its root)

Delete(x,T): delete x from tree T and return the resulting tree

Join2(T 1 ,T 2 ): return a tree representing the items in T1 followed by


the items in T 2 , destroying T1 and T 2 , (this assumes
that all elements of T1 are smaller than all elements of
T2 )

JOin3(T 1 ,x,T 3 ): return a tree representing the items in T1 followed bv


x, followed by the items in T 2 , destroying T1 and T2
(this assumes that all elements of T1 are smaller than
x which in turn is smaller than all items in ~2) .

Split(x,T) returns two trees T1 and T2i T1 contains all items of


T smaller than x and T2 contains all items of T larger
than x (this assumes that x is in tree T)i tree T is
destroyed.

Change Weight(x,T,o): changes the weight of element x by o. It is


assumed that x belongs to tree T. The operation returns
a tree representing the same set of elements as tree T.

We will implement all operations listed above by means of the following


operation Splay(x,T), which is unique to splay-trees and gives them
their name.

Splay(x,T) returns a tree representing the same set of elements as


265

T. If x is in the tree then x becomes the root. If x is


not in the tree then either the immediate predecessor x-
of x or the immediate successor x+ of x in T becomes the
root. This operation destroys T.

We will now show how to reduce all other operations to operation Splay.
In order to do Access(x,T) we do Splay(x,T) and then inspect uhe root.
Note that x is stored in tree T iff x is stored in the root of the tree
returned by Splay(x,T). To do Insert(x,T) we first do Splay(x,T), then
split the resulting tree into one containing all items less than x
and one containing all items greater than x (this is tantamount to
breaking one of the linKs leaving the root) and then build a new tree
with the root storing x and the two trees being the left and right
subtree. To do Delete(x,T) we do Splay(x,T), discard the root and
join the two subtrees T 1 ,T 2 by Join2(T 1 ,T 2 ). To do Join2(T 1 ,T 2 ) we do
splay(+00,T 1 ) where +00
is assumed to be larger than all elements of U
and then make T2 the right son of the root of the resulting tree. Note
that splay(+00,T 1 ) makes the largest element of T1 the root and hence
creates a tree with an empty right subtree. To do Join3(T 1 ,x,T 2 ) we
make T1 and T2 the subtrees of a tree with root x. To do Split(x,T)
we do Splay(x,T) and then break the two links leaving the root. Finally,
to do Change Weight(x,t,8) we do Splay(x,T).

The following diagram illustrates how all other operations are reduced
to Splay

6
inspect root
~
Access (x,T): splay(x,T).

Insert(X~T):splay(x,T)

266

Delete(x'8T~ splay(x,Tl JOin2(T 1 ,T )


• ----'---..;:; ..
2b
T'
'----->

Join2(T 1 ,T 2 ):

&
x

Split(x,T):
b 'play (x ' ;....)_ _---->

Change Weight(x,T,o) Splay(x,T)


267

It remains to describe the all important operation Splay(x,T). We first


locate the node which is made the root by the splay operation.

v - troot;
while v * nil and vt.content *x
do u v;
if x < vt.content
then v - vt.lson else v - vt.rson fi
od;
if v * nil then u - v fi

If x is stored in tree T then clearly u points to the node containing x.


If x is not stored in tree T then u points to the last non-nil node on
the search path, i.e. to a node containing either the predecessor or
the successor of x.

We will make node u the root of the tree by a sequence of rotations.


More precisely, we move u to the root by a sequence of splay steps. For
the splay step we distinguish three cases.

Case 1: Node u has a father but no grandfather. Then we perform a


rotation at v = father(u) and terminate the splay operation.

Case 2: Node u has a father v and a grandfather w. Let v the the a-son
of wand let u be the b-son of v, a,b E {left,right}.

Case 2.1. a *
b: We perform a rotation at v followed by a rotation at
w. This is tantamount to a double rotation at w.
Case 2.2. a b: We perform a rotation at w followed by a rotation at
v.

Remark: It is very important that the rotations in case 2.2. are


applied in this unconventional order. Note that this order moves node u
and its subtrees A and B closer to the root. This is also true for case
2.1. and will be very crucial for the analysis. If the rotations in case
2.2. were performed in the inverse order then the following tree results
and this claim were not true.
269

This finishes the description of the splay operation. ~he following


figure shows an example.

2
10

7 9
splay(l,T) splay(2,T) 10

2
3
2

7 6

splay(7,T) splay(6,T)

10

10

Before we can analyse splay trees we need some more notation. For x E U
we write w(x) to denote the weight of element x. For v a node of a
splay tree we write tw(v) to denote the sum of the weights of all
elements which are stored in descendants of node v. Note that the total
weight of a node changes over time. If T is a splay tree we write twiT)
instead of tw(root(T)).

Let u be a node of a splay tree T and let x E U be the element stored


in u. If splay trees are a good implementation of dynamic weighted
dictionaries then the (amortized) cost of operation Access(x,T) and
hence of operation Splay(x,T) should be O(log tw(T)/w(x)). We aim for
the more ambitious bound O(log tw(T)/tw(u)) where u is the node with
content x.
270

What account should we use in order to derive such a bound? Consider a


splay tree T. If T were weight-balanced, i.e. a ~ tw(lson(v»/tw(v)
~ 1 - a for some constant a > 0 and every node v then the cost of an access
operation in T would be logarithmic. "Non logarithmic" access time is
therefore related to unbalanced nodes, i.e. nodes v with tw(lson(v»/
tw(v) ~ 1 or tw(rson(v»/tw(v) ~ 1. Let v be an unbalanced node and
consider an access operation which goes through v and proceeds to
lson(v), say. If tw(rson(v»/tw(v) ~ 1 and hence tw(lson(v)/tw(v) ~ 0
then this search step reduces the total weight of the subproblem more
than we hoped for, i.e. instead of an intended cost of O(log tw(v)/
tw(lson(v» for reducing the weight from tw(v) to tw(lson(v» the
actual cost is only 1. We should keep the difference between the
intended cost and the actual cost in an account to pay for later cost
overruns. It is natural to conceptually keep the difference between
intended and actual cost on the edge from v to lson(v). Suppose now
that tw(lson(v»/tw(v) ~ 1. Then the search step from v to lson(v)
brings hardly any progress and therefore we should pay for the search
step out of the account, say by removing one unit from the edge from
v to rson(v). Of course, we should also try to reduce the number of
unbalanced nodes. That is exactly what the splay steps do.

The discussion above suggests that we should use an account of the


form:
L log(tw(father(v»/tw(v»
v node of T

L log tw(v) - L log tw(v) + log tw(root of T)


v node of T v leaf of T

If we set the total weights of leaves to (note that leaves do not


contain elements of u), forget about the fact that the root is counted
twice, and for simplicity work with integers instead of reals then we
arrive at

bal(T):= L Llog tw(v)J


v node of T

or with the definintion of a rank rev) Llog tw(v)J of a node v

bal(T) L r (v) •
v node of T
271

For the following lemma we assume that each splay step takes time 1.
We have:

Lemma 3: The amortized cost of operation Splay(x,T) is at most


1 + 3(r(T) - r(u)) where u is the node of T which is made the root by
the splay operation.

Proof: It suffices to prove the following claim.

Claim: Let u,v, and w be as defined in the figures illustrating the


three cases of the splay step. The amortized cost of case 1 is at most
1 + 3(r(v) - r(u)), and of cases 2.1. and 2.2 is at most 3(r(w) - r(u)).

Proof: In this proof we use r' (u), r' (v), r' (w) to denote the ranks of
the various nodes after the splay step. Note that r'(u) = r(v) in case
1 and r' (u) = r(w) in cases 2.1. and 2.2.

We will frequently use the following simple observation about ranks. If


z is a node with sons z1 and z2 and r(z1) = r(z2) then r(z) ~ r(z1) + 1.
This follows since r(z1) = r(z2) =k implies 2k ~ tw(z1) ,tw(z2) < 2k+1
k+1
and hence tw(z) ~ tw(z1) + tw(z2) ~ 2 . Thus r(z) ~ r(z1) + 1. Also,
r(father(z)) ~ r(z) for all nodes z.

We are now ready to discuss the various cases of the splay step. Note
that the actual cost is one in all three cases.

Case 1 : The amortized cost of this splay step is


1 + r' (v) + r' (u) - r(v) - r(u)
~ 1 + r' (v) - r(u) since r' (u) r(v)
~ + r(v) - r(u) since r' (v) ~ r' (u) r(v)
~ + 3 (r (v) - r (u) ) , since r(v) ~r(u)

Case 2.1: The amortized cost of this splay step is


1 + r' (u) + r' (v) + r' (w) - r (u) - r (v) - r (w)
~ 1 + r' (v) + r' (w) - r(u) - r(v) since r' (u) r(w)
Assume first that r(w) > r(u). Then we conclude further, using
r' (v) ~ r' (u) = r(w), r' (w) ~ r' (u) r(w), r(v) ;:: r(u) and 1 ~r(w)-r(u),

that the amortized cost is bounded by


~ trw) - r(u) + r(w) + r(w) - r(u) - r(u)
3(r(w) - r(u))
272

This finishes the proof if r(w) > r(u) •

Assume next that r(w) = r(u). Then r(w) = rev) = r(u) r ' (u).

Also r' (w) :5 r' (u) = r(u) and r' (v) :5 r' (u) = r(u).
If r' (w) = r' (v) then r' (u) <:: r' (w) + 1 and hence r' (w) + r' (v)
:5 2r(u) - 1. This shows that the amortized cost is bounded above by
zero (= 3(r(w) - r(u») in this case.

Case 2.2: The amortized cost of this splay step is


+ r' (u) + r' (v) + r' (w) - r(u) - r(v) - r(w)
:5 1 + r' (v) + r' (w) r(u) rev) , since r' (u) r(w)

Assume first that r(w) > r(u). Then we conclude further, using
1 <:: r(w) - r(u), r(u) :5 rev) :5 r(w) and r' (w) :5 r' (v) :5 r' (u) = r(w),
that the amortized cost is bounded by
:5 r(w) - r(u) + r(w) + r(w) -r(u) - r(u)
3(r(w) - r(u»

Assume next that r(w) = r(u). Then r(w) = rev) = r(u) = r' (u) and
r' (u) :2: r' (v) :2: r' (w). If r' (u) > r' (w) then the amortized cost is
bounded by zero (= 3(r(w) - r(u» and we are done. 50 assume r' (u)
r' (w). Consider the middle tree in the figure illustrating case 2.2.
We use F(u) ,F(v) ,F(w) to denote the ranks in this tree. We have
F(u) r(u), F(w) = r' (w) and F(v) r(w). If r' (w) = r' (u) then
F(w) = r'(u) = r(w) = r(u)
r'(w) F(u) and hence F(v) > F(w) and
therefore r' (u) > r' (w), a contradiction. Hence r' (u) > r' (w) always.
This finishes the proof in case 2.2. o

The proof of lemma 3 is completed by summing the costs of the individual


splay steps. Note that the sum telescopes.
The amortized cost of the other operations is now readily computed.
We summarize in

Theorem 3:
The amortized cost of 5play(x,T) is O(log tw(T)/tw(x».

The amortized cost of Access (x,T) is O(log tw(T)/tw(x».

tw (T)
The amortized cost of Delete(x,T) is O(log
min(tw(x),tw(x-»
where x is the predecessor of x in tree T
273

tW(T1) + tW(T 2 )
The amortized cost of Join2(T 1 ,T 2 ) is O(log where
tw(x)
x is the largest element in tree T 1 .

tw ( T 1) + tw ( T 2 )
The amortized cost of Join3(T 1 ,x,T 2 ) is O(log w(x)

tw' (T) )
The amortized cost of Insert(x,T) is O(log
min(tw(x- ) ,tw(x+ ),w(x» '

where x is the predecessor, x+ is the successor of x in the final tree


and tw' (T) is the weight of T after the operation.

The amortized cost of Split(x,T) is O(log tw(T)/tw(x».

The amortized cost of Change Weight(x,T,o) is O(log(tw(T)+o)/tw(x».

The actual cost of a sequence OP1""'OPm of operations starting with


weight function w: U - lli and a forest of single node trees is bounded
by the sum of the amortized costs of the operations and the initial bal-
ance L Llog w (x) J •
xEU
Proof: The bounds on the amortized cost of the various operations
follows from the bound on the amortized cost of the Splay operation and
the realization of the various operations by the Splay operation.
We discuss the various operations briefly.
The bound for the Splay operation was shown in lemma 3. Operation Access
is identical to Splay and the cost of Split(x,T) is the cost of
Splay(x,T) plus 1. The bound on the amortized cost of Join2(T 1 ,T 2 ) is
O(log tW(T 1 )/tw(x) + 1 + (log (tw(T 1 ) + tw(T» - log tW(T 1 »)
= O(log (tw(T 1 ) + tw(T»/tw(x» where x is the largest element in tree
T 1 . In this bound, the first term accounts for the cost of Splay(+oo,T 1 )
and the second and third term account for the actual cost of making T2
a son of x and the change in the rank of x caused by making T2 a son of
x. The cost of Join3(T 1 ,x,T 2 ) is 0(1 + (log (tW(T 1 ) + w(x) + tw(T 2 »-
log w(x») where the last term accounts for the rank change of x.
The amortized cost of Delete(x,T) is O(log tw(T)/tw(x) + log tw(T)/
tw(x-» where the first term accounts for the cost of Splay(x,T) and
the second term accounts for the Join2 operation. The cost of Insert(x,T)
is O(log tw(T)/min(tw(x ), tw(x+» + 1 + (log (tw(T) + w(x» -
- +
log w(x)) = O(log (tw(T) + w(x) )/min(tw(x ) ,tw(x ) ,w(x») where the
first term accounts for the splay operation and the last term accounts
274

for the rank change of x. Finally, the cost of Change Weight(x,T,8)


is O(log(tw(T)/tw(x» + (log (tw(T) + 8) - log tw(T») =
O(log (tw(T) + 8)/tw(x» where the first term accounts for the Splay
operation and the second term accounts for the ran]~ change of x.
The bound on the cost of a sequence of operations follows from the
observation that the balance of a forest of single node trees is
L Llog w(x)J and that the account is positive.
xEU

Theorem 3 is very remarkable. Note that splay trees have no knowledge


of weights and nevertheless achieve logarithmic behavior. Moreover, the
bounds of theorem 3 are true for all weight functions.

We close this section with a comparison of splay trees and static trees.

Theorem 4: Consider a sequence of Access operations on a set of n


elements. Let t be the number of comparisons needed to process this
sequence in some static binary search tree. Then the cost of processing
this sequence using splay trees is OCt + n 2 ). This is true for any
initial tree.

Proof: Let U be the set of elements stored in the static tree. Let d be
the depth of the static tree and let d(x) be the depth of element x E U
in the static tree. We use the weight function w(x) = 3 d - d (x).

Consider any splay tree T for set U. The balance bal(T) is at most
L rex) L d+1 = O(n 2 ). Also the total weight of T is at most
xEU xEU
d
L w(x) = L L 2i 3 d - i ~ 3 d + 1 and therefore the amortized
xEU xEU i=o
cost of operation Access(x,T) is O(log tw(T)/tw(x» O(d(x) +1).
Since d(x) + 1 comparisons are needed to search for x in the static tree
this implies that the amortized cost of the sequence of operations is
OCt). Also the balance of the initial tree is O(n 2 ). This proves the
bound. o

We infer from theorem 4 that the cost of a long sequence of Access


operations in a splay tree is of the same order as the cost in the
optimum tree for the sequence. Note, however, that the splay tree
requires some time to "learn" the distribution. This is expressed in
2
the O(n ) term.
275

III. 6.2 D-trees

In this section we describe a second approach to dynamic weighted


trees: weighted BB[a]-trees or D-trees. Weighted BB[a]-trees are less
elegant than splay trees and in many respects less flexible. In par-
ticular, we will not discuss operations Split and concatenate at all,
and restrict Promote and Demote to weight changes by one, i.e. 0 1,
and restrict Deletion to elements of weight one. We leave the more
general operations to the exercises. However, weighted BB[a]-trees also
have one advantage over splay trees, namely their controlled update
cost. This fact will be crucial for the applications of weighted dy-
namic trees in chapter VIII.

We discussed the amortized rebalancing cost of weight balanced trees


and height balanced trees in sections 5.1. and 5.3.2. respectively. In
both cases amortized rebalancing cost was constant and rebalancing cost
at height h decreased exponentially in h. However, the basis of the
exponential function was different. In BB[a] trees, a node of weight w
(i.e. w leaf descendants) causes a rebalancing operation only every
Q(w) transactions which go through the node. No such statement is true
for (a,b)-trees. In the applications of chapter VIII, we will augment
search trees by additional information. Maintaining the additional in-
formation when rotating at a node of weight w will have cost o(w) or
even O(w log w). With the strong bound on the updating cost of BB[a]-
trees we will still be able to control the amortized update cost of
the augmented trees: with splay trees we cannot control it.

D-trees are an extension of BB[a]-trees. We imagine an object xi of


weight wi to consist of wi leaves of weight 1. A D-tree for set S is
then a BB[a]-tree T with W = w 1 + ••• + wn leaves. The leftmost w1
leaves are labelled by x 1 ' the next w2 leaves are labelled by x 2 ' ••••

Definition: a) A leaf labelled by Xj is a j-leaf.

b) A node v of T is a j-node iff all leaves in the subtree with root v


are j-leaves and v's father does not have this property.
276

c) A node v of T is the j-joint iff all j-Ieaves are descendants of v


and neither of v's sons has this property.

d) Consider the j-joint v. w'. j-Ieaves are to the left of v and w". j-
J J
leaves are to the right of v. If W'j ~ w'j then the j-node of minimal
depth to the left of v is active, otherwise the j-node of minimal
depth to the right of v is active.

e) The thickness th{v) of a node v is the number of leaves in the sub-


tree with root v.

only parts of the underlying BB[a]-tree actually need to be stored, in


particular all proper descendants of j-nodes can be pruned. Only their
number is essential and is stored in the j-node. More precisely, a D-
tree is obtained from the BB[a]-tree by

1) pruning all proper descendants of j-nodes


2) storing in each node.
a) a query of the form "if X :s; Xj then go left else go right"
b) the type of the node: jOint node, j-node or neither of above
c) its thickness
d) in the case of the j-joint the number of j-Ieaves in its left and
right subtree.

The queries are assigned in such a way as to direct a search for Xi


to the active i-node. More precisely, let v be any interior node of
the D-tree and let the active 1-node, ..• ,j-node be to the left of v.
Then the query "if X :s; x. then go left else go right" is stored in v.
- J--

The next figure shows a D-tree for the distribution (w 1 ,w 2 ,w 3 ,w 4 ) =


(2,7,3,4) based on a tree in BB[1/4]. The j-nodes are indicated by
squares, active j-nodes by double lines, the thickness of j-nodes is
written below them and the distribution of j-Ieaves with respect to
the j-joints is written below the joint nodes.
277

The following Lemma shows that D-trees are good search trees.

Lemma 4: Let b. be the depth of the active j-node in tree T. Then


------- J
bj ~ c 1 log W/Wj + c 2 where c 1 = 1/log(1/1-a)), c 2 = 1 + c 1 •

~f: Let v be the father of the active j-node. Then all j-leaves
which are on the same side of the j-joint as the active j-node are
descendants of v. Hence th(v) ~ Wj/2. The argument of theorem 2 of
section 5.1. finishes the proof. c

Next we have to address the question of how to maintain D-trees. The


answer is exactly as for BB[a]-trees, but be careful with the addi-
tional D-tree information. Suppose we execute an instruction. The
search will end in the active j-node. We have to update the thickness
of all nodes cn the path of search and the distribution of j-leaves
with respect to the j-joint. The j-joint lies on the path of search
and so this is easily done. Next we have to ascend the path of search
from the active j-node to the root and perform rotations and double-
rotations as required. Since a doucle-rotation is two rotations we on-
ly have to treat the case of a rotation. Let us call joint nodes and
j-nodes special nodes. If no special node is involved in the rotaticn
278

double rotation to [
the left about A )

~otation
~ ~eft
to the
about A

rotation to B~
right about ~"C~

then nc additional actions are required. Suppose now, a special node


is involved in the rotation.

Case 1: A j-node is involved. Then we have the following picture

and node B is a j-node before the rotation, i.e. trees T2 and T3 do


not exist explicitly. We create them by splitting B into two j-nodes
of thickness Lth(B)/2J and r th (B)/2' respectively. What query should
we assign to B (Note that B is in an interior node now)? Suppose first
that neither A nor B is the j-joint. Then A must be a left descendant
of the j-joint. Otherwise T1 can only contain j-leaves and hence A
279

would be a j-node and hence B would not exist. So A must be a left


descendant of the j-joint and hence the active j-node lies to the right
of A. But then it also lies to the right of B (T3 could be it) and
thus we only have to copy the query from A into B. The discussion
above also solves the case where B is the j-joint. Suppose next that A
is the j-joint. Then the active j-node will be to the left of B after
the split. Let Z be the nearest ancestor of A such that the left link
was taken out of Z during the search. Copy Z's query into B. Z can be
found as follows: When the nodes on the path of search are stacked
during the search, they are also entered into either one of two linear
lists: the L-list or the R-list. The L-list contains all nodes which
are left via their left links and the R-list contains all nodes which
are left via their right links. Then Z is the first node on the L-list.
This ends the discussion of B being a j-node.

Example: Rotation to the left about the 4-joint.

splitting

rotation

4-joint 4-joint

1 1

The second possibility is that T2 and T3 are A is


j-node after the rotation. In this case x 1 and x 2 are deleted after
the rotation.

Example: Rotation to the left about the father of the active 2-node
280

rotation combining

Case 2: A joint node is involved, i.e. either A or B is a joint node


or both. If B is a joint node then no additional actions are required.
So let us consider the case that A is the j-joint. Let w! ,w'~ be the
) )
distribution of j-leaves with respect to the j-joint A and let s be
the thickness of the root of T 2 • If s ~ wj then T3 contains no j-leaves
and hence A will be the j-joint after the rotation. No action is re-
quired in this case.

If s < w'!) then B will be the j-joint after the rotation. The distribu-
tion of j-leaves with respect to B is w! + s, w'! - s.
) )

Case 2.1.: wJ! + s ~ w'! - s. Then w'. ~ w'! and the active j-node was to
) ) )
the right of A, in fact it was node T 2 • Also the active j-node will be
to the right of B after the rotation and it still is to the right of A.
Hence we only have to copy A's query into B.

Case 2.2.: w'. + s > w'~ - s. Then the active j-node will be to the left
) )
of B after the rotation, and hence it will be node T 2 •

Case 2.2.1.: w! ~ w'~. Then T2 also was the active j-node before the
) )
rotation. No additional action is required in this case.
281

Case 2.2.2. : w~ > w'~. Then the active j-node was


J
to the left of A and
J
hence to the left of B before the rotati on. In
this case B's query
remain s unchan ged, but A's query has to be change
d. Suppos e first that
A's left son is a j-node . Then A ceases to exist
after the rotati on
and we are done. Suppos e next that A's left son
is not a j-node . The
next figure shows a micros copic view of tree T
1•

active j-node

We only have to copy Z's query into A. Z can be


found by a brute force
search . Note that th(Z) ~ w'. ~ w./2. Note also
that the thickn ess s of
J
T3 is less than wj ~ Wj/2. Since J s = th(T ) ~ a·th(B
3 ) (the underl ying
tree is in BB[a]) and th(B) ~ (1-a)th (A) (a rotati
on to the left about
A is perform ed) we have s ~ a(1-a) th(A) and hence
th(A) ~ w./(2 a(1-a) ).
o

The argum ent used in the proof of theore m 2 of J


sectio n 5.1. shows that
the depth of Z with respec t to A is at most log(IX
(1-a)) /log(1 -a).

We summa rize the discus sion in

Theore m 5: Consid er a D-tree based on a BB[a] -tree


with
1/4 ~ a ~ 1 - 12/2. Let wi be the weigh t of xi'
1 ~ i ~ n, and let
W = ~ wi. Then a search for xi takes time c log
1 W/w i + c 2 and a weigh t
change of xi by ± 1 takes also time c log w/w
1 i + c 2 for some small
consta nts c 1 and c 2 .

Examp le: We promo te x 2 by one in our examp le. This increa


ses the
thickn ess of the active 2-node from 2 to 3 and
moves the balanc e para-
meter of the root (the 2-join t) out of the range
[1/4,3 /4]. A double -
rotati on (to the left) about the root is requir
ed. It is simula ted by a
rotati on to the right about the 3~joint follow ed
by a rotati on to the
left about the 2-join t. The rotati on about the
3-join t requir es no
specia l action since s = th(fat her of active 3-node
) 5 :> 2 =
numbe r of 3-leav es to the left of 3-join t. We obtain
282

2-joint

same as
before

Next we have to rotate about the 2-joint. ~"'e have w 2= 2, w 2 6 and


s = 3 and hence case 2.2.1. of the discussion above applies. We obtain

2-joint

same as same as
before before
3
2~

We close this section with a brief discussion of the space requirement


and the update behavior of D-trees. The space requirement is clearly
O(W) since there are at most W leaves. Since an element xi can be re-
presented by as many as log wi i-nodes the space requirement may be
non-linear in n. There is a version of D-trees, namely compact D-trees,
which overcomes this problem. Also, in the applications in chapter VIII,
quantity Wand not n will be the relevant parameter.

The basic idea for compact D-trees is to only store special nodes
(= active nodes and joints) and nodes having special nodes in both
subtrees. Clearly there are only O(n) such nodes. All other nodes are
deleted and only some information about their size is kept. The diagram
below shows a D-tree for distribution (3,20,4,10) and also its compacted
version. In the compacted tree
284

the size of deleted subtrees is recalled in the expressions in square


brackets. For example, the expression [1,5] on the edge from the 4-joint
to the active 3-node represents subtrees emanating to the right from
this edge and having a total of one 3-leaf and five 4-leaves. It can be
shown that compacted D-trees can still be rebalanced efficiently. We
refer the reader to the literature for details.

Let us turn to amortized update cost next. Rotations and double rota-
tions in D-trees are only caused by the underlying BB[a]-tree. Hence
the results of section 5.1. carryover without any change. In particular,
theorem 5 of section 5.1. carries over.

Theorem 6: Let 1/4 :s; a < 1 - 12/2 and let f: lR -+ lR be a non-


decreasing function. Suppose that the cost of performing a rotation or
double rotation at node v of a D-tree based on a BB[a]-tree is f(th(v».
Then the total cost of the rebalancing operations for a sequence of
m insertions, deletions, promotions, and demotions into an initially
clogm . 1 .
empty D-tree is O(m ~ f«1-a)-1-) (1-a)1) where c = 1/1og (1/1-a».
i=1

We will use theorem 6 frequently in chapter VIII on algorithmic


geometry.

III. 6.3 An Application to Multidimensional Searching

Dynamic weighted trees have numerous applications. The most obvious one
is the organization of sets under changing or unknown access
probabilities. In this section we describe an application to TRIES and
exact match queries in multi-dimensional spaces. Let U be an ordered
set, d be an integer (=dimension), and let S =
u d • We want to maintain
set S under searches, insertions and deletions taking comparisons
between elements of U as our basic operation. One solution immediately
comes to mind: Order ud by lexicographic order, i.e. (x 1 ' ••• ,xd )
:s; (Y1""'Yd) if there is an i such that Xj = Yj for j < i and Xi < Yi'
and use ordinary balanced trees. This will allow us to perform all
three operations in time O(dolog lSI) since a comparison between two
elements of S takes time O(d). We will show next that this can be
improved to time O(d + log lSI).
285

Theorem 7: Let S =ud , lSI = n. Then operations Access, Insert and


Delete can be supported in (amortized) time Oed + log n) where a com-
parison between elements of U is supposed to take one unit of time.

Proof: Let W be the set of all prefixes of elements of S, i.e.


W= {(x 1 , ••• ,Xk )i O~k ~ d and (x 1 ,x 2 ' ••• ,xd ) E S}. For w E w, Iwl k,
let Pw : = I {(x 1 ' .•. , xn) E Si (x 1 ' ••. ,x k ) = w}l. Then PIC: = lSI,
~ Pwa = Pw for all w, Iwl < d, and Pw = 1 for Iwl = d. We represent S
aEU
by a tree of dynamic weighted trees. More precisely, for every w E W,
Iw I < d, we have a tree Tw for set {wa i a E U and wa E U} according
to weights Pwa' Furthermore, leaf wa of tree Tw pOints to the root
of tree Twa and the root of tree Tr is the entry point of the data
G

structure. An Access for x = (x 1 ' •.. ,x d ) is performed as follows. We


start in tree TIC: and search for x 1 in that tree. After locating ~ in
Tr we locate x 2 in T , then ~ in T , ... until the search is com-
G x1 x 1x2
pleted by locating x d in Tx x ••• x _ The total cost of operation
1 2 d 1
Access is

d
~
i=1

d
~ 0(1 + log(p /p » by theorem 3 or 5
i=1 x 1 ···x i _ 1 x 1 ···x i

d
O( ~
i=1

= Oed + log PIC: - log px) = Oed + log n - log 1) = Oed + log n)

An Insert of (x 1 ' ..• ,x d ) in set S is also easily performed. We first do


an Access and determine the maximal i such that x. occurs in Tx
1 l' .. x i - 1
Then we create trivial trees T , .•. ,T , insert x i + 1
x 1 •· .x i + 1 x 1 •• .xd - 1
into Tx .•. x and increase the weight of x.J in Tx .•• x _ by 1 for j ~ i.
1 i 1 j 1
Thus the cost of an insert is

i
~ 0(1 + log«p + 1)/p » + O(log p ) + Oed-i)
j=1 x 1 •· .x j _ 1 x 1 ·· .x j x 1 ·· .x i
286

i
o (d + !: (log ( 2p ) - log P ) + log P )
j=1 x 1 •• ,x j _ 1 x 1 ••• x j x 1 ••• x i

oed + log n)

A Deletion of (x 1 ' .•. ,xd ) from set S corresponds to a sequence of


Demote operations. It is easily seen that time bound Oed + log n) also
applies to deletions. o

Theorem 7 is readily extended to weighted multidimensional sets and to


operations Concatenate and Split (Exercises 39 and 40). The data struc-
ture used in the proof of theorem 7 is a symbiosis of trees and TRIES.
The qlobal data structure is a TRIE. i.e. the "characters" of x E u d
are determined one after the other. The local data structures are
weighted, dynamic trees, i.e. each node of the TRIE is realized by
either a splay tree or aD-tree.

III. 7. A Comparison of Search Structures

In this section we try to summarize the highlights of this chapter and


to compare the various data structures presented in the preceding six
sections. The following table summarizes the results.

junweighted Weightec Access Insert Concatenate Secondary Finger ~equential


Inata Data Delete Split Storage searches Access
TRIES x O(logkN) x x x

Hashing x O(S) x x
expected
Perfect x 0(1) x
Hashing
Interpola- x O(loglogn x
tion Search expected
static
weighted x O(logl/p) (x) x
search tree
BB[a]-trees x o (logn) x x x

(a, b)-trees x O(logn) x x x X x

splay trees x O(logl/p) x x x


amortized
D-trees x O(logl/p) x x
287

In the table N denotes the size of the universe, n denotes the size of
the set stored in the data structure, p is the probability of the
element to be accessed, k is the branching factor of the TRIE and S is
the loading factor of the hash table.

There are three data structures which support only operation Access:
Perfect hashing, interpolation search and static weighted search trees.
Perfect hashing guarantees an access time of 0(1) and uses about 3n
words of storage for the hash table and essentially n additional words
for the hash program. It can be used for secondary storage and then
requires two accesses to secondary storage, namely one to pick up the
relevant part of the hash program and one to access the actual data.
Perfect hashing (as all hashing methods) does not support sequential
access to the data in its natural order. Note however, that sequential
access in "hashed order" is possible. The other two methods support
sequential access. Interpolation search provides us with O(loglogn)
expected access time and requires no additional storage. Static weighted
trees support weighted data and allow us to access an item with access
probability p in time O(log 1/p). We have seen that expected access time
to a collection of items is 0(1) for a variety of frequency distribu-
tions. Multi-way weighted trees which were not discussed in the text,
can also be used in secondary storage. TRIES, hashing and balanced trees
(weight-balanced or height-balanced) can be used to handle dynamic
unweighted data. Hashing (with chaining) has an O(S) expected access
time, although worst case access time is 0(n) and expected worst case
access time is 0(log n), and supports Access, Insert and Delete.
The expected behavior of hashing with chaining can be turned into
probabilistic behavior by the use of universal hashing. For secondary
storage extendible hashing is particularly appropriate. It requires only
two accesses to secondary storage. Extendible hashing is closely related
to TRIE searching on the hashed keys. TRIES for the unhashed keys
support also sequential access. The branching factor k can be used to
trade between access time and storage requirement.

Balanced trees have logarithmic worst case behavior and also support
additional operations such as split, concatenate and finger searches.
Among the balanced trees, (a,b)-trees are the most flexible and elegant
version. The realization by colored trees is particularly useful.
(a,b)-trees with b ~ 2a exhibit s~all amortized rebalancing cost which
288

we exploit at several occasions, in particular A-sort and finger trees.


Weight-balanced trees are less elegant than (a, b)-trees, require
somewhat more space (an integer has to be stored in each node instead
of a bit as for colored trees), and are usually slower by a constant
factor. However, they also have their merits. Operation Concatenate is
faster (time O(log (n 1 + n 2 )/min(n 1 ,n 2 » for joining trees of size n 1
and n 2 respectively, instead of time 0(min(lh 1 - h 2 1, h 1 ,h 2 » =
O(log max(n 1 ,n 2 » as for ,(a,b)-trees) and more importantly the
amortized number of rotations and double rotations shows a very
controlled behavior. This makes BB[a]-trees the ideal basis for aug-
mented trees in which rotations (and double rotations) have non-
constant cost. For secondary storage, (a,b)-trees with a large value of
a are the preferred choice.

Balanced trees can be extended to weighted data. Splay trees provide us


with a very elegant solution to the weighted dictionary problem and
also show the potential of self-organizing data structures and amortized
analysis. D-trees are less elegant but inherit the strong bounds on
update cost from BB[a]-trees.
289

III. 8. Subsets of a Small Universe

So far we dealt with subsets S of a very large, basically infinite uni-


verse U. In this section we treat the other extreme; set S =
U is about
the same size as universe U. Whilst in the former case operation Access
is a non-trivial operation and in fact a large part of the preceding
sections was devoted to it, operation Access is trivial in the latter case.
Direct access by means of arrays is now a possibility. Small universes
come up quite frequently. One example is the set of accounts of a bank
(accessed via account number), another example are graph algorithms
(cf. chapters IV and V).

Throughout this section we assume w.l.o.g. that U {O, 1 , ••• , N-1} .

III. 8.1 The Boolean Array (Bitvector)

Apparently, a set S = U can be represented by a boolean array


BV[O •• N-1]. We have BV[i] = true if i E Sand BV[i] = false if i ( S.
Then operations Access, Insert and Delete take constant time, the best
we can hope for.

There is one small drawback of boolean arrays. Initialization takes


time O(N). If n(N) operations are performed on set S, as it is very often
the case in applications, then initialization can be amortized over the
sequence of operations.

It is interesting to know that initialization can be avoided altogether


by using more space. In addition to array BV we use an array A[O .. N-1]
and a pushdown store. The stack is realized by array K[O •• N-1] and
variable TOP as described in 1.4 •• Initially TOP = -1. We maintain the
following invariant (we assume that BV[i] = 0 for all i is the intended
initialization) :

BV[i] = 1 iff BV[i] = 1 and 0 ~ A[i] ~ TOP and K[A[i]] i

Initially, TOP = -1 and hence BV[i) = 0 for all i as intended. Apparent-


ly, the value of BV[i] can still be determined in constant time by
using the invariant. Suppose now, that we want to write boolean b into
BV[i). If 0 ~ A[i] ~ TOP and K[A[i)) = i then we write b into BV[i] and
290

are done. Otherwise we execute

TOP TOP + 1 ;
A[i] TOP;
K[TOP] it
BV[i] b;

It is easy to see that this piece of code maintains the invariant. Thus
initialization and operations Access, Insert and Delete take time 0(1)
each.

III. 8.2 The O(loq log N) Priority Queue

We saw already several methods for maintaining priority queues with


running time O(log n) for operations Insert, Min and Deletemin: Heap&
(11.1.2.), balanced trees (111.5.) and unordered (a,b)-trees (111.5.3.1.).
Here n denotes the number of elements in the queue. In this section we
describe an implementation of priority queues with time O(log log N)
per operation where N denotes the size of the universe U = {0, •.. ,N-1}.
Thus the data structure described here is faster provided that N is not
too large with respect to n, i.e. N S 2n.

We use the following notation. For integer k ~ 2 we use k' to denote


rk/2' and k" to denote Lk/2J' For x E [0 .. 2k_1] we let x' = x div 2k"
and x" = x mod 2k" • Then x = x'2 k" + x".

k
Definition: A k-structure T for set S c: [0 •• 2 -1]
consists of
1) integer T.SIZE = I {x 1 , •.• ,xm} I.

2) A doubly linked list T.LIST containing x 1 , •.• ,xm in increasing order.

3) A bitvector T.B[O •• 2k _1] with T.B[X i ] = true for all i and an


array T.P[O •• 2k -1] of pointers. Pointer T.P[X i ] points to element xi
on list T.LIST.

k'
4) A k'-structure T.TOP and an array T.BOTTOM[0 ••• 2 -1] of k"-
structures. If m S 1 then structures T.TOP and T.BOTTOM[i],
o SiS 2k' -1, are all empty, i.e. their size fields are 0, the list is
291

empty and the bitvector is all zero. If m > 1 then T.TOP is a k'-struc-
ture for set {x1""'x~} and for each x E [0 .• 2k '_1] ~.BOTTOM[x] is a
kg-structure for set {xi; 1 S i S m and x = xi} . 0

An example is badly heeded at this point. Let k = 4 and let S


{2,3,7,10,13} be the set stored in 4-structure T. Then T.SIZE 5 and

T.B

T.P

T.LIST

T.TOP is a 2-structure for {0,1,2,3}, T-BOTTOM[O] is a 2-structure for


{2,3}, T.BOTTOM[1] is a 2-structure for {3}, T.BOTTOM[2] is a 2-struc-
ture for {2} and T.BOTTOM[3] is a 2-structure for {1}. o

The intuition behind this definintion is as follows. In a priority


queue we want to support (at least) operations Insert, Min, and
Deletemin. Operations Insert and Deletemin (once the minimum is known)
are perfectly supported by a bitvector (called T.B) of length N 2k
and operation Min is supported by an ordered linear list (called
T.LIST). Of course, if we try to combine both data structures by provid-
ing pointers (called T.P) from the array into the linear list we have
a problem with operation Insert. If we want to insert x into the linear
list we need a fast method for locating its successor succ(x) in the
list; the predecessor would also do. The most obvious way of finding
successors is to put a complete binary tree on top of the bitvector
and to use tree search for finding successors. That is the method which
we used in the realization of priority queues by balanced trees. How-
ever, there is a major difference which we can use to our advantage:
We are dealing with a fixed complete binary tree. Suppose that we
provide from each leaf, say x, of the tree a pointer to its ancestor,
292

say x', at depth r(log N)/2', i.e. to its ancestor half-way up the tree.
In our implementation the nodes at depth r(log N/2' are represented by
array T.BOTTOM, structure T.TOP represents the top half of the tree and
r(log N)/2'
structures T.BOTTOM[i], 0 ~ i ~ 2 - 1 represent the bottom
half of the tree. The pointers from leaves x to ancestors x' are not
provided explicitely; we simulate them by a simple division by 2k "
Suppose next that we could decide in time 0(1) whether x and succ(x)
have the same ancestor at depth r(log N/2'. In our implementation we
can do so by comparing x" with the last element on list T.BOTTOM[x'].
LIST. If x and succ(x) have the same ancestor then we can restrict our
search to the O(IN) descendants of node x', i.e. we only need to find
the successor of x" in T.BOTTOM[x']. If x and succ(x) do not have the
same ancestor then BUCC(X) is the first element of the list
T.BOTTOM[z' ].LIST where z' is the successor of x' in the top half
T.TOP of the tree. Thus in either case we can reduce the size of the
problem from N to O(IN) in time 0(1) and hence a time bound of
O(loglog N) should result. The details are given below.

Let T be a k-structure for set S =


[0 •• 2k -1]. Then operations Min S
and Member(x,S) take constant time; the minimal element of S is the
first element on list T.LIST and xES iff T.B[x] = true. For opera-
tions Insert and Delete we have to work harder. The algori thros for In-
sert and Delete use operation Succ(x,S) = min{y E S; x < y} as a sub-
routine.

(1) function SUCC(x: [0 •• 2k -1], T: k-structure);


(2) if k = 1 or T.SIZE ~ 2
(3) then search through T.LIST (which is at most 2 elements long)
(4) else if T.SIZE = 0 2E x ~ max T.LIST
(5) then SUCC "does not exist"
- - . 2L k/2 J; x" .. x mod 2L k/2 J;
else x' .. x d~v
(6)
(7) if T.TOP.B[x'] = 1 and x" ~ MAX(T.BOTTOH[x'])
(8) then SUCC" x' 2Lk/2J + SUCC(x", T.BOTTOM[x'])
(9) else z' .. SUCC(x', T.TOP);
( 10) succ .. z' 2Lk/2J + MIN(T.BOTTOM[z'])
( 11) fi
(12) fi
(13) fi
293

Leroma 1: The program above correctly computes SUCC in time O(rlog k').

Proof: Note first that the successor of x in T does not exist iff
either T is empty or x is at least as large as all elements of T. So
suppose that T is non-empty and x has a successor and let x', x" be the
two parts of x. We have to distinguish two cases; either there is a
point in T with first part equal to x' or there is not. If there is a
point y in T with y' = x' then we find the successor of x" among the
points with first part equal to x'. If the successor exists then we are
done (line 8). If it does not exist or if there is no point in T with
first part equal to x' then we have to find the successor of x' in the
top structure (line 9) and coMbine it with the first element in the
appropriate bottom structure (line 10). This shows correctness.

Next we analyze the running time of function SUCC. Let R(k) be the
maximal running time of SUCC on any k-structure. Then R(1) = c for some
constant c. Next note that the running time of SUCC(x,T) is 0(1) if x
does not have a successor in T. This is true for any k. Thus the time
spent in line (7) is 0 (1) and we obtain the recurrence R(k) ~ c + R( rk/2')
for R where c is some constant. Note that we generate one re-
cursive calIon either a Lk/2J or a rk / 2'-structure and that only a
constant amount of time is spent outside the recursive calls. It is now
easy to verify by induction on k that R(k) ~ c(1+ r log k'). This is ob-
vious for k = 1. For k > 1 we have

, recurrence for R

~ c + c(1 + rlog rk/2"), induction hypothesis

For the last step, let ~ be such that 2~ < k ~ 2~+1. Then rlog k'
~ + 1 and 2~-1 < k/2 ~ 2~ and hence rlog rk /2" = ~. 0

The algorithms for Insert and Delete are now easily derived.

k
(1) procedure INSERT(x: [0 •• 2 -1], T: k-structure);
(2) if T.B[x] = false
294

(3) then T.B[x] true;


(4) insert x into T.LIST at the appropriate position (use
SUCC(x,T) to compute the successor y of x in T. Then insert x
next to y in T.LIST. The position of y in T.LIST can be
found via T.P[y]);
(5) x' - x div 2Lk/2J; x" - x mod 2 Lk / 2 J ;
(6) ~ T.SIZE of
(7) 0: do nothing;
(8) 1: let y be the other element of T.LIST and
let y' , y" be the parts of y;
(9) INSERT (x' , T.TOP);
(10) INSERT(y' , T.TOP);
( 11) INSERT(x", T.BOTTOM[x']) ;
( 12) INSERT(y", T • BOTTOM [ y' ]) ;
(13) 2: INSERT(x' , T.TOP) ;
(14 ) INSERT (x", T.BOTTOM[x' ])
(15 ) ~;
(16 ) T.SIZE - T.SIZE + 1
(17) f i
(18) end

Lemma 2: The program above inserts an element into a k-structure in


time 0 ( rlog k') •

Proof: The correctness is fairly obvious. There is one subtle pOint. If


we insert a point x into an empty structure then the parts x' and x" do
not have to be inserted into the top and bottom substructures (line 7).
However, if we insert a second point into a structure then the parts of
the new point x and the old point y have to be inserted (lines 8 - 12).

It remains to determine a bound on the running time of procedure INSERT.


Let R(k) be the maximal running time of INSERT on any k-structure. Then
R(1) = c for some constant c. Next note that INSERT(x,T) takes constant
time if x is already an element of T or if T is empty. This is true for
all k. So suppose that x is not an element of T. Let us concentrate on
the case statement (lines 6 - 15) first. We treat the case that T con-
tains only one element first. Note that the calls in line (9) and (11),
i.e. the calls inserting x' and x", insert pOints into empty structures
and therefore take time 0(1) each. Next note that line (10) takes con-
stant time if x' = y' and that line (12) takes constant time if x' * y'.
In the former case y' is already in T.TOP and in the latter case y" is
295

inserted into an empty structure. Thus only one "real" recursive call
is initiated. The same statement is true if T has more than one element
(lines 13 and 14). Either x' is already an element of T.TOP and then
line 13 is trivial or x' is not yet an element of T.TOP and then line
14 is trivial. In either case the cost arising in lines 6 - 15 is
bounded by c + R{rk/2') for some c. Line 4 takes time O{rlog k'). Thus
the following recurrence arises for R: R{k) ~ c{1+ r log k') + R{rk/2')
which solves for R{k) = O{{log k)2). This is not quite what we wanted.

A simple observation improves the bound to O(log k). We call SUCC in


line 4 to find the successor of x. Note that the sequence of recursive
calls in SUCC corresponds to the sequence of "non-trivial" recursive
calls in INSERT. Thus one call of SUCC computes all successors which we
are ever going to need in all calls of INSERT. Thus the total time spent
in line 4 summed over all calls of INSERT is O(log k) or 0(1) per
"non-trivial" call. Thus R(k) ~ 1 + R( rk/2') and hence R(k) = O(log k) •
c

procedure DELETE(x: [0 •. 2k -1], T: k-structure)1


i f T.B[x] = 1
then T.B[x] 0;
delete x from T.LIST;
T.SIZE T.SIZE - 11
~ T.SIZE.2!

0: do nothing;
1: DELETE(x', T.TOP)1
DELETE (x", T.BOTTOM[x'll;
~2: DELETE (x" , T.BOTTOM[x'll;

if T.BOTTOM[x'].SIZE = 0
then DELETE(x', T.TOP)
fi
esac
fi
end

Lemma 3: The program above correctly deletes an element from a k-struc-


ture in time O(log k).

Proof: Similar to the proof of lemma 2. c


296

Finally, we have to compute ~e cost of initializing a k-structure. It


is easy to see that the cost of initializing a k-structure is propor-
tional to the space requirement of a k-structure. Let Sp(k) be the space
requirement of a k-structure. Then

Sp(1) = c
Sp(k) c.2 k + Sp(rk/2') + 2rk/2'SP(Lk/2J) for k ~ 2

for some constant c.

Lemma 4: Sp(k) = O(2 k log k).

Proof: A simple induction on k shows that


rlog k'-1 )/,
Sp(k) ~ c.2 k IT (1+1/2 2 ) log(2·k)
)/,=1

The proof is completed by the observation that


)/,
IT (1+1/2 2 ) 0(1) _ c
)/'~1

We summarize in

Theorem 1: Let N = 2k, let U = {O,1, ••. ,N-1} and let S =


U be repre-
sented by a k-structure. Then operations Insert(x,S), Delete(x,S),
Min S take time O(log log N). Furthermore an empty set can be created
in time O(N log log N) and the representation takes space O(N log log N).

Proof: Immediate from lemmas 1 to 4 above. c

The space bound and the time for initialization can be improved to O(N)
with a little care without sacrifycing the O(log log N) bound for the
other operations (cf. exercise 47 ).

III. 8.3 The Union - Find Problem

The union-find problem is to manipulate a partition of U = {O, .•. ,N-1}


under the operations (x E U, A and B are names of blocks of the
parti tion) ~
297

Find(x) output the name of the block containing x


Union(A,B,C) take blocks named A and B and combine them to a
block named C.

We will always assume that we start with the partition consisting on N


singleton sets and that the name of set {iJ is i initially. The union-
find problem has numerous applications, among them handling EQUIVALENCE
and COMMON statements in FORTRAN, finding least cost spanning trees,
computing dominators in directed graphs, checking flow graphs for re-
ducibility, calculating depths in trees, computing least common an-
cestors in trees, and solving an off-line min~um problem.

The most obvious solution for the union-find problem is to use an array
IS_IN[O •• N-1]. IS_IN[i] contains the name of the set containing i.
Then execution of Find(x) reduces to table-lookup and therefore
takes constant time. Union(A,B,C) is simple but slow. We scan through
array IS_IN and change all A's and B's to C's in t~e O(N). A small
extension of the data structure allows us to reduce the time for the
Union operation. We associate with every set name a linear list, the
list of its members. Then we only have to step through the elements of
A U B in order to process Union(A,B,C). One further extension requires
us to only step through either the elements of A or the elements of B~
e.g. we might step through the elements of A and change all A's to B's.
In addition, we record the fact that the B's in array IS_IN are really
C's. This is best done by distinguishing between the internal name
(the name appearing in array IS_IN) and the external name (the name
appearing in the Union operations) of a set and to provide for two
arrays MAPOUT and MAPIN~ MAPOUT[i] is the external name of the set with
internal name i and MAPIN[A] is the internal name of the set with ex-
ternal name A.

We can now introduce an important idea for fast Union-Find algorithms:


weighting. \ihen executing Union(A,B,C) step through the smaller of sets
A and B.

The complete algorithm for Union(A,B,C) is given below. We use SIZE[A]


to store the number of elements in set A.
298

(1) if SIZE[A] ~ SIZE[B] then X A; Y B


else X B; Y
(2) j + MAPIN[Y];
(3) for all x E X do IS_IN[X] j od;
(4) SIZE[C] SIZE[A] + SIZE[B];
(5) concatenate lists MAPIN[X] and j and name it j;
(6) MAPOUT[j] + C;
(7) MAPIN[C] + j

Theorem 2: The algorithm above processes a sequence of n - 1 Union


operations and m Finds in time O{m + n log n) •

Proof: A Find clearly takes time 0(1). The cost of an operation


Union{A,B,C) is O{min{SIZE[A], SIZE[B]» ~ c min{SIZE[A], SIZE[B]) for
some constant c. Note that lines (1), (2),(4), (5) and (6) take constant
time and line (3) takes time proportional to the size of X, which is
the smaller of A and B. We use the following accounting technique. The
cost of Union{A,B,C) is accounted for by charging c time units to every
element of X.

Lemma 5: Let x E U be arbitrary. Then at most c·log n time units are


charged to x.

Proof: Whenever x is charged for participating in a Union operation it


finds itself in a set after the Union which is at least twice the size
of the set containing x before the Union. Since we assumed to start with
singleton sets n-1 Union operations can build sets of size at most n.
Thus x is charged at most log(n) times. c

By lemma 5 at most clog n time units are charged to any element of U


which ever participates in a Union. Also at most 2{n-1) elements of U
participate in the n-1 Unions. Thus the total cost of all Union opera-
tions is at most O(n log n). c

Our first approach to the union-find problem favours Finds. A Find costs
0(1) time units, whilst the (amortized) cost of a Union is O(log n)
time units. We will next describe a solution which favours Unions. Each
set is represented by a tree. The nodes and leaves of the tree are the
elements of the set and the root is in addition labelled by the (inter-
nal) name of the set. Then Unions are particularly easy. In order to
299

unite A and B we only have to make the root of the tree labelled A a
son of the root of the tree labelled B, or vice versa. Thus a Union
operation takes constant time. The cost of Find(x} is proportional to
the depth of node x in the tree containing x; access node x (via an
array), traverse the path to the root, and look up the label of the
root. Since the depth of a node is at most n (again assuming that n
Unions are performed) the cost of any Find is at most O(n} •

Again the running time can be reduced drastically by applying the idea
of weighting. When executing Union(A,B,C} we make the root of the
smaller set a son of the root of the larger set. Ties are broken arbi-
trarily. We refer to this rule as the weighted union rule. Before we
can analyse this algorithm we need some notation.

Definition: Suppose that we start with singleton sets and perform n-1
Unions. Let T be the resulting tree. For any x E U let rank(x} be the
height of x in T and let weight(x} be the number of descendants of x
in T. c

Lemma 6: If the weighted union rule is used then weight(x} ~ 2 rank (x}
for all x E U. In particular, rank (x) ~ log n.

Proof: (By induction on rank(x)}. If rank(x} = 0 then the claim is ob-


vious because every node is a descendant of itself and therefore
weight (x) ~ 1 for all x. So let us assume rank(x} ~ 1. Then there must
be a son y of x with rank(y} rank (x) - 1. When y was made a son of x
the number of descendants of x was at least the number of descendants
of y (weighted union rule) and hence after the Union which made y a
son of x the number of descendants of x is at least twice the number of
descendants of y. Later unions will not give y any additional descend-
ants, but they might increase the number of descendants of x. Thus

weight(x} ~ 2·weight(y}
~ 2.2 rank (y} , by induction hypothesis
2rank (x}

Finally, n-1 unions can build sets of size at most n and hence
weight (x) ~ n for all n. c
300

Theorem 3: If the weighted union rule is used then a sequence of n-1


Unions and m Finds takes time O(n + m log n) .

Proof: A Union takes time 0(1). Also the maximal height of any tree
built by the unions is log n by lemma 6. Thus a Find takes time at most
O(log n). c

A further idea reduces the (amortized) cost of a Find even further:


path compression. Suppose that we execute Find(x). Find(x) requires us
to traverse a path v o 'v 1 , ••• ,v£ from node x = Vo to the root r = v£ of
the tree containing x. We can compress this path by making nodes Vi'
°S i < £, direct descendants of the root v£ = r. Although this will
not decrease the cost of the present Find, in fact, it will increase
its cost by a constant factor, it will reduce the cost of future finds
for descendants of Vi' °S i < £.

The details of the Find algorithm are given below. In this program we
assume that an array FATHER[O •• N-1] is used to store son-to-father
pointers. More precisely, if FATHER[x] *x then FATHER[x] is the
father of x, if FATHER[x] = x then x is a root.

procedure Find(x)~

r ... Xi
while r * FATHER[r] do r .. FATHER[r] od~
while x * r do y .. x~ x FATHER[x] ~ FATHER[y]" rod.
output the label of r
end

Path compression by itself produces an efficient union-find algorithm


(cf. exercise 54) even without the weighted union rule. Path compres-
sion combined with weighted union provides us with a very efficient
algorithm, an algorithm whose running time is almost but not quite
linear.

Definition: a) Let A: INo x INo .. IN be defined by


0

A(i,O)
A(O,x) °2x for all i
for all x ~ 0
~
°
A(i+1 ,x+1) A(i, A(i+1 ,x» for all i,x ~ 0

b) a(m, n) = min{z ~ 1 ~ A(z, 4 r m/ n ,) > log n}


301

Theorem 4: If path compression and the weighted union rule is used


then a sequence of n-1 Unions and m ~ n Finds takes time O(ma(m,n».

Before we prove theorem 4, it is worthwhile to take a closer look at


£unctions A and a. A is a variant of Ackermann's function. It is not
primitive recursive. The table below lists values of A(i,x) for small
values of i and x.
x 0 1 2 3 4 5 x
i 0 0 2 4 6 8 10 2x
1 0 2 4 8 16 32 2x
265536 .2
2 0 2 4 16 65536 2• • }x-tiIres
3 0 2 4 65536 2 •• ·~5536-times

•• 2
In particular, if log n < A(3,4) = 2·· } 65536-times then a(m,n) ~ 3.
Thus for all practical purposes, a(m,n) ~ 3; the union-find algorithm

has practically linear running time.

Proof of theorem 4: It is convenient to slightly reformulate the prob-


lem. Let T be any tree which can be formed by n-1 unions using the
weighted union rule. We allow to change T by partial finds. A partial
find of cost k in some tree is a path v o ,v 1 , .•. ,vk from some node Vo
to some ancestor v k of v o ' v k is not necessarily a root. Subsequent
path compression makes all vi's, 0 ~ i < k, sons of v k • It is now easy
to see that any sequence of n-1 unions intermixed with m finds can be
modelled by a sequence of n-1 unions followed by m partial finds of the
same cost. The n-1 unions are just the unions in the original sequence.
A find is simulated by a partial find with exactly the same starting
and end vertex. Thus any sequence of unions and finds can be simulated
by a sequence of unions followed by a sequence of partial finds of the
same cost. It thus suffices to bound the total cost of sequences of
n-1 unions followed by m ~ n partial finds.

Let T be the tree formed by the n-1 unions, let rank (x) be the height
of node x in tree T. If (x,y) is an edge of T (in the sequel we will
always assume that edges pOint towards the root) then rank(x) < rank(y).
The total cost of all partial finds is proportional to the total num-
ber of edges traversed by all partial finds. Let F be that set. We
show IFI = O(ma(m,n» by partitioning the edges of F into groups and
then bounding the number of edges in each group. Edges are put into
302

groups according to the rank of their endpoints.

For 0 ~ i ~ z, 0 ~ j where z is a parameter to be fixed later, let

Gij = (Xi A(i,j) ~ rank(x) < A(i,j+1)}

set F is partitioned into groups Nk , 0 ~ k ~ z+1 where

{(x,y) E Fi k min(ii 3j x,y E Gij }}

for 0 ~ k ~ z and

We also define for 0 ~ k ~ z+1

Lk (x,y) E Nki of the edges on the partial find containing

(x,y), (x,y) is the last edge in Nk }.

Lemma 7: a) ILk' ~ m for 0 ~ k ~ z+1

b) INo - Lol ~ n

c) INk - Lkl ~ 5n/8 for 1 ~ k ~ z

d) I NZ+1 - Lz+1 I ~ n.a(z,n)


where a(z,n) min (i; A(z,i) > 109" n}

Proof: a) For every partial find there is at most one edge in Lk .

b) Let (x,y) E No - Lo. Then there must be a j such that 2j =


A(o,j) ~ rank(x) < rank(y) < A(o,j+1) = 2(j+1). Also there must be an
edge (s,t) E No following (x,y) on the same partial find path. Hence
rank(y) ~ rank(s) < rank(t). After path compression x's father, say u,
is an ancestor of t (maybe t itself) ; in particular rank(u) ~ rank(t)
~ A(o,j+1). Thus no later oartial find can include an edge (x,y') E No.
Hence IN o - Lol ~ n.

c) and d): Consider any node x and let x E Gkj , i.e. A(k,j) ~ rank(x)
< A(k,j+1). Suppose that there are q edges (x'Y1)' ... '(x,y q ) E Nk - Lk
303

where rank(Y1) S rank(Y2) S .•. S rank(x,y q ). For all i,1 S i < q, there
must be edge (s i' t i ) E Nk follo\·ling (x, Yi ) -on the same partial find
.
path. Thus rank(y~) S rank(s.) ~
< rank(t.).
~
Also after -path compression,
x's father is an ancestor of ti (maybe ti itself). In particular,
rank(t i ) S rank(Yi+1).

Also since (x,Y i ) ¢ Nk - 1 , (si,t i ) ¢ Nk - 1 there must be j', j" such that

rank (x) < A(k-1,j') S rank(y.) S rank(s.) < A(k-1,j") S


~ ~ .
rank(t~)

and hence rank(y i ) < A(k-1,j") S rank(Yi+1). Thus there exists j'" such
that

ranklY1) < A(k-1,jllr) S A(k-1,j"'+q-1) S rank(y q ).

At this point the proofs for parts c) and d) split.

c) continued: Since (x,y q ) E Nk and x E Gk ,). we have y qE,


Gk]. and
hence rank (Yq) < A(k,j+1) = A(k-1,A(k,j». Thus A(k-1,j"'+q-1) <
A(k-1,A(k,j» and hence j"' + q-1 < A(k,j) or q S A(k,j). Also note
that G0,0 = Gk ,0 and G0, 1 = Gk ,1 for all k and hence j ~ 2.

We have thus shown that for any x E Gkj , k ~ 1, j ~ 2, there are at


most A(k,j) edges (x,y) E Nk - Lk • Hence

Proof: Consider any ~ with A(k,j) S ~ < A(k,j+1). We count the number
of nodes x E Gkj with rank(x) = ~. Any two such nodes have disjoint
sets of descendants in T. Also any such node has at least 2~ descendants
by lemma 6 and hence there are at most n/2~ nodes of rank ~. Thus

L CJ
A(k,j)S~<A(k,j+1)

Substituting into the bound for INk - Lkl yields


304

INk - Lkl s r 2n A(k,j)/2 A (k,j)


j~2

. 2j
S r 2n 2 J /2 , since A(k, j) ~ 2j
j~2

S 5n/8

d) continued: By lemma 6) we have rank(y q ) S log n and hence


A(z,j'" + q-1) S log n. Note that k-1 = z in case d). Thus jill + q-1 <
a(z,n), or q S a(z,rt). Hence there are at most a(z,n) edges
(x,y) E Nz+1 - Lz+1 for any x. c

We infer from lemma 7

z+1 z+1
IF i r I Lk I + riNk - Lk I
k=o k=o

s m(z+2) + n + 5n/8z + na(z,n)

s (rn + 5n/8) ~(m,n) + 10m + n

, by choosing z min{i ~ 1; A(i,4 r m/n') > log n} = ~(m,n) and observ-


ing that a(z,n) a(a(m,n),n) = rnin{x; A(a(m,n),x) > log n} S
4 r m/n' S 8m/n

= O(m a(m,n»

since m ~ n. IJ

The running time of the union-find algorithm with path compression and
weighted union is almost linear. However, it is not linear. Tarjan has
shown that almost any conceivable union-find algorithm requires time
n(m a(m,n» to process a sequence of n-1 Unions and m ~ n Finds. Appli-
cations of the Union-Find problem are discussed in exercises 48 to 52.
305

III.9. Exercises

1) Write programs for operations Access, Delete and Insert in com-


pressed tries.

2) Write a program for operation Access in TRIES which are compressed


according to the overlay technique discussed in III.1.2 •• Make sure
that your program works correctly for unsuccessful searches.

3) Show that the expected worst case cost of hashing with chaining is
8«log n)/log log n) provided that 0.5 ~ S ~ 1. Note that theorem 3 of
section 2.1. only states an upper bound.

4) In section 2.4. we developed universal hashing for hashing with


chaining. Can we also apply the concept of universal hashing to hash-
ing with open addressing?

5) Let m = 10 and S = {2,19,31,64,93,103,111,115,7,9}. Construct a


perfect hash function. Repeat for m = 15.

6) Let H = {hi h: [0 •• N-1] - [0 •• m-1]} be c-universal. Then c ~ 1 - miN.


Hint: Show L 0h(x,y) ~ N(N-1)/m for every function h:
x,yEU
[0 •• N-1] - [0 •• m-1].

7) For sEN let reps: {0,1}s - [0 .•. 2 s -1] be defined by


s-1
rePs(as_1, ••• ,ao) = ,L a i 2i where a i E {0,1}. Let N = 2r, m = 2s
~=o
and let B be the set of s by r matrices over {0,1}. Let H = {hAiA E B},
where hA : [0 •• N-1] - [0 •• m-1] is defined as h.4 (x) = reps (A.rePr-1 (x» •
Here, matrix multiplication A.rep;1 (x) is over~2' the field of two
elements.

a) Show that H is 1-universal. Hint: Let x,y E [0 •• N-1], x *


y. Then
-+ -+ ... -1 -+ -1
hA(X) = hA(y) iff A(x - y) = 0 where x = rePr (x) and y = rePr (y).
Since the set of vectors of dimension r form a vector space overZ 2 ,
we conclude from A(~ - y)
= 0 that all rows of A are orthogonal to
-+ -+
x - y.

b) Let S c: [0 •• N-1], lSI n and let x E [0 •• N-1]. Use part a) to


306

compute ]1=[ L 0h(x,S)]/IHI.


hEH

c) Compute variance 0 2 (L 0h(X,S)2)/IHI + ]12 of random variable


hEH
0h (x,S) •

d) Use part c) and Chebychev's inequality to show prob(oh(x,S) ~ t'll)


~ (2 + m/n)/(t - 1)2.

8) Let U be the set of real numbers between 0 and 1. Discuss the use
of hash function h : x - LxmJ where m is the size of the hash table.

9) Let ~ be a permutation of 1,2, ... ,n. Let T[~] be the tree obtained
by inserting ~(1), ••• ,~(n) in that order into an initially empty tree.
Insertion is done as described in section 3.1 •.

a) Let P(T[~]) be the external path length of T[~], i.e. P(T[~]) =


L{d(v)/ v leaf of T[m} where d(v) is the depth of leaf v. Show that
L P(T[~])/n! = O(n log n), i.e. the expected external path length of a
¥andomly grown tree is O(n log n). Hint: compare the analysis of Quick-
sort.

b) Let d(T[~]) be the depth of T[~]. Show that L d(T[~])/n! = O(log n),
~
i.e. the expected depth of a randomly grown tree is O(log n). Note
that part b) does not follow from part a) .

10) Let Ai' 1 ~ i ~ n, be an n i by n i + 1 matrix. We want te compute


matrix product A1A2 ••• An • We assume that it costs O(pqr) time units
to multiply an p by q with an q by r matrix. Use dynamic programming
to find an optimal evaluation order. Note that (A 1A 2 )A 3 has cost
n 1 n 2 n 3 + n 1 n 3 n 4 and that A1 (A 2A3 ) has cost n 1 n 2 n 4 + n 2 n 3 n 4 •

11) Let L 1 , ••• ,L n be the set of words. We want to compute the product
(catenation) L 1L 2 ••• Ln • Assume that it costs p.q time units to multiply
a set of size p with a set of size q and that the resulting set has
size pq. Find the optimal evaluation order.

12) Given a 1 ,a 2 , ••• ,a n E ~ find S c {1,2, ••• ,n} such that


max ( L a~, L a.) is minimal. Use dynamic programming.
iES ~ i':S ~
307

13) Design a 2DPDA which runs for an exponential number of steps on


some inputs.

14) Let L = {a 1 ••• a ; a. E {O,1} and there is j ~ 2 such that a 1 ••• a.


n 1 ]
a j a j _ 1 ···ai, i.e. L consists of all strings which start with a non-
trivial palindrom. Show that L can be recognized by a 2DPDA.

15) Given strings a o ••• a n _ 1 and b o ••• b n _ 1 , find an O(n) algorithm to


determine whether there exists an k, 0 5 k 5 n-1, such that a i
b(k+i)mod n for 0 5 i < n.

16) Let S {P1, ••• ,Pm} be a set of patterns. Design an algorithm to


determine all occurrences of strings in S in some text x. Running time?

17) A string x =
a 1 ···a n is a subsequence of string y b 1 ••• b m i f
there are i1 < i2 < ...
< i n such that ]
a . b.
1j
for 5 i 5 n. Design

an O(nm) algorithm to decide whether x is a subsequence of y.

18) In III.4.1., lemma 6 we start with a binary tree T and derive a


probability distribution from it. Show that T is optimal for this dis-
tribution. (Hint: Construct-tree of section 4.2. constructs T when
applied to the derived distribution). Conclude that the lower bound
given in theorem 5 is eXistentially sharp.

19) Show that the upper bounds given in theorems 7 and 8 are existen-
tially sharp.

20) Analyse method 1 for constructing nearly optimal binary search


trees. Method 1 is described at the beginning of section 4.2 •• What is
the quality of the trees produced? What is the running time of the
algorithm?

21) Analyse the time complexity of construct-tree (section 4.2.) when k


is determined by linear search starting at both ends simultaneously.
Answer: O(n log n).

22) Design a balanced tree scheme where the worst case rebalancing cost
after an insertion or deletion is O(log log n). Hint : Use-weight
balanced trees. If n elements are stored then rebalance up to height
308

O(log log n) as described in the text. With every node v of height


log log n associate a pointer which points to an ancestor p(v) of v in
the tree. If a transaction goes through v then we also rebalance p(v),
if necessary, and advance p one step towards the root. Show that the
root balance of nodes of height log log n or more cannot deteriorate
too much.

23) Let L be a sequence of n elements. If x and yare pointers into


list L then Insert(x) inserts a new element immediately to the right of
x, Delete (x) deletes the element to which x points and Order(x,y)
returns true if x is before y in the list.

a) Show how to implement all three operations with worst case time
O(log n) .

b) A labelling Num : L - [1 .. nk] for some small k is a good labelling


if Order(x,y) iff Num(x) < Num(y). Show that a good labelling can be
maintained in amortized time O(log n) per insertion/deletion, i.e. the
total cost of a sequence of n insertions/deletions is O(n log n).
(Hint: use Lemma 2 of section 5.1.).

c) Divide L into n/log n pieces of length log n each. Realize each


piece as an ordinary linked list and keep the pieces in a balanced tree
as in part b). Design an algorithm which realizes all three operations
with amortized cost 0(1).

24) Consider the following operations on trees. Insert(x) gives node x


an additional (rightmost) son, Delete (x) deletes node x and makes all
sons of x to direct sons of father(x). Ancestor(x,y) returns true iff
x is an ancestor of y.

a) Associate with every node x of the tree labels x 1 and x 2 . For tree T
with root x and subtrees T 1 , ••. ,Tk let Pre(T) = x 1 pre(T 1 ) ... pre(T k ) x 2
and let Post(T) = x 1 post(Tk ) ... post(T 1 ) x 2 . Show: x is an ancestor of
y in Tiff x 1 precedes Y1 in Pre(T) and Post(T).

b) Use a) and exercise 23 to design a data structure which supports


Insert, Delete and Ancestor in amortized time 0(1).
309

25) Let T be a binary tree. The height hey) of node v is the longest
path from v to a leaf. The height balance hb(v) of v is the height dif-
ference of the two sons of v, i.e. hb(v) = hex) - hey) where x(y) is
the left (right) son of x. Tree T is an AVL-tree if hb(v) E {-l,O,+l}
for all nodes of T.

a) Are the following trees AVL-trees?

b) Let T be an AVL-tree of height hand n leaves. Then log n ~ h ~

1.44 log(n+1). (Hint: Show n ~ 2h and n ~ Fib(h+1) where Fib(O) =


Fib(l) = 1 and Fib(h+2) = Fib(h+1) + Fib(h) for h ~ ° by induction on
h; Fib is the sequence of Fibonacci numbers).

c) Show how to rebalance AVL-trees after insertions and deletions


(Hint: Adding or deleting a leaf may change the height balance of some
nodes to ± 2. Use rotations and double rotations to remedy the situa-
tion. One operation suffices in the case of insertions, many rotations/
double rotations might be required in the case of deletions.

26) Let T be a binary tree and v a node of T. Let sty) be the lenght of
a shortest path from v to a leaf and let hey) be the length of a longest
path to a leaf; hey) is the height of v. T is half-balanced if hey) ~

2 sty) for every node v of T.

a) Let T be a half-balanced tree with height hand n leaves. Then


h ~ 2 log(n+2) + 2. (Hint: show

2h/2+1 _ 2 if h is even
n ~ {
3 2(h-1)/2 - 2 if h is odd

by induction on h) .

b) Show how to rebalance half-balanced trees after insertions and dele-


310

tions. (Hint: Use rotations, double rotations and triple rotations).


Show that at most one single, double, triple rotation is required to
rebalance the tree after an insertion or deletion.

27) This exercise treats red-black trees in more details (cf. end
of section 111.4)
a) Design an algorithm for deleting a leaf from a red-black tree.
b) In the text, we used red-black trees with leaf-oriented
storage organization, i.e. set S was stored in the leaves and internal
nodes are only used as a directory. Develop the algorithms for node-
oriented storage organization, i.e. set S is stored in the internal
nodes and leaves have empty content. In order to improve storage
utilization use a single record of type node to represent all leaves.
The diagram below shows a node-oriented red-black tree for set
S = {2,4,7,S}.
Use the "single leaf" as a sentinel in searches, i.e. if you search
for x then store x in the sentinel first so as to make every search
successful.
c) Discuss operations Split and Concatenate for red-black trees.
Use both storage organizations.

d) Show how to implement (a,b)-trees for arbitrary a and b, b ~ 2a-1,


by colored trees (Hint: All leaves have identical black depth and are
attached via black edges. Moreover, if we delete all black edges then all
components (which are now kept together by red edges), except the compo-
nent containing the root, have at least a-1 and at most b-1 nodes).
311

28} Show that the following statement is false: There is c > 1 such
that for every (2,4}-tree with n leaves and node v of depth d we have:
the number of leaves below v is bounded by n/c d . Note that the statement
is true for BB[a]-trees.

29) Show how to rebalance (a,b}-trees top-down; b ~ 2a, a ~ 2. (Hint:


Follow a path down the tree as usual. Make sure that the father of the
current node has arity ~ b-1 (~a+1) in the case of an insertion (dele-
tion). This allows us to split (fuse, share) the current node if its
arity is b (a) without having to back up.

30} Formulate and prove an analogon to theorem 8 (section 5.3.1.) for


(a,2a-1}-trees and sequences of insertions only (Hint: Use the account
b(v) = 2a - 1 - p(v} where p is the arity of v}.

31} Same as exercise 30} but for theorem 10 instead of theorem 8.

32} In exercise 29} we outlined how to rebalance (a,b}-tree top-down.


Formulate and prove an analogon to theorem 8 (of section 5.3.1.) for
sequences of insertions and deletions provided that b ~ 2a + 2. Is a
similar theorem true if b = 2a or b = 2a + 1?

33} Operation Concatenate was defined in section 5.3.1 .. We assume for


this exercise that Concatenate is implemented as follows. If trees T1
and T2 are concatenated then we walk up the left spine of T1 and the
right spine of T2 simultaneously until one of the roots is met. Then we
proceed as described in section 5.3.1 •.

a} Show that the cost of concatenating T1 and T2 is O(s + min(h 1 ,h 2 }}


where s is the number of splittings required and hi is the height of Ti •

b} Start with n (a,b}-trees with one leaf each: Perform a sequence of n


Concatenate operations. Show that the total cost is O(n). (Hint: In
addition to the account used to prove theorem 8 (of 5.3.2.) use the
following account: the sum of the heights of all trees. Note that this
quality is n initially and is decreased by at least min(h 1 ,h 2 } - 1 by
concatenating T1 and T 2 } •

c} Use part b} to extend theorem 11 (of 5.3.3.) to also allow Concate-


nate.
312

34) Show that theorem 14 (of 5.3.3.) stays true if ordinary (2,4)-trees
are used instead of level-linked (2,4)-trees.

35) Start with n singleton sets and perform an arbitrary sequence of


set unions to build up a single ordered set of n elements. Show that
the total cost is O(n log n) if sets are represented as level-linked
(2,4)-trees (Hint: Use theorem 14, b of 5.3.3.).

36) Use fringe analysis to improve upon theorem 8 of 5.3.2. for se-
quences of random insertions. (Hint: Use it to improve upon fact 4 in
the proof of theorem 8).

37) Use fringe analysis to approximate the expected number of balanced


(hb(v) = 0) nodes in a random AVL-tree (cf. exercise 25 for a defini-
tion of AVL-trees).

38) Show how to do operations Concatenate and Split on BB[aJ-trees.


Show that the cost of Concatenate is O(log «n+m)/min(n,m))) if the brees
to be concatenated have nand m leaves respectively. Compare this bound
to the bound derived for (a,b)-trees in 5.3.1 •. Observe exercise 28.

39) Extend theorem 6 of 111.6. to weighted sets.

40) Extend theorem 6 of 111.6. to operations Concatenate and Split, i.e.


show how to do these operations in time O(d+log lSI).

41) Discuss the amortized behavior of the following variant of the


move-to-front-rule (section 6.1.1). Whenever an element is accessed it
is moved half-way to the front of the list. Show that
CHWR(s) ~ 4CA (s) + 2XA (s) for any algorithm A and any sequence s.

42) Write a RAM program for the move to front rule realizing the linear
list a) as an array and b) as a linked list. If the linear list is re-
alized as an array then moving an element from the i-th position to the
front also requires to physically move elements in positions 1,••• /i - 1
one position to the rear. This can be done simultaneously with the
search. Compute expected running time and compare with the running time
for the optimal arrangement.
313

43) Let S = (x 1 , ••• ,xn }, let e i be the probability of accessing xi and


let Li be the cost of comparing with xi. If the xi's are stored on
magnetic tape then Li may be the length of x;. The expected search cost
is I: Li 1: (e j : 1f(j) :2 1f(i)} when x is stored in the 1f(i)-th position show
i
that expected search cost is minimized if e./L. < ej/L j implies
~ ~

1f(i) < 1f(j). Can you generalize self-organizing linear search to this
situation?

44) Set S (x 1 ' ••• ,xn } and let e i be the probability of accessing xi.
Assume e 1 :2 e 2 :2 ••• :2 en.

a) Show that the stationary probability of arrangement 1f is

Y 1f

i=1
R
e~-1f(i) under the transposition rule where c is such that
~
I: Y1f = 1.
1f

b) Let 1f be an arrangement where x. is in front of x. and let -1f be the


~ J
arrangement obtained by interchanging Xj and xi. Then Y~ S (e j /e i )y 1f •
Conclude from this that 0TR(j,i) S (ej/e i ) (1-o TR (j,i)) where 0TR(j,i)
is the asymptotic probability that x. is in front of x. and j > i.
J ~
Conclude further that 0TR(j,i) S Yj/(Y i + Yj) = 0MFR(j,i) for j > i.

c) Use b) to show that PTR S PMFR for all distributions (e 1 , ••• ,e n ).


Hint: Use lemma 1, a to express P XYZ in terms of 0Xyz(j,i) where
XYZ E (TR,MFR}.

45) Use the explicite expression given for PMFR in theorem 1 to compute
PMFR and PMFR/Popt for the following distributions.

a) Zipf's law: e i = 1/(iHn ) where Hn I: 1/i.


1SiSn

b) Exponential distribution: e i = ca i where c = 1/ I: ai •


1SiSn
.-2
c) Lotka's law:e. = c/i2 where c = 1/ I: ~
~ 1SiSn

46) Let k :2 1 be an integer. Batch accesses into groups of k. Invoke


the move to front (transposition) rule only if all k requests in a
group are to the same element. Compute PMFR(k), the expected search
cost under the move to front rule if requests are batched into groups
314

of k requests.
47) Let S ~ [0 .. N-1] , N = 2 k (log k) for some k. Let S. =
k J.
{x E S; (log k) ~ X < (i+1)log k} for 0 ~ i < 2 • Represent S as
follows. Store {i; S; * ¢} in a priority queue as described in section
8.2. and store each non-empty Si in a ~inear list. Show that the data
structure requires linear space O(N), can be created in time O(N) and
supports Insert, Delete, Min in time O(log log N) .

48) Let N be an integer. Consider operations Insert(x,S) and Delete-


mintS) where x E [0 •.. N-1] and S ~ [0 ... N-1] • Consider a sequence
OP1, ... ,OPm and discuss the following variants of the problem.

a) On-line: The answer to operation OPi must be given before operation


OPi+1 is known. (Hint: Use the O(log log N) priority queue) .

b) Off-line: OP1""'OPm are known, before any answer must be given.


(Hint: Reduce to Union-Find. Let OP1, ... ,OPrn = U1 DU 2 DU 3 ... U mD where u i
is a sequence of Insert instructions and D represents a Deletemin in-
struction. Create m disjoint sets A1 , •• ,Am with i E A. if Insert(i)
J
occurs in u .• Observe, if 1 E A. then 1 is the output of the j-th
J J
Deletemin instruction, ... ).

49) Discuss the following weighted union rule for the Union-Find prob-
lem: If trees T1 and T2 are to be united then make the tree of smaller
height a subtree of the tree of larger height. Ties are broken arbi-
trarily. Show that the cost of a sequence of n unions and m finds is
o (n + m log n).

50) Show that theorem 2 of section 8.3. is best possible, i.e. describe
a sequence of n unions and m finds which force the algorithm to run for
~(m log n + n) steps.

51) Consider a forest of disjoint trees over node set 0, ..., n-1 .
Link(r,v) makes r, the root of one of the trees, a son of v, a node in
another tree. Depth (v) outputs the current depth of node v. Show how to
use the union-find data structure to solve this problem. (Hint: If T is
one of the trees in the forest then the nodes of T form one of the sets
in the union find problem. Recall that these sets are stored as trees.
315

Maintain function help on the nodes of the union-find trees such that
Depth (v) = L help(w) where the summation is over all ancestors of v in
the union-find tree containing v) .

52) Design a Union-Find algorithm with worst case complexity O(log n).
Can you do better?

53) Analyse the following Union-Find algorithm: Path compression is


used but the weighted union rule is not used.

IIL10 Bibliographic Notes: TRIES were introduced by Fredkin(60). The com-


pression technique for sparse tables is due to Ziegler, the analysis
(theorems 3, 4 and 5) is taken from Tarjan/Yao (79).

A very detailed account of hashing can be found in Knuth (73). The


analysis of the expected worst case cost of hashing is due to Gonnet
(81) and the analysis of open addressing is due to Peterson (57).
Perfect hashing was first discussed by Sprugnoli (77); he describes
heuristic methods for constructing perfect hash functions. Section 2.3.
on perfect hashing is based on Fredman/Komlos/Szemeredi (82), lemma 1,
theorems 10, 11, 12, and Mehlhorn (82), theorems 6,7,8,12. Theorem 13
has not appeared before. Universal hashing was first described by
Carter/Wegman and theorems 14, 15 and 16 are taken from Carter/Wegman
(77). Exercise 7 is taken from Markowskv, Carter and Weqrnan (78).
Theorem 17 is taken from Mehlhorn (82). Extendible Hashing is discussed in
Larson (78), Litwin (78), Fagin et al. (79), A. Yao (80), Flajolet/
Steyaert (82).

A detailed analysis of interpolation search can be found in Perl/Itai/


Avni (78). The discussion in the text is due to Perl/Reingold (77).
Willard (to appear) extended interpolation search to non-uniform prob-
ability distributions.

The o(n 2 ) dynamic programming algorithm for optimum binary search trees
is due to Knuth (71); theorem 2 on quadrangle inequalities is due to
F. Yao (80). If Si = 0 for all i then an optimum tree can be constructed
in time O(n log n), cf. Hu/Tucker (71) or Garsia/Wachs (77). The linear
time simulation of 2 DPDA's on RAMs is by Cook (71); the proof given in
text follows Jones (77). The linear time pattern matching algorithm
316

is from Knuth/Morris/Pratt (74). A general discussion of tabulation can


be found in Bird (80).

The section of nearly optimal trees is based on P. Bayer (77) (t'heorem


5), GUttIer/Mehlhorn/Schneider (80) (theorem 6), Fredman (75) (theorem
11), Mehlhorn (75) (exercise 21) and Mehlhorn (77) (theorem 7 and 8).
Extensions to multiway trees can be found in Altenkamp/Mehlhorn (80)
and Mehlhorn (80).

Weight-balanced trees (theorems 2 and 3) were introduced by Nievergelt/


Reingold (73); lemma 1 and theorem 4 are taken from Blum/Mehlhorn (80);
(a,b)-trees were introduced by Bayer/Me Creight (72); theorem 5 comes
from their paper. The extensions to mergable priority queues is by
Hopcroft (70). Theorems 8, 10, 11, 12, 13 and 14 are from Huddleston/
Mehlhorn (82), extending work of Brown/Tarjan (80). Theorem 9 was first
shown by Guibas et al (77); the proof given here is due to Brown/
Tarjan (80) and Mehlhorn (79). Fringe analysis was introduced by A. Yao
(78) and theorem 15 comes from that paper. Theorem 16 is taken from
Eisenbarth/ et. al. (82). An analysis of (a,b)-trees under random in-
sertions and deletions can be found in Mehlhorn (82). AVL-trees
(exercise 25) were introduced by Adel'son-Velskii (62), half-balanced
tree (exercise 26) by Olivie (82), and red-black trees (exercise 27) by
Guibas/Sedgewick. Exercises 23 and 24 are taken from A. Tsakalidis (83).

The move to front rule for self-organizing linear search was first
analysed by Me Cabe(65). Exercises 44,45 and 46 are taken from Rivest
(76), Hendricks (76), and Gonnet/Munro/Suwanda (79). The amortized
analysis of the move to front rule was started by Bentley/Me Geoch (82)
and then refined by Sleator/Tarjan (83).

Splay trees were introduced by Sleator/Tarjan (83). D-trees were intro-


duced by Mehlhorn (81). The application of weighted dynamic trees to
multi-dimensional searching is taken from Mehlhorn (79). Other solutions
to the weighted dictionary problem can be found in Bent/Sleator/Tarjan
80) and Gutting/Kriegel (82).

The O(log log N) priority queue is by v. Emde Boas/Kaas/Zijlstra (77)


and v. Emde Boas (77). The analysis of the union-find algorithm with
path compression and weighted union is due to R.E. Tarjan (75). Exer-
cises 48 and 51 are taken from Aho/Hopcroft/Ullman (73).
IX. Algorithmic Paradigms

There are basically two ways for structuring a book on data structures
and algorithms: problem or paradigm oriented. We have mostly followed
the first alternative because it allows for a more concise treatment.
However, at certain occassions (e.g. section VIII.4 on the sweep para-
digm in computational geometry) we have also followed the second ap-
proach. In this last chapter of the book we attempt to review the en-
tire book from the paradigm oriented point of view.

Solving an algorithmic problem means to search for a solution to the


problem within a set of possible candidates (= search space, state
space) .

Exhaustive search, i. e. a complete scan of the state space, is the


most obvious searching method. Pure exhaustive search is rarely effi-
cient and should only be used for small state spaces. We found several
ways of improving upon exhaustive search, most notably branch and bound,
tabulation, and dynamic programming. In the branch and bound approach
(VI.6.2) to optimization problems one explores the state space in the
order of decreasing promise, i. e. one has the means of estimating the
quality of partial solutions and always works on the partial solution
with maximal promise. The precision of the search depends on the quali-
ty of the estimates. It is usually quite difficult (or even impossible)
to analyse the complexity of branch and bound algorithms in a satisfying
way.

In more structured state spaces one can use dynamic programming and
tabulation (111.4.1, IV.7.3, and VI.6.1). Dynamic programming is par-
ticularly useful when the problem space ist structured by size in a
natural way and when solutions to larger problems are easily obtained
from solutions to (all, sufficiently many) smaller problems. In this
situation it is natural to solve all conceivable subproblems in order
of increasing size in a systematic way. The efficiency of dynamic pro-
gramming is directly related to the size of the state space. We en-
countered a large state space in the application to the travelling
salesman problem (VI.6.1) and a fairly small state space in the appli-
cation to optimum search trees (111.4.1) and least cost paths (IV.7.3).
In some occassions, e. g. 111.4.1, the search could be restricted to a
suitabl¥ chosen subset of the state space.
318

Tabulation (111.4.1) is a general method of obtaining dynamic program-


ming algorithms from top-down exhaustive search algorithms. The idea is
to store the solutions to all solved subproblems in a table for latter
look-up. We have used this idea for converting a backtracking algorithm
for optimum search trees into the dynamic programming algorithm and for
simulating 2-way deterministic pushdown automata in linear time on a
RAM. The latter simulation led to the linear time pattern matching algo-
rithm.

The divide -and - conguer paradigm is also applied to problem spaces


which are structured by size. A problem instance is solved by genera-
ting several subproblems (divide), solving the subproblems (conquer),
and combining the answer to the subproblems to an answer for the origi-
nal problem instance (merge). The efficiency of the method is determined
by the cost of generating the subproblems, the number and the size of
the subproblems, and the cost of merging the answers. Divide - and -
conquer algorithms lead to recursive programs and their analysis leads
to recursion equations. We discussed recursion equations in sections
11.1.3 and VII.2.2. The paradigm of divide - and - conquer was used very
frequently in this book: in sorting and selection algorithms (11.1.2,
11.1.3, and 11.4), in all data-structures based upon trees (111.3 to
111.7, VII.2.1 and VII.2.2, and VIII.5.1), in the planar separator theo-
rem and its applications (IV.10), in the matrix multiplication algo-
rithms (V.4), and in the divide - and conquer algorithms for computa-
tional geometry (VIII.5.2). Finally, the treatment of decomposable
searching problems and dynamization (VII.1) has a very close relation-
ship to the divide - and - conquer paradigm. In most applications of the
paradigm a natural structure of the problem instances was used for the
division step. For example, if the problem instance is a tuple then we
can split the tuple into its first and its second half (merge sort, bi-
nary search, matrix multiplication, ••. ) and if the problem instance is
a set of objects from an ordered set then we can split the set into its
lower and its upper half (the linear time selection algorithm, applica-
tions in geometry, •.• ). The situation was slightly different in multi-
dimensional divide - and - conquer (VII.2.2). There we frequently solved
an instance of size n in d-dimensional space by generating two d-dimen-
sional subproblems of size about n/2 and one (d-1)-dimensional subprob-
lem of size n. Another interesting application of the paradigm is to
planar graphs. We have seen two strategies. The first strategy is given
by the planar separator theorem of section IV.10.2. It allows us to
319

split a planar graph of n nodes into two subgraphs of about half the
size by the removal of only O(In) nodes. Moreover, the separating set
can be determined in linear time. We used the planar separator theorem
in several efficient algorithms on planar graphs, e. g. least cost path,
chromatic number, •••• The second strategy is given by the fact that a
planar graph always contains a large set of independent nodes of small
degree. We used this fact in searching planar subdivisions (VIII.3.2.1)
and in the hierarchical representation of convex polyhedra (VIII,
exercise 2).

Trees are a prime example for the divide - and - conquer paradigm. In
trees one either organizes the universe (section 111.1 on TRIES) or one
organizes the set to be stored in the tree. The latter approach was
used in sections 111.3 to 111.7 and leads to balanced trees. In these
trees one chooses an element of the set for the root which balances the
subproblems. In balanced trees for unweighted data balancing is done
either according to the cardinality of the subproblems (weight - bal-
anced trees) or according to the height of the subtrees (height - bal-
anced trees). In trees for weighted data balancing is done according to
the probability of the subproblems. We have also seen on two occassions
(111.6.1 on weighted dynamic trees for multidimensional searching and
VIII.S.1.3 on segment trees) that search structures for unweighted com-
plex data can sometimes be constructed from trees for simpler but weigh-
ted data. The former approach, i. e. organizing the universe, was used
in section 111.1 on TRIES and in the static version of interval, priori-
ty search, and segment trees (V1II.S.1). The organization of the uni-
verse gives rise to particularly simple tree structures.

Closely related to trees which organize the universe are key transfor-
mation ( =hashing) and direct access(II.2, 111.2 and 111.8). In these
methods one uses the key or a transformed key in order to directly
access data. This immediately implies small running times. Another
application of the very same idea is presorting, i. e. transforming a
problem on an arbitrary set into a problem on a sorted set by sorting.
It is then often possible to identify the objects with an initial
segment of the integers which opens up all methods of direct access. We
used presorting in sections VII.2.2 on multi-dimensional divide - and -
conquer and in section VIII.S on orthogonal objects in computational
geometry.
320

In graphs we studied two methods for their systematic exploration:


breadth - first and depth - first search. Breadth - first search is
particularly useful for distance type problems and was therefore used
intensively in least cost path computations (IV.7). Depth - first
search has the important property that components are explored one by
one and is therefore the natural method of exploration in connectivi-
ty problems. We used DFS to determine biconnected and strongly connec-
ted components and to test planarity.

Frequently, solutions to problem instances can be found iteratively


or in a step by step fashion. Examples are the construction of optimal
merging patterns (11.1.4), network flow and matching problems (IV.9),
the construction of least cost spanning trees (IV.8), and the construc-
tion of convex hulls (VIII.2). In some of these examples (e. g. least
cost spanning trees or optimal merging patterns) each step performs an
action which is locally optimal. This variant of iteration is sometimes
called the greedy approach. In other applications of this paradigm
(e. g. network flow) a solution is improved iteratively. Frequently,
the concept of augmentation applies to these situations.

In the chapter on algorithmic geometry we discussed the sweep paradigm


at length (VIII.4, VIII,5.1). Its power sterns from the fact that it re-
duces the dimension of geometric problems for the cost of turning static
into dynamic problems. In particular, two-dimensional static problems
can often be reduced to one-dimensional dynamic problems which can then
be solved using some sort of balanced tree.

The method of reduction also played a major role in other parts of the
book. The entire chapter on NP - completeness is centered around the
notion of reduction or transformation. We used reductions to structure
the world of problems, to define and explore classes of equivalent
problems (VI.1 to VI.5), to transfer algorithms (from network flow to
matching in IV.9, from matrix product over the integers to matrix pro-
duct over the set of booleans in V.5, from iso - oriented objects to
general objects in VIII.5.2, and from straight-line to circular objects
in VIII.6), and to transfer lower bounds (from sorting to element uni-
queness in 11.6, from decision trees to RAMs in 11.3 and from boolean
matrix product to matrix product over semi-rings of characteristic zero
in V. 7).
321

Balancing is also an important concept. In least cost path computa-


tions (IV.?) we balanced the cost.of various priority queue operations
by a careful choice of the data structure, in multi - dimensional trees
(VII.2.1) we balanced the power of the coordinates by using them in the
split fields in cyclic order, and in divide - and - conquer algorithms
we always tried to balance the size of the subproblems. It is important
to observe that perfect balancing is usually not required in order to
obtain efficient solutions; approximate balancing will also do. In fact,
approximate balancing is called for in order to cope with dynamic behavior.
A typical example are balanced trees. In BB[a]-trees (VIII.5.1) we do
not require each node to have root balance in the range [1/3,2/3] al-
though such a tree always exists but leave more leeway and in height-
balanced trees (VIII.5.2) we allow nodes to have between a and b SOns.
Introducing an amount of freedom beyond the necessary amount often has
dramatic effects on the (amortized) behavior of these schemes. Again,
balanced trees are typical examples but so are the dynamization methods
of VII.1. For example, BB[aJ-trees work for a ~ 1-12/2, but a < 1-12/2
improves the amortized rebalancing cost dramatically. Similary (a,b)-
trees work for b ~ 2a-1 but choosing b ~ 2a improves the behavior con-
siderably (III.5.2 and III.5.3).

Another way of interpreting approximate rebalancing is redundancv, i.e.


to allow additional freedom in representation. The concept of redundan-
cy can also be applied to storage space. We saw at several occassions,
most notably range trees (VII.2.2) and dd-trees (VII.2.1), that storing
objects several times can reduce search time considerably. In dd-trees
multi-dimensional objects are stored without redundancy; they provide
us with rootic search time and it was shown in VII.2.3.1. that this is
optimal. Range trees store data in a hightly redundant fashion: they
use non-linear storage space and provide us with polylogarithmic
search time. In fact, the slack parameter of range trees allows us to
trade between time and space.

Redundant structures frequently show good amortized behavior because


rebalancing a node of a redundant structure moves the node away from
the critical situations. Amortized analysis was used in the sections
on dynamization and weighting (VII.1), range trees (VII.2.2), (dynamic)
interval (VIII.5.1.1) and segment trees (VIII.5.1 .3), BB[a]-trees
(111.5.1), (a,b)-trees (111.5.3) and the union-find problem (111.8).
A general discussion of the bank account paradigm for amortized
analysis can be found in section 111.6.1.
322

Worst case analysis (and amortized analysis which is the worst case
analysis of sequences of operations) is the dominant method of analysis
used throughout this book. Expected case analysis was done in only a few
places; e. g. quicksort (11.3), selection (11.4), TRIES (111.1.1),
hashing (111.2), interpolation search (111.3.2), weighted trees (111.4),
self-organizing linear search (III.6.1.1),and transitive closure (IV.3).
Expected case analysis rests upon an a-priori probability distribution
on problem instances and therefore its predictions should be interpreted
with care. In particular, it should always be checked whether reality
conforms with the probability assumptions. Note however, that the ex-
pected running of many algorithms is fairly robust with respect to
changes in the distribution. For example, a near-optimal search tree
for distribution 8 ist also a near-optimal search tree for distribution
8' provided that 8 and 8' do not differ too much. Furthermore, a care-
ful analysis of algorithms with small expected running time sometimes
leads to fast algorithms with small wort case running time (e.g. selec-
tion) or to fast probabilistic algorithms (e.g. quicksort and hashing) .

Self-organization is another important principle. In self-organizing


data structures the items compete for the good places in the structure
and high-frequency elements are more likely to be there. This results
in good expected and sometimes also amortized behavior.

Generalization was the central theme of chapter V and also section


VII.1. In chapter V we dealt with path problems over closed semi-rings,
a generalization of least cost paths, transitive closure, maximal cost
paths, and many other path problems. In section VII.1 we derived gene-
ral methods for dynamizing static data structures for decomposable and
order decomposable searching problems. Numerous applications of these
general methods can be found in chapters VII and VIII.

The last two principles which we are going to discuss are approximation
algorithms and probabilistic algorithms. These paradigms suggest to
either change the problem to be solved (solve a simpler problem) or to
change our notion of computation (use a more powerful computing machine) •
We observed at several places that a "slight" change in the formulation
of a problem can have a drastic effect on its complexity: The satis-
fiability problem with three literals per clause is NP-complete but
323

with two literals per clause it becomes fairly simple, the precedence
constrained scheduling problem is NP-complete but if the precedence re-
lation is a tree or there are only two machines then the problem is in
P. Similarly, the computation of the convex hull of a point set takes
time e(n logn) but if the points are sorted by x-coordinate then time
O(n) suffices. For optimization problems there is a standard method
for simplifying the problem; instead of asking for an optimal solution
we are content with a nearly optimal solution. This approach is parti-
cularly important when the optimization problem is NP-complete and
therefore we devoted the entire section V.7 to approximation algorithms
for NP-complete problems. We saw that some NP-complete problems resist
even approximate solution but many others have good or even very good
approximation algorithms. Even inside P approximation algorithms are
important. A good example are the weighted trees of section 111.4. The
best algorithm for constructing optimum weighted trees has running time
e(n 2 ) and there is an O(n) algorithm which constructs nearly optimal
trees. Already for moderate size n, say n = 10 4 , the difference between
n 2 and n is substantial.

Probabilistic algorithms are based on a more flexible notion of compu-


tation, i. e. it is postulated that a oerfect coin is available
to the machine. (Less than perfect coins will also do for fast
probabilistic algorithms as we saw in section 1.2) . We encountered prob-
abilistic algorithms in many different contexts, e. g. the construction
of perfect hash functions (111.2.3), universal hashing (111.2.4), prob-
abilistic quicksort (11.1.3), graph connectivity (IV.9.2) and primality
testing (Vl.S). These applications may be grouped into two classes. In
the first class coin tosses are used to randomize inputs (probabilistic
quicksort, universal hashing). Typically, a random transformation is
applied to the input and then a standard deterministic algorithm with
small expected running time is used. The expected running time of the
probabilistic algorithm on a fixed input then matches the expected run-
ning of the deterministic algorithm. The important difference is that
the randomized algorithm controls the dices but a deterministic algo-
rithm does not; the latter is at the mercy of its user who generates
the problem instances. In the second class (construction of perfect
hash functions, graph connectivity, primality testing) coin tosses are
used to randomize the search for an element of some set with a desirable
property. Typically, the property is easily checked and the elements
having the property are abundant. However, no intimate knowledge about
their location is available.
324

The design of an efficient algorithm is particularly satisfying if its


performance matches a lower bound and hence the algorithm is optimal.
Unfortunately, only a few algorithms have been shown to be optimal. We
saw three approaches to proving lower bounds in this book. The first
approach is the information-theoretic one and the typical argument goes
as follows: In order to distinguish between N possibilities any algo-
rithm requires log N steps. Of course in order to make this argument
sound one has to define and study the primitive operations, the set of
possible outcomes, and how the primitives operate on the set of possible
outcomes. We used the information-theoretic approach in sections II.1.6
and II.3 on lower bounds for sorting and related problems, in section
III.4 on searching in weighted sets, and in a modified form also in
section VII.3.1 on lower bounds for partial match retrieval in minimum
space. The second approach is by simplification which we used to prove
the lower bound on the complexity of matrix multiplication (V.7). In
this approach one designs transformation rules which allow to simplify
an optimal program without increasing cost. The final product of the
simplification process is then amenable to direct attack. The third
approach uses combinatorial methods and was used in the sections on
dynamization (VII.1.1) and the spanning bound (VII.3.2). In this approach
one relates the complexity of an algorithm to a combinatorial quantity
(the spanning complexity of a family of sets in VII.3.2 and various path
lengths of binary trees in VII.1.1) and then analyses the combinatorial
quantity.
Appendix

The appendix contains some frequently used equalities and inequalities.


It is divided into three parts. The first part lists some facts about the
entropy function, the second part gives some summation formulae and the
third part lists a few inequalities.

Let '1' ••• "n be a probability distribution, i.e. ' i ElR'"Yi ~O, and
L ' i = 1. The entropy of this distribution is defined as
i
n
H('1'···"n) = - L ' i log "Yi
i=1
where O·log 0 = o. []

E1) Let 01, ••• ,on be another distribution. Then H('1' •.• "n) ~
n
- L " log 0i with equality iff '1.' = 0, for all i.
i=1 1. 1.

Proof: From log x (~nx)/~n 2 and ~n x ~ x-1


we infer
n n
H('1'···"n) + L ' i log 0i (1/~n 2) L ' i ~n(oi/'i)
i=1 i=1
n
~ ( 1 / ~n 2) L 1', (0 , II ' -1 )
i=1 1. 1. 1.

o . []

E2) o ~ H("Y1' •.• '"Y n ) ~ log n


Proof: 0 'i
1 implies -"Y i log"Y i ~ 0 and hence H("Y1' ... '"Y n ) ~ O.
~ ~
The second inequality follows from E1) with 0i = 1/n, 1 ~ i ~ n •

E3) (grouping property) :

Proof: By substituting the definition of H and simple calculation.


[]

In the second group we list some frequently used sums and inteqrals,

k
, i k+1
81) L 1. 2 = (k-1) 2 + 2 for k ~ 1
i=1
326

Proof: An elementary proof uses induction on k. More generally, we


can proceed as follows. Consider
k k k
f(x) = L L x • '<" d xi
<- dx
i=1 i=1 i=1

= x ci! «xk + 1 _1)/(x_1)) = (x+xk + 1 (kx-k-1))/(x-1)2

Hence f(2) = 2 + (k_1)2 k + 1 []

k
L 1/i is the k-th harmonic number. We have
i=1
J/,n k ;;;; Hk ;;;; 1 + J/,n k •

k+1 k
Proof: From f (1/x)dx :> 1/k ;;;; f dx
k k-1
k+1
we infer Hk ;;: f (1 Ix) dx J/,n(k+1) and
1

k k
Hk 1 + r 1/i ;;;; 1 + f (1 Ix) dx 1 + J/,n k . []

i=2 1
n
53) L Hk = (n+1) Hn - n for n ;;; 1 .
i=1
n n k n
Proof: L Hk L L 1/i L (n-i+1)/i = (n+1)H n - n []

k=1 k=1 i=1 i=1

In the third group we list some frequently used inequalities.

I 1) J/,n ( 1+x) ;;;; x

I2) J/,n (1+x) ;;; x/ (1+x) for x ;;;; °


Proof: Consider the line through point (1,0) with slope

d~ J/,n(1+y) Iy=x = 1!X • This line is below J/,n(1+x) at point x. []


327

I3) ~n(1+x) ~ x/(1-8) for -8 ;;,; x ;;,; 0


Proof: immediate from 12)

14) eX ~ 1+x

for 0 ;;,;x ;;,; X


o
Bibliography

We use the following abbreviations for journals and proceedings:

ACTA Acta Informatica


CACM Communications of the ACM
ElK Elektronische Informationsverarbeitung und Kybernetik
FCT Foundations of Computing Theory
FOCS IEEE Symposium on Foundations of Computer Science
ICALP International Colloquium on Automata, Languages and
Programming
Inf & Control ~nformation and Control
IPL Information Processing Letters
JACM Journal of the ACM
JCSS Journal of Computer and System Sciences
LNCS Springer Lecture Notes in Computer Science
MFCS Mathematical Foundations of Computer Science
SICOMP SIAM Journal of Computing
STOC ACM Symposium on Theory of Computing
TCS Theoretical Computer Science

Adel'son-Velskii, G.M., Landis, Y.M. (1962): An algorithm for the


organization of information, Soviet Math. Dokl. 3, 1259-1262

Adleman, L. (1978): Two Theorems of random polynomial Time, 19th


FOCS, 75-83

Aho, A.V., Hopcroft, J.E., Ullman, J.D. (1974): The Design and Analysis
of Computer Algorithms, Addison Wesley

Altenkamp, D., Mehlhorn, K. (1980): Codes: Unequal Letter Costs,


Unequal Probabilities, JACM 27, 412-427

Bayer, P.J. (1975): Improved Bounds on the Cost of Optimal and Balanced
Binary Search Trees, Technical Report, Dept. of Computer Science,
MIT

Bayer, R., McCreight, E. (1972): Organization and Maintenance of Large


Ordered Indizes, ACTA INFORMATICA 1, 173-189
329

Bayer, R., Schkolnik, M. (1977): Concurrency of Operations on B-Trees,


ACTA INFORMATICA 9, 1-22

Ben-Or, M. (1983): Lower Bounds for Algebraic Decision Trees,


15th STOC, 80-86

Bent, S.W., Sleator, D.O., Tarjan, R.E. (1980): Biased 2-3 Trees,
21st FOCS, 248-254

Bentley, J.L., Haken, D., Saxe, J.B. (1980): A General Method for
Solving Divide-and-Conquer Recurrences, SIGACT Newsletter 12, 36-44

Bentley, J.L., McGeoch, C. (1982): Worst-case analysis of self-


organizing sequential search heuristics, Proc. of the 20th
Allerton Conference on Communication, Control, and Computing

Bird, R.S. (1980): Tabulation Techniques for Recursive Programs, ACM


Computing Surveys 12, 403-417

Blum, N., Mehlhorn, K. (1980): On the Average Number of Rebalancing


Operations in Weight-Balanced Trees, Theoretical Computer
Science 11, 303-320

Blum, M., Floyd, R.W., Pratt, V.R., Rivest, R.L., Tarjan, R.E. (1972):
Time Bounds for Selection, JCSS 7, 448-461

Brown, M.R., Tarjan, R.E. (1978): A Representation for Linear Lists


with Movable Fingers, 10th STOC, 19-29

Carter, J.L., Wegman, M.N. (1977): Universal Classes of Hash Functions,


9th STOC, 106-112

Cook, S.A., (1971): Linear Time Simulation of two-way deterministic


pushdown automata, IFIP Congress, 172-179

Cook, S.A., Reckhow, R.A. (1973): Time bounded random access machines,
JCSS 7

Eisenbarth, B., Ziviani, N., Gonnet, G.H., Mehlhorn, K., Wood, D. (1982):
The Theory of Fringe Analysis and its Application to 2-3 Trees and
B-trees, Inform. & Control 55, 125-174

Elgot, C.C., Robinson, A. (1964): Random Access Stored Program Machines,


JACM 11, 365-399
330

Emde Boas, P.v. (1977): Preserving order in a forest in less than loga-
rithmic time and linear space, IPL 6, 80-82

Emde Boas, P.v., Kaas, R., Zijlstra, E. (1977): Design and Implementa-
tion of an efficient priority queue, Math. Systems Theory 10,
99-127

Fagin, R., Nievergelt, J., Pippenger, N., Strong, H.R. (1979):


Extendible Hashing - A Fast Access Method for Dynamic Files,
ACM Trans. of Database Systems 4, 315-344

Flajolet, Ph., Steyaert, J.M. (1982): A branching process arising in


dynamic hashing, trie searching and polynomial factorization, 9th
JCALP, LNCS 140, 239-251

Floyd, F.W. (1964): Algorithm 245: treesort 3, CACM 7, 701

Fredkin, E. (1960): Trie Memory, CACM 3, 490-499

Fredman, M.L. (1975): Two Applications of a Probabilistic Search Tech-


nique: Sorting X+Y and Building Balanced Search Trees, 7th STOC,
240-244

Fredman, M.L., Komlos, J., Szemeredi, E. (1982): Storing a Sparse Table


with 0(1) worst Case Access Time, 23rd FOCS, 165-169

Garsia, A.M., Wachs, M.L. (1977): A new algorithm for minimum cost
binary trees, SICOMP 4, 622-642

Gonnet, G.H. (1981): Expected Length of the longest probe sequence in


hash code searching, JACM 28, 289-304

Gonnet, G.H., Munro, J.I., Suwanda, H. (1979): Toward Self-Organizing


Linear Search, 20th FOCS, 169-174

Gotlieb, C.C., Walker, W.A. (1972): A Top-Down Algorithm for Construc-


ting Nearly Optimal Lexicographical Trees, Graph Theory and Com-
puting, Academic Press

Gries, D. (1971): Compiler Construction for digital computers, John


Wiley & Sons, New York

Guibas, L.J., McCreight, E.M., Plass, M.F., Roberts, J.R. (1977):


A new representation for linear lists, 9th STOC, 49-60
~1

Guibas, L.J., Sedgewick, R. (1978): A dichromatic framework for balanced


trees, 19th FOCS, 8-21

Glittler, R., Mehlhorn, K., Schneider, W. (1980): Binary Search Trees:


Average and worst Case Behavior, ElK 16, 41-61

Hendricks, W.J. (1976): An Account of Self-Organizing Systems, SICOMP 5,


715-723

Hoare, C.A.R. (1962): Quicksort, Computer Journal 5, 10-15

Hong, J.W. (1979): On Lower Bounds on Time Complexity of Some Algo-


rithms, Scientia Sinica 22, 890-900

Hotz, G. (1972): Rechenanlagen, Teubner-Studienblicher, Teubner-Verlag,


Stuttgart

Hu, T.C., Tucker, A. (1971): Optimum Computer Search Trees, SIAM J. of


Applied Math. 21, 514-532

Huddleston, S., Mehlhorn, K. (1982): A new data structure for repre-


senting sorted lists, ACTA INFORMATICA 17, 157-184

Huffman, D.A. (1952): A method for the construction of minimum-redun-


dancy codes, Proc. I.R.E. 40, 1098-1101

Jones, N.D. (1977): A note on linear time simulation of deterministic


two-way pushdown automata, IPL 6, 110-112

Knuth, D.E. (1968): The Art of Computer Programming, Vol. 1: Fundamental


Algorithms, Addison-Wesley

Knuth, D.E. (1971): Optimum Binary Search Trees, ACTA INFORMATICA 1,


14-25, 270

Knuth, D.E. (1973): The Art of Computer Programming, Vol. 3: Sorting


and Searching, Addison Wesley

Knuth, D.E., Morris, J., Pratt, V. (1974): Fast Pattern Matching in


Strings, Stanford Technical Report, 74-440

Larson, P.A. (1978): Dynamic Hashing, BIT 18, 184-201

Litwin, W. (1978): Virtual Hashing: A Dynamically Changing Hashing,


Proc. Very Large Data Base Conf., 517-523
332

Lum, V.Y., Yuen, P.S.T., Dodd, M. (1971): Key to address transformation


techniques, CACM 14, 228-239

Markowsky, G., Carter, J.L., Wegman, M. (1978): Analysis of a universal


class of hash functions, MFCS 78, LNCS 64, 345-354

Martin, T.H. (1971): Sorting, ACM Computing Surveys 3, 147-173

McCabe, J. (1965): On Serial Files with Relocatable Records, Operations


Research 12, 609-618

Mehlhorn, K. (1975): Nearly Optimum Binary Search Trees, ACTA INFOR-


MATICA 5, 287-295

Mehlhbvn, K. (1977): Best Possible Bounds on the Weighted Path Length


of Optimum Binary Search Trees, SICOMP 6, 235-239

Mehlhorn, K. (1979): Dynamic Binary Search, SICOMP 8, 175-198

Mehlhorn, K. (1979): Sorting Presorted Files, 4th GI-Conference on


Theoretical Computer Science, LNCS 67, 199-212

Mehlhorn, K. (1980): An Efficient Algorithm for the Construction of


Nearly Optimal Prefix Codes, IEEE Transactions on Information
Theory, IT-26, 513-517

Mehlhorn, K. (1981): Arbitrary Weight Changes in Dynamic Trees, RAIRO


Theoretical Informatics 15, 183-211

Mehlhorn, K. (1982): On the Program Size of Perfect and Universal Hash


Functions, 23rd FOCS, 170-175

Mehlhorn, K. (1982): A partial analysis of height-balanced trees under


random insertions and deletions, SICOMP 11, 748-760

Meijer, H., Akl, S.G. (1980): The Design and Analysis of a New Hybrid
Sorting Algorithm, IPL 10, 213-218

Nievergelt, I., Reingold, E.M. (1973): Binary Search Trees of Bounded


Balance, SICOMP 2, 33-43

Olivie, H.J. (1982): Half-balanced binary search trees, RAIRO Theoreti-


cal Informatics 16, 1, 51-71
Paul, W.J., Simon, J. (1980): Decision Trees and Random Access Machines,
Symposium tiber Logik und Algorithmik, Zurich

Perl, Y., Itai, A., Avni, H. (1978): Interpolation Search - A Log Log N
Search, CACM 21, 550-553

Perl, Y., Reingold, E. (1977): Understanding the Complexity of Inter-


polation Search, IPL 6, 219-222

Peterson, W.W. (1957): Uniform Hashing, IBM J. of Research and Devel-


opment 1, 135-136

Reif, J.W. (1982): On the Power of Probabilistic choice in synchronous


parallel computation, 9th JCALP, LNCS 140, 442-450

Rivest, R.L. (1976): On Self-Organizing Sequential Search Heuristics,


CACM 19, 63-68

Rivest, R.L., Knuth, D.E. (1972): Computer Sorting, Computing Reviews


13, 283-289

Schmidt, A. (1981): On the Number of relational operators necessary to


compute certain functions of real variables, Int. Report,
TU Karlsruhe

Sedgewick, R. (1977): The Analysis of Quicksort Programs, ACTA INFOR-


MATICA 7, 327-355

Shepherson, J.C., Sturgis, H.E. (1963): Computability of Recursive


Functions, JACM 10, 217-255

Sleator, D.O., Tarjan, R.E. (1983): Self-Adjusting Binary Trees, 15th


STOC, 235-245

Sleator, D.O., Tarjan, R.E. (1983): Amortized Efficiency of List Up-


date and Paging Rules, Bell Laboratories, Intern. Report

Sprugnoli, R. (1977): Perfect Hash Functions: A single probe retrieval


method for static sets, CACM 20, 841-850

Strassen, V. (1973): Die Berechnungskomplexitat von elementarsymrnetri-


schen Funktionen und von Interpolationskoeffizienten, Num. Math.
20, 238-251
334

Tarjan, R.E. (1975): Efficiency of a good but not linear set union
algorithm, JACM 22, 215-225

Tarjan, R.E., Yao, A.C.-C. (1979): Storing a Sparse Table, CACM 22,
606-611

Tsakalidis, A. (1983): Einige Resultate fur das Worterbuchproblem,


Ph.D. thesis, Univ. des Saarlandes

van Leeuwen, J. (1976): On the construction of Huffmann Trees, 3rd


ICALP, 382-410, Edinburgh University Press

Williams, J.W.J. (1964): Algorithm 232: Heapsort, CACM 7, 347-348

Willard, D.E. (1983): Searching Nonuniformly Generated Files in log


log n runtime, to appear SICOMP

Yao, A.C. (1977): Probabilistic Computation - Toward a Unified Measure


of Complexity, 18th FOCS, 222-227

Yao, A.C.-C. (1978): On Random 2-3 Trees, ACTA INFORMATICA 9, 159-170

Yao, A.C.-C. (1980): A note on the Analysis of Extendible Hashing,


IPL 11, 84-86

Yao, A.C.-C. (1981): A Lower Bound to Finding Convex Hulls, JACM 28,
780-787

Yao, A.C.-C. (1982): Theory and Applications of Trapdoor Functions,


23rd FOCS, 80-91

Yao, F.F. (1980): Efficient Dynamic Programming Using Quadrangle Ine-


qualities, 12th STOC, 429-435
335

Subject Index

(a,b)-trees 199 - extendible- 145


algebraic decision tree 76 - load factor 120
algorithm - open addressing 124
- deterministic- 3 - perfect- 108, 127
- Las Vegas- 14 - universal- 139
- randomized- 12, 54, 139 heap
amortized cost 195, 218, 253 -heapsort 45
analysis - priority queues 213
- amortized- 195, 218, 253
- asymptotic- 2, 37 interpolation search 155
arrays 24
- boolean- 289 Las Vegas algorithm 14
- sparse- 108, 127 lists 26
AVL-tree 309 lower bounds
- algebraic decision trees 75
BB[ ex ]-tree 189 - comparisons 45, 60, 69
binary search 152 - rational decision trees 74

codes 62 median 93
convex hull 79 merging
cost measure - many sequences 62
- logarithmic- 6 - two sequences
- unit- 5 sirriple- 60
optimal- 240
decision tree 69 multi-dimensional searching 282
D-tree 275
dynamic programming 163 path compression 292, 300
path length
element uniqueness 75 expected- 306
entropy 174, 325 - lower bounds 175
exponential and binary search - optimum- 159
184 pattern matching 171
fringe analysis 241 priority queues
- heaps 45
half-balanced tree 309 - mergable queues 213
hashing small universe 289
- chaining 118 pseudo- random 18
- expected worst case 120 pushdown automata 167
336

queues 24 - AVL- 309


- balanc ed- 187
RAM 3 - BB [ ex ] - 1 89

RASP 9 - conca tenate 213, 264


random number 17 - decisi on- 69
random ized algori thm 12, 54, 139 - delete 153, 192, 203, 264
ration al decisi on tree 73 - D-tree s 275
recurs ion - expect ed depth 306
- equati ons 36, 55 expect ed path length 306
- implem entatio n 33 - finger - 228
red-bl ack tree 206, 310 - fringe analy sis 241
runnin g time - half-b alance d- 309
- averag e case 2 - height -balan ced- 199
- worst case - insert 153, 192, 201, 208, 264
- ration al decisi on- 73
search - rebala ncing cost 195, 218, 224
- binary search 152 red-bl ack- 206, 310
- expon ential and binary - 184 search - 153, 192, 200, 208,
- interp olatio n- 155 264
select ion 94 - splay- 263
self-o rganiz ing data struct ures - split 213, 264
- linear lists 256 weigh t-bala nced- 189
- trees 263 TRIES
sortin g - compr essed- 101
- bucke tsort 81 defin ition 104
- heaps ort 45 static - 108
- lower bounds union -find proble m
decisi on trees 69 - basics 286
RAM 85 - path compr ession 301
- merge sort 59 - weigh ted union 299
- presor ted files 222
- quick sort 50 weigh ted trees
- stable - 41 - D-tree s 257
sparse tables 108, 127 - dynam ic- 249
- lower bounds on path length 175
splay tree 263
stacks 24 - near-o ptima l- 177
- optimu m- 159
trees - path length 159

- (a,bJ- 199 - splay trees 263

- algebr aic decisi on- 76


W. M. Waite, G. Goos

Compiler
Construction
1984. 196 figures. XIV, 446 pages
(Texts and Monographs in Computer Science)
ISBN 3-540-90821-8

Contents:. Introduction and Overview. - Properties of


Programming Languages. - Properties of Real and
Abstract Machines. - Abstract Program Representa-
tions. - Elements of Formal Systems. - Lexical
Analysis. - Parsing. - Attribute Grammars. -
Semantic Analysis. - Code Generation. - Assembly. -
Error Handling. - Optimization. - Implementing the
Compiler. - Appendix A: Sample Programming
Language LAX. - Appendix B: Useful Algorithms for
Directed Graph. - Bibliography. - Index.

This text, written by two leaders in the field of


compiler construction, explains to the reader how
compilers for programming languages are built. Des-
cribing the necessary tools (and how to create and use
them), the authors break the task into modules,
placing equal emphasis on the action and data aspects
of compilation. Attribute grammars are used exten-
sively to provide a uniform treatment of semantic
analysis, competent code generation and assembly.
The authors also show how intermediate representa-
tions can be chosen automatically on the basis of attri-
bute dependence. Thus semantic analysis, code gener-
Springer-Verlag ation and assembly no longer appear idiosyncratic, but
Berlin are discussed in terms of a uniform model subject to
automation. This will improve the reader's under-
Heidelberg standing of the compilation process and of the
New York decisions that must be made when designing a
Tokyo compiler.
D.Gries

The Science of
Programming
2nd printing. 1983. XV, 366 pages
(Texts and Monographs in Computer Science)
ISBN 3-S40-90641-X

Contents: Why Use Logic? Why Prove


Programs Correct? - Propositions and Predica-
tes. - The Semantics of a Small Language. - The
Development of Programs. - Appendices 1-4.-
Answers to Exercises. - References. - Index.

This is the first text to discuss the theory and


principles of computer programming on the basis
of the idea that a proof of correctness and a pro-
gram should be developed hand in hand. It is
built around the method first proposed by Edsger
W. Dijkstra in his monograph The discipline of
Programming (1976), involving a "calculus for
the derivation of programs." Directing his mate-
rials to the computer programmer with at least
one year of experience, Gries presents explicit
principles behind program development, and
then leads the reader through programs using
those principles. Propositions and predicate cal-
Springer-Verlag culus are presented as a tool for the programmer,
Berlin rather than simply an object of study. The reader
Heidelberg should come away with a fresh outlook on pro-
New York gramming theory and practice, and assurance to
Tokyo develop correct programs effectively.

You might also like