Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcconnell
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcconnell
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcconnell
Analysis Of Algorithms An Active Learning Approach 1st Edition Jeffrey J Mcconnell
1. Analysis Of Algorithms An Active Learning
Approach 1st Edition Jeffrey J Mcconnell
download
https://ebookbell.com/product/analysis-of-algorithms-an-active-
learning-approach-1st-edition-jeffrey-j-mcconnell-979596
Explore and download more ebooks at ebookbell.com
2. Here are some recommended products that we believe you will be
interested in. You can click the link to download.
An Introduction To The Analysis Of Algorithms 2nd Edition Robert
Sedgewick
https://ebookbell.com/product/an-introduction-to-the-analysis-of-
algorithms-2nd-edition-robert-sedgewick-58328550
An Introduction To The Analysis Of Algorithms 3rd Ed Soltyskulinicz
https://ebookbell.com/product/an-introduction-to-the-analysis-of-
algorithms-3rd-ed-soltyskulinicz-22034734
An Introduction To The Analysis Of Algorithms 2nd Michael Soltys
https://ebookbell.com/product/an-introduction-to-the-analysis-of-
algorithms-2nd-michael-soltys-2623346
An Introduction To The Analysis Of Algorithms 2nd Edition Michael
Soltys
https://ebookbell.com/product/an-introduction-to-the-analysis-of-
algorithms-2nd-edition-michael-soltys-4158962
3. An Introduction To The Analysis Of Algorithms Second Edition Robert
Sedgewick Philippe Flajolet
https://ebookbell.com/product/an-introduction-to-the-analysis-of-
algorithms-second-edition-robert-sedgewick-philippe-flajolet-57063242
An Elementary Approach To Design And Analysis Of Algorithms Lekh Raj
Vermani
https://ebookbell.com/product/an-elementary-approach-to-design-and-
analysis-of-algorithms-lekh-raj-vermani-22188630
Guide To Sidechannel Analysis Of Embedded Systems An Efficient
Algorithmic Approach Maamar Ouladj Sylvain Guilley
https://ebookbell.com/product/guide-to-sidechannel-analysis-of-
embedded-systems-an-efficient-algorithmic-approach-maamar-ouladj-
sylvain-guilley-33727206
Algorithmic Aspects Of Analysis Prediction And Control In Science And
Engineering An Approach Based On Symmetry And Similarity 1st Edition
Jaime Nava
https://ebookbell.com/product/algorithmic-aspects-of-analysis-
prediction-and-control-in-science-and-engineering-an-approach-based-
on-symmetry-and-similarity-1st-edition-jaime-nava-4935460
Analysis Of Algorithms Jeffrey Mcconnell
https://ebookbell.com/product/analysis-of-algorithms-jeffrey-
mcconnell-23644508
10. P r e f a c e
he two major goals of this book are to raise awareness of the impact
that algorithms can have on the efficiency of a program and to
develop the skills necessary to analyze any algorithms that are used in
programs. In looking at many commercial products today, it appears that some
software designers are unconcerned about space and time efficiency. If a pro-
gram takes too much space, they expect that the user will buy more memory.
If a program takes too long, they expect that the user will buy a faster com-
puter.
There are limits, however, on how fast computers can ever become because
there are limits on how fast electrons can travel down "wires," how fast light
can travel along fiber optic cables, and how fast the circuits that do the calcula-
tions can switch. There are other limits on computation that go beyond the
speed of the computer and are directly related to the complexity of the prob-
lems being solved. There are some problems for which the fastest algorithm
known will not complete execution in our lifetime. Since these are important
problems, algorithms are needed that provide approximate answers.
In the early 1980s, computer architecture severely limited the amount of
speed and space on a computer. Some computers of that time frequently lim-
ited programs and their data to 64K of memory, where today's personal com-
puters regularly come equipped with more than 1,000 times that amount.
Though today's software is much more complex than that in the 1980s and
today's computers are much more capable, these changes do not mean we
can ignore efficiency in our program design. Some project specifications will
include time and space limitations on the final software that may force pro-
grammers to look for places to save memory and increase speed.The com-
T
11. vi P R E F A C E
pact size of personal digital assistants (PDAs) also limits the size and speed of
software.
Pedagogy
What I hear, I forget.
What I see, I remember.
What I do, I understand.
—Confucius
The material in this book is presented with the expectation that it can be read
independently or used as part of a course that incorporates an active and coop-
erative learning methodology. To accomplish this, the chapters are clear and
complete so as to be easy to understand and to encourage readers to prepare by
reading before group meetings. All chapters include study suggestions. Many
include additional data sets that the reader can use to hand-execute the algo-
rithms for increased understanding of them. The results of the algorithms
applied to this additional data are presented in Appendix C. Each section has a
number of exercises that include simple tracing of the algorithm to more com-
plex proof-based exercises.The reader should be able to work the exercises in
each chapter.They can, in connection with a course, be assigned as homework
or can be used as in-class assignments for students to work individually or in
small groups.An instructor's manual that provides background on how to teach
this material using active and cooperative learning as well as giving exercise
solutions is available. Chapters 2, 3, 5, 6, and 9 include programming exercises.
These programming projects encourage readers to implement and test the
algorithms from the chapter, and then compare actual algorithm results with
the theoretical analysis in the book.
Active learning is based on the premise that people learn better and retain
information longer when they are participants in the learning process. To
achieve that, students must be given the opportunity to do more that just listen
to the professor during class. This can best be accomplished in an analysis of
algorithms course by the professor giving a short introductory lecture on the
material, and then having students work problems while the instructor circu-
lates around the room answering questions that this application of the material
raises.
12. P R E F A C E vii
Cooperative work gives students an opportunity to answer simple questions
that others in their group have and allows the professor to deal with bigger
questions that have stumped an entire group. In this way, students have a
greater opportunity to ask questions and have their concerns addressed in a
timely manner. It is important that the professor observe group work to make
sure that group-wide misconceptions are not reinforced.An additional way for
the professor to identify and correct misunderstandings is to have groups regu-
larly submit exercise answers for comments or grading.
To support student preparation and learning, each chapter includes the pre-
requisites needed, and the goals or skills that students should have on comple-
tion, as well as suggestions for studying the material.
Algorithms
Since the analysis of algorithms is independent of the computer or program-
ming language used, algorithms are given in pseudo-code. These algorithms
are readily understandable by anyone who knows the concepts of conditional
statements (for example, IF and CASE/SWITCH), loops (for example, FOR
and WHILE), and recursion.
Course Use
One way that this material could be covered in a one-semester course is by
using the following approximate schedule:
Chapters 2, 4, and 5 are not likely to need a full week, which will provide time
for an introduction to the course, an explanation of the active and cooperative
learning pedagogy, and hour examinations. Depending on the background of
the students, Chapter 1 may be covered more quickly as well.
Chapter 1 2 weeks
Chapter 2 1 week
Chapter 3 2 weeks
Chapter 4 1 week
Chapter 5 1 week
Chapter 6 2 weeks
Chapter 7 2 weeks
Chapter 8 1 week
Chapter 9 2 weeks
13. viii P R E F A C E
Acknowledgements
I would like to acknowledge all those who helped in the development of this
book. First, I would like to thank the students in my “Automata and Algo-
rithms” course (Spring 1997, Spring 1998, Spring 1999, Spring 2000, and Fall
2000) for all of their comments on earlier versions of this material.
The reviews that Jones and Bartlett Publishers obtained about the manu-
script were most helpful and produced some good additions and clarifications.
I would like to thank Douglas Campbell (Brigham Young University), Nancy
Kinnersley (University of Kansas), and Kirk Pruhs (University of Pittsburgh)
for their reviews.
At Jones and Bartlett, I would like to thank my editors Amy Rose and
Michael Stranz, and production assistant Tara McCormick for their support of
this book. I am especially grateful to Amy for remembering a brief conversa-
tion about this project from a few years ago. Her memory and efforts are
appreciated very much. I would also like to thank NancyYoung for her copy-
editing and Brooke Albright for her proofreading. Any errors that remain are
solely the author’s responsibility.
Lastly, I am grateful to Fred Dansereau for his support and suggestions dur-
ing the many stages of this book, and to Barney for the wonderful diversions
that only a dog can provide.
14. C o n t e n t s
Preface v
Chapter 1 Analysis Basics 1
1.1 What is Analysis? 3
1.1.1 Input Classes 7
1.1.2 Space Complexity 9
1.1.3 Exercises 10
1.2 What to Count and Consider 10
1.2.1 Cases to Consider 11
Best Case 11
Worst Case 12
Average Case 12
1.2.2 Exercises 13
1.3 Mathematical Background 13
1.3.1 Logarithms 14
1.3.2 Binary Trees 15
1.3.3 Probabilities 15
1.3.4 Summations 16
1.3.5 Exercises 18
1.4 Rates of Growth 20
1.4.1 Classification of Growth 22
Big Omega 22
Big Oh 22
Big Theta 23
Finding Big Oh 23
Notation 23
1.4.2 Exercises 23
1.5 Divide and Conquer Algorithms 24
Recursive Algorithm Efficiency 26
1.5.1 Tournament Method 27
1.5.2 Lower Bounds 28
1.5.3 Exercises 31
15. x C O N T E N T S
1.6 Recurrence Relations 32
1.6.1 Exercises 37
1.7 Analyzing Programs 38
Chapter 2 Searching and Selection Algorithms 41
2.1 Sequential Search 43
2.1.1 Worst-Case Analysis 44
2.1.2 Average-Case Analysis 44
2.1.3 Exercises 46
2.2 Binary Search 46
2.2.1 Worst-Case Analysis 48
2.2.2 Average-Case Analysis 49
2.2.3 Exercises 52
2.3 Selection 53
2.3.1 Exercises 55
2.4 Programming Exercise 55
Chapter 3 Sorting Algorithms 57
3.1 Insertion Sort 59
3.1.1 Worst-Case Analysis 60
3.1.2 Average-Case Analysis 60
3.1.3 Exercises 62
3.2 Bubble Sort 63
3.2.1 Best-Case Analysis 64
3.2.2 Worst-Case Analysis 64
3.2.3 Average-Case Analysis 65
3.2.4 Exercises 67
3.3 Shellsort 68
3.3.1 Algorithm Analysis 70
3.3.2 The Effect of the Increment 71
3.3.3 Exercises 72
3.4 Radix Sort 73
3.4.1 Analysis 74
3.4.2 Exercises 76
3.5 Heapsort 77
FixHeap 78
Constructing the Heap 79
Final Algorithm 80
16. C O N T E N T S xi
3.5.1 Worst-Case Analysis 80
3.5.2 Average-Case Analysis 82
3.5.3 Exercises 83
3.6 Merge Sort 83
3.6.1 MergeLists Analysis 85
3.6.2 MergeSort Analysis 86
3.6.3 Exercises 88
3.7 Quicksort 89
Splitting the List 90
3.7.1 Worst-Case Analysis 91
3.7.2 Average-Case Analysis 91
3.7.3 Exercises 94
3.8 External Polyphase Merge Sort 95
3.8.1 Number of Comparisons in Run Construction 99
3.8.2 Number of Comparisons in Run Merge 99
3.8.3 Number of Block Reads 100
3.8.4 Exercises 100
3.9 Additional Exercises 100
3.10 Programming Exercises 102
Chapter 4 Numeric Algorithms 105
4.1 Calculating Polynomials 107
4.1.1 Horner’s Method 108
4.1.2 Preprocessed Coefficients 108
4.1.3 Exercises 111
4.2 Matrix Multiplication 112
4.2.1 Winograd’s Matrix Multiplication 113
Analysis of Winograd’s Algorithm 114
4.2.2 Strassen’s Matrix Multiplication 115
4.2.3 Exercises 116
4.3 Linear Equations 116
4.3.1 Gauss-Jordan Method 117
4.3.2 Exercises 119
Chapter 5 Matching Algorithms 121
5.1 String Matching 122
5.1.1 Finite Automata 124
5.1.2 Knuth-Morris-Pratt Algorithm 125
Analysis of Knuth-Morris-Pratt 127
17. xii C O N T E N T S
5.1.3 Boyer-Moore Algorithm 128
The Match Algorithm 129
The Slide Array 130
The Jump Array 132
Analysis 135
5.1.4 Exercises 135
5.2 Approximate String Matching 136
5.2.1 Analysis 138
5.2.2 Exercises 139
5.3 Programming Exercises 139
Chapter 6 Graph Algorithms 141
6.1 Graph Background and Terminology 144
6.1.1 Terminology 145
6.1.2 Exercises 146
6.2 Data Structure Methods for Graphs 147
6.2.1 The Adjacency Matrix 148
6.2.2 The Adjacency List 149
6.2.3 Exercises 149
6.3 Depth-First and Breadth-First Traversal Algorithms 150
6.3.1 Depth-First Traversal 150
6.3.2 Breadth-First Traversal 151
6.3.3 Traversal Analysis 153
6.3.4 Exercises 154
6.4 Minimum Spanning Tree Algorithm 155
6.4.1 The Dijkstra-Prim Algorithm 155
6.4.2 The Kruskal Algorithm 159
6.4.3 Exercises 162
6.5 Shortest-Path Algorithm 163
6.5.1 Dijkstra’s Algorithm 164
6.5.2 Exercises 167
6.6 Biconnected Component Algorithm 168
6.6.1 Exercises 171
6.7 Partitioning Sets 172
6.8 Programming Exercises 174
18. C O N T E N T S xiii
Chapter 7 Parallel Algorithms 177
7.1 Parallelism Introduction 178
7.1.1 Computer System Categories 179
Single Instruction Single Data 179
Single Instruction Multiple Data 179
Multiple Instruction Single Data 179
Multiple Instruction Multiple Data 180
7.1.2 Parallel Architectures 180
Loosely versus Tightly Coupled Machines 180
Processor Communication 181
7.1.3 Principles for Parallelism Analysis 182
7.1.4 Exercises 183
7.2 The PRAM Model 183
7.2.1 Exercises 185
7.3 Simple Parallel Operations 185
7.3.1 Broadcasting Data in a CREW PRAM Model 186
7.3.2 Broadcasting Data in a EREW PRAM Model 186
7.3.3 Finding the Maximum Value in a List 187
7.3.4 Exercises 189
7.4 Parallel Searching 189
7.4.1 Exercises 191
7.5 Parallel Sorting 191
7.5.1 Linear Network Sort 191
7.5.2 Odd-Even Swap Sort 195
7.5.3 Other Parallel Sorts 196
7.5.4 Exercises 197
7.6 Parallel Numerical Algorithms 198
7.6.1 Matrix Multiplication on a Parallel Mesh 198
Analysis 203
7.6.2 Matrix Multiplication in a CRCW PRAM Model 204
Analysis 204
7.6.3 Solving Systems of Linear Equations with an SIMD
Algorithm 205
7.6.4 Exercises 206
7.7 Parallel Graph Algorithms 207
7.7.1 Shortest-Path Parallel Algorithm 207
7.7.2 Minimum Spanning Tree Parallel Algorithm 209
Analysis 210
7.7.3 Exercises 211
19. xiv C O N T E N T S
Chapter 8 Nondeterministic Algorithms 213
8.1 What is NP? 214
8.1.1 Problem Reductions 217
8.1.2 NP-Complete Problems 218
8.2 Typical NP Problems 220
8.2.1 Graph Coloring 220
8.2.2 Bin Packing 221
8.2.3 Backpack Problem 222
8.2.4 Subset Sum Problem 222
8.2.5 CNF-Satisfiability Problem 222
8.2.6 Job Scheduling Problem 223
8.2.7 Exercises 223
8.3 What Makes Something NP? 224
8.3.1 Is P = NP? 225
8.3.2 Exercises 226
8.4 Testing Possible Solutions 226
8.4.1 Job Scheduling 227
8.4.2 Graph Coloring 228
8.4.3 Exercises 229
Chapter 9 Other Algorithmic Techniques 231
9.1 Greedy Approximation Algorithms 232
9.1.1 Traveling Salesperson Approximations 233
9.1.2 Bin Packing Approximations 235
9.1.3 Backpack Approximation 236
9.1.4 Subset Sum Approximation 236
9.1.5 Graph Coloring Approximation 238
9.1.6 Exercises 239
9.2 Probabilistic Algorithms 240
9.2.1 Numerical Probabilistic Algorithms 240
Buffon’s Needle 241
Monte Carlo Integration 242
Probabilistic Counting 243
9.2.2 Monte Carlo Algorithms 244
Majority Element 245
Monte Carlo Prime Testing 246
9.2.3 Las Vegas Algorithms 246
9.2.4 Sherwood Algorithms 249
20. C O N T E N T S xv
9.2.5 Probabilistic Algorithm Comparison 250
9.2.6 Exercises 251
9.3 Dynamic Programming 252
9.3.1 Array-Based Methods 252
9.3.2 Dynamic Matrix Multiplication 255
9.3.3 Exercises 257
9.4 Programming Exercises 258
Appendix A Random Number Table 259
Appendix B Pseudorandom Number Generation 261
Appendix C Results of Chapter Study Suggestion 265
Appendix D References 279
Index 285
22. C H A P T E R
1
Analysis Basics
PREREQUISITES
Before beginning this chapter, you should be able to
• Read and create algorithms
• Read and create recursive algorithms
• Identify comparison and arithmetic operations
• Use basic algebra
GOALS
At the end of this chapter you should be able to
• Describe how to analyze an algorithm
• Explain how to choose the operations that are counted and why others are
not
• Explain how to do a best-case, worst-case, and average-case analysis
• Work with logarithms, probabilities, and summations
• Describe θ( f ), Ω( f ), O( f ), growth rate, and algorithm order
• Use a decision tree to determine a lower bound on complexity
• Convert a simple recurrence relation into its closed form
STUDY SUGGESTIONS
As you are working through the chapter, you should rework the examples to
make sure you understand them. Additionally, you should try to answer any
questions before reading on. A hint or the answer to the question is in the sen-
tences following it.
23. 2 A N A L Y S I S B A S I C S
here are many algorithms that can solve a given problem. They will
have different characteristics that will determine how efficiently each
will operate. When we analyze an algorithm, we first have to show
that the algorithm does properly solve the problem because if it doesn’t, its effi-
ciency is not important. Next, we look at how efficiently it solves the prob-
lem. This chapter sets the groundwork for the analysis and comparison of
more complex algorithms.
Analyzing an algorithm determines the amount of “time” that algorithm
takes to execute. This is not really a number of seconds or any other clock
measurement but rather an approximation of the number of operations that an
algorithm performs. The number of operations is related to the execution
time, so we will sometimes use the word time to describe an algorithm’s com-
putational complexity. The actual number of seconds it takes an algorithm to
execute on a computer is not useful in our analysis because we are concerned
with the relative efficiency of algorithms that solve a particular problem. You
should also see that the actual execution time is not a good measure of algo-
rithm efficiency because an algorithm does not get “better” just because we
move it to a faster computer or “worse” because we move it to a slower one.
The actual number of operations done for some specific size of input data
set is not very interesting nor does it tell us very much. Instead, our analysis
will determine an equation that relates the number of operations that a partic-
ular algorithm does to the size of the input. We can then compare two algo-
rithms by comparing the rate at which their equations grow. The growth rate
is critical because there are instances where algorithm A may take fewer opera-
tions than algorithm B when the input size is small, but many more when the
input size gets large.
In a very general sense, algorithms can be classified as either repetitive or
recursive. Repetitive algorithms have loops and conditional statements as their
basis, and so their analysis will entail determining the work done in the loop
and how many times the loop executes. Recursive algorithms solve a large
problem by breaking it into pieces and then applying the algorithm to each of
the pieces. These are sometimes called divide and conquer algorithms and
provide a great deal of power in solving problems. The process of solving a
large problem by breaking it up into smaller pieces can produce an algorithm
that is small, straightforward, and simple to understand. Analyzing a recursive
T
24. 1 . 1 W H A T I S A N A L Y S I S ? 3
algorithm will entail determining the amount of work done to produce the
smaller pieces and then putting their individual solutions together to get the
solution to the whole problem. Combining this information with the number
of the smaller pieces and their sizes, we can produce a recurrence relation for
the algorithm. This recurrence relation can then be converted into a closed
form that can be compared with other equations.
We begin this chapter by describing what analysis is and why we do it. We
then look at what operations will be considered and what categories of analysis
we will do. Because mathematics is critical to our analysis, the next few sec-
tions explore the important mathematical concepts and properties used to ana-
lyze iterative and recursive algorithms.
1.1 WHAT IS ANALYSIS?
The analysis of an algorithm provides background information that gives us a
general idea of how long an algorithm will take for a given problem set. For
each algorithm considered, we will come up with an estimate of how long it
will take to solve a problem that has a set of N input values. So, for example,
we might determine how many comparisons a sorting algorithm does to put a
list of N values into ascending order, or we might determine how many arith-
metic operations it takes to multiply two matrices of size N × N.
There are a number of algorithms that will solve a problem. Studying the
analysis of algorithms gives us the tools to choose between algorithms. For
example, consider the following two algorithms to find the largest of four
values:
largest = a
if b > largest then
largest = b
end if
if c > largest then
largest = c
end if
if d > largest then
largest = d
end if
return largest
25. 4 A N A L Y S I S B A S I C S
if a > b then
if a > c then
if a > d then
return a
else
return d
end if
else
if c > d then
return c
else
return d
end if
end if
else
if b > c then
if b > d then
return b
else
return d
end if
else
if c > d then
return c
else
return d
end if
end if
end if
If you examine these two algorithms, you will see that each one will do
exactly three comparisons to find the answer. Even though the first is easier
for us to read and understand, they are both of the same level of complexity for
a computer to execute. In terms of time, these two algorithms are the same,
but in terms of space, the first needs more because of the temporary variable
called largest. This extra space is not significant if we are comparing num-
bers or characters, but it may be with other types of data. In many modern
programming languages, we can define comparison operators for large and
complex objects or records. For those cases, the amount of space needed for
the temporary variable could be quite significant. When we are interested in
the efficiency of algorithms, we will primarily be concerned with time issues,
but when space may be an issue, it will also be discussed.
26. 1 . 1 W H A T I S A N A L Y S I S ? 5
The purpose of determining these values is to then use them to compare
how efficiently two different algorithms solve a problem. For this reason, we
will never compare a sorting algorithm with a matrix multiplication algorithm,
but rather we will compare two different sorting algorithms to each other.
The purpose of analysis of algorithms is not to give a formula that will tell
us exactly how many seconds or computer cycles a particular algorithm will
take. This is not useful information because we would then need to talk about
the type of computer, whether it has one or many users at a time, what proces-
sor it has, how fast its clock is, whether it has a complex or reduced instruction
set processor chip, and how well the compiler optimizes the executable code.
All of those will have an impact on how fast a program for an algorithm will
run. To talk about analysis in those terms would mean that by moving a pro-
gram to a faster computer, the algorithm would become better because it now
completes its job faster. That’s not true, so, we do our analysis without regard
to any specific computer.
In the case of a small or simple routine it might be possible to count the
exact number of operations performed as a function of N. Most of the time,
however, this will not be useful. In fact, we will see in Section 1.4 that the dif-
ference between an algorithm that does N + 5 operations and one that does
N + 250 operations becomes meaningless as N gets very large. As an introduc-
tion to analysis of algorithms, however, we will count the exact number of
operations for this first section.
Another reason we do not try to count every operation that is performed by
an algorithm is that we could fine-tune an algorithm extensively but not really
make much of a difference in its overall performance. For instance, let’s say
that we have an algorithm that counts the number of different characters in a
file. An algorithm for that might look like the following:
for all 256 characters do
assign zero to the counter
end for
while there are more characters in the file do
get the next character
increment the counter for this character by one
end while
When we look at this algorithm, we see that there are 256 passes for the initial-
ization loop. If there are N characters in the input file, there are N passes for
27. 6 A N A L Y S I S B A S I C S
the second loop. So the question becomes What do we count? In a for loop,
we have the initialization of the loop variable and then for each pass of the
loop, a check that the loop variable is within the bounds, the execution of
the loop, and the increment of the loop variable. This means that the initial-
ization loop does a set of 257 assignments (1 for the loop variable and 256 for
the counters), 256 increments of the loop variable, and 257 checks that this
variable is within the loop bounds (the extra one is when the loop stops). For
the second loop, we will need to do a check of the condition N + 1 times (the
+ 1 is for the last check when the file is empty), and we will increment N
counters. The total number of operations is
Increments N + 256
Assignments 257
Conditional checks N + 258
So, if we have 500 characters in the file, the algorithm will do a total of 1771
operations, of which 770 are associated with the initialization (43%). Now
consider what happens as the value of N gets large. If we have a file with
50,000 characters, the algorithm will do a total of 100,771 operations, of
which there are still only 770 associated with the initialization (less than 1% of
the total work). The number of initialization operations has not changed, but
they become a much smaller percentage of the total as N increases.
Let’s look at this another way. Computer organization information shows
that copying large blocks of data is as quick as an assignment. We could initial-
ize the first 16 counters to zero and then copy this block 15 times to fill in the
rest of the counters. This would mean a reduction in the initialization pass
down to 33 conditional checks, 33 assignments, and 31 increments. This
reduces the initialization operations to 97 from 770, a saving of 87%. When
we consider this relative to the work of processing the file of 50,000 characters,
we have saved less than 0.7% (100,098 vs. 100,771). Notice we could save
even more time if we did all of these initializations without loops, because only
31 pure assignments would be needed, but this would only save an additional
0.07%. It’s not worth the effort.
We see that the importance of the initialization is small relative to the overall
execution of this algorithm. In analysis terms, the cost of the initialization
becomes meaningless as the number of input values increases.
The earliest work in analysis of algorithms determined the computability of
an algorithm on a Turing machine. The analysis would count the number of
28. 1 . 1 W H A T I S A N A L Y S I S ? 7
times that the transition function needed to be applied to solve the problem.
An analysis of the space needs of an algorithm would count how many cells of
a Turing machine tape would be needed to solve the problem. This sort of
analysis is a valid determination of the relative speed of two algorithms, but it is
also time consuming and difficult. To do this sort of analysis, you would first
need to determine the process used by the transition functions of the Turing
machine that carries out the algorithm. Then you would need to determine
how long it executes—a very tedious process.
An equally valid way to analyze an algorithm, and the one we will use, is to
consider the algorithm as it is written in a higher-level language. This language
can be Pascal, C, C++, Java, or a general pseudocode. The specifics don’t really
matter as long as the language can express the major control structures common
to algorithms. This means that any language that has a looping mechanism, like
a for or while, and a selection mechanism, like an if, case, or switch, will
serve our needs. Because we will be concerned with just one algorithm at a
time, we will rarely write more than a single function or code fragment, and so
the power of many of the languages mentioned will not even come into play.
For this reason, a generic pseudocode will be used in this book.
Some languages use short-circuit evaluation when determining the value of
a Boolean expression. This means that in the expression A and B, the term B
will only be evaluated if A is true, because if A is false, the result will be false no
matter what B is. Likewise, for A or B, B will not be evaluated if A is true. As
we will see, counting a compound expression as one or two comparisons will
not be significant. So, once we are past the basics in this chapter, we will not
worry about short-circuited evaluations.
■ 1.1.1 Input Classes
Input plays an important role in analyzing algorithms because it is the input
that determines what the path of execution through an algorithm will be. For
example, if we are interested in finding the largest value in a list of N numbers,
we can use the following algorithm:
largest = list[1]
for i = 2 to N do
if (list[i] > largest) then
largest = list[i]
end if
end for
29. 8 A N A L Y S I S B A S I C S
We can see that if the list is in decreasing order, there will only be one
assignment done before the loop starts. If the list is in increasing order, how-
ever, there will be N assignments (one before the loop starts and N 1 inside
the loop). Our analysis must consider more than one possible set of input,
because if we only look at one set of input, it may be the set that is solved the
fastest (or slowest). This will give us a false impression of the algorithm.
Instead we consider all types of input sets.
When looking at the input, we will try to break up all the different input
sets into classes based on how the algorithm behaves on each set. This helps to
reduce the number of possibilities that we will need to consider. For example,
if we use our largest-element algorithm with a list of 10 distinct numbers,
there are 10!, or 3,628,800, different ways that those numbers could be
arranged. We saw that if the largest is first, there is only one assignment done,
so we can take the 362,880 input sets that have the largest value first and put
them into one class. If the largest value is second, the algorithm will do
exactly two assignments. There are another 362,880 inputs sets with the largest
value second, and they can all be put into another class. When looking at this
algorithm, we can see that there will be between one and N assignments. We
would, therefore, create N different classes for the input sets based on the num-
ber of assignments done. As you will see, we will not necessarily care about
listing or describing all of the input sets in each class, but we will need to know
how many classes there are and how much work is done for each.
The number of possible inputs can get very large as N increases. For
instance, if we are interested in a list of 10 distinct numbers, there are
3,628,800 different orderings of these 10 numbers. It would be impossible to
look at all of these different possibilities. We instead break these possible lists
into classes based on what the algorithm is going to do. For the above algo-
rithm, the breakdown could be based on where the largest value is stored and
would result in 10 different classes. For a different algorithm, for example, one
that finds the largest and smallest values, our breakdown could be based on
where the largest and smallest are stored and would result in 90 different
classes. Once we have identified the classes, we can look at how an algorithm
would behave on one input from each of the classes. If the classes are properly
chosen, all input sets in the class will have the same number of operations, and
all of the classes are likely to have different results.
30. 1 . 1 W H A T I S A N A L Y S I S ? 9
■ 1.1.2 Space Complexity
Most of what we will be discussing is going to be how efficient various algo-
rithms are in terms of time, but some forms of analysis could be done based on
how much space an algorithm needs to complete its task. This space complex-
ity analysis was critical in the early days of computing when storage space on a
computer (both internal and external) was limited. When considering space
complexity, algorithms are divided into those that need extra space to do their
work and those that work in place. It was not unusual for programmers to
choose an algorithm that was slower just because it worked in place, because
there was not enough extra memory for a faster algorithm.
Computer memory was at a premium, so another form of space analysis
would examine all of the data being stored to see if there were more efficient
ways to store it. For example, suppose we are storing a real number that has only
one place of precision after the decimal point and ranges between 10 and +10.
If we store this as a real number, most computers will use between 4 and 8 bytes
of memory, but if we first multiply the value by 10, we can then store this as an
integer between 100 and +100. This needs only 1 byte, a savings of 3 to 7
bytes. A program that stores 1000 of these values can save 3000 to 7000 bytes.
When you consider that computers as recently as the early 1980s might have
only had 65,536 bytes of memory, these savings are significant. It is this need to
save space on these computers along with the longevity of working computer
programs that lead to all of theY2K bug problems. When you have a program
that works with a lot of dates, you use half the space for the year by storing it as
99 instead of 1999. Also, people writing programs in the 1980s and earlier never
really expected their programs to still be in use in 2000.
Looking at software that is on the market today, it is easy to see that space
analysis is not being done. Programs, even simple ones, regularly quote space
needs in a number of megabytes. Software companies seem to feel that making
their software space efficient is not a consideration because customers who
don’t have enough computer memory can just go out and buy another 32
megabytes (or more) of memory to run the program or a bigger hard disk to
store it. This attitude drives computers into obsolescence long before they
really are obsolete.
A recent change to this is the popularity of personal digital assistants (PDAs).
These small handheld devices typically have between 2 and 8 megabytes for
31. 10 A N A L Y S I S B A S I C S
both their data and software. In this case, developing small programs that store
data compactly is not only important, it is critical.
1.1.3
1. Write an algorithm in pseudocode to count the number of capital letters in
a file of text. How many comparisons does it do? What is the fewest num-
ber of increments it might do? What is the largest number? (Use N for the
number of characters in the file when writing your answer.)
2. There is a set of numbers stored in a file, but we don’t know how many it
contains. Write an algorithm in pseudocode to calculate the average of the
numbers stored in this file. What type of operations does your algorithm
do? How many of each of these operations does your algorithm do?
3. Write an algorithm, without using compound conditional expressions, that
takes in three integers and determines if they are all distinct. On average,
how many comparisons does your algorithm do? Remember to examine all
input classes.
4. Write an algorithm that takes in three distinct integers and determines the
largest of the three. What are the possible input classes that would have to
be considered when analyzing this algorithm? Which one causes your algo-
rithm to do the most comparisons? Which one causes the least? (If there is
no difference between the most and least, rewrite the algorithm with simple
conditionals and without using temporary variables so that the best case gets
done faster than the worst case.)
5. Write an algorithm to find the second largest element in a list of N values.
How many comparisons does your algorithm do in the worst case? (Later,
we will see an algorithm that will do this with about N comparisons.)
1.2 WHAT TO COUNT AND CONSIDER
Deciding what to count involves two steps. The first is choosing the significant
operation or operations, and the second is deciding which of those operations
are integral to the algorithm and which are overhead or bookkeeping.
There are two classes of operations that are typically chosen for the signifi-
cant operation: comparison or arithmetic. The comparison operators are all
considered equivalent and are counted in algorithms such as searching and
1.1.3 EXERCISES
■
32. 1 . 2 W H A T T O C O U N T A N D C O N S I D E R 11
sorting. In these algorithms, the important task being done is the comparison
of two values to determine, when searching, if the value is the one we are
looking for or, when sorting, if the values are out of order. Comparison oper-
ations include equal, not equal, less than, greater than, less than or equal, and
greater than or equal.
We will count arithmetic operators in two groups: additive and multiplica-
tive. Additive operators (usually called additions for short) include addition,
subtraction, increment, and decrement. Multiplicative operators (usually
called multiplications for short) include multiplication, division, and modulus.
These two groups are counted separately because multiplications are consid-
ered to take longer than additions. In fact, some algorithms are viewed more
favorably if they reduce the number of multiplications even if that means a sim-
ilar increase in the number of additions. In algorithms beyond the scope of
this book, logarithms and geometric functions that are used in algorithms
would be another group even more time consuming than multiplications
because those are frequently calculated by a computer through a power series.
A special case is integer multiplication or division by a power of 2. This
operation can be reduced to a shift operation, which is considered as fast as an
addition. There will, however, be very few cases when this will be significant,
because multiplication or division by 2 is commonly found in divide and con-
quer algorithms that frequently have comparison as their significant operation.
■ 1.2.1 Cases to Consider
Choosing what input to consider when analyzing an algorithm can have a sig-
nificant impact on how an algorithm will perform. If the input list is already
sorted, some sorting algorithms will perform very well, but other sorting algo-
rithms may perform very poorly. The opposite may be true if the list is ran-
domly arranged instead of sorted. Because of this, we will not consider just
one input set when we analyze an algorithm. In fact, we will actually look for
those input sets that allow an algorithm to perform the most quickly and the
most slowly. We will also consider an overall average performance of the algo-
rithm as well.
Best Case
As its name indicates, the best case for an algorithm is the input that requires
the algorithm to take the shortest time. This input is the combination of values
33. 12 A N A L Y S I S B A S I C S
that causes the algorithm to do the least amount of work. If we are looking at
a searching algorithm, the best case would be if the value we are searching for
(commonly called the target or key) was the value stored in the first location
that the search algorithm would check. This would then require only one
comparison no matter how complex the algorithm is. Notice that for search-
ing through a list of values, no matter how large, the best case will result in a
constant time of 1. Because the best case for an algorithm will usually be a
very small and frequently constant value, we will not do a best-case analysis
very frequently.
Worst Case
Worst case is an important analysis because it gives us an idea of the most time
an algorithm will ever take. Worst-case analysis requires that we identify the
input values that cause an algorithm to do the most work. For searching algo-
rithms, the worst case is one where the value is in the last place we check or is
not in the list. This could involve comparing the key to each list value for a
total of N comparisons. The worst case gives us an upper bound on how
slowly parts of our programs may work based on our algorithm choices.
Average Case
Average-case analysis is the toughest to do because there are a lot of details
involved. The basic process begins by determining the number of different
groups into which all possible input sets can be divided. The second step is to
determine the probability that the input will come from each of these groups.
The third step is to determine how long the algorithm will run for each of
these groups. All of the input in each group should take the same amount of
time, and if they do not, the group must be split into two separate groups.
When all of this has been done, the average case time is given by the following
formula:
(1.1)
where n is the size of the input, m is the number of groups, pi is the probability
that the input will be from group i, and ti is the time that the algorithm takes
for input from group i.
In some cases, we will consider that each of the input groups has equal proba-
bilities. In other words, if there are five input groups, the chance the input will
be in group 1 is the same as the chance for group 2,and so on. This would mean
A n
( ) pi * ti
i=1
m
∑
=
34. 1 . 3 M A T H E M A T I C A L B A C K G R O U N D 13
that for these five groups all probabilities would be 0.2. We could calculate the
average case by the above formula,or we could note that the following simplified
formula is equivalent in the case where all groups are equally probable:
(1.2)
1.2.2
1. Write an algorithm that finds the middle, or median, value of three distinct
integers. The input for this algorithm falls into six groups; describe them.
What is the best case for your algorithm? What is the worst case? What is
the average case? (If the best and worst cases are the same, rewrite your
algorithm with simple conditionals and without temporary variables so the
best case is better than the worst case.)
2. Write an algorithm that determines if four integers are distinct. Depending
on your viewpoint, the input for this algorithm can be divided into classes
based on the structure of your algorithm or the structure of the problem.
Describe how one of these two class divisions would be set up. Using your
classes, what is the best case for your algorithm? What is the worst case?
What is the average case? (If the best and worst cases are the same, rewrite
your algorithm with simple conditionals and without temporary variables so
the best case is better than the worst case.)
3. Write an algorithm that determines, given a list of numbers and the average
or mean of those numbers, if there are more numbers above the average
than below. Describe the groups that the input would fall into for this algo-
rithm. What is the best case for your algorithm? What is the worst case?
What is the average case? (If the best and worst cases are the same, rewrite
your algorithm so it stops as soon as it knows the answer, making the best
case better than the worst case.)
1.3 MATHEMATICAL BACKGROUND
There are a few mathematical concepts that will be used through out this
book. The first of these are the floor and ceiling of a number. We say that
the floor of X (written X) is the largest integer that is less than or equal to
X. So, 2.5 would be 2 and 7.3 would be 8. We say that the ceiling
A n
( )
1
m
---
- ti
i 1
=
m
∑
=
1.2.2 EXERCISES
■
35. 14 A N A L Y S I S B A S I C S
of X (written X) is the smallest integer that is greater than or equal to X.
So, 2.5 would be 3 and 7.3 would be 7. Because we will be using
just positive numbers, you can think of the floor as truncation and the ceiling
as rounding up. For negative numbers, the effect is reversed.
The floor and ceiling will be used when we need to determine how many
times something is done, and the value depends on some fraction of the items
it is done to. For example, if we compare a set of N values in pairs, where the
first value is compared to the second, the third to the fourth, and so on, the
number of comparisons will be N / 2. If N is 10, we will do five com-
parisons of pairs and 10 / 2 = 5 = 5. If N is 11, we will still do five
comparisons of pairs and 11 / 2 = 5.5 = 5.
The factorial of the number N, written N!, is the product of all of the num-
bers between 1 and N. For example, 3! is 3 * 2 * 1, or 6, and 6! is 6 * 5 * 4 *
3 * 2 * 1, or 720. You can see that the factorial gets large very quickly. We will
look at this more closely in Section 1.4.
■ 1.3.1 Logarithms
Because logarithms will play an important role in our analysis, there are a few
properties that must be discussed. The logarithm base y of a number x is the
power of y that will produce the number x. So, the log10 45 is about 1.653
because 101.653 is 45. The base of a logarithm can be any number, but we will
typically use either base 10 or base 2 in our analysis. We will use log as short-
hand for log10 and lg as shorthand for log2.
Logarithms are a strictly increasing function. This means that given two
numbers X and Y, if X Y, logB X logB Y for all bases B. Logarithms are
one-to-one functions. This means that if logB X = logB Y, X = Y. Other
properties that are important for you to know are
(1.3)
(1.4)
(1.5)
(1.6)
(1.7)
logB1 0
=
logBB 1
=
logB X * Y
( ) logBX logBY
+
=
logBX
Y
Y * logBX
=
logAX
logBX
( )
logBA
( )
------------------
-
=
36. 1 . 3 M A T H E M A T I C A L B A C K G R O U N D 15
These properties can be combined to help simplify a function. Equation 1.7 is
a good fact to know for base conversion. Most calculators do log10 and natural
logs, but let’s say you need to know log42 75. Equation 1.7 would help you
find the answer of 1.155.
■ 1.3.2 Binary Trees
A binary tree is a structure in which each node in the tree is said to have at
most two nodes as its children, and each node has exactly one parent node.
The top node in the tree is the only one without a parent node and is called
the root of the tree. A binary tree that has N nodes has at least lg N + 1 lev-
els to the tree if the nodes are packed as tightly as possible. For example, a full
binary tree with 15 nodes has one root, two nodes on the second level, four
nodes on the third level, eight nodes on the fourth level, and our equation
gives lg 15 + 1 = 3.9 + 1 = 4. Notice, if we add one more node to this
tree, it has to start a new level and now lg 16+ 1 = 4+ 1 = 5. The largest
binary tree that has N nodes will have N levels if each node has exactly one
child (in which case the tree is actually a list).
If we number the levels of the tree, considering the root to be on level 1,
there are 2K–1 nodes on level K. A complete binary tree with J levels (num-
bered from 1 to J) is one where all of the leaves in the tree are on level J, and all
nodes on levels 1 to J 1 have exactly two children. A complete binary tree
with J levels has 2 J 1 nodes. This information will be useful in a number of
the analyses we will do. To better understand these formulas, you might want
to draw some binary trees and compare your count of the nodes with the
results of these formulas.
■ 1.3.3 Probabilities
Because we will analyze algorithms relative to their input, we may at times
need to consider the likelihood of a certain set of input. This means that we
will need to work with the probability that the input will meet some condi-
tion. The probability that something will occur is given as a number in the
range of 0 to 1, where 0 means it will never occur and 1 means it will always
occur. If we know that there are exactly 10 different possible inputs, we can
say that the probability of each of these is between 0 and 1 and that the total of
all of the individual probabilities is 1, because one of these must happen. If
there is an equal chance that any of these can occur, each will have a probabil-
ity of 0.1 (one out of 10, or 1/10).
37. 16 A N A L Y S I S B A S I C S
For most of our analyses, we will first determine how many possible situa-
tions there are and then assume that all are equally likely. If we determine that
there are N possible situations, this results in a probability of 1 / N for each of
these situations.
■ 1.3.4 Summations
We will be adding up sets of values as we analyze our algorithms. Let’s say we
have an algorithm with a loop. We notice that when the loop variable is 5, we
do 5 steps and when it is 20, we do 20 steps. We determine in general that
when the loop variable is M, we do M steps. Overall, the loop variable will
take on all values from 1 to N, so the total steps is the sum of the values from 1
through N. To easily express this, we use the equation . The expression
below the Σ represents the initial value for the summation variable, and the
value above the Σ represents the ending value. You should see how this expres-
sion corresponds to the sum we are looking for.
Once we have expressed some solution in terms of this summation notation,
we will want to simplify this so that we can make comparisons with other for-
mulas. Deciding whether or is greater would be difficult to
do by inspection, so we use the following set of standard summation formulas
to determine the actual values these summations represent.
, with C a constant expression not dependent on i (1.8)
(1.9)
(1.10)
(1.11)
(1.12)
i
i=1
N
∑
i
2
i
–
i=11
N
∑ i
2
20i
–
i=0
N
∑
C * i
i=1
N
∑ C * i
i=1
N
∑
=
i
i=C
N
∑ i C
+
( )
i=0
N–C
∑
=
i
i=C
N
∑ i i
i=0
C–1
∑
–
i=0
N
∑
=
A B
+
( )
i=1
N
∑ A B
i=1
N
∑
+
i=1
N
∑
=
N i
–
( )
i=0
N
∑ i
i=0
N
∑
=
38. 1 . 3 M A T H E M A T I C A L B A C K G R O U N D 17
Equation 1.12 just shows that adding the numbers from N down to 0 is the
same as adding the numbers from 0 up to N. In some cases, it will be easier to
solve equations if we can apply Equation 1.12.
(1.13)
(1.14)
(1.15)
Equation 1.15 is easy to remember if you consider pairing up the values.
Matching the first and last, second and second last, and so on gives you a set of
values that are all N + 1. How many of these N + 1 totals do you get? Well,
you get half of the number of values you started with before you paired them,
or N / 2. So, the result is
(1.16)
(1.17)
Equation 1.17 is easy to remember if you consider binary numbers. When
you add the powers of 2 from 0 to 10, this is the same as the binary number
11111111111. If we add 1 to this number, we get 100000000000, which is
211. But because we added 1 to it, it is 1 larger than the sum of the powers of
2 from 0 to 10, so the sum must be 211 1. If we now substitute N for 10, we
get Equation 1.17.
, for some number A (1.18)
(1.19)
1
i=1
N
∑ N
=
C
i=1
N
∑ C * N
=
i
i=1
N
∑
N N 1
+
( )
2
-----------------------
=
N
2
---
- N 1
+
( )
N N 1
+
( )
2
-----------------------
=
i
2
i=1
N
∑
N N 1
+
( ) 2N 1
+
( )
6
---------------------------------------------
-
2N
3
3N
2
N
+ +
6
-------------------------------------
-
= =
2
i
i=0
N
∑ 2
N+1
1
–
=
A
i
i=1
N
∑
A
N+1
1
–
A 1
–
--------------------
-
=
i2
i
i=1
N
∑ N 1
–
( )2
N+1
2
+
=
39. 18 A N A L Y S I S B A S I C S
(1.20)
(1.21)
When we are trying to simplify a summation equation, we can apply Equa-
tions 1.8 through 1.12 to break down the equation into simpler parts and then
apply the rest to get an equation without summations.
1.3.5
1. Typical calculators have the ability to calculate natural logs (to the base e)
and logs base 10. How would you use a calculator with just these capabili-
ties to calculate log27 59?
2. Assume that we have a fair five-sided die with the numbers 1 through 5 on
its sides. What is the probability that each of the numbers 1 through 5 will
be rolled? If we roll two of these dice, what is the range of possible totals of
the values showing on the two dice? What is the chance that each of these
totals will be rolled?
3. Assume we have a fair eight-sided die with the numbers 1, 2, 3, 3, 4, 5, 5, 5
on its sides.What is the probability that each of the numbers 1 through 5
will be rolled? If we roll two of these dice, what is the range of possible
totals of the values showing on the two dice? What is the chance that each
of the numbers in this range will be rolled?
4. You are given four dice that have numbers on their faces according to the
following lists:
d1: 1, 2, 3, 9, 10, 11
d2: 0, 1, 7, 8, 8, 9
d3: 5, 5, 6, 6, 7, 7
d4: 3, 4, 4, 5, 11, 12
For each pair of dice, compute the probability that the first die will have a
higher value showing than the second will, and vice versa. You can easily
show your results in a 4 4 matrix where the row represents one die and
1
i
--
i=1
N
∑ N
ln
=
lgi
i=1
N
∑ N lg N 1.5
–
≈
1.3.5 EXERCISES
■
40. 1 . 3 M A T H E M A T I C A L B A C K G R O U N D 19
the column represents another. (Because we assume that you will toss two
different dice, the diagonal of this matrix should be left blank because it
represents matching a die against itself.) These dice have an interesting
property—can you determine it?
5. There are five coins on the table. You choose one at random and flip it. For
each of the four cases below, what is the chance that the majority of coins
will be tails when you are done?
a. Two heads and three tails c. Four heads and one tail
b. Three heads and two tails d. One head and four tails
6. There are five coins on the table. Each coin is flipped exactly once. For
each of the four cases below, what is the chance that the majority of coins
will be tails when you are done?
a. Two heads and three tails c. Four heads and one tail
b. Three heads and two tails d. One head and four tails
7. For the following summations, give an equivalent equation without the
summation:
a.
b.
c.
d.
e.
f.
3i 7
+
( )
i=1
N
∑
i
2
2i
–
( )
i=1
N
∑
i
i=7
N
∑
2i
2
1
+
( )
i=5
N
∑
6
i
i=1
N
∑
4
i
i=7
N
∑
41. 20 A N A L Y S I S B A S I C S
1.4 RATES OF GROWTH
In analysis of algorithms, it is not important to know exactly how many opera-
tions an algorithm does. Of greater concern is the rate of increase in oper-
ations for an algorithm to solve a problem as the size of the problem increases.
This is referred to as the rate of growth of the algorithm. What happens with
small sets of input data is not as interesting as what happens when the data set
gets large.
Because we are interested in general behavior, we just look at the overall
growth rate of algorithms, not at the details. If we look closely at the graph in
Fig. 1.1, we will see some trends. The function based on x2 increases slowly at
first, but as the problem size gets larger, it begins to grow at a rapid rate. The
functions that are based on x both grow at a steady rate for the entire length of
the graph. The function based on log x seems to not grow at all, but this is
because it is actually growing at a very slow rate. The relative height of the
functions is also different when we have small values versus large ones. Con-
sider the value of the functions when x is 2. At that point, the function with
200
180
160
140
120
100
80
60
40
20
0
2 6 10 14 18 22 26 30 34 38
x2/8
3* x–2
2*log x
x + 10
■ FIGURE 1.1
Graph of four
functions
42. 1 . 4 R A T E S O F G R O W T H 21
the smallest value is x2 / 8 and the one with the largest value is x + 10. We can
see, however, that as the value of x gets large, x2 / 8 becomes and stays the
function with the largest value.
Putting all of this together means that as we analyze algorithms, we will be
interested in which rate of growth class an algorithm falls into rather than try-
ing to find out exactly how many of each operation are done by the algorithm.
When we consider the relative “size” of a function, we will do so for large val-
ues of x, not small ones.
Some of the common classes of algorithms can be seen in the chart in Fig.
1.2. In this chart, we show the value for these classes over a wide range of
input sizes. You can see that when the input is small, there is not a significant
difference in the values, but once the input value gets large, there is a big dif-
ference. This reinforces what we saw in the graph in Fig. 1.1. Because of this,
we will always consider what happens when the size of the input is large,
because small input sets can hide rather dramatic differences.
The data in Figs. 1.1 and 1.2 illustrate a second point. Because the faster-
growing functions increase at such a significant rate, they quickly dominate the
slower-growing functions. This means that if we determine that an algorithm’s
complexity is a combination of two of these classes, we will frequently ignore
all but the fastest growing of these terms. For example, if we analyze an algo-
1
2
5
10
15
20
30
40
50
60
70
80
90
100
1.0
2.0
5.0
10.0
15.0
20.0
30.0
40.0
50.0
60.0
70.0
80.0
90.0
100.0
0.0
2.0
11.6
33.2
58.6
86.4
147.2
212.9
282.2
354.4
429.0
505.8
584.3
664.4
0.0
1.0
2.3
3.3
3.9
4.3
4.9
5.3
5.6
5.9
6.1
6.3
6.5
6.6
Ig n n Ig n
n
1.0
4.0
25.0
100.0
225.0
400.0
900.0
1600.0
2500.0
3600.0
4900.0
6400.0
8100.0
10000.0
1.0
8.0
125.0
1000.0
3375.0
8000.0
27000.0
64000.0
125000.0
216000.0
343000.0
512000.0
729000.0
1000000.0
2.0
4.0
32.0
1024.0
32768.0
1048576.0
1073741824.0
1099511627776.0
1125899906842620.0
1152921504606850000.0
1180591620717410000000.0
1208925819614630000000000.0
1237940039285380000000000000.0
1267650600228230000000000000000.0
n2 n3 2n
■ FIGURE 1.2
Common algorithm
classes
43. 22 A N A L Y S I S B A S I C S
rithm and find that it does x3 30x comparisons, we will just refer to this
algorithm as growing at the rate of x3. This is because even at an input size of
just 100 the difference between x3 and x3 30x is only 0.3%. This idea is for-
malized in the next section.
■ 1.4.1 Classification of Growth
Because the rate of growth of an algorithm is important, and we have seen that
the rate of growth is dominated by the largest term in an equation, we will dis-
card the terms that grow more slowly. When we strip all of these things away,
we are left with what we call the order of the function or related algorithm. We
can then group algorithms together based on their order. We group them in
three categories—those that grow at least as fast as some function, those that
grow at the same rate, and those that grow no faster.
Big Omega
We use Ω( f ), called big omega, to represent the class of functions that grow at
least as fast as the function f. This means that for all values of n greater than
some threshold n0, all of the functions in Ω( f ) have values that are at least as
large as f. You can view Ω( f ) as setting a lower bound on a function, because
all the functions in this class will grow as fast as f or even faster. Formally, this
means that if g(x) ∈ Ω( f ), g(n) ≥ cf(n) for all n ≥ n0 (where c is a positive con-
stant).
Because we are interested in efficiency, Ω( f ) will not be of much interest to
us because Ω(n2), for example, includes all functions that grow faster than n2
including n3 and 2n.
Big Oh
At the other end of the spectrum, we have O( f ), called big oh, which repre-
sents the class of functions that grow no faster than f. This means that for all
values of n greater than some threshold n0, all of the functions in O( f ) have
values that are no greater than f. The class O( f ) has f as an upper bound, so
none of the functions in this class grow faster than f. Formally this means that
if g(x) ∈ O( f ), g(n) ≤ cf(n) for all n ≥ n0 (where c is a positive constant).
This is the class that will be of the greatest interest to us. Considering two
algorithms, we will want to know if the function categorizing the behavior of
the first is in big oh of the second. If so, we know that the second algorithm
does no better than the first in solving the problem.
44. 1 . 4 R A T E S O F G R O W T H 23
Big Theta
We use θ( f ), called big theta, to represent the class of functions that grow at the
same rate as the function f. This means that for all values of n greater than
some threshold n0, all of the functions in θ( f ) have values that are about the
same as f. Formally, this class of functions is defined as the place where big
omega and big oh overlap, so θ( f ) = Ω( f ) ∩ O( f ).
When we consider algorithms, we will be interested in finding algorithms
that might do better than the one we are considering. So, finding one that is
in big theta (in other words, is of the same complexity) is not very interesting.
We will not refer to this class very often.
Finding Big Oh
We can find if a function is in O( f ), by using the formal description above or
by using the following alternative description:
(1.22)
This means that if the limit of g(n) / f(n) is some real number less than , g is in
O( f ). With some functions, it might not be obvious that this is the case. We
can then take the derivative of f and g and apply this same limit.
Notation
Because θ( f ), Ω( f ), and O( f ) are sets, it is proper to say that a function g is an
element of these sets. The analysis literature, however, accepts that a function g
is equal to these sets as being equivalent to being a member of the set. So,
when you see g = O( f ), this really means that g ∈ O( f ).
1.4.2
1. List the following functions from highest to lowest order. If any are of the
same order, circle them on your list.
6
g O f
( )
∈ if
g n
( )
f n
( )
---------
-
n ∞
→
lim c, for some c R
*
∈
=
1.4.2 EXERCISES
■
2
n
lg lg n n
3
lg n
+
lg n n n
2
5n
3
+
– 2
n–1
n
2
n
3
n lg n
lg n
( )
2
n
n! n 3 2
⁄
( )
n
45. 24 A N A L Y S I S B A S I C S
2. For each of the following pairs of functions f (n) and g(n), either
f (n)=O(g(n)) or g(n)=O( f (n)), but not both. Determine which is the case.
a.
b.
c.
d.
e.
f.
g.
h.
1.5 DIVIDE AND CONQUER ALGORITHMS
As the introduction indicated, divide and conquer algorithms can provide a
small and powerful means to solve a problem; this section is not about how to
write such an algorithm but rather how to analyze one. When we count com-
parisons that occur in loops, we only need to determine how many compari-
sons there are inside the loop and how many times the loop is executed. This
is made more complex when a value of the outer loop influences the number
of passes of an inner loop.
When we look at divide and conquer algorithms, it is not clear how many
times a task will be done because it depends on the recursive calls and perhaps
on some preparatory and concluding work. It is usually not obvious how
many times the function will be called recursively. As an example of this, con-
sider the following generic divide and conquer algorithm:
DivideAndConquer( data, N, solution )
data a set of input values
N the number of values in the set
solution the solution to this problem
if (N ≤ SizeLimit) then
DirectSolution( data, N, solution )
else
DivideInput( data, N, smallerSets, smallerSizes, numberSmaller )
f n
( ) n
2
n
–
( ) 2 g n
( )
,
⁄ 6n
= =
f n
( ) n 2 n
+ g n
( )
, n
2
= =
f n
( ) n n n
log g n
( )
,
+ n n
= =
f n
( ) n
2
3n 4
+ + g n
( )
, n
3
= =
f n
( ) n n
log g n
( )
, n n 2
⁄
= =
f n
( ) n n
log
+ g n
( )
, n
= =
f n
( ) 2 n
log
( )
2
g n
( )
, n 1
+
log
= =
f n
( ) 4n n n
+
log g n
( )
, n
2
n
–
( ) 2
⁄
= =
46. 1 . 5 D I V I D E A N D C O N Q U E R A L G O R I T H M S 25
for i = 1 to numberSmaller do
DivideAndConquer(smallerSets[i], smallerSizes[i], smallSolution[i])
end for
CombineSolutions(smallSolution, numberSmaller, solution)
end if
This algorithm will first check to see if the problem size is small enough to
determine a solution by some simple nonrecursive algorithm (called Direct-
Solution above) and, if so, will do that. If the problem is too large, it will
first call the routine DivideInput, which will partition the input in some
fashion into a number (numberSmaller) of smaller sets of input values.
These smaller sets may be all of the same size or they may have radically differ-
ent sizes. The elements in the original input set will all be put into at least one
of the smaller sets, but values can be put in more than one. Each of these
smaller sets will have fewer elements than the original input set. The Divide-
AndConquer algorithm is then called recursively for each of these smaller
input sets, and the results from those calls are put together by the Combine-
Solutions function.
The factorial of a number can easily be calculated by a loop, but for the pur-
pose of this example, we consider a recursive version. You can see that the fac-
torial of the number N is just the number N times the factorial of the number
N 1. This leads to the following algorithm:
Factorial( N )
N is the number we want the factorial for
Factorial returns an integer
If (N = 1) then
return 1
else
smaller = N - 1
answer = Factorial( smaller )
return (N * answer)
end if
This algorithm is written in simple detailed steps so that we can match
things up with the standard algorithm above. Even though earlier in this chap-
ter we discussed how multiplications are more complex than additions and are,
therefore, counted separately, to simplify this example we are going to count
them together.
47. 26 A N A L Y S I S B A S I C S
In matching up the two algorithms, we see that the size limit in this case is
1, and our direct solution is to return the answer of 1, which takes no mathe-
matical operations. In all other cases, we use the else clause. The first step in
the general algorithm is to “divide the input” into smaller sizes, and in the fac-
torial function that is the calculation of smaller, which takes one subtraction.
The next step in the general algorithm is to make the recursive calls with these
smaller problems, and in the factorial function there is one recursive call with a
problem size that is 1 smaller than the original. The last step in the general
algorithm is to combine the solutions, and in the factorial function that is the
multiplication in the last return statement.
Recursive Algorithm Efficiency
How efficient is a recursive algorithm? Would it make it any easier if you
knew that the direct solution is quadratic, the division of the input is logarith-
mic, and the combination of the solutions is linear,1 all with respect to the size
of the input, and that the input set is broken up into eight pieces all one-
quarter of the original? This is probably not a problem for which you can
quickly find an answer or for that matter are even sure where to start. It turns
out, however, that the process of analyzing any divide and conquer algorithm
is very straightforward if you can map the steps of your algorithm into the four
steps shown in the generic algorithm above: a direct solution, division of the
input, number of recursive calls, and combination of the solutions. Once you
know how each piece relates to the others, and you know how complex each
piece is, you can use the following formula to determine the complexity of the
divide and conquer algorithm:
where DAC is the complexity of DivideAndConquer
DIR is the complexity of DirectSolution
DIV is the complexity of DivideInput
COM is the complexity of CombineSolutions
1 To say that an algorithm is linear is the same as saying its complexity is in O(N ). If it’s quadratic, it is in
O(N2), and logarithmic is in O(lg N ).
DAC N
( )
DIR N
( ) for N SizeLimit
≤
DIV N
( ) DAC smallerSizes i
[ ]
( ) COM N
( )
+
i=1
numberSmaller
∑
+ for N SizeLimit
=
48. 1 . 5 D I V I D E A N D C O N Q U E R A L G O R I T H M S 27
Now that we have this generic formula, the answer to the question posed at
the start of the last paragraph is quite easy. All we need to do is to plug in the
complexities for each piece given into the previous general equation. This
gives the following result:
or a bit more simply, because all smaller sets are the same size,
This form of equation is called a recurrence relation because the value of
the function is based on itself. We prefer to have our equations in a form that
is dependent only on N and not other function calls. The process that is used
to remove the recursion in this equation will be covered in Section 1.6, which
covers recurrence relations.
Let’s return to our factorial example. We identified all of the elements in
the factorial algorithm relative to the generic DivideAndConquer. We now
use that identification to decide what values get put into the general equation
above. For the Factorial function, we said that the direct solution does no
calculations, the input division and result combination steps do one calculation
each, and the recursive call works with a problem size that is one smaller than
the original. This results in the following recurrence relation for the number
of calculations in the Factorial function:
■ 1.5.1 Tournament Method
The tournament method is based on recursion and can be used to solve a
number of different problems where information from a first pass through the
data can help to make later passes more efficient. If we use it to find the largest
value, this method involves building a binary tree with all of the elements in
DAC N
( )
N
2
for N SizeLimit
≤
lg N DAC N 4
⁄
( ) N
+
i=1
8
∑
+ for N SizeLimit
=
DAC N
( ) N
2
for N SizeLimit
≤
lg N 8 DAC N 4
⁄
( ) N
+ + for N SizeLimit
=
Calc N
( ) 0 for N 1
=
1 Calc N 1
–
( ) 1
+ + for N 1
=
49. 28 A N A L Y S I S B A S I C S
the leaves. At each level, two elements are paired and the larger of the two gets
copied into the parent node. This process continues until the root node is
reached. Figure 1.3 shows a complete tournament tree for a given set of data.
In Exercise 5 of Section 1.1.3, it was mentioned that we would develop an
algorithm to find the second largest element in a list using about N compari-
sons. The tournament method helps us do this. Every comparison produces
one “winner” and one “loser.” The losers are eliminated and only the winners
move up in the tree. Each element, except for the largest, must “lose” one
comparison. Therefore, building the tournament tree will take N 1 com-
parisons.
The second largest element could only have lost to the largest element. We
go down the tree and get the set of elements that lost to the largest one. We
know that there can be at most lg N of these elements because of our tree
formulas in Section 1.3.2. There will be lg N comparisons to find these ele-
ments in the tree and lg N 1 comparisons to find the largest in this collec-
tion. The entire process takes N + 2 lg N 2 comparisons, which is O(N ).
The tournament method could also be used to sort a list of values. In
Chapter 3, we will see a method called heapsort that is based on the tourna-
ment method.
■ 1.5.2 Lower Bounds
An algorithm is optimal when there is no algorithm that will work more
quickly. How do we know when have we found an algorithm that is optimal
or when is an algorithm not optimal, but good enough? To answer these ques-
8
6 8
6
4 6
3
3 2
8
8 7
5
1 5
■ FIGURE 1.3
Tournament tree
for a set of eight
values
50. 1 . 5 D I V I D E A N D C O N Q U E R A L G O R I T H M S 29
tions, we need to know the absolute smallest number of operations needed to
solve a particular problem. This must be determined by looking at the prob-
lem itself and not any particular algorithm to solve it. This lower bound tells us
the amount of work that is necessary to solve the problem and shows that any
algorithm that claims to be able to solve the problem more quickly must fail in
some cases.
We can again use a binary tree to help us analyze the process of sorting a list
of three numbers. We can construct a binary tree for the sorting process by
labeling each internal node with the two elements of the list that would be
compared. The ordering of the elements that would be necessary to move
from the root to that leaf would be in the leaves of the tree. The tree for a list
of three elements is shown in Fig. 1.4. Trees of this form are called decision
trees.
Each sort algorithm produces a different decision tree based on the elements
that it compares. Within a decision tree, the longest path from the root to a
x1 ≤ x2
x1 ≤ x3
x1 ≤ x3
x3, x1, x2
x2 ≤ x3 x2 ≤ x3
x1, x3, x2
x1, x2, x3
x2, x1, x3
x2, x3, x1 x3, x2, x1
■ FIGURE 1.4
The decision tree for
sorting a three-
element list
51. 30 A N A L Y S I S B A S I C S
leaf represents the worst case. The best case is the shortest path. The average
case is the total number of edges in the decision tree divided by the number of
leaves in the tree. As simple as it would seem to be able to determine these
numbers by drawing decision trees and counting, think about what the deci-
sion tree would look like for a sort of 10 numbers. As was said before, there
are 3,628,800 different ways these can be ordered. A decision tree would need
at least 3,628,800 different leaves, because there may be more than one way to
get to the same order. This tree would then need at least 22 levels.
So, how can decision trees be used to give us an idea of the bounds on an
algorithm? We know that a correct sorting algorithm must properly order all
of the elements no matter what order in which they begin. There must be at
least one leaf for every possible permutation of input values, which means that
there must be at least N ! leaves in the decision tree. A truly efficient algorithm
would have each permutation appear only once. How many levels does a tree
with N! leaves have? We have already seen that each new level of the tree will
have twice as many nodes as the previous level. Because there are 2K–1 nodes
on level K, our decision tree will have L levels, where L is the smallest integer
with N! ≤ 2L–1. Applying algebraic transformations to this formula we get
Because we are trying to find out the smallest value for L, is there anyway to
simplify this equation further to get rid of the factorial? Let’s see what we can
observe about the factorial of a number. Consider the following:
By Equation 1.5, we get
By Equation 1.21, we get
lg N! L 1
–
≤
lg N! lg N * N 1
–
( ) * N 2
–
( ) * … * 1
( )
=
lg N * N 1
–
( ) * N 2
–
( ) * … * 1
( ) lg N
( ) lg N 1
–
( ) lg N 2
–
( ) … lg(1)
+ + + +
=
lg N
( ) lg N 1
–
( ) lg N 2
–
( ) … lg 1
( )
+ + + + lg i
i=1
N
∑
=
lg i
i=1
N
∑ N lg N 1.5
–
≈
lg N! N lg N
≈
52. 1 . 5 D I V I D E A N D C O N Q U E R A L G O R I T H M S 31
This means that L, the minimum depth of the decision tree for sorting
problems, is of order O(N lg N ). We now know that any sort that is of order
O(N lg N ) is the best we will be able to do, and it can be considered optimal.
We also know that any sort algorithm that runs faster than O(N lg N ) must not
work.
This analysis for the lower bound for a sorting algorithm assumed that it
does its work through the comparison of pairs of values from the list. In
Chapter 3, we will see a sorting algorithm (radix sort) that will run in linear
time. That algorithm doesn’t compare key values but rather separates them
into “buckets” to accomplish its work.
1.5.3
1. Fibonacci numbers can be calculated with the algorithm that follows. What
is the recurrence relation for the number of “additions” done by this algo-
rithm? Be sure to clearly indicate in your answer what you think the direct
solution, division of the input, and combination of the solutions are.
int Fibonacci( N )
N the Nth Fibonacci number should be returned
if (N = 1) or (N = 2) then
return 1
else
return Fibonacci( N-1 ) + Fibonacci( N-2 )
end if
2. The greatest common divisor (GCD) of two integers M and N is the largest
integer that divides evenly into both M and N. For example, the GCD of 9
and 15 is 3, and the GCD of 51 and 34 is 17. The following algorithm will
calculate the greatest common divisor of two numbers:
GCD(M, N)
M, N are the two integers of interest
GCD returns the integer greatest common divisor
if ( M N ) then
swap M and N
end if
if ( N = 0) then
return M
else
quotient = M / N //NOTE: integer division
1.5.3 EXERCISES
■
53. 32 A N A L Y S I S B A S I C S
remainder = M mod N
return GCD( N, remainder )
end if
Give the recurrence relation for the number of multiplications (in this case,
the division and mod) that are done in this function.
3. We have a problem that can be solved by a direct (nonrecursive) algorithm
that operates in N2 time. We also have a recursive algorithm for this prob-
lem that takes N lg N operations to divide the input into two equal pieces
and lg N operations to combine the two solutions together. Show whether
the direct or recursive version is more efficient.
4. Draw the tournament tree for the following values: 13, 1, 7, 3, 9, 5, 2, 11,
10, 8, 6, 4, 12. What values would be looked at in stage 2 of finding the
second largest value in the list?
5. What is the lower bound on the number of comparisons needed to do a
search through a list with N elements? Think about what the decision tree
might look like for this problem in developing your answer. (Hint: The
nodes would be labeled with the location where the key is found.) If you
packed nodes into this tree as tightly as possible, what does that tell you
about the number of comparisons needed to search?
1.6 RECURRENCE RELATIONS
Recurrence relations can be directly derived from a recursive algorithm, but
they are in a form that does not allow us to quickly determine how efficient
the algorithm is. To do that we need to convert the set of recursive equations
into what is called closed form by removing the recursive nature of the equa-
tions. This is done by a series of repeated substitutions until we can see the
pattern that develops. The easiest way to see this process is by a series of exam-
ples.
A recurrence relation can be expressed in two ways. The first is used if there
are just a few simple cases for the formula:
T n
( ) 2T n 2
–
( ) 15
–
=
T 2
( ) 40
=
T 1
( ) 40
=
54. 1 . 6 R E C U R R E N C E R E L A T I O N S 33
The second is used if the direct solution is applied for a larger number of cases:
These forms are equivalent. We can convert from the second form to the first
by just listing those values for which we have the direct answer. This means
that the second recurrence relation above could also be given as
Consider the following recurrence relation:
We will want to substitute an equivalent value for T(n 2) back into the first
equation. To do so, we replace every n in the first equation with n 2, giving:
But now we can see when this substitution is done, we will still have T(n 4)
to eliminate. If you think ahead, you will realize that there will be a series of
these values that we will need. As a first step, we create a set of these equations
for successively smaller values:
T n
( ) 4 if n 4
≤
4T n 2
⁄
( ) 1
– otherwise
=
T n
( ) 4T n 2
⁄
( ) 1
–
=
T 4
( ) 4
=
T 3
( ) 4
=
T 2
( ) 4
=
T 1
( ) 4
=
T n
( ) 2T n 2
–
( ) 15
–
=
T 2
( ) 40
=
T 1
( ) 40
=
T n 2
–
( ) 2T n 2
– 2
–
( ) 15
–
=
2T n 4
–
( ) 15
–
=
T n 2
–
( ) 2T n 4
–
( ) 15
–
=
T n 4
–
( ) 2T n 6
–
( ) 15
–
=
T n 6
–
( ) 2T n 8
–
( ) 15
–
=
T n 8
–
( ) 2T n 10
–
( ) 15
–
=
T n 10
–
( ) 2T n 12
–
( ) 15
–
=
56. Much importance has been credited to the fusion (no suture) or
separation (suture present) of the hypoplastra and hyoplastra. The
fusion of these bones distinguishes the genera Lissemys, Cyclanorbis
and Cycloderma from Trionyx, Pelochelys, and Chitra (Siebenrock,
op. cit.:815, 817; Loveridge and Williams, 1957:415). This character
is also one of the criteria used by Hummel (1929: 768) in his
erection of the two subfamilies Cyclanorbinae (= Lissemyinae) and
Trionychinae. In my examination of specimens this character,
unfortunately, was not given full attention. I have noted the fusion of
the hypoplastra and hyoplastra in KU 1878 (muticus, right side only),
KU 2219 (kyphotic spinifer), KU 16528 (ferox) and KU 60121 (ferox).
Dr. Ernest E. Williams informs me in a letter of November 17, 1959,
that of six specimens of ferox in the MCZ, the hyoplastra are fused
with the hypoplastra in three (54689-90, 54686). I suspect that
these bones in the three American species of the genus Trionyx,
especially in ferox, fuse more often than is supposed.
In muticus the constricted part of the hyoplastron and
hypoplastron is wider anteroposteriorly than in spinifer or ferox
(Fig. 17).
The three American species have on the hyoplastra, hypoplastra,
and xiphiplastra well-developed callosities, which enlarge with
increasing size. The medial borders of the hyoplastral and
hypoplastral callosities in larger specimens are rounded and closely
approximated, often touching, as do the callosities of each
xiphiplastron; seemingly, the callosities are relatively larger in
muticus than in spinifer and ferox. I have seen one adult male
muticus (KU 41380) that lacked median fontanelles or vacuities
owing to the contact of the plastral elements (as viewed through
overlying skin, alcoholic specimen). The bony plastron
(approximately 9 cm. in maximal length) of a small muticus (KU
19460) resembles the plastron of larger individuals of muticus in
having well-developed hyoplastral and hypoplastral callosities that
are closely approximated medially. Large individuals of muticus
usually have small, ovoid callosities on the preplastra, and a well-
57. developed, angular callosity on the epiplastron (Fig. 17a).
Siebenrock (op. cit.:823) suggests that the presence of callosities on
the preplastra and epiplastron of muticus is subject to individual
variation. I can not substantiate or dispute the supposition of Baur
(1888:1122), Siebenrock (1924:193) and Stejneger (1944:12, 19)
that the callosities are larger in males of muticus than in the
females. Some individuals of spinifer have seven plastral callosities
(KU 2842) as does muticus, but the callosities on the preplastra and
epiplastron are less frequent and less well-developed in large
specimens of spinifer than in muticus. The small epiplastral callosity
in spinifer is located at the medial angle and does not extend
posterolaterally to cover the entire surface of the epiplastron as it
may in muticus (Fig. 17b). The epiplastron of a spinifer (KU 2826)
has a medial callosity and another on the right posterolateral
projection; three separate callosities occur on the epiplastron of MCZ
46615. The last specimen mentioned, a large, stuffed female,
possesses a round, intercalary bone that tends to occlude the
posteromedial vacuity. Seemingly, the callosity on the epiplastron
appears prior to those on the preplastra; I have not seen any plastra
having callosities on the preplastra and lacking a callosity on the
epiplastron. I have not noted callosities on the preplastra or
epiplastron of specimens of ferox.
The callosities on the plastral bones are sculptured; small,
recently formed callosities on the preplastra and epiplastron lack
sculpturing. The pattern [476] of sculpturing on the plastral bones as
well as that of the carapace is generally of anastamosing ridges. I
am unable to discern any differences in pattern of sculpturing
between the three American species. Stejneger distinguished adult
specimens of ferox from the other American species by the
coarseness of the sculpture of the bony callosities (1944:24) and of
the bony carapace (op. cit.:32). The sculpturing on the plastral
callosities and carapace seems to be correlated with size; larger
specimens (ferox) have coarser sculpturing than do smaller
specimens (muticus). Stejneger also mentioned that the sculpturing
on many specimens of ferox is specialized into prominent,
58. longitudinal welts (loc. cit.); these welts occur also on the carapace
of spinifer.
On the basis of the osteological characters examined by me, T.
muticus is distinguished from spinifer and ferox by a number of
characters (plastron and especially skull) whereas the species
spinifer and ferox are not easily distinguished from one another.
Composition of the Genus Trionyx in North
America
Analysis of the characters previously mentioned and their
geographic distribution permits the recognition of ten taxa,
comprising four species and eight subspecies. Two subspecies, T.
spinifer pallidus and T. s. guadalupensis are described as new. The
four species and the included subspecies here recognized are:
Trionyx ferox
Trionyx spinifer spinifer
hartwegi
asper
emoryi
guadalupensis
pallidus
Trionyx ater
Trionyx muticus muticus
calvatus
The following key is designed to permit quick identification of
living individuals; therefore, ratios and osteological characters are
avoided as much as possible in favor of other characters that are the
least variable and most typical. Because there is considerable
variation correlated with sex and size, each taxon occurs in the key
in more than one couplet. Large females having mottled and
blotched patterns will be the most difficult to identify. The characters
listed should be used in combination because one character alone
59. may not be sufficient; it is advisable to read both choices of each
couplet. The text, figures and illustrations should be consulted for
final identification.
Artificial Key to North American Species and Subspecies of
the Genus Trionyx
1. Septal ridges present; tubercles on anterior
edge of carapace present or absent
2
Septal ridges absent; anterior edge of
carapace lacking tubercles or raised
prominences
19
2. Plastral area a uniform dark slate or
blackish; soft parts of body blackish
having large pale marks dorsally;
carapace having large black blotches,
often fused along margin, on pale
background, and many well-defined
longitudinal ridges
T. ferox, p. 479
Combination of characters not as above;
ventral surface whitish, blackish
flecks or blotches sometimes present
3
60. 3. Carapace having pattern of white dots, or
black ocelli and/or spots; carapace
sometimes gritty resembling
sandpaper
4
Carapace uniform pale brownish or grayish,
or having mottled and blotched
pattern, contrasting or not; white
dots or tubercles, black ocelli and/or
spots may be present; carapace not
gritty
10
4. Carapace having pattern of black ocelli
and/or spots; numerous, conspicuous
whitish spots or tubercles absent
5
Carapace having pattern of white dots that
are sometimes surrounded by small
black ocelli; small black dots may be
interspersed among larger white dots
7
61. 5. Carapace having two or more marginal
lines, these often diffuse and
interrupted; black spots sometimes
ocellate or bacilliform, or
interspersed among smaller black
dots; postocular and postlabial
stripes usually united
spinifer asper, p. 502
Carapace having only one dark marginal
line; pattern of black ocelli or spots;
postocular and postlabial stripes
usually not united
6
6. Carapace having prominent ocelli, which
are much larger near the center than
at the sides
spinifer spinifer, p. 489
Carapace having numerous small, dark
spots, sometimes small ocelli, which
are not much larger near the center
than the sides
spinifer hartwegi, p. 497
62. 7. White spots on anterior third of carapace;
white spots on carapace often
surrounded by narrow blackish ocelli;
small black dots sometimes
interspersed among white spots
spinifer guadalupensis, p. 517
White spots absent on anterior third of
carapace, or small and
inconspicuous; white spots not
surrounded by narrow blackish ocelli
8
8. Pale rim of carapace narrow, partly
obscured; over-all dorsal coloration
(including soft parts of body) dark
and lacking pattern; few, small, white
tubercles confined to posterior third
of carapace
ater, p. 528
Pale rim distinct, without markings; soft
parts of body dorsally not uniformly
dark; many white tubercles usually
contrasting on pale carapace
9
63. 9. White spots confined to posterior third of
carapace; ground color of carapace
usually pale brown or tan, sometimes
darker; a dark, slightly curved, line
connecting anterior margins of
orbits; postocular stripe usually
interrupted leaving pale, blotch
behind eye; pale rim of carapace four
or five times wider posteriorly than
laterally
spinifer emoryi, p. 510
Small white spots on posterior half of
carapace gradually decreasing in size
anteriorly, often indistinct or absent
on anterior third of carapace; pale
rim of carapace no more than three
times wider posteriorly than laterally
spinifer pallidus, p. 522
10. Marginal ridge present; carapace having
ill-defined dark blotches on uniform
grayish, lacking whitish tubercles or
well-defined black spots or ocelli;
pale rim of carapace absent;
tubercles on anterior edge of
carapace resembling flattened
64. hemispheres; anterior parts of
plastron often visible in dorsal view;
postocular stripe, if present, having
thick, blackish borders
ferox, p. 479
Marginal ridge absent
11
11. Carapace uniform pale brownish, lacking
mottled and blotched pattern, white
dots, black ocelli or spots
12
Carapace having mottled and blotched
pattern, contrasting or not; white
spots or tubercles, black ocelli or
spots may be present
13
12. Pale rim of carapace four or five times
wider posteriorly than laterally; dark,
straight or slightly curved, line
connecting anterior margins of orbits
spinifer emoryi, p. 510
65. Pale rim of carapace no more than three
times wider posteriorly than laterally
spinifer pallidus, p. 522
13. Rear margin of carapace usually
roughened by fine corrugations, edge
often ragged; pale rim absent;
carapace having dark brown-blackish,
mottled and blotched pattern;
anterior edge of carapace more or
less smooth having scarcely elevated
prominences; posterior part of
plastral area and especially ventral
surface of carapace having numerous
black marks
ater, p. 528
Rear margin of carapace smooth, edge
entire; usually some evidence of pale
rim
14
14. White, rounded tubercles or spots usually
evident posteriorly on carapace,
sometimes indistinct; black ocelli or
spots lacking in center of carapace,
sometimes present at sides; shape of
66. tubercles on anterior edge of
carapace variable
15
White spots or tubercles absent; margin of
carapace usually having black ocelli
or spots; tubercles on anterior edge
of carapace equilateral or conical, not
low and flattened
17
15. White spots often present on anterior half
of carapace; tubercles on anterior
edge equilateral and wartlike, or less
elevated, not conical
spinifer guadalupensis, p. 517
White spots usually absent on anterior half
of carapace, sometimes indistinct;
shape of tubercles on anterior edge
of carapace variable
16
16. White spots absent on anterior half of
carapace; tubercles on anterior edge
of carapace low, scarcely elevated,
67. never equilateral or conical; mottled
and blotched pattern often not
contrasting; ground color of carapace
sometimes dark; pale rim of carapace
four or five times wider posteriorly
than laterally; dark, straight or
slightly curved, line connecting
anterior margins or orbits
spinifer emoryi, p. 510
White spots sometimes indistinct on
carapace, or few, small spots present
on posterior half of carapace;
tubercles on anterior edge of
carapace equilateral and wartlike or
conical; mottled and blotched pattern
usually contrasting; pale rim less
than three times wider posteriorly
than laterally
spinifer pallidus, p. 522
17. Carapace having evidence of more than
one dark marginal line, and
scattered, black spots or ocelli
spinifer asper, p. 502
68. Carapace having only one, dark, marginal
line
18
18. Carapace having small black spots, lacking
large interrupted ocelli
spinifer hartwegi, p. 497
Carapace having small black spots
interspersed among larger,
interrupted ocelli
spinifer spinifer, p. 489
19. Carapace having pattern of dusky spots,
sometimes short lines
20
Carapace lacking pattern of dark spots or
lines, having a mottled and blotched
pattern
21
20. Pattern of circular spots, lacking short
lines or bacilliform marks; spots
sometimes slightly ocellate; no pale
stripes on snout
69. muticus calvatus, p. 539
Pattern of dots, or dots and short lines; pale
stripes on snout, at least just in front
of eyes
muticus muticus, p. 534
21. Mottled and blotched pattern usually
contrasting; ill-defined, blackish
blotch absent behind eye
muticus muticus, p. 534
Mottled and blotched pattern usually not
contrasting; ill-defined, dark blotch
may be present behind eye
muticus calvatus, p. 539
Systematic Account of Species and Subspecies
Trionyx ferox (Schneider)
Florida Softshell
Plates 31 and 32
Testudo ferox Schneider, Naturg. Schildkr., p. 330,
1783 (based on Pennant, Philos. Trans.
London, 61 (Pt. 1, Art. 32): 268, pl. 10 [figs.
1-3], 1772).
71. Type.—Holotype, British Museum (Natural History) 1947.3.6.17;
original number 53A, presumably that of Royal Society; stuffed adult
female and skull; obtained from the Savannah River, Georgia, by Dr.
Alexander Garden.
Range.—Southern South Carolina, southeastern Georgia, and all
of Florida except the Keys and perhaps the western end of the
panhandle (see map, Fig. 18).
Fig. 18. Map of southeastern United States showing geographic
distribution of Trionyx ferox.
Diagnosis.—Marginal ridge present; longitudinal rows of tubercles
that resemble ridges on carapace of hatchlings; plastron often
extending farther forward than carapace in adults; plastral area dark
72. slate or gray in hatchlings; juvenal pattern of large slate or blackish
blotches (often with pale centers) on a pale background; pale outer
rim of carapace (absent on adults) narrow, not separated from
ground color of carapace by distinct, dark line.
Size large; head wide; carapace relatively long and narrow; snout
short; greatest width of skull at level of quadratojugal; often no
suture between hypoplastra and hyoplastra; callosities on epiplastron
and preplastra usually lacking.
Description.—Plastral length of smallest hatchling, 2.9
centimeters (UMMZ 95613), of largest male, 26.0 centimeters
(AMNH 63642), of largest female, 34.0 centimeters (UMMZ 38123).
Septal ridges present; over-all coloration of carapace and
plastron, and soft parts of body of hatchlings slate or blackish;
carapace having blackish, circular blotches, usually fused at margin,
often with pale centers on buff background forming coarse
reticulum; pale, narrow rim of carapace not separated from ground
color by dark marginal line; pale rim, coincident with marginal ridge,
absent from anteriormost nuchal region; longitudinal rows of
tubercles on carapace resembling ridges; undersurface blackish,
usually having posterior part of carapace pale with irregular blackish
marks; blackish soft parts of body dorsally having large, pale
markings, most consistent of which are postocular mark that may
contact orbit, postlabial mark that curves around angle of jaws,
inverted Y on top of snout, and one or two streaks on side of neck.
Over-all coloration of adults grayish, paler than in hatchlings;
carapace gray sometimes having slightly darker, large, irregular
markings; mottled and blotched pattern on females not contrasting;
sex of many large individuals not distinguishable on basis of pattern
on carapace; pale rim of carapace obscure or absent; soft parts of
body dorsally gray or brownish on large adults of both sexes,
sometimes having slightly paler, large markings; small adult males
usually having contrasting pattern on head; surface of carapace
smooth (not sandpaper) on adult males; undersurface whitish,
73. throat often grayish; well-defined marginal ridge; anterior edge of
carapace laterally to region of insertion of forelimbs studded with
low, flattened tubercles resembling hemispheres, never conical;
carapace usually having blunted tubercles, best developed anteriorly
and posteriorly on midline, but sometimes linearly arranged,
resembling ridges, especially at margins; anterolateral parts of
plastron often extending farther forward than corresponding parts of
carapace.
Range in length (in cm.) of plastron of ten largest specimens of
each sex (mean follows extremes), males, 17.0-26.0, 20.0; females
23.3-34.0, 27.9; ontogenetic variation in PL/HW, mean PL/HW of
specimens having plastral lengths 6.5 centimeters or less, 3.52, and
exceeding 6.5 centimeters, 4.87; ontogenetic variation in CL/CW,
mean CL/CW of specimens having plastral lengths 8.0 centimeters or
less, 1.18, and exceeding 8.0 centimeters, 1.30; mean CL/PCW,
2.01; mean HW/SL, 1.44; mean CL/PL, 1.26.
Jaws of some skulls that exceed 75 millimeters in basicranial
length having expanded alveolar surfaces; greatest width of skull
usually at level of quadratojugal (72%); ventral surface of
supraoccipital spine narrow proximally, usually having medial ridge;
foramen magnum rhomboidal; opisthotic-exoccipital spur absent
(82%), sometimes indicated by ridge (16%); distal part of opisthotic
wing [481] tapered, not visible in dorsal view; lateral condyle of
articular surface of quadrate larger than medial articular surface, not
tapered posteriorly; maxillaries in contact above premaxillaries;
usually a combination of seven neurals, seven pairs of pleurals, and
contact of seventh pair of pleurals (56%), often eight pairs of
pleurals (31%); angle of epiplastron forming approximate right
angle; often no suture between hypoplastra and hyoplastra;
callosities on preplastra and epiplastron usually lacking.
Variation.—Crenshaw and Hopkins (1955:19) stated that in
specimens from Lake Okeechobee and southward the carapace is
wider relative to the width of the head, and Neill (1951:19) quoted
74. Allen's observations that ferox from southern Florida average larger
and darker than those collected farther north.
Carr (1952:417) reported that the pale reticulum on the carapace
is yellowish olive, the markings on head are yellow on an olive
ground color, some markings more orange, and the plastron slate
gray. Duellman and Schwartz (1958:271) mentioned that the
carapace of hatchlings is edged in orange grading to yellow
posteriorly and has a pattern of bluish-black blotches on a dull
brown background, whereas the carapace is dull brown or blackish
on adults. Neill (op. cit.:18) wrote that the head stripes and the
marginal ring of the 'carapace' are orange rather than yellow (yellow
at the time of hatching, however).
The transition from the dark coloration of hatchlings to the paler
coloration of adults is gradual and subject to individual variation. The
loss of dark color ventrally occurs first on the plastral area, then the
hind limbs, forelimbs, posterior part of carapace and last on the neck
and throat. The soft parts of the body dorsally are gray or dark gray,
and do not become so pale as the ventral surface. The smallest
specimen that I have seen displaying the dark features of the
hatchlings is a male, 7.7 centimeters (UMMZ 100673); a female, 9.5
centimeters (UMMZ 110987), is the smallest specimen having a
whitish plastral area. The change from dark to pale coloration on the
ventral surface occurs at a size of 8.0 to 9.0 centimeters. The largest
specimens I have seen having indistinct, dusky blotches of the
underside of the carapace are a female, 11.3 centimeters (UMMZ
100836), and a male, 16.0 centimeters (UMMZ 106322). A
contrasting pattern on head and limbs, and a dark throat are still
evident in a female 19.2 centimeters (UMMZ 106302).
Comparisons.—Trionyx ferox can be distinguished from all other
species of the genus in North America by the presence of a marginal
ridge, longitudinal ridges of tubercles on the carapace of juveniles
(less evident in adults), and the unique juvenal pattern and
coloration. The lack of a juvenal pattern and a smooth surface on
the carapace (not gritty like sandpaper) distinguish adult males from
75. those of T. spinifer. Most adults of both sexes can be distinguished
from spinifer and muticus by the extension of the plastron farther
forward than the carapace (developed to a slight degree in some
specimens of T. s. emoryi). Both sexes of all ages can be
distinguished from muticus by the presence of knoblike tubercles on
the anterior edge of the carapace, and septal ridges.
T. ferox is the largest species in North America; the maximum
size of the plastron in adult males is approximately 26.0 centimeters
(16.0 in spinifer) and of adult females, 34.0 centimeters (31.0 in
spinifer). The head is wider in ferox than in muticus and most
subspecies of spinifer (closely approached [482] by asper,
guadalupensis, emoryi and T. ater). The carapace is narrower in
ferox than in muticus and most subspecies of spinifer (closely
approached by emoryi and T. ater). The snout is shortest in ferox,
but almost as short in T. s. emoryi and T. ater. T. ferox has
proportionately the longest plastron in relation to length of carapace.
Most skulls of ferox differ from those of muticus and spinifer in
having the greatest width at the level of the quadratojugal (as do
some T. s. asper; see account of that subspecies). In the skull, ferox
resembles spinifer but differs from muticus in having the 1) ventral
surface of the supraoccipital spine narrow proximally, and usually
having a medial ridge, 2) foramen magnum rhomboidal, 3) distal
part of opisthotic wing tapered, 4) lateral condyle of articular surface
of quadrate not tapered posteriorly, and larger than medial articular
surface, and 5) maxillaries in contact above premaxillaries. T. ferox
resembles muticus but differs from most individuals of spinifer in
lacking a well-developed opisthotic-exoccipital spur. T. ferox
resembles spinifer but differs from muticus in having the epiplastron
bent at approximately a right angle; ferox differs from both muticus
and spinifer in lacking a callosity on the epiplastron and probably in
the more frequent fusion of the hyoplastra and hypoplastra.
Remarks.—The early taxonomic history of Trionyx ferox has been
discussed in detail by Stejneger (1944:27-32), who explained that
Dr. Alexander Garden of Charleston, South Carolina, sent a
76. description and specimen of T. ferox to Thomas Pennant, and at the
same time sent another specimen with drawings to a friend, John
Ellis, in London. Pennant presented one of the specimens and
drawings and the description to the Royal Society of London in 1771;
the description was published in 1772 and included Garden's
drawings. Because two specimens were involved the possibility exists
that the description (text, drawings and type specimen) is a
composite based on two specimens.
I have not seen the type. Garden's original description (in
Pennant, 1772:268-271) leaves little doubt that the text subject is a
large adult female of ferox (see especially the statements, fore part,
[of carapace] just where it covers the head and neck, is studded full
of large knobs, [and] The under, or belly plate, … is … extended
forward two or three inches more than the back plate, …). I am
indebted to Mr. J. C. Battersby, British Museum (Natural History),
Department of Zoology (Reptiles), for information concerning the
type and for comparing it with the text description and three figures
published by Pennant. The carapace of the type is approximately 16
inches long, 131/2 inches wide, and has low, flattened, knoblike
tubercles along the anterior edge. Some inaccuracies on the part of
the artist (such as five claws on both feet on the right side of Fig. 3,
and four claws on the left front foot of Fig. 2 are evident), and slight
changes in the proportions of the type would have occurred after
death and preservation. It is the opinion of Mr. Battersby that the
type, text description and three figures represent one specimen.
Figures 1 and 2, dorsal and ventral views respectively, probably
represent the same specimen from life; the neck is withdrawn and
the tail tip is visible in dorsal view, but concealed beneath the
posterior edge of the carapace in ventral view. Presumably the same
specimen (probably drawn from dried and stuffed animal) is depicted
in Figure 3 (dorsal view); the neck is fully extended and a large part
of the thick, pyramidal tail is visible in dorsal view. British Museum
(Natural History) 1947.3.6.17 is considered a holotype. The three
figures published [483] by Pennant have been duplicated by
Schoepff (1795:Pl. 19) and Duméril and Bibron (1835:482). To my
77. knowledge, the holotype was first specifically designated as the
(Type.) of T. ferox by Boulenger (1889:259). The skull of the
holotype is figured by Stejneger (1944:Pl. 5).
Garden did not list a specific locality for the two specimens that
he sent to London, but did mention that the turtle was common in
the Savannah and Altamaha rivers (of Georgia), and rivers in east
Florida. Boulenger (loc. cit.) stated that the locality of the holotype
was Georgia. Baur (1893:220) restricted the type locality to the
Savannah river, Ga. Neill (1951:17), who believed T. ferox to be
absent from the Savannah River, changed the type locality of ferox
to east Florida. Schwartz (1956:8) reappraised the status of
softshells in Georgia and Florida and reëstablished the Savannah
River (at Savannah), Georgia, as the type locality of T. ferox.
Pennant failed to use binomial nomenclature when he published
the type description of Garden. The first name-combination (Testudo
ferox) was proposed by Schneider (1783:220).
Lacépède (1788:137, Pl. 7) referred to Garden's description in
Pennant only as The Molle but on a folded paper chart entitled
Table Méthodique des Quadrupèdes ovipares, which is inserted
after an introduction of 17 pages, listed T. mollis; this name is again
listed on another folded chart, entitled Synopsis methodica
Quadrupedum oviparorum, which is inserted between pages 618
and 619 under the genus Testudo. The illustration (Pl. 7) was taken
from Pennant (Duméril and Bibron, loc. cit.). The type locality has
been designated (following Stejneger, 1944) as eastern Florida by
Schmidt (1953:108).
Bartram failed to use a binomial name with his description of the
great soft shelled tortoise, which appeared in his Travels (1791:177-
179, Pl. 4 and unnumbered plate between pages 282 and 283) and
two editions of a French translation (1799 and 1801, 1:307); see
Harper (1940). Recently, Bartram's Travels has been placed on the
Official Index of Rejected and Invalid Works in Zoological
Nomenclature, Opinion 447 (see Hemming, 1957). Bartram's
78. description of a soft-shelled turtle has provided the basis for the
proposal of at least three name-combinations. The first was Testudo
(ferox?) verrucosa proposed in 1795 by Schoepff; it appeared
simultaneously in The Historia Testudinum and in a German
translation, Naturgeschichte der Schildkröten (see Mittleman,
1944:245). Stejneger (1944:26) listed the type locality as eastern
Florida. Daudin (1801:74), also referring to Bartram's description in
his Voyage (French translation), proposed the name Testudo
bartrami; Harper (op. cit.:717) restricted the type locality of T.
bartrami from Halfway pond, east Florida, to southwestern Putnam
County between Palatka and Gainesville, Florida. Rafinesque
(1832:64-65), relying on the authenticity of the illustrations in
Bartram's Travels that depict a soft-shelled turtle having five claws
on each of the hind feet, tubercles on the sides of the head and
neck, and ten scales in the middle of the carapace (presumably
inaccuracies or a composite on the part of the artist), referred to
Bartram's description as a new genus, Mesodeca bartrami, a name
which Boulenger (1889:245, footnote) referred to as mythical.
Geoffroy (1809a:18-19) considered Bartram's description the basis
for the recognition of a second species of Chelys (binomial
nomenclature not employed), and Duméril and Bibron (loc. cit.)
suggested that the description was based partly on a Chelyde
Matamata. [484] The descriptive comments of Bartram are not
clearly applicable to Testudo ferox Schneider; Trionyx ferox, however,
is the only species of soft-shelled turtle known to occur in the region
of Bartram's observations (east Florida), and the type locality was
restricted to Putnam County, Florida, by Harper. The name-
combinations, Testudo (ferox?) verrucosa Schoepff, Testudo bartrami
Daudin, and Mesodeca bartrami Rafinesque are junior synonyms of
Testudo ferox Schneider.
Schweigger (1812:285) referred ferox to the genus Trionyx
following the description of that genus by Geoffroy in 1809. Testudo
ferox was listed as a synonym by Geoffroy in the description of
Trionyx georgicus (1809a:17); Duméril and Bibron (1835:432)
mentioned that the specific characters of georgicus were taken from
79. Pennant. The name Trionyx georgianus presumably appears for this
taxon in Geoffroy's earlier-published synopsis (1809:367). T.
georgicus was listed as occurring in rivers of Georgia and the
Carolinas; the type locality was restricted by Schmidt (op. cit.:109)
to the Savannah River, Georgia. The two specific names georgicus
and georgianus are regarded as substitute names and junior
synonyms of T. ferox.
Geoffroy (1809a:14-15) also described Trionyx carinatus, a
name-combination that hitherto has been considered a synonym of
Trionyx ferox. There is no indication from the description that
carinatus is applicable to ferox. Most comments pertain to a
description of the bony carapace and plastron, which Geoffroy
depicts in Plate 4. It is a young specimen judging from the small and
isolated preneural; the seventh pair of pleurals is unusual in being
fused (no middorsal suture), and the neurals seem large in
proportion to the size of the pleurals. The anterior border of the
carapace is described as having tubercles. Geoffroy listed Testudo
membranacea and Testudo rostrata as synonyms of carinatus.
Fitzinger (1835:127) listed T. membranacea, T. rostrata and T.
carinatus as synonyms of Trionyx javanicus (= T. cartilagineus),
which was also described by Geoffroy (op. cit.:15). Duméril and
Bibron (op. cit.:478, 482) considered carinatus to be the young of
spinifer (ferox as synonym). Gray (1844:48), however, referred T.
membranacea and T. rostrata to the synonymy of T. javanicus, but
considered T. carinatus to be a synonym of T. ferox (op. cit.:50), an
interpretation followed by all subsequent authors. Trionyx carinatus
is questionably listed as a synonym of ferox by Stejneger (1944:27).
Duméril and Bibron (op. cit.:482) wrote that the young type of
carinatus is in the museum at Paris. Dr. Jean Guibé informs me in
letter of September 24, 1959, that the type of Geoffroy's T. carinatus
cannot be found in the Natural History Museum at Paris. For the
present, T. carinatus is considered a nomen dubium. According to
Stejneger (1944:27), Trionyx brongniarti Schweigger is a substitute
name for T. carinatus.
80. I am unable to add anything to Stejneger's (op. cit.:32) account
of Trionyx harlani; the mention of its occurrence in east Florida
indicates that it is indistinguishable from Testudo ferox Schneider.
T. ferox was considered to be indistinguishable from Lesueur's
Trionyx spiniferus (described in 1827), until Agassiz (1857:401)
pointed out the differences between the two species. However,
Agassiz (op. cit.:402, Pl. 6, Fig. 3) regarded juveniles of T. spinifer
asper as the young of ferox. Consequently, the geographic range of
ferox, as envisioned by Agassiz, extended from Georgia and Florida
west to Louisiana. Neill (1951:15) considered all [485] American
forms conspecific. Crenshaw and Hopkins (1955) and Schwartz
(1956) demonstrated that ferox is a distinct species.
Fitzinger (1843:30) designated the species ferox as the type
species of his genus Platypeltis as follows: Platypeltis. Fitz.
Am[erica]. Platypelt. ferox. Fitz. Typus. If populations of soft-shelled
turtles that are referable to Testudo ferox Schneider are considered
to comprise a distinct genus by future workers, Platypeltis Fitzinger,
1835, is available as a generic name with Testudo ferox Schneider,
1783, as the type species (by subsequent designation).
Trionyx ferox in the northern part of its range is sympatric with T.
spinifer asper. In the region of overlap, the two species are nearly
always ecologically isolated; ferox inhabits lentic waters, whereas T.
s. asper is partial to lotic waters (Crenshaw and Hopkins, op.
cit.:16). There is no evidence of intergradation or hybridization.
Many characters of Trionyx ferox that are lacking in other North
American forms are shared with some Asiatic softshells, such as the
large size, longitudinal rows of tubercles that resemble ridges on the
carapace, and the marginal ridge. It is thought that, of the living
softshells in North America, ferox is more closely allied to Old World
forms of the genus than to muticus or spinifer.
Carr (1940:107) recorded ferox from Okaloosa County, Florida, in
the western end of the panhandle, whereas Crenshaw and Hopkins
81. (1955:16) list the known westward extent of range as Leon and
Wakulla counties. AMNH 6933 from west of the Apalachicola
drainage in Washington County, Florida, tends to substantiate Carr's
record, which is not included on the distribution map.
Specimens examined.—Total 144, as follows: Florida: Alachua:
UMMZ 64178, 100969; USNM 10545, 10704, near Gainesville;
UMMZ 56599, Levy Lake. Brevard: AMNH 12878, Canaveral.
Broward: UMMZ 109441, Hugh Taylor Birch State Park; USNM
109548, 22 mi. WNW, 6 mi. SSE Fort Lauderdale. Collier: USNM
86828, Tamiami Trail, near Birdon. Dade: AMNH 50936, UMMZ
10183, 110981, Miami; USNM 84079, 86942, 15 mi. from (west)
Miami, Tamiami Trail; UMMZ 111371, 19 mi. W, 1.3 mi. S Miami; UI
28984, 35 mi. W. (Miami) Tamiami Trail; AMNH 69932-33, UMMZ
101582, 101584, 104024, 40-45 mi. W Miami, Tamiami Trail. Glades:
UMMZ 100836, mouth of Kissimmee River. Hendry: UMMZ 106302,
10.2 mi. SE Devil's Garden; UMMZ 106303-04, 106321-22, 30 mi. S
Clewiston, near Devil's Garden. Hernando: TU 13624, 0.5 mi. S
Citrus Co. line on US Hwy. 19. Highland: AMNH 65537, 71618,
Archbold Biol. Stat., Lake Placid; AMNH 65622, Hicoria. Hillsborough:
TU 13960, Hillsborough River, ca. 20 mi. NE Tampa; USNM 51184,
Tampa; USNM 71156, Plant City. Indian River: USNM 55316, Vero
Beach; USNM 59318, Sebastian. Lake: UMMZ 36072, USNM 20189,
029210, 029339, 38123, Eustis; UMMZ 76754-56, Lake Griffin. Lee:
UMMZ 102276, 14 mi. SE Punta Gorda. Leon: CNHM 33701, USNM
95767, Lake Iamonia; USNM 103736, Silver Lake. Marion: AMNH
8294-95, UMMZ 95613 (4), USNM 52476-83, 100902-04, Eureka;
AMNH 63642, near Salt Springs. Martin: TNHC 1292, 8.4 mi. N Port
Mayaca. Okeechobee: AMNH 57379-84, Lake Okeechobee; AMNH
5931-32, Kissimmee Prairie. Orange: USNM 51421, 56805, Orlando;
KU 16528. Osceola: USNM 029448, 029450-64, 029467-68, 029470,
029474-75, Kissimmee. Palm Beach: UMMZ 54101, Palm Beach;
USNM 73199, Delray Beach. Pinellas: USNM 51417-20, St.
Petersburg. Polk: AMNH 25543, Lakeland; UMMZ 112380, 6.7 mi. S
Lake Wales; USNM 60496, 60532, 60534, 61083-87, Auburndale.
Putnam: USNM 4373, 7651, Palatka; USNM 26035, ponds near
82. Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com