Data Structures And Algorithm Analysis In C By Mark Allen .

Transcription

Structures, Algorithm Analysis: Table of ContentsPage 1 of 1Data Structures and AlgorithmAnalysis in Cby Mark Allen WeissPREFACECHAPTER 1: INTRODUCTIONCHAPTER 2: ALGORITHM ANALYSISCHAPTER 3: LISTS, STACKS, AND QUEUESCHAPTER 4: TREESCHAPTER 5: HASHINGCHAPTER 6: PRIORITY QUEUES (HEAPS)CHAPTER 7: SORTINGCHAPTER 8: THE DISJOINT SET ADTCHAPTER 9: GRAPH ALGORITHMSCHAPTER 10: ALGORITHM DESIGN TECHNIQUESCHAPTER 11: AMORTIZED s\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: PREFACEPage 1 of 5PREFACEPurpose/GoalsThis book describes data structures, methods of organizing largeamounts of data, and algorithm analysis, the estimation of therunning time of algorithms. As computers become faster and faster,the need for programs that can handle large amounts of input becomesmore acute. Paradoxically, this requires more careful attention toefficiency, since inefficiencies in programs become most obvious wheninput sizes are large. By analyzing an algorithm before it isactually coded, students can decide if a particular solution will befeasible. For example, in this text students look at specificproblems and see how careful implementations can reduce the timeconstraint for large amounts of data from 16 years to less than asecond. Therefore, no algorithm or data structure is presentedwithout an explanation of its running time. In some cases, minutedetails that affect the running time of the implementation areexplored.Once a solution method is determined, a program must still bewritten. As computers have become more powerful, the problems theysolve have become larger and more complex, thus requiring developmentof more intricate programs to solve the problems. The goal of thistext is to teach students good programming and algorithm analysisskills simultaneously so that they can develop such programs with themaximum amount of efficiency.This book is suitable for either an advanced data structures (CS7)course or a first-year graduate course in algorithm analysis.Students should have some knowledge of intermediate programming,including such topics as pointers and recursion, and some backgroundin discrete math.ApproachI believe it is important for students to learn how to program forthemselves, not how to copy programs from a book. On the other hand,it is virtually impossible to discuss realistic programming issueswithout including sample code. For this reason, the book usuallyprovides about half to three-quarters of an implementation, and thestudent is encouraged to supply the r.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: PREFACEPage 2 of 5The algorithms in this book are presented in ANSI C, which, despitesome flaws, is arguably the most popular systems programminglanguage. The use of C instead of Pascal allows the use ofdynamically allocated arrays (see for instance rehashing in Ch. 5).It also produces simplified code in several places, usually becausethe and (&&) operation is short-circuited.Most criticisms of C center on the fact that it is easy to write codethat is barely readable. Some of the more standard tricks, such asthe simultaneous assignment and testing against 0 viaif (x y)are generally not used in the text, since the loss of clarity iscompensated by only a few keystrokes and no increased speed. Ibelieve that this book demonstrates that unreadable code can beavoided by exercising reasonable care.OverviewChapter 1 contains review material on discrete math and recursion. Ibelieve the only way to be comfortable with recursion is to see gooduses over and over. Therefore, recursion is prevalent in this text,with examples in every chapter except Chapter 5.Chapter 2 deals with algorithm analysis. This chapter explainsasymptotic analysis and its major weaknesses. Many examples areprovided, including an in-depth explanation of logarithmic runningtime. Simple recursive programs are analyzed by intuitivelyconverting them into iterative programs. More complicated divide-andconquer programs are introduced, but some of the analysis (solvingrecurrence relations) is implicitly delayed until Chapter 7, where itis performed in detail.Chapter 3 covers lists, stacks, and queues. The emphasis here is oncoding these data structures using ADTS, fast implementation of thesedata structures, and an exposition of some of their uses. There arealmost no programs (just routines), but the exercises contain plentyof ideas for programming assignments.Chapter 4 covers trees, with an emphasis on search trees, includingexternal search trees (B-trees). The UNIX file system and expressiontrees are used as examples. AVL trees and splay trees are introducedbut not analyzed. Seventy-five percent of the code is written,leaving similar cases to be completed by the student. hms\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: PREFACEPage 3 of 5coverage of trees, such as file compression and game trees, isdeferred until Chapter 10. Data structures for an external medium areconsidered as the final topic in several chapters.Chapter 5 is a relatively short chapter concerning hash tables. Someanalysis is performed and extendible hashing is covered at the end ofthe chapter.Chapter 6 is about priority queues. Binary heaps are covered, andthere is additional material on some of the theoretically interestingimplementations of priority queues.Chapter 7 covers sorting. It is very specific with respect to codingdetails and analysis. All the important general-purpose sortingalgorithms are covered and compared. Three algorithms are analyzed indetail: insertion sort, Shellsort, and quicksort. External sorting iscovered at the end of the chapter.Chapter 8 discusses the disjoint set algorithm with proof of therunning time. This is a short and specific chapter that can beskipped if Kruskal's algorithm is not discussed.Chapter 9 covers graph algorithms. Algorithms on graphs areinteresting not only because they frequently occur in practice butalso because their running time is so heavily dependent on the properuse of data structures. Virtually all of the standard algorithms arepresented along with appropriate data structures, pseudocode, andanalysis of running time. To place these problems in a propercontext, a short discussion on complexity theory (including NPcompleteness and undecidability) is provided.Chapter 10 covers algorithm design by examining common problemsolving techniques. This chapter is heavily fortified with examples.Pseudocode is used in these later chapters so that the student'sappreciation of an example algorithm is not obscured byimplementation details.Chapter 11 deals with amortized analysis. Three data structures fromChapters 4 and 6 and the Fibonacci heap, introduced in this chapter,are analyzed.Chapters 1-9 provide enough material for most one-semester datastructures courses. If time permits, then Chapter 10 can be covered.A graduate course on algorithm analysis could cover Chapters 7-11.The advanced data structures analyzed in Chapter 11 can easily bereferred to in the earlier chapters. The discussion of %20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: PREFACEPage 4 of 5completeness in Chapter 9 is far too brief to be used in such acourse. Garey and Johnson's book on NP-completeness can be used toaugment this text.ExercisesExercises, provided at the end of each chapter, match the order inwhich material is presented. The last exercises may address thechapter as a whole rather than a specific section. Difficultexercises are marked with an asterisk, and more challenging exerciseshave two asterisks.A solutions manual containing solutions to almost all the exercisesis available separately from The Benjamin/Cummings PublishingCompany.ReferencesReferences are placed at the end of each chapter. Generally thereferences either are historical, representing the original source ofthe material, or they represent extensions and improvements to theresults given in the text. Some references represent solutions toexercises.AcknowledgmentsI would like to thank the many people who helped me in thepreparation of this and previous versions of the book. Theprofessionals at Benjamin/Cummings made my book a considerably lessharrowing experience than I had been led to expect. I'd like to thankmy previous editors, Alan Apt and John Thompson, as well as CarterShanklin, who has edited this version, and Carter's assistant, VivianMcDougal, for answering all my questions and putting up with mydelays. Gail Carrigan at Benjamin/Cummings and Melissa G. Madsen andLaura Snyder at Publication Services did a wonderful job withproduction. The C version was handled by Joe Heathward and hisoutstanding staff, who were able to meet the production scheduledespite the delays caused by Hurricane Andrew.I would like to thank the reviewers, who provided valuable comments,many of which have been incorporated into the text. Alphabetically,they are Vicki Allan (Utah State University), Henry Bauer (Universityof Wyoming), Alex Biliris (Boston University), Jan \Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: PREFACEPage 5 of 5(University of North Texas), Dan Hirschberg (University ofCalifornia, Irvine), Julia Hodges (Mississippi State University),Bill Kraynek (Florida International University), Rayno D. Niemi(Rochester Institute of Technology), Robert O. Pettus (University ofSouth Carolina), Robert Probasco (University of Idaho), CharlesWilliams (Georgia State University), and Chris Wilson (University ofOregon). I would particularly like to thank Vicki Allan, whocarefully read every draft and provided very detailed suggestions forimprovement.At FIU, many people helped with this project. Xinwei Cui and John Tsoprovided me with their class notes. I'd like to thank Bill Kraynek,Wes Mackey, Jai Navlakha, and Wei Sun for using drafts in theircourses, and the many students who suffered through the sketchy earlydrafts. Maria Fiorenza, Eduardo Gonzalez, Ancin Peter, Tim Riley,Jefre Riser, and Magaly Sotolongo reported several errors, and MikeHall checked through an early draft for programming errors. A specialthanks goes to Yuzheng Ding, who compiled and tested every program inthe original book, including the conversion of pseudocode to Pascal.I'd be remiss to forget Carlos Ibarra and Steve Luis, who kept theprinters and the computer system working and sent out tapes on aminute's notice.This book is a product of a love for data structures and algorithmsthat can be obtained only from top educators. I'd like to take thetime to thank Bob Hopkins, E. C. Horvath, and Rich Mendez, who taughtme at Cooper Union, and Bob Sedgewick, Ken Steiglitz, and Bob Tarjanfrom Princeton.Finally, I'd like to thank all my friends who provided encouragementduring the project. In particular, I'd like to thank Michele Dorchak,Arvin Park, and Tim Snyder for listening to my stories; Bill Kraynek,Alex Pelin, and Norman Pestaina for being civil next-door (office)neighbors, even when I wasn't; Lynn and Toby Berk for shelter duringAndrew, and the HTMC for work relief.Any mistakes in this book are, of course, my own. I would appreciatereports of any errors you find; my e-mail address is weiss@fiu.edu.M.A.W.Miami, FloridaSeptember 1992Go to Chapter 1 Return to Table of s\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 1 of 17CHAPTER 1: INTRODUCTIONIn this chapter, we discuss the aims and goals of this text andbriefly review programming concepts and discrete mathematics. We willSee that how a program performs for reasonably large input is justas important as its performance on moderate amounts of input.Review good programming style.Summarize the basic mathematical background needed for the rest ofthe book.Briefly review recursion.1.1. What's the Book About?Suppose you have a group of n numbers and would like to determine thekth largest. This is known as the selection problem. Most studentswho have had a programming course or two would have no difficultywriting a program to solve this problem. There are quite a few"obvious" solutions.One way to solve this problem would be to read the n numbers into anarray, sort the array in decreasing order by some simple algorithmsuch as bubblesort, and then return the element in position k.A somewhat better algorithm might be to read the first k elementsinto an array and sort them (in decreasing order). Next, eachremaining element is read one by one. As a new element arrives, it isignored if it is smaller than the kth element in the array.Otherwise, it is placed in its correct spot in the array, bumping oneelement out of the array. When the algorithm ends, the element in thekth position is returned as the answer.Both algorithms are simple to code, and you are encouraged to do so.The natural questions, then, are which algorithm is better and, moreimportantly, is either algorithm good enough? A simulation using arandom file of 1 million elements and k 500,000 will show thatneither algorithm finishes in a reasonable amount of time--eachrequires several days of computer processing to terminate (albeiteventually with a correct answer). An alternative method, discussedin Chapter 7, gives a solution in about a second. Thus, although ourproposed algorithms work, they cannot be considered good algorithms,because they are entirely impractical for input sizes that a r.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 2 of 17algorithm can handle in a reasonable amount of time.A second problem is to solve a popular word puzzle. The inputconsists of a two-dimensional array of letters and a list of words.The object is to find the words in the puzzle. These words may behorizontal, vertical, or diagonal in any direction. As an example,the puzzle shown in Figure 1.1 contains the words this, two, fat, andthat. The word this begins at row 1, column 1 (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 straightforward algorithms that solvethe problem. For each word in the word list, we check each orderedtriple (row, column, orientation) for the presence of the word. Thisamounts 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, wecan test whether the word indicated is in the word list. Again, thisamounts to lots of nested for loops. It is possible to save some timeif the maximum number of characters in any word is known.It is relatively easy to code up either solution and solve many ofthe real-life puzzles commonly published in magazines. Thesetypically have 16 rows, 16 columns, and 40 or so words. Suppose,however, we consider the variation where only the puzzle board isgiven and the word list is essentially an English dictionary. Both ofthe solutions proposed require considerable time to solve thisproblem and therefore are not acceptable. However, it is possible,even with a large word list, to solve the problem in a matter ofseconds.An important concept is that, in many problems, writing a workingprogram is not good enough. If the program is to be run on a largedata set, then the running time becomes an issue. Throughout thisbook we will see how to estimate the running time of a program forlarge inputs and, more importantly, how to compare the running timesof two programs without actually coding them. We will see techniquesfor drastically improving the speed of a program and for determiningprogram bottlenecks. These techniques will enable us to find thesection of the code on which to concentrate our optimization �.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTION2wats3oahg4fgdtPage 3 of 17Figure 1.1 Sample word puzzle1.2. Mathematics ReviewThis section lists some of the basic formulas you need to memorize orbe able to derive and reviews basic proof techniques.1.2.1. Exponentsxa xb xa bxa-- xa-bxb(xa)b xabxn xn 2xnx2n2n 2n 2n 11.2.2. LogarithmsIn computer science, all logarithms are to base 2 unless specified otherwise.DEFINITION: xa b if and only if logxb aSeveral convenient equalities follow from this definition.THEOREM hms\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONLet x logPage 4 of 17b, y log a, and z log b. Then, by the definition ofcaxyzlogarithms, c b, c a, and a b. Combining these three equalities yieldsy zx(c ) c b. Therefore, x yz, which implies z x/y, proving the theorem.cTHEOREM 1.2.log ab log a log bPROOF:xLet x log a, y log b, z log ab. Then, assuming the default base of 2, 2 yzx yza, 2 b, 2 ab. Combining the last three equalities yields 2 2 2 ab.Therefore, x y z, which proves the theorem.Some other useful formulas, which can all be derived in a similar manner, follow.log a/b log a - log blog(ab) b log alog x x for all x 0log 1 0,log 2 1,log 1,024 10,log 1,048,576 201.2.3. SeriesThe easiest formulas to remember areand the companion,In the latter formula, if 0 a 1, thenand as n tends toseries" formulas., the sum approaches 1/(1 -a). These are the hms\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONWe can derive the last formula forS be the sum. ThenPage 5 of 17in the following manner. LetS 1 a a2 a3 a4 a5 . . .ThenaS a a2 a3 a4 a5 . . .If we subtract these two equations (which is permissible only for a convergentseries), virtually all the terms on the right side cancel, leavingS - aS 1which implies thatWe can use this same technique to computefrequently. We write, a sum that occursand multiply by 2, obtainingSubtracting these two equations yieldsThus, S 2.Another type of common series in analysis is the arithmetic series. Any suchseries can be evaluated from the basic formula. . .For instance, to find the sum 2 5 8 (3k - 1), rewrite it as 3(1 2 . . . . .3 k) - (1 1 1 1), which is clearly 3k(k 1)/2 - k. Anotherway to remember this is to add the first and last terms (total 3k 1), %20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 6 of 17second and next to last terms (total 3k 1), and so on. Since there are k/2 ofthese pairs, the total sum is k(3k 1)/2, which is the same answer as before.The next two formulas pop up now and then but are fairly infrequent.When k -1, the latter formula is not valid. We then need the following formula,which is used far more in computer science than in other mathematicaldisciplines. The numbers, H , are known as the harmonic numbers, and the sum isNknown as a harmonic sum. The error in the following approximation tends to y0.57721566, which is known as Euler's constant.These two formulas are just general algebraic manipulations.1.2.4. Modular ArithmeticWe say that a is congruent to b modulo n, written ab(mod n), if n divides a -b. Intuitively, this means that the remainder is the same when either a or b isdivided by n. Thus, 81 61 1(mod 10). As with equality, if a b (mod n), thena c b c(mod n) and a d b d (mod n).There are a lot of theorems that apply to modular arithmetic, some of whichrequire extraordinary proofs in number theory. We will use modular arithmeticsparingly, and the preceding theorems will suffice.1.2.5. The P WordThe two most common ways of proving statements in data structure analysis areproof by induction and proof by contradiction (and occasionally a proof byintimidation, by professors only). The best way of proving that a theorem 20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 7 of 17false is by exhibiting a counterexample.Proof by InductionA proof by induction has two standard parts. The first step is proving a basecase, that is, establishing that a theorem is true for some small (usuallydegenerate) value(s); this step is almost always trivial. Next, an inductivehypothesis is assumed. Generally this means that the theorem is assumed to betrue for all cases up to some limit k. Using this assumption, the theorem is thenshown to be true for the next value, which is typically k 1. This proves thetheorem (as long as k is finite).As an example, we prove that the Fibonacci numbers, F3, F 5, . . . , F4definitions have Fi F -1 Fii-2, satisfy F0 1, Fii1 (5/3) , for i 1, F2 2, F3 1. (Some0 which shifts the series.) To do this, we first verify0 ,that the theorem is true for the trivial cases. It is easy to verify that F 11 5/3 and F 2 25/9; this proves the basis. We assume that the theorem is true2for i 1, 2, . . . , k; this is the inductive hypothesis. To prove the theorem,k 1we need to show that F (5/3). We havek 1Fk 1 Fk Fk-1by the definition, and we can use the inductive hypothesis on the right-handside, obtainingFk 1 (5/3)k (5/3)k-1 (3/5)(5/3)k 1 (3/5)2(5/3)k 1 (3/5)(5/3)k 1 (9/25)(5/3)k 1which simplifies toFk 1 (3/5 9/25)(5/3)k 1 (24/25)(5/3)k 1 (5/3)k 1proving the theorem.As a second example, we establish the following theorem.THEOREM .%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 8 of 17PROOF:The proof is by induction. For the basis, it is readily seen that the theorem istrue when n 1. For the inductive hypothesis, assume that the theorem is truefor 1 k n. We will establish that, under this assumption, the theorem is truefor n 1. We haveApplying the inductive hypothesis, we obtainThus,proving the theorem.Proof by CounterexampleThe statement F2kk is false. The easiest way to prove this is to compute F11 2144 11 .Proof by ContradictionProof by contradiction proceeds by assuming that the theorem is false and showingthat this assumption implies that some known property is false, and hence theoriginal assumption was erroneous. A classic example is the proof that there isan infinite number of primes. To prove this, we assume that the theorem is false,so that there is some largest prime p . Let p , p , . . . , p be all the hms\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 9 of 17in order and considerN p1p2p3. . . pk 1Clearly, N is larger than p , so by assumption N is not prime. However, none ofkp , p , . . . , p divide N exactly, because there will always be a remainder of12k1. This is a contradiction, because every number is either prime or a product ofprimes. Hence, the original assumption, that p is the largest prime, is false,kwhich implies that the theorem is true.intf( int x ){/*1*/if ( x/*2*/ 0 )return 0;else/*3*/return( 2*f(x-1) x*x );}Figure 1.2 A recursive function1.3. A Brief Introduction to RecursionMost mathematical functions that we are familiar with are described by a simpleformula. For instance, we can convert temperatures from Fahrenheit to Celsius byapplying the formulaC 5(F - 32)/9Given this formula, it is trivial to write a C function; with declarations andbraces removed, the one-line formula translates to one line of C.Mathematical functions are sometimes defined in a less standard form. As anexample, we can define a function f, valid on nonnegative integers, that2satisfies f(0) 0 and f(x) 2f(x - 1) x . 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 termsof itself is called recursive. C allows functions to be recursive.* It isimportant to remember that what C provides is merely an attempt to follow therecursive spirit. Not all mathematically recursive functions are efficiently (orcorrectly) implemented by C's simulation of recursion. The idea is that therecursive function f ought to be expressible in only a few lines, just like 0Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 10 of 17non-recursive function. Figure 1.2 shows the recursive implementation of f.*Using recursion for numerical calculations is usually a bad idea. We have doneso to illustrate the basic points.Lines 1 and 2 handle what is known as the base case, that is, the value for whichthe function is directly known without resorting to recursion. Just as declaring2f(x) 2 f(x - 1) x is meaningless, mathematically, without including the factthat f (0) 0, the recursive C function doesn't make sense without a base case.Line 3 makes the recursive call.There are several important and possibly confusing points about recursion. Acommon question is: Isn't this just circular logic? The answer is that althoughwe are defining a function in terms of itself, we are not defining a particularinstance of the function in terms of itself. In other words, evaluating f(5) bycomputing f(5) would be circular. Evaluating f(5) by computing f(4) is notcircular--unless, of course f(4) is evaluated by eventually computing f(5). Thetwo most important issues are probably the how and why questions. In Chapter 3,the how and why issues are formally resolved. We will give an incompletedescription here.It turns out that recursive calls are handled no differently from any others. Iff(3)* 44. Thus, a call is made to compute f(3). This requires the computation of 2*f(2) 3 3. Therefore, another call is made to compute f(2). This means that**2f(1) 2 2 must be evaluated. To do so, f(1) is computed as 2 f(0) 1****1. Now, f(0) must be evaluated. Since this is a base case, we know a priori thatf(0) 0. This enables the completion of the calculation for f(1), which is nowseen to be 1. Then f(2), f(3), and finally f(4) can be determined. All thebookkeeping needed to keep track of pending function calls (those started butwaiting for a recursive call to complete), along with their variables, is done bythe computer automatically. An important point, however, is that recursive callswill keep on being made until a base case is reached. For instance, an attempt toevaluate f(-1) will result in calls to f(-2), f(-3), and so on. Since this willnever get to a base case, the program won't be able to compute the answer (whichis undefined anyway). Occasionally, a much more subtle error is made, which isexhibited in Figure 1.3. The error in the program in Figure 1.3 is that bad(1) isdefined, by line 3, to be bad(1). Obviously, this doesn't give any clue as towhat 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 runout of space, and the program will crash. Generally, we would say that thisfunction doesn't work for one special case but is correct otherwise. This isn'ttrue here, since bad(2) calls bad(1). Thus, bad(2) cannot be evaluated either.Furthermore, bad(3), bad(4), and bad(5) all make calls to bad(2). Since bad(2) isunevaluable, none of these values are either. In fact, this program doesn't workfor any value of n, except 0. With recursive programs, there is no such thing asa "special case."f is called with the value of 4, then line 3 requires the computation of 2These considerations lead to the first two fundamental rules of hms\Dr.%20Dobb%60s%2010%20部算.2010-5-13

