DATA STRUCTURES Evangel P. Quiwa Department of Computer Science College of Engineering University of the Philippines The preparation of this book was supported through a textbook writing grant by the UniversityofthePhilippinesSystemthroughtheOfficeoftheVice-PresidentforAcademic Affairs. Data Structures Philippine Copyright c 2007 by Evangel P. Quiwa and Office of the Vice-President for ° Academic Affairs, University of the Philippines System All rights reserved. No patent liability is assumed with respect to the use of the informa- tion contained herein. Every precaution has been taken in the preparation of this book; however, the publisher assumes no responsibility for errors or omissions. Neither is any liability assumed for damages resulting from the use of the information contained herein. ISBN 971-897806-1 For feedback on this book please contact: [email protected] Send all inquiries to: Electronics Hobbyists Publishing House P.O. Box 4052 Manila Printed in the Philippines Cover design: Leslie Q. Quiwa Cover photo: Tree Silhouette 3 by Christophe Libert To Pilar Preface This book is based on ‘session notes’ which the author developed and used in teaching a course on Data Structures to sophomore Computer Science students over a period of several years. The book retains the original organization of the ‘notes’ in which a ‘session’ (the equivalent of one or more class meetings) begins with a list of OBJECTIVES (indicating what the student is expected to be able to do after the session), followed by a set of READINGS (which refer the student to specific reference materials for the session notes) and ends with an extended DISCUSSION of the material covered by the session (the main body) and a set of EXERCISES. The first three sessions comprise an introduction to the study of data structures and algorithms proper, which is covered in the remaining twelve sessions. Session 1 begins with a question the answer to which impacts the rest of the sessions: ‘Given a problem P, how do we solve P on a computer?’ It highlights the fact that at the heart of the problem- solving process on a computer lie two intimately related tasks, viz., the ‘structuring of data’ and the ‘synthesis of algorithms’. Data structures and algorithms (or the two fused togetherasasingleentitycalledan‘object’)arethebuildingblocksofcomputerprograms. Session 2 is a review of familiar mathematical entities, tools and concepts, and an introduction to some less familiar topics which will be expounded in their proper setting in later sessions. Session3tacklestwoimportantissuesaboutalgorithms, viz., ‘Howdowecommunicate an algorithm?’ and ‘How do we analyze an algorithm?’ For reasons articulated in this session, we choose pseudocode (called Easy) as our medium of communication and we implement algorithms as Easy procedures. To illustrate how Easy translates easily into the syntax of actual programming languages, we transcribe a number of Easy procedures for stacks, queues and binary trees in subsequent sessions into running Pascal and C programs. The second half of Session 3 expounds on what it means to ‘analyze an algorithm.’ Using the analysis of insertion sort as the vehicle for exposition, we lead the student to a firm understanding of very important ‘asymptotic notations’ which will be used in the remainder of the book to denote the space and time complexity of running algorithms. The quest for suitable data structures and efficient algorithms to solve a given problem on a computer is a thread that runs throughout these Notes. By now it should have become abundantly clear that we cannot study data structures apart from algorithms. Thus in Sessions 4 through 15 we will consider in turn each of the v vi Preface following data structures — stacks, queues, deques, binary trees, priority queues, trees and forests, graphs, linear lists, generalized lists, sequential tables, binary search trees and hash tables — and associated algorithms. Applications of these data structures to the solution of both classical CS problems as well as real-world problems are discussed at great length in this book; often the solutions can be described as nothing less than ‘elegant’ as well. After all, true programming is nothing less than an art. Acknowledgments I thank all the authors whose books served as my references in preparing the ‘session notes’ for my Data Structures classes, and from which this book is derived. I thank the University of the Philippines System for providing me, through the Office of the Vice President for Academic Affairs, a textbook writing grant. I thank my colleagues in the Department of Computer Science who used the original ‘session notes’ in their own classes and encouraged me to consolidate them into a book. I thank Dan Custodio who initiated me into the use of LATEX. I prepared this entire document in LATEX. Writing a book of this size can be an overwhelming task. I thank my wife, Pilar, for her quiet support and encouragement without which I could not have completed this task. Evangel P. Quiwa February 8, 2007 Contents Preface v 1 Basic Concepts 1 1.1 How do we solve a problem on a computer? . . . . . . . . . . . . . . . . . 2 1.2 What is a data structure? . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 What is an algorithm? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4 Implementing ADT’s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4.1 The contiguous or sequential design . . . . . . . . . . . . . . . . . . 8 1.4.2 The linked design . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5 Formulating a solution to the ESP . . . . . . . . . . . . . . . . . . . . . . 12 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2 Mathematical Preliminaries 21 2.1 Mathematical notations and elementary functions . . . . . . . . . . . . . . 22 2.1.1 Floor, ceiling and mod functions . . . . . . . . . . . . . . . . . . . . 22 2.1.2 Polynomials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.3 Exponentials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.1.4 Logarithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.1.5 Factorials . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.1.6 Fibonacci numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.2 Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.3 Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 2.4 Permutations and Combinations . . . . . . . . . . . . . . . . . . . . . . . . 32 2.4.1 Rule of sum and rule of product . . . . . . . . . . . . . . . . . . . . 32 vii viii CONTENTS 2.4.2 Permutations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.4.3 Combinations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 2.5 Summations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.5.1 Arithmetic series . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.5.2 Geometric series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 2.5.3 Harmonic series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.5.4 Miscellaneous sums . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.6 Recurrences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 2.7 Methods of proof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 2.7.1 Proof by mathematical induction . . . . . . . . . . . . . . . . . . . 42 2.7.2 Proof by contradiction (reductio ad absurdum) . . . . . . . . . . . . 45 2.7.3 Proof by counterexample . . . . . . . . . . . . . . . . . . . . . . . . 45 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3 Algorithms 49 3.1 Communicating an algorithm . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.1.1 The Easy assignment statement . . . . . . . . . . . . . . . . . . . 51 3.1.2 The Easy unconditional transfer statements . . . . . . . . . . . . . 51 3.1.3 The Easy conditional transfer statements . . . . . . . . . . . . . . 52 3.1.4 The Easy iteration statements . . . . . . . . . . . . . . . . . . . . 52 3.1.5 The Easy input/output statements . . . . . . . . . . . . . . . . . . 53 3.1.6 The Easy declaration statements . . . . . . . . . . . . . . . . . . . 53 3.1.7 The Easy control statements . . . . . . . . . . . . . . . . . . . . . 54 3.1.8 Easy program stucture . . . . . . . . . . . . . . . . . . . . . . . . 54 3.1.9 Sample Easy procedures . . . . . . . . . . . . . . . . . . . . . . . . 55 3.2 Analyzing an algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.2.1 Analysis of insertion sort . . . . . . . . . . . . . . . . . . . . . . . . 59 3.2.2 Asymptotic notations . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.2.3 The O-notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 3.2.4 The Ω-notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 3.2.5 The Θ-notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.2.6 The preponderance of the O-notation . . . . . . . . . . . . . . . . . 68 3.2.7 Comparative growth of functions . . . . . . . . . . . . . . . . . . . 69 3.2.8 Complexity classes . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 CONTENTS ix 4 Stacks 75 4.1 Sequential implementation of a stack . . . . . . . . . . . . . . . . . . . . . 77 4.1.1 Implementing the auxiliary operations . . . . . . . . . . . . . . . . 78 4.1.2 Implementing the insert operation . . . . . . . . . . . . . . . . . . . 78 4.1.3 Implementing the delete operation . . . . . . . . . . . . . . . . . . 79 4.1.4 A Pascal implementation of the array representation of a stack . . . 79 4.1.5 A C implementation of the array representation of a stack . . . . . 81 4.2 Linked list implementation of a stack . . . . . . . . . . . . . . . . . . . . . 83 4.2.1 Implementing the auxiliary stack operations . . . . . . . . . . . . . 84 4.2.2 Implementing the insert operation . . . . . . . . . . . . . . . . . . . 85 4.2.3 Implementing the delete operation . . . . . . . . . . . . . . . . . . 85 4.2.4 A Pascal implementation of the linked list representation of a stack 86 4.2.5 A C implementation of the linked list representation of a stack . . . 87 4.3 Applications of stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 4.3.1 A simple pattern recognition problem . . . . . . . . . . . . . . . . . 89 4.3.2 Conversion of arithmetic expressions from infix to postfix form . . . 90 4.4 Sequential implementation of multiple stacks . . . . . . . . . . . . . . . . . 98 4.4.1 The coexistence of two stacks in a single array . . . . . . . . . . . . 99 4.4.2 The coexistence of three or more stacks in a single array . . . . . . 99 4.4.3 Reallocating memory at stack overflow . . . . . . . . . . . . . . . . 101 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 5 Queues and Deques 111 5.1 Sequential implementation of a straight queue . . . . . . . . . . . . . . . . 112 5.1.1 Implementing the insert operation . . . . . . . . . . . . . . . . . . . 113 5.1.2 Implementing the delete operation . . . . . . . . . . . . . . . . . . 114 5.2 Sequential implementation of a circular queue . . . . . . . . . . . . . . . . 115 5.2.1 Implementing the insert and delete operations for a circular queue . 116 5.2.2 A C implementation of the array representation of a circular queue 118 5.3 Linked list implementation of a queue . . . . . . . . . . . . . . . . . . . . . 120 5.3.1 Implementing the insert operation . . . . . . . . . . . . . . . . . . . 120 5.3.2 Implementing the delete operation . . . . . . . . . . . . . . . . . . 121 5.3.3 A C implementation of the linked list representation of a queue . . 121 5.4 Application of queues: topological sorting . . . . . . . . . . . . . . . . . . 124 x CONTENTS 5.5 The deque as an abstract data type . . . . . . . . . . . . . . . . . . . . . . 132 5.6 Sequential implementation of a straight deque . . . . . . . . . . . . . . . . 133 5.6.1 Implementing the insert operation . . . . . . . . . . . . . . . . . . . 134 5.6.2 Implementing the delete operation . . . . . . . . . . . . . . . . . . 135 5.7 Sequential implementation of a circular deque . . . . . . . . . . . . . . . . 135 5.7.1 Implementing the insert and delete operations for a circular deque . 137 5.8 Linked list implementation of a deque . . . . . . . . . . . . . . . . . . . . . 138 5.8.1 Implementing the insert and delete operations . . . . . . . . . . . . 138 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 6 Binary Trees 143 6.1 Definitions and related concepts . . . . . . . . . . . . . . . . . . . . . . . . 144 6.2 Binary tree traversals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 6.3 Binary tree representation in computer memory . . . . . . . . . . . . . . . 153 6.4 Implementing the traversal algorithms . . . . . . . . . . . . . . . . . . . . 154 6.4.1 Recursive implementation of preorder and postorder traversal . . . 154 6.4.2 Iterative implementation of preorder and postorder traversal . . . . 155 6.4.3 Two simple applications of the traversal algorithms . . . . . . . . . 161 6.5 Threaded binary trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 6.5.1 Finding successors and predecessors in a threaded binary tree . . . 164 6.5.2 Traversing inorder threaded binary trees . . . . . . . . . . . . . . . 167 6.5.3 Growing threaded binary trees . . . . . . . . . . . . . . . . . . . . . 168 6.5.4 Similarity and equivalence of binary trees . . . . . . . . . . . . . . . 171 6.6 Traversal by link inversion . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 6.7 Sikl´ossy traversal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Bibliographic Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181