[EBOOK PDF] Download complete Data structure and algorithm analysis C language English 2 Adapted China Edition Mark Allen Weiss ebook
[EBOOK PDF] Download complete Data structure and algorithm analysis C language English 2 Adapted China Edition Mark Allen Weiss ebook
https://ebookultra.com/download/data-structures-and-problem-solving-
using-c-2nd-international-edition-edition-mark-allen-weiss/
https://ebookultra.com/download/data-structures-and-algorithm-
analysis-in-c-fourth-edition-international-edition-chandavarkar/
https://ebookultra.com/download/data-structures-and-algorithm-
analysis-in-c-3rd-edition-dr-clifford-a-shaffer/
https://ebookultra.com/download/discovering-language-the-structure-of-
modern-english-1st-edition-lesley-jeffries/
https://ebookultra.com/download/data-analysis-and-applications-2-1st-
edition-edition-bozeman/
https://ebookultra.com/download/andrea-zanzotto-the-language-of-
beauty-s-apprentice-beverly-c-allen/
https://ebookultra.com/download/data-structures-and-algorithm-
analysis-in-java-
%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84%e4%b8%8e%e7%ae%97%e6%b3%95%e5%88%
86%e6%9e%90-java%e8%af%ad%e8%a8%80%e6%8f%8f%e8%bf%b0-
%e6%95%b0%e6%8d%ae%e7%bb%93/
https://ebookultra.com/download/techniques-of-saxophone-playing-
english-and-german-edition-marcus-weiss/
Data structure and algorithm analysis C language English
2 Adapted China Edition Mark Allen Weiss Digital
Instant Download
Author(s): Mark Allen Weiss
ISBN(s): 9787115139849, 7115139849
Edition: 2
File Details: PDF, 20.07 MB
Year: 2005
Language: english
. ‘Ta
I P w
A
‘4’ III
..
.— V V
Data Structures
arid
Algorithm AnaIVsIs In C
9::
=
4
I. . : I.
- in: •1
= : .... I•
I-
II
S.
-- t
:4l_ S : ::Er
I I I
=tfl*
I I 11 I I I -——•—ll
I I .1
ISBN 7—115—13984—9 I I I I I I I I I I I I 1 I •I
lg_ •.59
ISW7-1 15-13984-9/’1P4957
‘iLfft:49.(K) )L
9 787115 139849 >
-
TURING;0]
(Second Edition)
..L+I- ‘-1
I,-, h:i
(3&•2&)
[] Mark Allen Weiss
(QWJ&. itfltJLWi)
ISBN 7-115-13984-9
t1-fl43J
iFIIMiA! (t1t&
4&***Ji—C 2 }&)
A B&4±+1J!i&t ,tihlflV9iWfll 14 4
WIS 100061 k !pgilt 315ptpress com.cn
l lit hltp://www.ptpress.com.cn
njAt1 uDJrpAi
1gj1rj ,jffi2ffi
)F4-: 800x1000 1/16
141*: 32.5
: 7271$ 2005W8Jj3W1&
a4Tu 01-2005-3578 -
ISBN 7-115-13984-9/TP 4957
ffr 49.OO5L
jNR*)M: (010)88593802 P MM: (010)67129223
Adapter’s Foreword
Purpose
The original of this book is an excellent work of Mark Allen Weiss. All the
fundamental topics are covered. The ADT concepts and the analysis of the
algorithms (especially the average analysis)
case emphasized. The extensive
are
re-composition is made to trim the contents of the book so that it better fits a
second-year undergraduate course in data structures and algoritlun analysis for the
Chinese students.
What’sNew
The recomposition includes two major changes. First, the review section
structure
of mathematics has been canceled since sophomore students in China have taken
sufficient courses in mathematics in their first-year study, including calculus, linear
algebra, and discrete mathematics. Secondly, the original Chapter 5 is moved to
follow Chapter 7, in order to show hashing as a method to break the lower bound
of searching by comparisons only.
Other minor changes include adding some interesting data structures and
methods, and rearranging part of the contents. Introduction of the sparse matrix
representation is added as an example of application of mu.ltilists in Section 3.2.
At the mean time, bucket sort and radix sort are discussed in more details in
example in Section 3.2. In Chapter 4, the two sections about tree traversals, namely
Sections 4.1.2 and 4.6, are merged into one and are inserted into Section 4.2.3.
Threaded binary tree is then formally introduced instead of being mentioned in
exercises only. At the beginning of Chapter 7 (which was Chapter 5 in the original
Acknowledgments
We feel grateful to Mark Allen Weiss, the author of the original book, and Pearson
Education, the original publisher, for their great support on this recomposition. It is
their understanding and generosity that make it possible for more Chinese students to
Finally I would like to thank everyone at Turing Book Company, the publisher of
this adapted edition, who have put in great effort to make this kind of cooperation
possible.
It is my very first attempt on making a recomposition of a textbook. If you have
any suggestions for improvements, I would very much appreciate your comments.
Yue Chen
chenyuecs.zju.edu.cn
Zhejiang University
PREFACE
Purpose/Goals
This book describes data structures, methods of organizing large amounts of data,
and algorithm analysis, the estimation of the running time of algorithms. As computers
become faster and faster, the need for programs that canhandle large amounts
of input becomes more acute. Paradoxically, this requires more careful attention to
efficiency, since inefficiencies in programs become most obvious when input sizes are
large. By analyzing an algorithm before it is actually coded, students can decide if a
particular solution will be feasible. For example, in this text students look at specific
problems and see how careful implementations can reduce the time constraint for
large amounts of data from 16 years to less than a second. Therefore, no algorithm
or data structure is presented without an explanation of its running time. In some
cases, minute details that affect the running time of the implementation are explored.
Approach
I believe it is important for students to learn how to program for themselves, not
discuss realistic programming issues without including sample code. For this reason,
the book usually provides about one-half to three-quarters of an implementation,
and the student is encouraged to supply the rest. Chapter 12, which is new to this
edition, discusses additional data structures with an emphasis on implementation
details.
PREFACE
if (x=y)
are generally used in the text, since the loss of clarity is compensated by only a
not
few keystrokes and no increased speed. I believe that this book demonstrates that
unreadable code can be ivoided by exercising reasonable care.
Overview
Chapter 5 is about priority queues. Binary heaps are covered, and there is
additional material on of the theoretically interesting implementations of
some
priority queues. The Fibonacci heap is discussed in Chapter 11, and the pairing heap
is discussed in Chapter 12.
PREFACE lx
Chapter 6 covers sorting. It is very specific with respect to coding details and
and
analysis. All the important general-purpose sorting algorithms are covered
are analyzed in detail: insertion sort, Shellsort, heapsort,
compared. Four algorithms
and quicksort. The analysis of the average-case running time of heapsort is new to
this edition. External sorting is covered at the end of the chapter.
hash tables. Some analysis is
Chapter 7 is a relatively short chapter concerning
at the end of the chapter.
performed, and extendible hashing is covered
Chapter 8 discusses the disjoint set algorithm with proof of the running time.
This is a short and specific chapter that can be skipped if Kruskal’s algorithm is not
discussed.
Chapter 9 covers graph algorithms. Algorithms on graphs are interesting, not
only because they frequently occur in practice but also because their running time is
so heavily dependent on the proper use of data structures. Virtually all of the standard
algorithms are presented along with appropriate data structures, pseudocode, and
analysis of running time. To place these problems in a proper context, a short
discussion on complexity theory (including NP-completeness and undecidability) is
provided.
Chapter 10 covers algorithm design by examining common problem-solving
techniques. This chapter is heavily fortified with examples. Pseudocode is used in
these later chapters so that the student’s appreciation of an example algorithm is not
obscured by implementation details.
Chapter 11 deals with amortized analysis. Three data from Chapters
structures
Chapter 12 is new to this edition. It covers search tree algorithms, the k-d tree,
and the pairing heap. This chapter departs from the rest of the text by providing
complete and careful implementations for the search trees and pairing heap. The
material is structured so that the instructor can integrate sections into discussions
from other chapters. For example, the top-down red black tree in Chapter 12 can
be discussed under AVL trees (in Chapter 4).
Chapters 1—9
provide enough material for most one-semester data structures
courses. If time permits, then Chapter 10 be covered. A graduate course
can
text.
Exercises
Exercises, provided at the end of each chapter, match the order in which material
is presented. The last exercises may address the chapter as a whole rather than a
specific section. Difficult exercises are marked with an asterisk, and more challenging
exercises have two asterisks.
PREFACE
References
References are placed at the end of each chapter. Generally the references either
are historical, representing the original of the material, or they represent
source
extensions and improvements to the results given in the text. Some references
represent solutions to exercises.
Code Availability
The example program code in this book is available via anonymous ftp
at ftp://ftp.csfiu.edu/pub/weiss/WEISS_2E.tar.Z
Acknowledgments
Many, many people have helped me in the preparation of books in this series. Some
are listed in other versions of the book; thanks to all.
For this edition, I would like to thank my editors at Addison-Wesley, Carter
Shanklin and Susan Hartman. Ten Hyde did another wonderful job with the
production, and Matthew Harris and his staff at Publication Services did their usual
fine work putting the final pieces together.
M.A.W.
Miami, Florida
July, 1996
CONTENTS
Adapter’s Foreword
Preface
Introduction 1
1.1. What’s the Book About? 1
Summary 7
Exercises 7
References 8
2 Algorithm Analysis 9
xi
CONTENTS
3.2. TheLisLwT 36
3.2.1. Simple Array Implementation of Lists 37
3.2.2. Linked Lists 37
3.2.3. Programming Details 38
3.2.4. Common Errors 43
3.2.5. DoublyLinked Lists 45
3.2.6. Circularly Linked Lists 46
3.2.7. Examples 46
3.2.8. Cursor Implementation of Linked Lists 50
3.3. The StackAnT 56
3.3.1. stack Model 56
3.3.2. Implementation of Stacks 57
3.3.3. Applications 65
3.4. The QueueMT 73
3.4.1. Queue Model 73
3.4.2. Array Implementation of Queues 73
3.4.3. Applications of Queues 78
Summary 79
Exercises 79
4 Trees 83
4.1. Preliminaries 83
4.1.1. Terminology 83
4.1.2. TreeThtversalswithanApplication 84
4.2. Binary Trees 85
4.2.1. Implementation 86
4.2.2. Expression Trees 87
4.2.3. Tree Traversals 90
Summary 133
Exercises 134
References 141
6 Sorting 187
6.1. Preliminaries 187
6.2. Insertion Sort 188
-
7 Hashing 235
7.1. General Idea 235
7.2. Hash Function 237
7.3. Separate Chaining 239
7.4. Open Addressing 244
7.4.1. Linear Probing 244
7.4.2. Quadratic Probing 247
7.4.3. Double Hashing 251
CONTENTS XV
Summary 339
Exercises 339
References 345
Summary 415
Exercises 417
References 424
CONTEWFS xvii
Introduction
In thischapter, we discuss the aims and goals of this text and briefly review
Suppose you have a group of N numbers and would like to determine the kit largest.
This is known as the selection problem. Most students who have had a programming
course or two would have no difficulty writing a
program to solve this problem.
sort the array in decreasing order by some simple algorithm such as bubblesort, and
then return the element in position k.
A somewhat better algorithm might be to read the first k elements into an array
and sort them (in decreasing order). Next, each remaining element is read one by
one. As a element arrives, it is ignored if it is smaller than the kit element
new
in the array. Otherwise, it is placed in its correct spot in the array, bumping one
element of the array. When the algorithm ends, the element in the kth position
out
natural questions, then, which algorithm is better and, more important, is either
are
and that. The word this begins at row 1, column 1, or (1,1), and extends to (1,4);
two goes from (1,1) to (3,1); fat goes from (4,1) to (2,3); and that goes from (4,4)
to (1,1).
Again, there are at least two straightfonvard algorithms that solve the problem.
For each word in the word list, we check each ordered triple (row, column,
orientation) for the presence of the word. This amounts to lots of nested for loops
but is basically straightforward.
Alternatively, for each ordered quadruple (row, column, orientation, number
of characters) that doesn’t run off an end of the puzzle, we can test whether the
word indicated is in the word list. Again, this amounts to lots of nested for loops. It
is possible to save some time if the maximum number of characters in any word is
known.
It is relatively easy to code up either method of solution and solve many of the
real-life puzzles commonly published in magazines. These typically have 16 rows, 16
columns, and 40 or so words. Suppose, however, we consider the variation where
only the puzzle board is given and the word list is essentially an English dictionary.
Both of the solutions proposed require considerable time to solve this problem and
therefore are not acceptable. However, it is possible, even with a large word list, to
solve the problem in a matter of seconds.
An important concept is that, in many problems, writing a working program is
not good enough. If the program is to be runon a large data set, then the running
time becomes an issue. Throughout this book we will see how to estimate the
running time of a program for large inputs and, more important, how to compare
the running times of two programs without actually coding them. We will see
techniques for drastically improving the speed of a program and for determining
program bottlenecks. These techniques will enable us to find the section of the code
on which to concentrate our
optimization efforts.
1 2 3 4
1 t Ii 1 s
2 w a t s
3 o a h g
4 f g d t
1.2. A BRIEF INTRODUCTION TO RECURSION 3
C =
S(F 32)19
Given this formula, it is trivial to write a C function; with declarations and braces
removed, the one-line formula translates to one line of C.
Mathematical functions are sometimes defined in a less standard form. As an
example, we can define a function F, valid on nonnegative integers, that satisfies
F(O) 0 and F(X)
=
2F(X 1) + V. From this definition we see that F(1)
=
1, =
F(2) =
6, F(3) =
21, and F(4) =
58. A function that is defined in terms of itself
is called recursive. C allows functions to be recursive.* It is important to remember
that what C provides is merely an attempt to follow the recursive spirit. Not all
mathematically recursive functions are efficiently (or correctly) implemented by
C’s simulation of recursion. The idea is that the recursive function F ought to be
expressible in only a few lines, just like a nonrecursive function. Figure 1.2 shows
the recursive implementation of F.
Lines I and 2 handle what is known as the base case, that is, the value for
which the function is directly known without resorting to recursion. Just as declaring
F(X) 2F(X
=
1) + X2 is meaningless, mathematically, without including the fact
that F(0) 0, the recursive C function doesn’t make sense without a base case.
=
There are several important and possibly confusing points about recursion. A
common question is: Isn’tthis just circular logic? The answer is that although we are
a function in terms of itself, we are not defining a
defining particular instance of the
function in terms of itself. In other words, evaluating F(S) by computing F(S) would
be circular. Evaluating F(S) by computing F(4) is not circular—unless, of course,
F(4) is evaluated by eventually computing F(S). The important two most issues are
‘Using recursion for numerical calculations is usually a bad idea. We have done so to illustrate the basic
points.
CHAFfER V1NTRODUCTION
F(3), and finally F(4)can be determined. All the bookkeeping needed to keep track
of pending function calls (those started but waiting for a recursive call to complete),
along with their variables, is done by the computer automatically. An important
point, however, is that recursive calls will keep on being made until a base case
is
reached. For instance, an attempt to evaluate F(—1) will result in calls to F(—2),
F(—3), and so on. Since this will never get to a base case, the program won’t be able
to compute the answer (which is undefined anyway). Occasionally, a much more
subtle error is made, which is exhibited in Figure 1.2. The error in the program in
Figure 1.2 is that Bad(1) is defined, by line 3, to be Bad(1). Obviously, this doesn’t
give any clue as to what Bad( 1) actually is. The computer will thus repeatedly
make calls to Bad(1) in an attempt to resolve its values. Eventually, its bookkeeping
system will run out of space, and the program will crash. Generally, we would say
that this function doesn’t work for one special case but is correct otherwise. This
isn’t true here, since Bad(2) calls Bad(1). Thus, Bad(2) cannot be evaluated either.
Furthermore, Bad(3), Bad(4), and Bad(S) all make calls to Bad(2). Since Bad(2)
is unevaluable, none of these values are either. In fact, this program doesn’t work
for any value of N, except 0. With recursive programs, there is no such thing as a
“specialcase.”
These considerations lead to the first two fundamental rules of recursion:
1. Base cases. You must always have some base cases, which can be solved
without recursion.
2. Making progress. For the cases that are to be solved recursively, the recursive
call must always be to a case that makes progress toward a base case.
irit
Bad( unsigned mt N )
{
7*1*, if(N==O)
/* 2*! return 0;
else
returnBad(N/3+1)-i-N-1;
understand that definition and retrace our path through the other definitions) or
will find that the definitions circular and we are stuck, or that some word
(2) we are
don’t know. This procedure will terminate if the dictionary is well defined but can
Suppose we have a positive integer, N, that we wish to print out. Our routine will
have the heading PrintOut(N). Assume that the only 110 routines available will
take a single-digit number and output it to the terminal. We will call this routine
Let us
prove (somewhat) rigorously that the recursive number-prinzing program
works. To do so, we’ll use a proof by induction.
void
Printout( unsigned ‘mt ‘N ) /* Print nonnegative N /
if(N>=10)
PrintOut( N / 10 );
I
PrintDigit( N % 10 );
}
ThEOREM 1.1
-
First, if N hasone
digit, then the program is trivially corrects since it merely
makes a call to PrintDigit. Assume then that PrintOut works for all numbers
of k or fewer digits. A number of k + L digits is expressed by its first k digits
followed by its least significant digit. But the number formed by the first k digits
is exactly [Nib], which, by the inductive hypothesis, is correctly printed, and
the last digit is Nmod 10, so the program prints out any (k + 1)-digit number
correctly. Thus, by induction, all numbers are correctly printed.
This proof probably seems a little strange in that it is virtually identical to the
algorithm description, it illustrates that in designing a recUrsive program, all smaller
instances of the same problem (which are on the path to a base case) may be assumed
to work correctly. The recursive program needs only to combine solutions to smaller
problems, which are “magically”obtained by recursion, into a solution for the
current problem. The mathematical justification for this is proof by induction. This
gives the third rule of recursion:’
3. Design rule. Assume that all the recursive calls work.
This rule is important because it means that when designing recursive programs,
you generally don’tneed to know the details of the bookkeeping arrangements, and
you don’t have to try to trace through the myriad of recursive calls. Frequently, it is
extremely difficult to track down the actual sequence of recursive calls. Of course,
in many cases this is an indication of a good use of recursion, since the computer is
being allowed to work out the complicated details.
The main problem with’recursion is the hidden bookkeeping costs. Although
these costs are almost always justifiable, because recursive programs not only simplify
the algorithm design but also tend to give cleaner code, recursion should never be
used as a substitute for a simple for loop. We’ll discuss the overhead involved in
recursion in
more detail in Section 3.3.
When writing recursive routines, it is crucial to keep in mind the four basic
rules of recursion:
1. Base cases. You must always have some base cases, which can be solved
without recursion.
SUMMARY
2. Making progress. For the cases that are to be solved recursively, the recursive
must always be to a case that makes progress toward a base case.
call
3. Design rule. Assume that all the recursive calls work.
4. Compound interest rule. Never duplicate work by solving the same instance
ofa problem in separate recursive calls.
The fourth rule, which will be justified (along with its nickname) in later sections,
is the reason that it is generally a bad idea to use recursion to evaluate simple
mathematical functions, such as the Fibonacci numbers. As long as you keep these
rules in mind, recursive programming should be straightforward.
Summary
This chapter sets the stage for the rest of the book. The time taken by an algorithm
confronted with large amounts of input will be an important criterion for deciding if
it is agood algorithm. (Of course, correctness is most important.) Speed is relative.
What is fast for one problem on one machine might be slow for another problem or
a different machine. We will begin to address these issues in the next chapter and
will establish a formal mathematical model.
Exercises
#include filename
which reads filename and inserts its contents in place of the include statement.
Include statements may be nested; in other words, the file filename may itself
contain an include statement, but, obviously, a file can’t include itself in any
chain. Write a program that reads in a file and outputs the file as modified by
the include statements.
b. FN <IN, with 4 =
(1 +
*
*c. Give a precise closed-form expression for FN.
CHAFFER I/INTRODUCTION
References
There are
many textbooks covering the basic mathematics that you may need
good
to better understand the following chapters. A small subset is [1], [2], [3], [9], [10],
and [11].Reference [9] is specifically geared toward the analysis of algorithms. It is
the first volume of three-volume series that will, be cited
a throughout this text.
More advanced material is covered in [5].
pointers and recursion (the recursion summary in this chapter is meant to be a quick
review). We will attempt to provide hints on their use where appropriate throughout
the textbook. Readers familiar with these should consult [12]
not or any good
intermediate programming textbook.
Algorithm Analysis
An algorithm is a clearly specified set of simple instructions to be followed to solve
a problem. Once an algorithm is given for a problem and decided (somehow) to be
correct, an important step is to determine how much in the way of resources, such
as time or space, the algorithm willrequire. An algorithm that solves a problem but
requires a year is hardly of any use. Likewise, an algorithm that requires a gigabyte
of main memory is not (currently) useful on most machines.
In this chapter, we shall discuss
T(N)
DEFINITION: O(f(N)) if there are
positive constants c and n0 such that
DEFINmON: T(N) =
O(h(N)) if and only if T(N) =
O(h(N)) and T(N) =
DEFJNmON: T(N) =
o(p(N)) if T(N) =
O(p(N)) and T(N) e(?(N)). 9
CIIAPTSR YALGORITIIM ANALYSIS
The idea of these definitions is to establish a relative order among functions. Given
two functions, there usually points where one function is smaller than the other
are
“Big-Oh....”
If we use the traditional inequality operators to compare growth rates, then
the first definition says that the growth rate of T(N) is less than or
equal to ()
that of ((N). The second definition, T(N) fl(g(N)) (pronounced “omega”),
=
says
that the growth rate of T(N) is greater than or
equal to () that of g(N). The
third definition, T(N) 0(h(N)) (pronounced “theta”),
=
says that the growth rate
of T(N) equals (“)the growth rate of h(N). The last definition, T(N)
o(p(N)) =
(pronounced “little-oh”),says that the growth rate of T (N) is less than (<) the
growth rate of p(N). This is different from Big-Oh, because
Big-Oh allows the
possibility that the growth rates are the same.
To
prove that some function T(N) O(f(N)), we usually do not apply these
=
definitions formally but instead use a repertoire of known results. In general, this
means that a proof (or determination that the assumption is incorrect) is a
very simple
calculation and should not involve calculus, except in extraordinary circumstances
(not likely to occur in an
algorithm analysis).
When we say that T(N) O(f(N)), we are guaranteeing that the function
=
T(N) grows at a rate no faster than ((N); thus ((N) is an upper bound on T(N).
Since this implies that [(N) fl(T(N)), we say that T(N) is a lower bound on
=
[(N).
As an example, N3 grows faster than
N2, so we can say that N2 0(N3) =
or N3 =
0(N2). ((N) =
N2 and g(N) 2N2 grow at the both
same rate, so
((N) =
O(g(N)) and f(N) =
fl(g(N)) are true. When twofunctions grow at
the same rate, then the decision of whether or not to signify this with 0() can
depend on the particular context. Intuitively, if g(N) 2N2, then g(N) 0(N4), = =
is the best answer. Writing g(N) 0(N2) says not only that g(N) 0(N2), but
=
=
RULE 1:
O(g(N)), then =
Function Name
c Constant
log N Logarithmic
log2 N Log-squared
N Linear
N logN
N2 Quadratic
N3 Cubic
Exponential
RIJLE2:
RUI 3:
logk N =
0(N) for any constant k. This tells us that logarithms grow very
slowly.
This information is sufficient to arrange most of the common functions by
growth (see Figure 2.1).
rate
Several points are in order. First, it is very bad style to include constants or low-
order terms inside a Big-Oh. Do not say T(N) =
0(2N2) or 0(N2 N).
T(N) =
+
In both cases, the correct form is T(N) 0(N2). This means that in any
analysis
that will require a Big-Oh answer, all sorts of shortcuts are possible. Lower-order
terms can generally be ignored, and constants can be thrown away. Considerably
Using this method almost always amounts to overkill. Usually the relation between
and g(N) N15, then to decide which of ((N) and g(N) grows faster, one really
needs to determine which of log N and N o•grows faster. This is like determining
limN.. f’(N)/g(N), where [‘(N) and g’(N) are the derivatives of [(N) and g(N), respectively.
CHAPrER ZIALGORIThM ANALYSIS
f(N).
One stylistic note: It is bad to say [(N) O(g(N)), because the inequality is
implied by the definition. It is wrong to write [(N) O(g(N)), which does not
make sense.
2.2. Model
important, we cannot deal with them here. The other main factors are the algorithm
used and the input to the algorithm.
Typically, the size of the input is the main consideration. We define two
functions, ?vg(N) and T0(N), as the average and worst-case running time,
respectively, used by an algorithm on input of size N. Clearly, Tavg(N) Tworst(N).
If there is more than one input, these functiqns may have more than one argument.
Generally, the quantity required is the worst-case time, unless otherwise specified.
One reason for this is that it provides a bound for all input, including
particularly bad input, which an average-case analysis does not provide. The other
reason is that average-case bounds are usually much more difficult to compute. In
some instances, the definition of “average”can affect the result. (For instance, what
is average input for the following problem?)
2.3. WHATTOANALYZE 13
Given (possibly negative) integers A1, A2, ,A, find the maximum value
. . .
all the
of Ak. (For convenience, the maximum subsequence sum is 0 if
integers are negative.)
Example:
For 11, —4,
input —2, —2,
13, —5, the answer is 20 (A2 through A4).
This problem is interesting mainly because there are so many algorithms to
solve it, and the of these algorithms varies drastically. We will discuss
performance
four algorithms to The running time on some computer (the
solve this problem.
exact computer is unimportant) for these algorithms is given in Figure 2.2.
There are several important things worth noting in this table. For a small
amount of input, the algorithms all run in a blink of the eye, so if only a small
amount of input is expected, it might be silly to expend a great deal of effort to
design a clever algorithm. On the other hand, there is a large market these days
for rewriting programs that were written five years ago based on a no-longer-valid
assumption of small input size. These programs are nowtoslow, beãause they used
poor algorithms. large For amounts of input, algorithm 4 is clearly the best choice
(although algorithm 3 is still usable).
Second, the times given do not include the time reqdired to readthe input. For
algorithm 4, the time merely to read in the input from a disk is likely to be an order
of magnitude larger than the time required to solve the problem. This is typical of
many efficient algorithms.. Reading the data is generally the bottleneck;: once the
data are read, the problem can be solved quickly. For inefficient algarithrns this
is not true, and significant computer resources must be used. Thus it is important
that, whenever possible, algorithms be efficient enough nqt to be the bottleneck of a
problem.
Figure 2.3 shows the growth rates of the running times of the four algorithms.
Even though this graph encompasses only values of N ranging from 10 to 100, the
relative growth rates are still evident. Although the graph for algorithm 3 seems
linear, it is easy to verify that it is not by using a straight-edge (or piece of paper).
Figure 2.4 shows the performance for larger values. It dramatically illustrates how
useless inefficient algorithms are for even moderately large amounts of input.
Figure 2.2 Running times of several algorithms for maximum subsequence sum
(in seconds)
Algorithm 1 2 3 4
Al 1. 0(N3) Al 2. 0(N2)
AIg 3. 0(NlogN)
4
1
A1g4.0(N)
00 10 20 30 40 50 60 70 80 90 100
algorithms
Aig 1. 0(N3)
0(N2)
g 2.
0.4
0.3
0.2
0.1
Al 4.0(N)
0.00 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000
FIgure 2.4 Plot (N vs. seconds) of various maximum subsequence sum algorithms
There are several ways to estimate the running time of a program. The previous
table was obtained empirically. If two programs are expected to take similar times,
probably the best way to decide which is faster is to code them both up and run
them!
2.4. RUNNING TIME CAlCUlATIONS
Generally, there are several algorithmic ideas, and we would like to eliminate
the bad ones early, so an analysis is usually required. Furthermore, the ability to do
an analysis usually provides insight into designing efficient algorithms.
The analysis
also generally pinpoints the bottlenecks, which are worth coding carefully.
To simplify the analysis, we will adopt the convention that there are no particular
units of time. Thus, we throw away leading constants. We will also throw away
low-order terms, so what we are essentially doing is computing a Big-Oh running
time. Since Big-Oh is an upper bound, we must be careful never to underestimate the
running time of the program. In effect, the answer provided is a guarantee that the
program will terminate within a certain time period. The program may stop earlier
than this, but never later.
/* 1*! PartialSum 0; =
The analysis of this program is simple. The declarations count for no time.
Lines 1 and 4 count for one unit each. Line 3 counts for four units per time executed
(two multiplications, one addition, and one assignment) and is executed N times,
for a total of 4N units. Line 2 has the hidden costs of initializing i, testing i N,
and incrementing i. The total cost of all these is I to initialize, N + 1 for all the
tests, and N for all the increments, which is 2N + 2. We ignore the costs of calling
the function and returning, for a total of 6N + 4. Thus, we say that this function is
0(N).
If we had to perform all this work every time we needed to analyze a program,
the task would quickly become infeasible. Fortunately, since we are giving the
answer in terms of Big-Oh, there are lots of shortcuts that can be taken without
affecting the final answer. For instance, line 3 is obviously
statement (per an 0(1)
execution), so it is silly to precisely whether it is two, three, or four units; it
count
does not matter. Line 1 is obviously insignificant compared with the for loop, so it
is silly to waste time here. This leads to several general rules.
R 1—FOR
LOOPS:
The running time of a for loop is at most the running time of the statements
inside the for loop (including tests) times the number of iterations.
CHAFflIR 2/ALGORITHM ANALYSIS
FOR LOOPS:
RULE 2—NESfED
inside
Analyze these inside out. The total running time of a statement group a
SATEMENTS:
RULE 3—CONSECUTIVE
These just add (which means that the maximum is the one that counts; see
rule 1(a)on
page 16).
As an example, the following program fragment, which has 0(N) work followed
by 0(N2) work, is also 0(N2):
for( 0; i < N; i++
I =
)
A[ I
] 0; =
RULE 4—IF/ElSE:
the running time of an if/else statement is never more than the running time of
the test plus the larger of the running times of Si and S2.
Clearly, this can be an overestimate in some cases, but it is never an underestimate.
Other rules are obvious, but a basic strategy of analyzing from the inside (or
deepest part) out works. If there are function calls, these must be analyzed first. If
there are recursive procedures, there are several options. If the recursion is really
just a thinly veiled for loop, the analysis is usually trivial. For instance, the following’
function is really just a simple loop and is 0(N):
long mt
Factorial( mt N )
{
if( N <= 1 )
return 1;
else
return N *
Factorial( N -
1 );
}
2.4. RUNNING TIME CALCUlATIONS
This example is really a poor use of recursion. When recursion is properly used,
it is difficult to convert the recursion into simple loop athis case, the structure. In
long mt
Fib( mt N )
{
/* 1*! if( N <= 1 )
/* 2*! return 1;
else
/* 3*/ return Fib( N -
1 ) + Fib( N -
2 );
program is coded up and run for values of N around 30, it becomes apparent that
this program is terribly inefficient. The analysis is fairly simple. Let T (N) be the
running time for the function Fib(N). If N 0 or N 1, then the running time is
= =
some constant value, which is the time to do the test at line 1 and return. We can
say that T(0) T(1) I because constants do not matter. The running time for
= =
other values of N is then measured relative to the running time of the base case. For
N > 2, the time to execute the function is the constant work at line I plus the work
at line 3. Line 3 consists of an addition and two function calls. Since the function
calls are not simple operations, they must be
themselves. The first analyzed by
function call is Fib(N 1) and hence, by the definition ofT, requires T(N 1) units
of time. A similar argument shows that the second function call requires T (N 2)
units of time. The total time required is then T(N 1) + T(N 2) + 2, where the
2 accounts for the work at line 1 plus the addition at line 3. Thus, for N 2, we
T(N) =
T(N 1) + T(N —2)
+ 2
Since Fib(N) =
Fib(N 1) + Fib(N 2), it is easy to show by induction that
T(N) Fib(N). In Section 1.2.5, we showed that Fib(N) < (5/3)N A similar
calculation shows that (for N > 4) Fib(N) (3/2)N, and so the running time of
this program grows exponentially. This is about as bad as possible. By keeping a
simple array and using a for loop, the running time can be reduced substantially.
This program is slow because there is huge of redundant work being
a amount
performed, violating the fourth major rule of recursion (the compound interest rule),
which was presented in Section 1.3. Notice that the first call on line 3, Fib(N 1),
actually computes Fib(N 2) at some point. This information is thrown away
and recomputed by the second call on line 3. The amount of information thrown
away compounds recursively and results in the huge running time. This is perhaps
the finest example of the maxim “Don’tcompute anything more than once” and
should not scare you away from using recursion. Throughout this book, we shall
see outstanding uses of recursion.
CHAPTER 2/ALGORITHM ANALYSIS
is of size N.
The second loop has size N i which could be small but could also be of size
N. We must assume the worst, with the knowledge that this could make the final
bound a bit high. The third loop has size j i + 1, which, again, we must assume
is of size N. The total is 0(1 N .
N .
N) =
0(N3). Statement 1 takes only 0(1)
total, and statements 7 and 8 take only 0(N2) total, since they are easy expressions
inside only two loops.
It turns out that a more precise analysis, taking into account the actual size
of these loops, shows that the answer is 9(N3) and that our estimate above was a
factor of 6 too high (which is all right, because constants do not matter). This is
generally true in these kinds of problems. The precise analysis is obtained from the
sum 1, which tells how many times line 6 is executed. The sum
can be evaluated inside out. In particular, we will use the formulas for the sum of
the first N integers and first N squares. First we have
1 =
j
-
i + 1
-mt
MaxSubsequenceSum( const mt A[ 1, mt N )
mt ThisSum, MaxSu,n, I, j, k;
/* 1*! MaxSum 0; =
/* 2*! for( i 0; =
1 < N; i++ )
/* 3*/ for( j =
1; j < N; j++ )
/* 4*/ ThisSum 0; =
for(k=i;k<=j;k++)
/* 6*! ThisSum += A[ k 1;
Next we evaluate
N—I
(N i + 1)(N I)
2
This that it is just the of the first N i integers.
sum is computed by observing sum
(N—i+1)(N—i)
=—j+1—1+2)
=
—(N + +
(N2 +3N
+2)1
1N(N-i-1)(2N+1) N 3’N(N+1) + NZ+3N+2N
2 6 2 2
N3 + 3N2 + 2N
6
We avoid the cubic running time by removing a for loop. This is not
can
always possible, but in this case there are an awful lot of unnecessary computations
present in the algorithm. The inefficiency that the improved algorithm corrects can
be seen by noticing that A, A, + =
4Z
Ak, so the computation at lines 5
and 6 inalgorithm unduly expensive. Figure 2.6 shows an improved algorithm.
1 is
Algorithm 2 is clearly 0(N2); the analysis is even simpler than before.
There is a recursive and relatively complicated O(N log N) solution to this
problem, which we now describe. If there didn’t happen to be an 0(N) (linear)
Figure 2.6 Algorithm 2
mt
MaxSubSequenceSum( const mt A[ 1, int N )
mt ThisSum, MaxSum, i, j;
/* 1*! MaxSum =
0
/* 2*! for( i =
0; 1 < N; i--+ )
{
/* 3*/ ThisSum =
0;
/* 4*/ for( j =
1; j < N; j-i-+ )
/* 5*/ ThisSum += A[ j 1;
}
/* 8*! return MaxSum;
}
CHAPTER 2/ALGORITHM ANALYSIS
In our case, the maximum subsequence sum can be in one of three places. Either
it occurs entirely in the left half of the input, or entirely in the right half, or it crosses
the middle and is in both halves. The first two cases can be solved recursively. The
last case can be obtained by finding the largest sum in the first half that includes
the last element in the first half, and the largest sum in the second half that includes
the first element in the second half. These two sums can then be added together. As
an example, consider the following input:
4 5
—3 —2 —12 6 —2
The maximum subsequence for the first half is 6 (elements A1 through A3) and
sum
it is the maximum subsequence if the element is nonnegative. The case Left> Right
is not possible unless N is negative (although minor perturbations in the code could
mess this up). Lines 6 and 7 perform the two recursive calls. We can see that the
recursive calls are always on a smaller problem than the original, although minor
perturbations in the code could destroy this property. Lines 8 to 12 and 13 to 17
calculate the two maximum that touch the center divider. The sum of these
sums
two values is the maximum sum that spans both halves. The pseudoroutine Max3
returns the largest of the three possibilities.
Algorithm 3 clearly requires more effort to code than either of the two previous
algorithms. However, shorter code does not always mean better code. As we have
seen in the earlier table showing the
running times of the algorithms, this algorithm
is considerably faster than the other two for all but the smallest of input sizes.
2.4. RUNNING TIME CALCULATIONS
static mt
MaxSubSum( const mt AL 1. mt Left, mt Right )
mt MaxLeftsum, MaxRightSum;
I nt MaxLeftBorderSum, MaxRi ghtBorderSum;
I nt LeftBorderSum, RI ghtBorderSum;
mt Center, I;
1* 5*/ Center =
C Left + Right ) / 2;
1* 6*! MaxLeftSum =
MaxSubsum( A, Left, Center );
1* 7*/ MaxRlghtSum =
MaxSubSum( A, Center + 1, RIght );
/* 8*! MaxLeftBorderSum =
0; LeftBorderSum = 0
1* 9*, for( I =
Center; I >= Left; I-- )
{
1*10*! LeftBorderSum += AL I 1;
1*11*! if( Leftsordersum > MaxLeftBorderSum )
1*12*! MaxLeftBordersum LeftBorderSum; =
1*13*! MaxRightBorderSum =
0; RlghtBorderSum =
0;
1*14*! for( I =
Center ÷ 1; 1 <= Right; 1++ )
{
1*15*! RlghtBorderSum += AL 1 1;
1*16*! If( RightBorderSum > MaxRIghtBordersum )
1*17*! MaxRightBorderSum RightBorderSum;
=
mt
MaxSubsequenceSum( const mt AL ], mt N )
{
return MaxSubSum( A, 0, N -
1 );
amount of time to execute lines 1 to 4, which we shall call one unit. Thus, T (1)
1. =
Otherwise, the program must perform two recursive calh, the two for loops between
lines 9 and 17, and some small amount of bookkeeping, such as lines 5 and 18.
The two for loops touch every element from A0 to AN-I, and there is
combine to
constant work inside the so the time expended in lines 9 to 17 is 0(N). The
loops,
code in lines 1 to 5, 8, 13, and 1$ is all a constant amount of work and can thus
be ignored compared with 0(N). The remainder of the work is performed in lines
6 and 7. These lines solve two subsequence problems of size N/2 (assuming N is
even). Thus, these lines take T(N/2) units of time each, for a total of 2T(N/2). The
total time for the algorithm then is 2T(N/2) + 0(N). This gives the equations
T(1) =
1
T(N) =
2T(N/2) + 0(N)
To simplify the calculations, we can replace the 0(N) term in the equation above
with N; since T (N) will be expressed in Big-Oh notation anyway, this will not affect
the answer. In Chapter 7, we shall see how to solve this equation rigorously. For now,
ifT(N) =
2T(N/2)+N,andT(1) =
1, then T(2) =
4 =
2*2,T(4) =
12 =
4*3,
T(8) =
32 8*4,andT(16)
=
80 = =
16*S.Thepatternthatisevident,andcanbe
derived, is that ifN 2,thenT(N)
= =
N*(k+1) NlogN+N
=
O(NlogN).
=
This analysis ‘assumes N is even, since otherwise N/2 is not defined. By the
recursive nature of the analysis, it is really valid only when N is a power of 2, since
otherwise we eventually get a subproblem that is not an even size, and the equation
is invalid. When N is not a power of 2, a somewhat more complicated analysis is
required, but the Big-Oh result remains unchanged.
In future chapters, we will see several clever applications of recursion. Here,
we present a fourth
algorithm to find the maximum subsequence sum. This algorithm
is simpler to implement than the recursive algorithm and also is more efficient. It is
shown in Figure 2.8.
It should be clear why the time bound is correct, but it takes a little thought to
see why the algorithm actually works; this is left to the reader. An extra advantage
of this algorithm is that it makes only one pass through the data, and once A[iJ is
read and processed, it does not need to be remembered. Thus, if the array is on a
disk tape, it can be read sequentially, and there is no need to store any part of
or
it in main memory. Furthermore, at any point in time, the algorithm can correctly
give an answer to the subsequence problem for the data it has already read (the
other algorithms do not share this property). Algorithms that can do this are called
on-line algorithms. An on-line algorithm that requires only constant space and runs
in linear time is just about as good as possible.
i nt
MaxSubsequencesumC const mt A[ ), mt N )
mt Thissum, MaxSum, j;
}
1* 8*! return MaxSum;
}
run in O(N log N) time. Besides divide-and-conquer algorithms, the most frequent
appearance of logarithms centers around the following general rule: An algorithm is
O(log N) if it takes constant (0(1)) time to cut the problem size by a fraction (which
is usually ). On the other hand, if constant time is required to merely reduce the
problem by a constant amount (such as to make the problem smaller by 1), then the
algorithm is 0(N).
It should be obvious that only special kinds of problems can be 0(logN). For
instance, if the input is a list of N numbers, an algorithm must take 11(N) merely to
read the input in. Thus, when we talk about O(logN) algorithms for these kinds of
problems, we usually presume that the input is preread. We provide three examples
of logarithmic behavior.
Binary Search
BINARY SEARCH:
input.
The obvious solution consists of scanning through the list from left to right
and runs in linear time. However, this algorithm does not take advantage of the
fact that the list is sorted, and is thus not likely to be best. A better strategy is to
check if X is the middle element. If so, the answer is at hand. If X is smaller than the
middle element, we can apply the same strategy to the sorted subarray to the left of the
24 CHAPTER 2/ALC,oRmIibI ANALYSIS
mt
ElementType X, mt N
BinarySearch( const ElementType A[ 1,
Mid=(Low+High)/2;
/* 4*/ if( A[ Mid I < X )
/* 5*/ Low Mid + 1;
=
else
1*6*1 if(A[Mid]>X)
/* 7*/ High Mid =
1; -
else
/* 8*! return Mid; 1* Found *1
middle element; likewise, if X is larger than the middle element, we look to the right
half. (There is also the case of when stop.) Figure 2.9 shows the code for binary
to
search (the answer is Mid). As usual, the code reflects C’s convention that arrays
begin with index 0.
Clearly, all the work done inside the ioop takes 0(1) per iteration, so the analysis
requires determining the number of times around the loop. The ioop starts with
High Low N I and finishes with High Low —1. Every time through
the ioop the value High Low must be at least halved from its previous value; thus,
the number of times around the ioop is at most [log(N 1)1 + 2. (As an example, if
High Low =
128, thcn the maximum values of High Low after each iteration
are Thus, the running time is 0(logN). Equivalently,
64, 32, 16, 8, 4, 2, 1, 0, —1.)
we could write a recursive formula for the running time, but this kind of brute-force
that needs to maintain information about the periodic table of elements (which
arises in chemistry and physics). This table is relatively stable, as new elements are
added infrequently. The element names could be kept sorted. Since there are only
about 110 elements, at most eight accesses would be required to find an element.
Performing a sequential search would require many more accesses.
2.4. RUNNING TIME CALCULATIONS
Euclid’s Algorithm
determining how long the sequence of remainders is. Although log N seems like a
good answer, it is not at all obvious that the value of the remainder has to decrease
by a constant factor, since we see that the remainder went from 399 to only 393
in the example. Indeed, the remainder does not decrease by a constant factor in
one iteration. However, we can prove that after two iterations, the remainder is at
most half of its original value. This would show that the number of iterations is at
most 2 log N =
O(log N)
and establish the running time. This proof is easy, so we
THEOREM 2.1.
PROOF:
There are two cases. If N M/2, then since the remainder is smaller than N,
the theorem is true for this case. The other case is N > M/2. But then N goes
into M once with a remainder M N <M12, proving the theorem.
One might wonder if this is the best bound possible, since 2 log N is about 20
for our example, and only seven operations were performed. It turns out that the
unsigned mt
Gcd( unsigned mt N, unsigned mt N )
unsigned mt Rem;
/ 2*/ Rem =
M % N;
1* 3*/ M =
N;
/* 4*/ N =
Rem;
/* 5*/ return N;
CHAFFER 2/ALGORITHM ANALYSIS
constant can be improved slightly, to roughly 1.44 log N, in the worst case (which
is achievable if M and N are consecutive Fibonacci numbers). The average-case
Exponentiaion
Our last example in this section deals with raising an integer to a power (which is
also an integer). Numbers that result from exponentiation are generally quite large,
so an analysis works only if we can assume that we have a machine that can store
such large integers (or a compiler that
simulate this). We will count the number
can
= . .
x.
For instance, to compute X62, the algorithm does the following calculations,
which involves only nine multiplications:
=
(X)X,X7 =
(X3)2X,X15 =
(X7)ZX =
(X15)2X,X62 (X31)2
The number of multiplications required is clearly at most 2 log N, because at most
two multiplications (if N is odd) are required to halve the problem. Again, a
in O(log N), because the sequence of multiplications is the same as before. However,
long mt
long mt X, unsigned in N )
r0wC
if(N==O)
/* 2*! return 1;
/*3*/ if(N==i)
/* 4*/ return X;
/* 5*/ if( IsEven( N ) )
1*6*1 return Pow(X*X, N/2);
else
/* 7*/ return Pow(X*X, N/2 ) *X;
}
2.4. RUNNING TIME CALCUlATIONS 27
all of the following alternatives for line 6 are bad, even though they look correct:
Both lines 6a and 6b are incorrect because when N is 2, one of the recursive calls to
Pow has 2 as the second argument. Thus no progress is made, and an infinite loop
running time.
the same circumstances. These increases can be hard to spot if the lower-order terms
have relatively large coefficients and N is
not large enough. An example is the jump
from N 10 to N
=
100 in the running time for the various implementations of
=
the maximum subsequence sum problem. It also can be very difficult to differentiate
linear programs from 0(N log N) programs purely on empirical evidence.
Another commonly used trick to verify that some program is 0(1(N)) is to
compute the values T(N)/f(N) for a range of N (usually spaced out by factors of
2), where T(N) is the empirically observed running time. If [(N) is a tight answer
for the running time, then the computed values converge to a positive constant. If
[(N) is an overestimate, the values converge to zero. If [(N) is an underestimate
and hence wrong, the values diverge.
As an example, the program fragment in Figure 2.12 computes the probability
that two distinct positive integers, less than or equal to N and chosen randomly, are
relatively prime. (As N gets large, the answer approaches 6/r2.)
You should be able to do the analysis for this program instantaneously. Figure
2.13 shows the actual observed running time for this routine on a real computer. The
table shows that the last column is most likely, and thus the analysis that you should
have gotten is probably correct. Notice that there is not a great deal of difference
between 0(N2) and O(N2 log N), since logarithms grow so slowly.
2.4.6. AGrainofSalt
Sometimes the analysis is shown empirically to be an overestimate. If this is the
case, then either the analysis needs to be tightened (usually by a clever observation),
or it may be that the
average running time is significantly less than the worst-case
CHAFFER 2/ALGORIThM ANALYSIS
Re] 0; Tot
=
0; =
for( I 1; i <= N;
= I-i-+ )
for( j i + 1; =
j <= N; j+÷ )
{
Tot+±;
if( Ccd( I, j ) ==
1)
Re]++;
running time and no improvement in the bound is possible. For many complicated
algorithms the worst-case bound is achievable by some bad input but is usually an
overestimate in practice. Unfortunately, for most of these problems, an average-case
analysis is extremely complex (in many cases still unsolved), and a worst-case bound,
even
though overly pessimistic, is the best analytical result known.
Summary
This chapter gives some hints on how to analyze the complexity of programs.
Unfortunately, it is not a complete guide. Simple programs usually have simple
Another Random Scribd Document
with Unrelated Content
[921] Historia, dec. ii. lib. x, cap. 18.
[922] [Cf. the bibliography of these letters in chap. vi. The notes in
Brinton’s Floridian Peninsula are a good guide to the study of the
various Indian tribes of the peninsula at this time.—Ed.]
[927] Historia, dec. iii. lib. v. cap. 5. Cf. also Barcia, Ensayo
cronológico, p. 8, and Galvano (Hakluyt Society’s ed.), pp. 133,
153.
[930] Vol. iii. p. 69. His conjectures and those of modern writers
(Stevens, Notes, p. 48), accordingly require no examination. As
the documents of the first voyage name both 33° 30´ and 35° as
the landfall, conjecture is idle.
[931] Dec. ii. lib. xi. cap. 6. This statement is adopted by many
writers since.
[933] Gomara, Historia, cap. xlii.; Herrera, Historia, dec. iii. lib. v.
cap. 5.
[936] Vol. iii. pp. 72-73. Recent American writers have taken
another view. Cf. Brevoort, Verrazano, p. 70; Murphy, Verrazzano,
p. 123.
[937] Historia, lib. xxxvii. cap. 1-4, in vol. iii. pp. 624-633.
[940] Cf. Vol. IV. p. 28. The capitulacion is given in the Documentos
inéditos, xxii. 74.
[941] [Harrisse, Bibl. Amer. Vet., no. 239; Sabin, vol. iii. no. 9,767.
There is a copy in the Lenox Library. Cf. the Relacion as given in
the Documentos inéditos, vol. xiv. pp. 265-279, and the
“Capitulacion que se tomó con Panfilo de Narvaez” in vol. xxii. p.
224. There is some diversity of opinion as to the trustworthiness
of this narrative; cf. Helps, Spanish Conquest, iv. 397, and
Brinton’s Floridian Peninsula, p. 17. “Cabeça has left an artless
account of his recollections of the journey; but his memory
sometimes called up incidents out of their place, so that his
narrative is confused.”—Bancroft: History of the United States,
revised edition, vol. i. p. 31.—Ed.]
[952] [The writing of his narrative, not during but after the
completion of his journey, does not conduce to making the
statements of the wanderer very explicit, and different
interpretations of his itinerary can easily be made. In 1851 Mr.
Smith made him cross the Mississippi within the southern
boundary of Tennessee, and so to pass along the Arkansas and
Canadian rivers to New Mexico, crossing the Rio Grande in the
neighborhood of thirty-two degrees. In his second edition he
tracks the traveller nearer the Gulf of Mexico, and makes him
cross the Rio Grande near the mouth of the Conchos River in
Texas, which he follows to the great mountain chain, and then
crosses it. Mr. Bartlett, the editor of the Carter-Brown Catalogue
(see vol. i. p. 188), who has himself tracked both routes, is not
able to decide between them. Davis, in his Conquest of New
Mexico, also follows Cabeza de Vaca’s route. H. H. Bancroft
(North Mexican States, i. 63) finds no ground for the northern
route, and gives (p. 67) a map of what he supposes to be the
route. There is also a map in Paul Chaix’ Bassin du Mississipi au
seizième siècle. Cf. also L. Bradford Prince’s New Mexico (1883),
p. 89.—Ed.] The buffalo and mesquite afford a tangible means of
fixing the limits of his route.
[953] Including the petition of Narvaez to the King and the royal
memoranda from the originals at Seville (p. 207), the instructions
to the factor (p. 211), the instructions to Cabeza de Vaca (p.
218), and the summons to be made by Narvaez (p. 215). Cf.
French’s Historical Collections of Louisiana, second series, ii. 153;
Historical Magazine, April, 1862, and January and August, 1867.
[954] Smith’s Cabeça de Vaca, p. 100; Torquemada (Monarquia
Indiana, 1723, iii. 437-447) gives Lives of these friars. Barcia says
Xuarez was made a bishop; but Cabeza de Vaca never calls him
bishop, but simply commissary, and the portrait at Vera Cruz has
no episcopal emblems. Torquemada in his sketch of Xuarez
makes no allusion to his being made a bishop. and the name is
not found in any list of bishops. We owe to Mr. Smith another
contribution to the history of this region and this time, in a
Coleccion de varios documentos para la historia de la Florida y
tierras adyacentes,—only vol. i. of the contemplated work
appearing at Madrid in 1857. It contained thirty-three important
papers from 1516 to 1569, and five from 1618 to 1794; they are
for the most part from the Simancas Archives. This volume has a
portrait of Ferdinand V., which is reproduced ante, p. 85. Various
manuscripts of Mr. Smith are now in the cabinet of the New York
Historical Society.
[964] [Rich in 1832 (no. 34) cited a copy at £31 10s., which at that
time he believed to be unique, and the identical one referred to
by Pinelo as being in the library of the Duque de Sessa. There is
a copy in the Grenville Collection, British Museum, and another is
in the Lenox Library (B. Smith’s Letter of De Soto, p. 66). It was
reprinted at Lisbon in 1844 by the Royal Academy at Lisbon
(Murphy, no. 1,004; Carter-Brown, vol. i. no. 596). Sparks says of
it: “There is much show of exactness in regard to dates; but the
account was evidently drawn up for the most part from memory,
being vague in its descriptions and indefinite as to localities,
distances, and other points.” Field says it ranks second only to
the Relation of Cabeza de Vaca as an early authority on the
Indians of this region. There was a French edition by Citri de la
Guette in 1685, which is supposed to have afforded a text for the
English translation of 1686 entitled A Relation of the Conquest of
Florida by the Spaniards (see Field’s Indian Bibliography, nos.
325, 340). These editions are in Harvard College Library. Cf.
Sabin, Dictionary, vi. 488, 491, 492; Stevens, Historical
Collections, i. 844; Field, Indian Bibliography, no. 1,274; Carter-
Brown, vol. iii. nos. 1,324, 1,329; Arana, Bibliografía de obras
anónimas (Santiago de Chile, 1882), no. 200. The Gentleman of
Elvas is supposed by some to be Alvaro Fernandez; but it is a
matter of much doubt (cf. Brinton’s Floridian Peninsula, p. 20).
There is a Dutch version in Gottfried and Vander Aa’s Zee-und
Landreizen (1727), vol. vii. (Carter-Brown, iii. 117).—Ed.]
[965] [Carter-Brown, vol. ii. no. 86; Murphy, no. 1,118. Rich (no.
110) priced it in 1832 at £2 2s.—Ed.]
[972] [Carter-Brown, vol. ii. no. 42; Sunderland, vol. v. no. 12,815;
Leclerc, no. 881, at 350 francs; Field, Indian Bibliography no.
587; Brinley, no. 4,353. Rich (no. 102) priced it in 1832 at £2 2s.
—Ed.]
[980] [Pages 25-41. Pickett in 1849 printed the first chapter of his
proposed work in a tract called, Invasion of the Territory of
Alabama by One Thousand Spaniards under Ferdinand de Soto in
1540 (Montgomery, 1849). Pickett says he got confirmatory
information respecting the route from Indian traditions among
the Creeks.—Ed.]
[981] “We are satisfied that the Mauvila, the scene of Soto’s bloody
fight, was upon the north bank of the Alabama, at a place now
called Choctaw Bluff, in the County of Clarke, about twenty-five
miles above the confluence of the Alabama and Tombigbee”
(Pickett, i. 27). The name of this town is written “Mauilla” by the
Gentleman of Elvas, “Mavilla” by Biedma, but “Mabile” by Ranjel.
The u and v were interchangeable letters in Spanish printing, and
readily changed to b. (Irving, second edition, p. 261).
[982] Bancroft, United States, i. 51; Pickett, Alabama, vol. i.;
Martin’s Louisiana, i. 12; Nuttall’s Travels into Arkansas (1819), p.
248; Fairbanks’s History of Florida, chap. v.; Ellicott’s Journal, p.
125; Belknap, American Biography, i. 192. [Whether this passage
of the Mississippi makes De Soto its discoverer, or whether
Cabeza de Vaca’s account of his wandering is to be interpreted as
bringing him, first of Europeans, to its banks, when on the 30th
of October, 1528, he crossed one of its mouths, is a question in
dispute, even if we do not accept the view that Alonzo de Pineda
found its mouth in 1519 and called it Rio del Espiritu Santo
(Navarrete, iii. 64). The arguments pro and con are examined by
Rye in the Hakluyt Society’s volume. Cf., besides the authorities
above named, French’s Historical Collections of Louisiana;
Sparks’s Marquette; Gayarré’s Louisiana; Theodore Irving’s
Conquest of Florida; Gravier’s La Salle, chap. i., and his “Route du
Mississipi” in Congrès des Américanistes (1877), vol. i.; De Bow’s
Commercial Review, 1849 and 1850; Southern Literary
Messenger, December, 1848; North American Review, July, 1847.
—Ed.]
[988] Edited by Charles Deane for the Maine Historical Society, pp.
20, 195, 213.
[997] [O’Callaghan, no. 463; Rich (1832), no. 60. There was an
edition at Cologne in 1612 (Stevens, Nuggets, no. 2,300; Carter-
Brown, ii. 123). Sparks (Life of Ribault, p. 152) reports a De
navigatione Gallorum in terram Floridam in connection with an
Antwerp (1568) edition of Levinus Apollonius. It also appears in
the same connection in the joint German edition of Benzoni,
Peter Martyr, and Levinus printed at Basle in 1582 (Carter-Brown,
vol. i. no. 344). It may have been merely a translation of Challeux
or Ribault (Brinton, Floridian Peninsula, p. 36)—Ed.].
[1007] Cf. Shea’s edition with notes, where (vol. i. p. 71) Charlevoix
characterizes the contemporary sources; and he points out how
the Abbé du Fresnoy, in his Méthode pour étudier la géographie,
falls into some errors.
[1009] Boston, 1865. Mr. Parkman had already printed parts of this
in the Atlantic Monthly, xii. 225, 536, and xiv. 530.
[1011] Cf., for instance, Bancroft’s United States, chap. ii.; Gay’s
Popular History of the United States, chap. viii.; Warburton’s
Conquest of Canada, app. xvi.; Conway Robinson’s Discoveries in
the West, ii. chap. xvii. et seq.; Kohl’s Discovery of Maine;
Fairbanks’s Florida; Brinton’s Floridian Peninsula,—among
American writers; and among the French,—Guérin, Les
navigateurs Français (1846); Ferland, Canada; Martin, Histoire de
France; Haag, La France protestante; Poussielgue, “Quatre mois
en Floride,” in Le tour du monde, 1869-1870; and the Lives of
Coligny by Tessier, Besant, and Laborde. There are other
references in Gaffarel, p. 344.
There is a curious article, “Dominique de Gourgues, the
Avenger of the Huguenots in Florida, a Catholic,” in the Catholic
World, xxi. 701.
[1021] Mr. Ticknor, however, says that these two treatises “are not
absolutely proved” to be by Las Casas.—History of Spanish
Literature, i. 566.
[1025] Sabin’s Works of Las Casas, and his Dictionary, iii. 388-402,
and x. 88-91; Field’s Indian Bibliography; Carter-Brown
Catalogue; Harrisse’s Notes on Columbus, pp. 18-24; the Huth
Catalogue; Brunet’s Manuel, etc.
[1027] [Field does not give it a date; but Sabin says it was written
in 1552. Cf. Field, nos. 860, 870, note; Sabin, no. 2; Carter-
Brown, i. 165; Ticknor Catalogue, p. 62.—Ed.]
[1028] [Field says it was written “soon after” no. 1; Sabin places it
in 1543. Cf. Field, no. 862, 870, note; Carter-Brown, i. 166;
Sabin, 3; Stevens, Bibl. Geog., no. 595; Ticknor Catalogue, p. 62.
—Ed.]
[1032] [Sabin says it was written in Spain in 1548 Cf. Field, nos.
867, 870, note; Sabin, no. 7; Carter-Brown, i. 171.—Ed.]
[1034] [This is the longest and one of the rarest of the series. Sabin
says it was written about 1543. There were two editions of the
same date, having respectively 80 and 84 leaves; but it is
uncertain which is the earlier, though Field supposes the fewer
pages to indicate the first. Field, nos. 869, 870, note; Sabin, no.
5; Carter Brown, i. 172.—Ed.]
[1035] [It is only of late years that the entire series has been
described. De Bure gives only five of the tracts; Dibdin
enumerates but seven; and Llorente in his edition omits three, as
was done in the edition of 1646. Rich in 1832 priced a set at £12
12s. A full set is now worth from $100 to $150; but Leclerc (nos.
327, 2,556) has recently priced a set of seven at 700 francs, and
a full set at 1,000 francs. An English dealer has lately held one at
£42. Quaritch has held four parts at £10, and a complete set at
£40. Single tracts are usually priced at from £1 to £5. Recent
sales have been shown in the Sunderland (no. 2,459, 9 parts);
Field (no. 1,267); Cooke (vol. iii. no. 369, 7 parts); Stevens, Hist.
Coll. (no. 311, 8 parts); Pinart (no. 536); and Murphy (no. 487)
catalogues. The set in the Carter-Brown Library belonged to
Ternaux; that belonging to Mr. Brevoort came from the
Maximillian Library. The Lenox Library and Mr. Barlow’s Collection
have sets. There are also sets in the Grenville and Huth
collections.
The 1646 reprint, above referred to, has sometimes a
collective title, Las Obras, etc., but most copies, like the Harvard
College copy, lack it. As the titles of the separate tracts (printed
in this edition in Roman) retained the original 1552 dates, this
reprint is often called a spurious edition. It is usually priced at
from $15 to $30. Cf. Sabin, no. 13; Field, p. 216; Quaritch, no.
11,856; Carter-Brown, i. 173; ii. 584; Stevens, Hist. Coll., i. 312;
Cooke, iii. 370.
Some of the Tracts are included in the Obras escogidas de
filósofos, etc. Madrid, 1873.—Ed.]
[1036] [Field, no. 870, and note; Sabin, no. 11; the Carter-Brown
Collection lacks it. It was reprinted at Tübingen, and again at
Jena, in 1678. It has never been reprinted in Spain, says Stevens
(Bibl. Hist., no. 1,096).—Ed.]
[1043] [I trace no copy earlier than one Rich had made. Prescott
had one, which was probably burned in Boston (1872). Helps
used another. There are other copies in the Library of Congress,
in the Lenox Library, and in H. H. Bancroft’s Collection.—Ed.]
[1044] [Harrisse, Bibl. Amer. Vet., p. 119, says the purpose of the
Academy at one time was to annotate the manuscript, so as to
show Las Casas in a new light, using contemporary writers.—Ed.]
[1048] [This included the first, second, and sixth of the tracts of
1552. In 1582 there was a new edition of the Tyrannies, etc.,
printed at Paris; but some copies seem to have had a changed
title, Histoire admirable des horribles insolences, etc. It was again
reissued with the original title at Rouen in 1630. Cf. Field, 873,
874; Sabin, nos. 41, 42, 43, 45; Rich (1832); Stevens, Bibl. Hist.,
no. 1,098; Leclerc, nos. 334, 2,558; Carter-Brown, i. 329, 345,
347; O’Callaghan, no. 1,336; a London catalogue (A. R. Smith,
1874) notes an edition of the Histoire admirable des horribles
Insolences, Cruautez et tyrraines exercées par les Espagnols, etc.,
Lyons, 1594.—Ed.]
[1050] [Field, p. 877; Carter-Brown, ii. 804; Sabin, no. 60. The first
tract is translated in Purchas’s Pilgrimes, iv. 1,569.—Ed.]
[1051] [Some copies read, Account of the First Voyages, etc. Cf.
Field, no. 880; Carter-Brown, vol. ii. no. 1,556; Sabin, no. 63;
Stevens, Bibl. Geog., no. 603; and Prince Library Catalogue, p.
34. Another English edition, London, 1689, is called Popery truly
display’d in its Bloody Colours. Cf. Carter-Brown, vol. ii. no. 1,374;
Sabin, no. 62. Another London book of 1740, Old England for
Ever, is often called a Las Casas, but it is not his. Field, no. 888.
—Ed.]
[1053] [It followed the French edition of 1579, and was reissued at
Oppenheim in 1614. Cf. Field, p. 871; Carter-Brown, i. 453, 524;
ii. 164; Sabin, nos. 57, 58.
The Heidelberg edition of 1664, Regionum Indicarum per
Hispanos olim devastatarum descriptio, omits the sixteen pages
of preliminary matter of the early editions; and the plates,
judging from the Harvard College and other copies, show wear.
Sabin, no. 59; Carter-Brown, ii. 944.—Ed.]
[1062] The authorities are not in unison about all these figures. Cf.
H. H. Bancroft, Mexico, i. 70.
[1064] Marina did more. She impressed Cortés, who found her
otherwise convenient for a few years; and after she had borne
him children, married her to one of his captains. What purports to
be a likeness of her is given in Cabajal’s México, ii. 64.
[1065] Prescott (Mexico, revised edition, i. 345) points out how this
site was abandoned later for one farther south, where the town
was called Vera Cruz Vieja; and again, early in the seventeenth
century, the name and town were transferred to another point
still farther south,—Nueva Vera Cruz. These changes have caused
some confusion in the maps of Lorenzana and others. Cf. the
maps in Prescott and H. H. Bancroft.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebookultra.com