Structures, Algorithm Analysis: CHAPTER 1: INTRODUCTIONPage 11 of 171. Base cases. You must always have some base cases, which can be solved withoutrecursion.2. Making progress. For the cases that are to be solved recursively, therecursive call must always be to a case that makes progress toward a base case.Throughout this book, we will use recursion to solve problems. As an example of anonmathematical use, consider a large dictionary. Words in dictionaries aredefined in terms of other words. When we look up a word, we might not alwaysunderstand the definition, so we might have to look up words in the definition.Likewise, we might not understand some of those, so we might have to continuethis search for a while. As the dictionary is finite, eventually either we willcome to a point where we understand all of the words in some definition (and thusunderstand that definition and retrace our path through the other definitions),or we will find that the definitions are circular and we are stuck, or that someword we need to understand a definition is not in the dictionary.intbad( unsigned int n ){/*2*/return 0;else/*3*/return( bad (n/3 1) n - 1 );}Figure 1.3 A nonterminating recursive programOur recursive strategy to understand words is as follows: If we know the meaningof a word, then we are done; otherwise, we look the word up in the dictionary. Ifwe understand all the words in the definition, we are done; otherwise, we figureout what the definition means by recursively looking up the words we don't know.This procedure will terminate if the dictionary is well defined but can loopindefinitely if a word is either not defined or circularly defined.Printing Out NumbersSuppose we have a positive integer, n, that we wish to print out. Our routinewill have the heading print out(n). Assume that the only I/O routines availablewill take a single-digit number and o

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 (i