100% found this document useful (6 votes)
86 views

Download ebooks file Data Structures And Problem Solving Using C 2nd International Edition Edition Mark Allen Weiss all chapters

Data

Uploaded by

doryambaxhia
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (6 votes)
86 views

Download ebooks file Data Structures And Problem Solving Using C 2nd International Edition Edition Mark Allen Weiss all chapters

Data

Uploaded by

doryambaxhia
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 55

Download the full version of the ebook at

https://ebookultra.com

Data Structures And Problem Solving Using C


2nd International Edition Edition Mark Allen
Weiss

https://ebookultra.com/download/data-structures-
and-problem-solving-using-c-2nd-international-
edition-edition-mark-allen-weiss/

Explore and download more ebook at https://ebookultra.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Data Structures and Problem Solving Using Java 4th,


intern. Edition Weiss

https://ebookultra.com/download/data-structures-and-problem-solving-
using-java-4th-intern-edition-weiss/

ebookultra.com

Object Orientation Abstraction and Data Structures Using


Scala 2nd Edition Edition Mark C. Lewis

https://ebookultra.com/download/object-orientation-abstraction-and-
data-structures-using-scala-2nd-edition-edition-mark-c-lewis/

ebookultra.com

Data structure and algorithm analysis C language English 2


Adapted China Edition Mark Allen Weiss

https://ebookultra.com/download/data-structure-and-algorithm-analysis-
c-language-english-2-adapted-china-edition-mark-allen-weiss/

ebookultra.com

Data Structures Using C C 2nd Edition Edition Aaron M.


Tenebaum

https://ebookultra.com/download/data-structures-using-c-c-2nd-edition-
edition-aaron-m-tenebaum/

ebookultra.com
Data structures using C 1st Edition Patil

https://ebookultra.com/download/data-structures-using-c-1st-edition-
patil/

ebookultra.com

Data Abstraction Problem Solving with C 6th Edition Frank


M. Carrano

https://ebookultra.com/download/data-abstraction-problem-solving-
with-c-6th-edition-frank-m-carrano/

ebookultra.com

Objects Abstraction Data Structures and Design Using C 1st


Edition Elliot B. Koffman

https://ebookultra.com/download/objects-abstraction-data-structures-
and-design-using-c-1st-edition-elliot-b-koffman/

ebookultra.com

Problem Solving with C 6th Edition Savitch

https://ebookultra.com/download/problem-solving-with-c-6th-edition-
savitch/

ebookultra.com

Data structures and algorithm analysis in C Fourth


Edition, International Edition / Chandavarkar

https://ebookultra.com/download/data-structures-and-algorithm-
analysis-in-c-fourth-edition-international-edition-chandavarkar/

ebookultra.com
Data Structures And Problem Solving Using C 2nd
International Edition Edition Mark Allen Weiss Digital
Instant Download
Author(s): Mark Allen Weiss
ISBN(s): 9780321205001, 0321205006
Edition: 2nd International Edition
File Details: PDF, 41.20 MB
Year: 2003
Language: english
DATA STRUCTURES AND
PROBLEM SOLVING USING C++
Second Edition

MARK ALLEN WElSS


Florida International U n i v e r s i ~

Pearson Education International Inc., Upper Saddle River, N.J. 07458


If you purchased this book within the United States or Canada
you should be aware that it has been wrongfully imported
without the approval of the Publisher or the Author.

Acquisitions Editor: Susan Hartman


Project Editor: Katherine Harutunian
Production Management: Shepherd, lnc.
Composition: Shepherd. Inc.
Cover Design: Diana Coe
Cover Photo: O Mike ShepherdPhotonica

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks.
Where those designations appear in this book, and the publisher was aware of a trademark claim. the des~gnationshave
been printed in ~nitialcaps or in all caps.

The programs and the applications presented In this book have been included for their instruct~onalvalue. They have
been tested with care but are not guaranteed for any particular purpose. Neither the publisher or the author offers any
warranties or representations. nor do they accept any liabilities with respect to the programs or applications.

@Copyright 2003 Pearson Education International


Upper Saddle River. N.J. 04758
@Copyright 2002 by Addison Wesley Longman, Inc.

All rights reserved. No part of this publication may be reproduced. stored In a database or retrieval system.
or transmitted in any form or by any means. electronic, mechanical, photocopying, recording. or any other
media embodiments now known or hereafter to become known. without the prior written permis5lon of the
publisher. Printed in the United States of Amenca.

ISBN: 0321 205006

10987654321
I Contents

Part I: Objects and C++

Chapter 1 Arrays, Pointers, and Structures 3


I .I What Are Pointers, Arrays, and Structures? 3
1.2 Arrays and Strings 4
1.2.1 First-Class Versus Second-Class Objects 4
1.2.2 Using the vector 6
1.2.3 Resizing a vector 7
1.2.4 gush-back:sizeandcapacity 1 1
1.2.5 Parameter-Passing Mechanisms 1 1
1.2.6 Primitive Arrays of Constants 13
1.2.7 Multidimensional Arrays 14
1.2.8 TheStandardLibrarystringType 14
1.3 Pointer Syntax in C++ 15
1.4 Dynamic Memory Management 20
1.4.1 The new Operator 2 1
I .4.2 Garbage Collection and delete 21
1.4.3 Stale Pointers, Double Deletion, and More 22
1.5 Reference Variables 24
1.6 Structures 26
1.6.1 Pointers to Structures 28
1.6.2 Exogenous Versus Indigenous Data and Shallow Versus Deep
Copying 29
1.6.3 Noncontiguous Lists: Linked Lists 30
Summary 32
Objects of the Game 32
Common Errors 34
On the Internet 35
Exercises 35
References 38
Chapter 2 Objects and Classes 41
2.1 What Is Object-Oriented Programming? 4 1
2.2 Basic class Syntax 43
2.2.1 Class Members 43
2.2.2 Extra Constructor Syntax and Accessors 45
2.2.3 Separation of Interface and Implementation 48
2.2.4 The Big Three: Destructor, Copy Constructor, and
operator= 51
2.2.5 Default Constructor 57
2.3 Additional C++ Class Features 57
2.3.1 Initialization Versus Assignment in the Constructor
Revisited 61
2.3.2 Type Conversions 63
2.3.3 Operator Overloading 64
2.3.4 Input and Output and Friends 67
2.4 Some Common Idioms 68
2.4.1 Avoiding Friends 70
2.4.2 Static Class Members 7 I
2.4.3 The enum Trick for Integer Class Constants 71
2.5 Exceptions 72
2.6 A string Class 73
2.7 Recap: What Gets Called and What Are the Defaults? 82
2.8 Composition 84
Summary 85
Objects of the Game 85
Common Errors 87
On the Internet 89
Exercises 90
References 96

Chapter 3 Templates 97
3.1 What Is a Template? 97
3.2 Function Templates 98
3.3 A Sorting Function Template 100
3.4 Class Templates 103
3.4.1 A MemoryCell Template 103
3.4.2 Implementing the vector Class Template 108
3.5 Templates of Templates: A matrix Class 108
3.5.1 The Data Members, Constructor. and Basic Accessors 1 1 1
3.5.2 operator [ I 112
3.5.3 Destructor, Copy Assignment, and Copy Constructor 112
--
Contents

3.6 Fancy Templates 1 12


3.6.1 Multiple Template Parameters 1 12
3.6.2 Default Template Parameters 1 13
3.6.3 The Reserved Word typename 1 13
3.7 Bugs Associated with Templates 1 14
3.7.1 Bad Error Messages and Inconsistent Rules 1 14
3.7.2 Template-Matching Algorithms 1 14
3.7.3 Nested Classes in a Template 114
3.7.4 Static Members in Class Templates 1 15
Summary 1 15
Objects of the Game 1 15
Common Errors 1 15
On the Internet 1 16
Exercises 1 17

Chapter 4 Inheritance 119


4. I What Is Inheritance? 1 19
4.2 Inheritance Basics 123
4.2.1 Visibility Rules 124
4.2.2 The Constructor and Base Class Initialization 125
4.2.3 Adding Members 126
4.2.4 Overriding a Method 128
4.2.5 Static and Dynamic Binding 129
4.2.6 The Default Constructor, Copy Constructor, Copy Assignment
Operator, and Destructor 13 1
4.2.7 Constructors and Destructors: Virtual or Not Virtual? 132
4.2.8 Abstract Methods and Classes 133
4.3 Example: Expanding the Shape Class 136
4.4 Tricky C++ Details 142
4.4.1 Static Binding of Parameters 142
4.4.2 Default Parameters 143
4.4.3 Derived Class Methods Hide Base Class Methods 144
4.4.4 Compatible Return Types for Overridden Methods 145
4.4.5 Private Inheritance 146
4.4.6 Friends 146
4.4.7 Call by Value and Polymorphism Do Not Mix 146
4.5 Multiple Inheritance 147
Summary 149
Objects of the Game 149
Common Errors 150
On the Internet 152
Exercises 152
R e f e r e n c e s 154
- - -
- - -- - - - - - - - - - -
Chapter 5 Design Patterns 155
5.1 What Is a Pattern'? 155
5.2 The Functor (Function Objects) 156
5.3 Adapters and Wrappers 162
5.3.1 Wrapper for Pointers 162
5.3.2 A Constant Reference Wrapper 168
5.3.3 Adapters: Changing an Interface 169
5.4 lterators 170
5.4.1 Iterator Design 1 171
5.4.2 Iterator Design 2 174
5.4.3 Inheritance-Based Iterators and Factories 174
5.5 Composite (Pair) 179
5.6 Observer 179
Summary 184
Objects of the Game 184
Common Errors 185
On the Internet 186
Exercises 186
References 190

Part ZI: Algorithms and Building Blocks

Chapter 6 Algorithm Analysis 193


6.1 What Is Algorithm Analysis? 193
6.2 Examples of Algorithm Running Times 198
6.3 The Maximum Contiguous Subsequence Sum Problem 199
6.3.1 The Obvious O(N3) Algorithm 200
6.3.2 An Improved O(N2) Algorithm 203
6.3.3 A Linear Algorithm 204
6.4 General Big-Oh Rules 206
6.5 The Logarithm 2 1 1
6.6 Static Searching Problem 21 4
6.6.1 Sequential Search 2 14
6.6.2 Binary Search 215
6.6.3 Interpolation Search 217
6.7 Checking an Algorithm Analysis 2 19
6.8 Limitations of Big-Oh Analysis 220
Contents

Summary 221
Objects of the Game 22 1
Common Errors 222
On the Internet 223
Exercises 223
References 228

Chapter 7 The Standard Template Library 231


7.1 Introduction 232
7.2 Stacks and Queues 233
7.2.1 Stacks 233
7.2.2 Stacks and Computer Languages 235
7.2.3 Queues 236
7.3 Containers and Iterators 237
7.3.1 Containers 238
7.3.2 The i t e r a t o r 238
7.4 STL Algorithms 240
7.4.1 STL Function Objects 240
7.4.2 Binary Search 243
7.4.3 Sorting 244
7.5 Implementation of vector with an Iterator 245
7.6 Sequences and Linked Lists 247
7.6.1 T h e l i s t c l a s s 247
7.6.2 Stacks and Queues 249
7.7 Sets 249
7.8 Maps 251
7.9 Priority Queues 253
Summary 257
Objects of the Game 257
Common Errors 259
On the Internet 259
Exercises 260
References 264

Chapter 8 Recursion 265


8.1 What Is Recursion? 265
8.2 Background: Proofs by Mathematical Induction 267
8.3 Basic Recursion 269
8.3.1 Printing Numbers in Any Base 27 1
8.3.2 Why It Works 274
8.3.3 How It Works 275
8.3.4 Too Much Recursion Can Be Dangerous 276
8.3.5 Preview of Trees 278
8.3.6 Additional Examples 279
8.4 Numerical Applications 284
8.4.1 Modular Arithmetic 285
8.4.2 Modular Exponentiation 285
8.4.3 Greatest Common Divisor and Multiplicative Inverses 287
8.4.4 The RSA Cryptosystem 289
8.5 Divide-and-Conquer Algorithms 292
8.5.1 The Maximum Contiguous Subsequence Sum Problem 293
8.5.2 Analysis of a Basic Divide-and-Conquer Recurrence 297
8.5.3 A General Upper Bound for Divide-and-Conquer Running
Times 301
8.6 Dynamic Programming 303
8.7 Backtracking 308
Summary 3 10
Objects of the Game 3 12
Common Errors 3 13
On the Internet 3 14
Exercises 3 14
References 3 19

Chapter 9 Sorting Algorithms 321


9.1 Why Is Sorting Important? 322
9.2 Preliminaries 323
9.3 Analysis of the Insertion Sort and Other Simple Sorts 324
9.4 Shellsort 326
9.4.1 Performance of Shellsort 328
9.5 Mergesort 330
9.5.1 Linear-Time Merging of Sorted Arrays 330
9.5.2 The Mergesort Algorithm 332
9.6 Quicksort 334
9.6.1 The Quicksort Algorithm 335
9.6.2 Analysis of Quicksort 337
9.6.3 Picking the Pivot 340
9.6.4 A Partitioning Strategy 342
9.6.5 Keys Equal to the Pivot 344
9.6.6 Median-of-Three Partitioning 345
9.6.7 Small Arrays 346
9.6.8 C++ Quicksort Routine 346
9.7 Quickselect 348
9.8 A Lower Bound for Sorting 349
9.9 Indirect Sorting 352
9.9.1 Using Pointers to Reduce Comparable Copies to 2N 352
9.9.2 Avoiding the Extra Array 353
Summary 355
Objects of the Game 356
Common Errors 357
On the Internet 357
Exercises 358
References 363

Chapter 10 Randomization 365


10.1 Why Do We Need Random Numbers? 365
10.2 Random Number Generators 366
10.3 Nonuniform Random Numbers 37 1
10.4 Generating a Random Permutation 373
10.5 Randomized Algorithms 375
10.6 Randomized Prjmality Testing 378
Summary 380
Objects of the Game 382
Common Errors 383
On the Internet 383
Exercises 383
References 386

Part I l l : Applications

Chapter 11 Fun and Games 389


1 1.1 Word Search Puzzles 389
11.1.1 Theory 390
1 1.1.2 C++ Implementation 39 1
1 1.2 The Game of Tic-Tac-Toe 395
I 1.2.1 Alpha-Beta Pruning 397
I 1.2.2 Transposition Tables 398
1 1.2.3 Computer Chess 404
Summary 405
Objects of the Game 405
-- - .-A

Contents

Common Errors 406


On the Internet 406
Exercises 406
References 408

Chapter 12 Stacks and Compilers 409


12.1 Balanced-Symbol Checker 409
12.1.I Basic Algorithm 409
12.1.2 Implementation 4 1 1
12.2 A Simple Calculator 420
12.2.1 Postfix Machines 421
12.2.2 Infix to Postfix Conversion 422
12.2.3 Implementation 424
12.2.4 Expression Trees 432
Summary 435
Objects of the Game 435
Common Errors 436
On the Internet 436
Exercises 436
References 438

Chapter 13 Utilities 439


13.1 File Compression 439
13.1.1 Prefix Codes 440
13.1.2 Huffman's Algorithm 442
13.1.3 Implementation 445
13.2 A Cross-Reference Generator 46 1
13.2.1 Basic Ideas 46 1
13.2.2 C++ Implementation 462
Summary 466
Objects of the Game 466
Common Errors 466
On the Internet 467
Exercises 467
References 470

Chapter 14 Simulation 471


14.1 The Josephus Problem 47 1
14.l . l The Simple Solution 473
14.1.2 A More Efficient Algorithm 473
14.2 Event-Driven Simulation 475
14.2.1 Basic Ideas 477
14.2.2 Example: A Modem Bank Simulation 478
Summary 486
Objects of the Game 486
Common Errors 486
On the Internet 486
Exercises 486

Chapter 15 Graphs and Paths 489


15.1 Definitions 489
15.1.1 Representation 49 1
15.2 Unweighted Shortest-Path Problem 503
15.2.1 Theory 504
1 5.2.2 C++ Implementation 509
15.3 Positive-Weighted, Shortest-Path Problem 509
15.3.1 Theory: Dijkstra's Algorithm 509
15.3.2 C++ Implementation 5 13
15.4 Negative-Weighted. Shortest-Path Problem 5 14
15.4.1 Theory 514
15.4.2 C++ Implementation 5 17
15.5 Path Problems in Acyclic Graphs 5 17
15.5.1 Topological Sorting 5 17
15.5.2 Theory of the Acyclic Shortest-Path Algorithm 520
15.5.3 C++ Implementation 522
15.5.4 An Application: Critical-Path Analysis 522
Summary 526
Objects of the Game 527
Common Errors 528
On the Internet 529
Exercises 529
References 533

Part ZV: Zmplementations

Chapter 16 Stacks and Queues 537


16.1 Dynamic Array Implementations 537
16.1.1 Stacks 538
16.1.2 Queues 541
16.2 Linked List Implementations 548
16.2.1 Stacks 548
16.2.2 Queues 553
16.3 Comparison of the Two Methods 557
16.4 The STL Stack and Queue Adapters 558
16.5 Double-Ended Queues 558
Summary 559
Objects of the Game 56 1
Common Errors 561
On the Internet 56 1
Exercises 562

Chapter 17 Linked Lists 565


17.1 Basic Ideas 565
17.1.1 Header Nodes 567
17.1.2 Iterator Classes 569
17.2 C++ Implementation 570
17.3 Doubly Linked Lists and Circularly Linked Lists 579
17.4 Sorted Linked Lists 582
17.5 lmplementingtheSTLlistClass 582
Summary 597
Objects of the Game 597
Common Errors 598
On the Internet 598
Exercises 599

Chapter I 8 Trees 605


18.1 General Trees 605
18.1.1 Definitions 605
1 8.1.2 Implementation 607
1 8.1.3 An Application: File Systems 608
18.2 Binary Trees 61 1
18.3 Recursion and Trees 6 19
18.4 Tree Traversal: lterator Classes 622
18.4.1 Postorder Traversal 624
18.4.2 Inorder Traversal 630
18.4.3 Preorder Traversal 630
18.4.4 Level-Order Traversals 630
Summary 633
Objects of the Game 636
Common Errors 637
On the Internet 637
Exercises 637

Chapter 19 Binary Search Trees 641


19.1 Basic Ideas 64 1
19.1.1 The Operations 642
19.1.2 C++ lmplementation 644
19.2 Order Statistics 652
19.2.1 C++ Implementation 653
19.3 Analysis of Binary Search Tree Operations 657
19.4 AVL Trees 661
19.4.1 Properties 662
19.4.2 Single Rotation 664
19.4.3 Double Rotation 667
19.4.4 Summary of AVL Insertion 670
19.5 Red-Black Trees 670
19.5.1 Bottom-Up Insertion 672
19.5.2 Top-Down Red-Black Trees 674
19.5.3 C++ Implementation 676
19.5.4 Top-Down Deletion 680
19.6 AA-Trees 685
19.6.1 Insertion 686
19.6.2 Deletion 688
19.6.3 C++ Implementation 690
19.7 Implementing the STL set and map Classes 693
19.8 B-Trees 707
Summary 714
Objects of the Game 7 15
Common Errors 7 17
On the Internet 7 17
Exercises 7 18
References 72 1

Chapter 20 Hash Tables 725


20.1 Basic Ideas 725
20.2 Hash Function 727
20.3 Linear Probing 729
20.3.1 Naive Analysis of Linear Probing 73 1
20.3.2 What Really Happens: Primary Clustering 732
20.3.3 Analysis of the find Operation 733
20.4 Quadratic Probing 735
20.4.1 C++ Implementation 739
20.4.2 Analysis of Quadratic Probing 745
20.5 Separate Chaining Hashing 746
20.6 Hash Tables Versus Binary Search Trees 746
20.7 Hashing Applications 747
Summary 747
Objects of the Game 748
Common Errors 749
On the Internet 749
Exercises 749
References 752

Chapter 21 A Priority Queue: The Binary Heap 755


21.1 Basic Ideas 755
2 1.1.1 Structure Property 756
2 1.1.2 Heap-Order Property 758
2 1.1.3 Allowed Operations 759
21.2 Implementation of the Basic Operations 761
2 1.2.1 The insert Operation 762
21.2.2 The deleteMin Operation 763
2 1.3 The buildHeap Operation: Linear-Time Heap Construction 766
21.4 STL priority-queue lmplementation 77 1
21.5 Advanced Operations: decreaseKey and merge 773
2 1.6 Internal Sorting: Heapsort 773
2 1.7 External Sorting 778
21.7.1 Why We Need New Algorithms 778
2 1.7.2 Model for External Sorting 778
21.7.3 The Simple Algorithm 779
2 1.7.4 Multiway Merge 78 1
2 1.7.5 Polyphase Merge 782
21.7.6 Replacement Selection 783
Summary 785
Objects of the Game 785
Common Errors 786
On the Internet 787
Exercises 787
References 79 1
Part V: Advanced Data Structures

Chapter 22 Splay Trees 795


22.1 Self-Adjustment and Amortized Analysis 795
22.1 .I Amortized Time Bounds 797
22.1.2 A Simple Self-Adjusting Strategy (That Does Not Work) 797
22.2 The Basic Bottom-Up Splay Tree 799
22.3 Basic Splay Tree Operations 802
22.4 Analysis of Bottom-Up Splaying 803
22.4.1 Proof of the Splaying Bound 806
22.5 Top-Down Splay Trees 809
22.6 Implementation of Top-Down Splay Trees 81 2
22.7 Comparison of the Splay Tree with Other Search Trees 8 18
Summary 8 19
Objects of the Game 8 19
Common Errors 820
On the Internet 820
Exercises 820
References 822

Chapter 23 Merging Priority Queues 823


23.1 The Skew Heap 823
23.1.1 Merging Is Fundamental 823
23.1.2 Simplistic Merging of Heap-Ordered Trees 824
23.1.3 The Skew Heap: A Simple Modification 825
23.1.4 Analysis of the Skew Heap 826
23.2 The Pairing Heap 828
23.2.1 Pairing Heap Operations 829
23.2.2 Implementation of the Pairing Heap 830
23.2.3 Application: Dijkstra's Shortest Weighted Path Algorithm 836
Summary 840
Objects of the Game 840
Common Errors 84 1
On the Internet 84 1
Exercises 84 1
References 842

Chapter 24 The Disjoint Set Class 845


24.1 Equivalence Relations 845
24.2 Dynamic Equivalence and Two Applications 846
- - - - ----

contents

24.2.1 Application: Generating Mazes 847


24.2.2 Application: Minimum Spanning Trees 850
24.2.3 Application: The Nearest Common Ancestor Problem 853
24.3 The Quick-Find Algorithm 857
24.4 The Quick-Union Algorithm 858
24.4.1 Smart Union Algorithms 860
24.4.2 Path Compression 862
24.5 C++ Implementation 863
24.6 Worst Case for Union-by-Rank and Path Compression 865
24.6.1 Analysis of the UnionIFind Algorithm 866
Summary 873
Objects of the Game 873
Common Errors 875
On the Internet 875
Exercises 875
References 877

Appendices

Appendix A Miscellaneous C++ Details A-3


A. 1 None of the Compilers Implement the Standard A-3
A.2 Unusual C++ Operators A-4
A.2.1 Autoincrement and Autodecrement Operators A-4
A.2.2 Type Conversions A-5
A.2.3 Bitwise Operators A-6
A.2.4 The Conditional Operator A-8
A.3 Command-Line Arguments A-8
A.4 Input and Output A-9
A.4.1 Basic Stream Operations A-9
A.4.2 Sequential Files A- 13
A.4.3 String Streams A- 13
A.5 Namespaces A-15
A.6 New C++ Features A- 17
Common C++ Errors A- 17
Appendix B Operators A-21

Appendix C Some Library Routines A-23


C.l Routines Declared in <ctype. h> and <cctype> A-23
C.2 Constants Declared in <limits. h> and <climits> A-24
C.3 Routines Declared in <math.h> and <cmath> A-25
C.4 Routines Declared in <stdlib.h> and <cstdlib> A-26

Appendix D Primitive Arrays in C++ A-27


D.1 Primitive Arrays A-27
D. 1 . 1 The C++ Implementation: An Array Name Is a Pointer A-28
D. 1.2 Multidimensional Arrays A-3 1
D. I .3 The char * Type, const Pointers, and Constant Strings A-3 I
D.2 Dynamic Allocation of Arrays: new [ ] and delete [ I A-35
D.3 Pointer Arithmetic, Pointer Hopping, and Primitive Iteration A-4 1
D.3.1 Implications of the Precedence of *, &, and [ I A-41
D.3.2 What Pointer Arithmetic Means A-42
D.3.3 A Pointer-Hopping Example A-44
D.3.4 Is Pointer Hopping Worthwhile? A-45
Common C++ Errors A-47
On the Internet A-47
I Preface

This book is designed for a two-semester sequence in computer science,


beginning with what is typically known as Data Structures (CS-2) and con-
tinuing with advanced data structures and algorithm analysis.
The content of the CS-2 course has been evolving for some time.
Although there is some general consensus concerning topic coverage, con-
siderable disagreement still exists over the details. One uniformly accepted
topic is principles of software development, most notably the concepts of
encapsulation and information hiding. Algorithmically, all CS-2 courses
tend to include an introduction to running-time analysis, recursion, basic
sorting algorithms, and elementary data structures. An advanced course is
offered at many universities that covers topics in data structures, algorithms,
and running-time analysis at a higher level. The material in this text has been
designed for use in both levels of courses, thus eliminating the need to pur-
chase a second textbook.
Although the most passionate debates in CS-2 revolve around the choice
of a programming language, other fundamental choices need to be made,
including

whether to introduce object-oriented design or object-based design


early,
the level of mathematical rigor,
the appropriate balance between the implementation of data struc-
tures and their use, and
programming details related to the language chosen.

My goal in writing this text was to provide a practical introduction to


data structures and algorithms from the viewpoint of abstract thinking and
problem solving. I tried to cover all of the important details concerning the
data structures, their analyses, and their C++ implementations, while staying
away from data structures that are theoretically interesting but not widely
used. It is impossible to cover in a single course all the different data struc-
tures, including their uses and the analysis, described in this text. So, I
designed the textbook to allow instructors flexibility in topic coverage. The
instructor will need to decide on an appropriate balance between practice
and theory and then choose those topics that best fit the course. As I discuss
later in this Preface, I organized the text to minimize dependencies among
the various chapters.

A Unique Approach
My basic premise is that software development tools in all languages come
with large libraries, and many data structures are part of these libraries. I
envision an eventual shift in emphasis of data structures courses from imple-
mentation to use. In this book I take a unique approach by separating the
data structures into their specification and subsequent implementation and
take advantage of an already existing data structures library, the Standard
Template Library (STL).
A subset of the STL suitable for most applications is discussed in a sin-
gle chapter (Chapter 7) in Part 11. Part 11 also covers basic analysis tech-
niques, recursion, and sorting. Part I11 contains a host of applications that
use the STL's data structures. Implementation of the STL is not shown until
Part IV, once the data structures have already been used. Because the STL is
part of C++ (older compilers can use the textbook's STL code instead-see
Code Availability, xxix), students can design large projects early on, using
existing software components.
Despite the central use of the STL in this text, it is neither a book on the
STL nor a primer on implementing the STL specifically; it remains a book
that emphasizes data structures and basic problem-solving techniques. Of
course, the general techniques used in the design of data structures are appli-
cable to the implementation of the STL, so several chapters in Part IV
include STL implementations. However, instructors can choose the simpler
implementations in Part IV that do not discuss the STL protocol. Chapter 7,
which presents the STL, is essential to understanding the code in Part 111. I
attempted to use only the basic parts of the STL.
Many instructors will prefer a more traditional approach in which each
data structure is defined, implemented, and then used. Because there is no
dependency between material in Parts I11 and IV, a traditional course can
easily be taught from this book.
Prerequisites
Students using this book should have knowledge of either an object-oriented
or procedural programming language. Knowledge of basic features, includ-
ing primitive data types, operators, control structures, functions (methods),
and input and output (but not necessarily arrays and classes) is assumed.
Students who have taken a first course using C++ or Java may find the
first two chapters "light" reading in some places. However, other parts are
definitely "heavy" with C++ details that may not have been covered in intro-
ductory courses.
Students who have had a first course in another language should begin at
Chapter 1 and proceed slowly. They also should consult Appendix A which
discusses some language issues that are somewhat C++ specific. If a student
would like also to use a C++ reference book, some recommendations are
given in Chapter 1, pages 38-39.
Knowledge of discrete math is helpful but is not an absolute prerequi-
site. Several mathematical proofs are presented, but the more complex
proofs are preceded by a brief math review. Chapters 8 and 19-24 require
some degree of mathematical sophistication. The instructor may easily elect
to skip mathematical aspects of the proofs by presenting only the results. All
proofs in the text are clearly marked and are separate from the body of the
text.

Summary of Changes in the Second Edition


1. Much of Part I was rewritten. In Chapter 1, primitive arrays are no
longer presented (a discussion of them was moved to Appendix D);
vectors are used instead, and push-back is introduced. Pointers
appear later in this edition than in the first edition. In Chapter 2,
material was significantly rearranged and simplified. Chapter 3 has
additional material on templates. In Chapter 4, the discussion on
inheritance was rewritten to simplify the initial presentation. The
end of the chapter contains the more esoteric C++ details that are
important for advanced uses.
2. An additional chapter on design patterns was added in Part I. Sev-
eral object-based patterns, including Functor, Wrapper, and Iterator,
are described, and patterns that make use of inheritance. including
Observer, are discussed.
3. The Data Structures chapter in Part I1 was rewritten with the STL in
mind. Both generic interfaces (as in the first edition) and STL inter-
faces are illustrated in the revised Chapter 7.
4. The code in Part I11 is based on the STL. In several places, the code
is more object-oriented than before. The Huffman coding example
is completely coded.
5. In Part IV, generic data structures were rewritten to be much sim-
pler and cleaner. Additionally, as appropriate, a simplified STL
implementation is illustrated at the end of the chapters in Part IV.
lmplemented components include vector, 1ist, stack,queue,
set, map, priority-queue, and various function objects and
algorithms.

Using C++ presents both advantages and disadvantages. The C++ class
allows the separation of interface and implementation, as well as the hid-
ing of internal details of the implementation. It cleanly supports the notion
of abstraction. The advantage of C++ is that it is widely used in industry.
Students perceive that the material they are learning is practical and will
help them find employment, which provides motivation to persevere
through the course. One disadvantage of C++ is that it is far from a perfect
language pedagogically, especially in a second course, and thus additional
care needs to be expended to avoid bad programming practices. A second
disadvantage is that C++ is still not a stable language, so the various com-
pilers behave differently.
It might have been preferable to write the book in a language-indepen-
dent fashion, concentrating only on general principles such as the theory of
the data structures and referring to C++ code only in passing, but that is
impossible. C++ code is complex, and students will need to see complete
examples to understand some of its finer points. As mentioned earlier, a brief
review of parts of C++ is provided in Appendix A . Part I of the book
describes some of C++'s more advanced features relevant to data structures.
Several parts of the language stand out as requiring special consider-
ation: templates, inheritance, exceptions, namespaces and other recent C++
additions, and the Standard Library. 1 approached this material in the follow-
ing manner.

Templates: Templates are used extensively. Some instructors may


have reservations with this approach because it complicates the code,
but I included them because they are fundamental concepts in any
sophisticated C++ program.
I~zheritance: I use inheritance relatively sparingly because it adds
complications, and data structures are not a strong application area
-- --
Preface

for it, This edition contains less use of inheritance than in the previ-
ous edition. However, there is a chapter on inheritance, and part of the
design patterns chapter touches on inheritance-based patterns. For the
most part, instructors who are eager to avoid inheritance can do so,
and those who want to discuss inheritance will find sufficient material
in the text.
Exceptions: Exception semantics have been standardized and
exceptions seem to work on many compilers. However, exceptions
in C++ involve ugly code, significant complications (e.g., if used in
conjunction with templates), and probably require discussing inher-
itance. So I use them sparingly in this text. A brief discussion of
exceptions is provided, and in some places exceptions are thrown in
code when warranted. However, I generally do not attempt to catch
exceptions in any Part I11 code (most of the Standard Library does
not attempt to throw exceptions).
Namespaces: Namespaces, which are a recent addition to C++, do not
work correctly on a large variety of compilers. I do not attempt to use
namespaces and I import the entire s t d namespace when necessary
(even though not great style, it works on the largest number of com-
pilers). Appendix A discusses the namespace issues.
Recent language additions: The boo1 data type is used throughout.
The new s t a t i c - c a s t operator is used in preference to the old-style
cast. Finally, I use e x p l i c i t when appropriate. For the most part,
other additions are not used (e.g., I generally avoid using typename).
Standard Library: As previously mentioned, the STL is used through-
out, and a safe version (that does extra bounds checking) is available
online (and implemented in Part IV). We also use the s t r i n g class
and the newer i s t r i n g s t r e a m class that are part of the standard
library.

Text Organization
In this text I introduce C++ and object-oriented programming (particularly
abstraction) in Part I. I discuss arrays, pointers and some other C++ topics
and then go on to discuss the syntax and use of classes, templates, and inher-
itance. The material in these chapters was substantially rewritten. New to
this edition is an entire chapter on design patterns.
In Part I1 I discuss Big-Oh and algorithmic paradigms, including recur-
sion and randomization. An entire chapter is devoted to sorting, and a sepa-
rate chapter contains a description of basic data structures. I use the STL in
presenting the interfaces and running times of the data structures. At this
Preface

point in the text, the instructor may take several approaches to present the
remaining material, including the following two.

I . Discuss the corresponding implementations (either the STL ver-


sions or the simpler versions) in Part IV as each data structure is
described. The instructor can ask students to extend the classes in
various ways, as suggested in the exercises.
2. Show how the STL class is used and cover implementation at a later
point in the course. The case studies in Part 111 can be used to sup-
port this approach. As complete implementations are available on
every modern C++ compiler (or on the Internet for older compil-
ers). the instructor can use the STL in programming projects.
Details on using this approach are given shortly.

Part V describes advanced data structures such as splay trees, pairing


heaps, and the disjoint set data structure, which can be covered if time per-
mits or, more likely, in a follow-up course.

Chapter-by-ChapterText Organization
Part I consists of ti ve chapters that describe some advanced features of C++
used throughout the text. Chapter I describes arrays, strings, pointers, refer-
ences, and structures. Chapter 2 begins the discussion of object-oriented pro-
gramming by describing the class mechanism in C++. Chapter 3 continues
this discussion by examining templates, and Chapter 4 illustrates the use of
inheritance. Several components, including strings and vectors, are written
in these chapters. Chapter 5 discusses some basic design patterns, focusing
mostly on object-based patterns such as function objects, wrappers and
adapters, iterators, and pairs. Some of these patterns (most notably the wrap-
per pattern) are used later in the text.
Part IT focuses on the basic algorithms and building blocks. In Chapter 6
a complete discussion of time complexity and Big-Oh notation is provided,
and binary search is also discussed and analyzed. Chapter 7 is crucial
because it covers the STL and argues intuitively what the running time of the
supported operations should be for each data structure. (The implementation
of these data structures. in both STL-style and a simplified version, is not
provided until Part IV. The STL is available on recent compilers.) Chapter 8
describes recursion by ti rst introducing the notion of proof by induction. It
also discusses divide-and-conquer, dynamic programming, and backtrack-
ing. A section describes several recursive numerical algorithms that are used
to implement the RSA cryptosystem. For many students, the material in the
second half of Chapter 8 is more suitable for a follow-up course. Chapter 9
describes. codes, and analyzes several basic sorting algorithms, including
the insertion sort, Shellsort, mergesort, and quicksort, as well as indirect
sorting. It also proves the classic lower bound for sorting and discusses the
related problems of selection. Finally, Chapter 10 is a short chapter that dis-
cusses random numbers, including their generation and use in randomized
algorithms.
Part 111 provides several case studies, and each chapter is organized
around a general theme. Chapter I I illustrates several important techniques
by examining games. Chapter 12 discusses the use of stacks in computer
languages by examining an algorithm to check for balanced symbols and the
classic operator precedence parsing algorithm. Complete implementations
with code are provided for both algorithms. Chapter 13 discusses the basic
utilities of file compression and cross-reference generation, and provides a
complete implementation of both. Chapter 14 broadly examines simulation
by looking at one problem that can be viewed as a simulation and then at the
more classic event-driven simulation. Finally, Chapter 15 illustrates how
data structures are used to implement several shortest path algorithms effi-
ciently for graphs.
Part IV presents the data structure implementations. Implementations
that use simple protocols (insert,find,remove variations) are provided.
In some cases, STL implementations that tend to use more complicated C++
syntax are presented. Some mathematics is used in this part, especially in
Chapters 19-21, and can be skipped at the discretion of the instructor. Chap-
ter 16 provides implementations for both stacks and queues. First these data
structures are implemented using an expanding array; then they are imple-
mented using linked lists. The STL versions are discussed at the end of the
chapter. General linked lists are described in Chapter 17.Singly linked lists
are illustrated with a simple protocol, and the more complex STL version
that uses doubly linked lists is provided at the end of the chapter. Chapter 18
describes trees and illustrates the basic traversal schemes. Chapter 19 is a
detailed chapter that provides several implementations of binary search
trees. Initially, the basic binary search tree is shown, and then a binary
search tree that supports order statistics is derived. AVL trees are discussed
but not implemented; however, the more practical red-black trees and AA-
trees are implemented. Then the STL set and map are implemented.
Finally, the B-tree is examined. Chapter 20 discusses hash tables and imple-
ments the quadratic probing scheme, after examination of a simpler alterna-
tive. Chapter 21 describes the binary heap and examines heapsort and
external sorting. The STL pr iority-queue is implemented in this chapter.
Part Chapter V contains material suitable for use in a more advanced
course or for general reference. The algorithms are accessible even at the
first-year level; however, for completeness sophisticated mathematical anal-
yses were included that are almost certainly beyond the reach of a first-year
student. Chapter 22 describes the splay tree, which is a binary search tree
that seems to perform extremely well in practice and is also competitive with
the binary heap in some applications that require priority queues. Chapter 23
describes priority queues that support merging operations and provides an
implementation of the pairing heap. Finally, Chapter 24 examines the classic
disjoint set data structure.
The appendices contain additional C++ reference material. Appendix A
describes tricky C++ issues, including some unusual operators, 110, and
recent language changes. Appendix B lists the operators and their prece-
dence. Appendix C summarizes some C++ libraries. Appendix D describes
primitive arrays and strings for those who want details of what is going on
under the hood of the v e c t o r and s t r i n g classes.

Chapter Dependencies
Generally speaking, most chapters are independent of each other. However,
the following are some of the notable dependencies.

Part I: The first three chapters should be covered in their entirety first. I
recommend a brief discussion of inheritance in Chapter 4. Some instruc-
tors will want to cover all of inheritance, but it is possible to get by with
just the basics of inheritance and avoid some of the more difficult C++
issues that inheritance involves. Some of the object-based patterns (e.g.,
wrappers and function objects) in Chapter 5 can be discussed shortly
after templates, or later in the course as the need arises. Some of these
patterns are used in the chapter on sorting and in Part IV.
Chapter 6 (Algorithm Analysis): This chapter should be covered prior
to Chapters 7 and 9. Recursion (Chapter 8) can be covered prior to
this chapter, but the instructor will have to gloss over some details
about avoiding inefficient recursion.
Chapter 7 (STL): This chapter can be covered prior to, or in conjunc-
tion with, material in Part 111or IV.
Chapter 8 (Recursion): The material in Sections 8.1-8.3 should be
covered prior to discussing recursive sorting algorithms, trees, the tic-
tac-toe case study, and shortest-path algorithms. Material such as the
RSA cryptosystem, dynamic programming, and backtracking (unless
tic-tac-toe is discussed) is otherwise optional.
Chapter 9 (Sorting): This chapter should follow Chapters 6 and 8.
However, it is possible to cover Shellsort without Chapters 6 and 8.
Shellsort is not recursive (hence there is no need for Chapter 8), and a
rigorous analysis of its running time is too complex and is not cov-
ered in the book (hence there is little need for Chapter 6).
Chapters 16 and 17 (Stacks/Queues/Lists): These chapters may be
covered in either order. However, I prefer to cover Chapter 16 first,
because I believe that it presents a simpler example of linked lists.
Chapters 18 and 19 (TreesBearch trees): These chapters can be cov-
ered in either order or simultaneously.

Separate Entities
The other chapters have little or no dependencies:

Chapter 10 (Randomization): The material on random numbers can


be covered at any point as needed.
Part III (Case Studies): Chapters 11-15 can be covered in conjunction
with, or after, the STL (in Chapter 7), and in roughly any order. There
are a few references to earlier chapters. These include Section 1 1.2 (tic-
tac-toe), which references a discussion in Section 8.7, and Section 13.2
(cross-reference generation), which references similar lexical analysis
code in Section 12.1 (balanced symbol checking).
CIzapters 20 and 21 (Hashing/Priority Queues): These chapters can
be covered at any point.
Part V (Advanced Data Structures): The material in Chapters 22-24
is self-contained and is typically covered in a follow-up course.

Mathematics
I have attempted to provide mathematical rigor for use in CS-2 courses that
emphasize theory and for follow-up courses that require more analysis.
However, this material stands out from the main text in the form of separate
theorems and, in some cases, separate sections (or subsections). Thus it can
be skipped by instructors in courses that deemphasize theory.
In all cases, the proof of a theorem is not necessary to the understanding
of the theorem's meaning. This is another illustration of the separation of an
interface (the theorem statement) from its implementation (the proof). Some
inherently mathematical material, such as Section 8.4 (Numerical Applica-
tions of Recursion), can be skipped without affecting comprehension of the
rest of the chapter.
Preface

Course Organization
A crucial issue in teaching the course is deciding how the materials in Parts
11-IV are to be used. The material in Part I should be covered in depth, and
the student should write one or two programs that illustrate the design,
implementation, and testing of classes and generic classes-and perhaps
object-oriented design, using inheritance. Chapter 6 discusses Big-Oh nota-
tion. An exercise in which the student writes a short program and compares
the running time with an analysis can be given to test comprehension.
In the separation approach, the key concept of Chapter 7 is that different
data structures support different access schemes with different efficiency.
Any case study (except the tic-tac-toe example that uses recursion) can be
used to illustrate the applications of the data structures. In this way, the stu-
dent can see the data structure and how it is used but not how it is efficiently
implemented. This is truly a separation. Viewing things this way will greatly
enhance the ability of students to think abstractly. Students can also provide
simple implementations of some of the STL components (some suggestions
are given in the exercises in Chapter 7) and see the difference between effi-
cient data structure implementations in the existing STL and inefficient data
structure implementations that they will write. Students can also be asked to
extend the case study, but, again, they are not required to know any of the
details of the data structures.
Efficient implementation of the data structures can be discussed after-
ward, and recursion can be introduced whenever the instructor feels it is
appropriate, provided it is prior to binary search trees. The details of sorting
can be discussed at any time after recursion. At this point, the course can
continue by using the same case studies and experimenting with modifica-
tions to the implementations of the data structures. For instance, the student
can experiment with various forms of balanced binary search trees.
Instructors who opt for a more traditional approach can simply discuss
a case study in Part I11 after discussing a data structure implementation in
Part IV. Again, the book's chapters are designed to be as independent of
each other as possible.

Q Exercises
Exercises come in various flavors; I have provided four varieties. The basic In
Short exercise asks a simple question or requires hand-drawn simulations of an
algorithm described in the text. The In Theory section asks questions that either
require mathematical analysis or asks for theoretically interesting solutions to
problems. The In Practice section contains simple programming questions,
including questions about syntax or particularly tricky lines of code. Finally, the
Programming Projects section contains ideas for extended assignments.
Pedagogical Features
Margin notes are used to highlight important topics.
The Objects of the Game section lists important terms along with def-
initions and page references.
The Common Errors section at the end of each chapter provides a list
of commonly made errors.
References for further reading are provided at the end of most chapters.

Code Availability
The code in the text is fully functional and has been tested on numerous plat-
forms. It is available from my home page h t t p : / /www. fiu . ed~/-weiss.
Be sure to browse the README file for information on compiler dependencies
and bug fixes. The On the Internet section at the end of each chapter lists the
filenames for the chapter's code.

Instructor's Resource Guide


An Instructor's Guide that illustrates several approaches to the material is
available. It includes samples of test questions, assignments, and syllabi.
Answers to select exercises are also provided. Instructors should contact
their Addison Wesley Longman local sales representative for information on
its availability or send an e-mail message to aw .cse@awl. corn. This guide
is not available for sale and is available to instructors only.

Acknowledgments
Many, many people have helped me in the preparation of this book. Many
have already been acknowledged in the first edition and the related title,
Data Structures and Problem Solving Using Java. Others, too numerous to
list, have sent e-mail messages and pointed out errors or inconsistencies in
explanations that I have tried to fix in this version.
For this book, I would like to thank all of the folks at Addison Wesley
Longman: my editor, Susan Hartman, and associate editor, Katherine Haru-
tunian, helped me make some difficult decisions regarding the organization
of the C++ material and were very helpful in bringing this book to fruition.
My copyeditor, Jerrold Moore, and proofreaders, suggested numerous
rewrites that improved the text. Diana Coe did a lovely cover design. As
always, Michael Hirsch has done a superb marketing job. I would especially
like to thank Pat Mahtani, my production editor, and Lynn Steines at Shep-
herd, Inc. for their outstanding efforts coordinating the entire project.
1 also thank the reviewers, who provided valuable comments, many of
which have been incorporated into the text:
Zhengxin Chen, University of Nebraska at Omaha
Arlan DeKock, University of Missouri-Rolla
Andrew Duchowski, Clemson University
Seth Copen Goldstein, Carnegie Mellon University
G. E. Hedrick, Oklahoma State University
Murali Medidi, Northern Arizona University
Chris Nevison, Colgate University
Gurpur Prabhu, Iowa State University
Donna Reese, Mississippi State University
Gurdip Singh, Kansas State University
Michael Stinson, Central Michigan University
Paul Wolfgang, Temple University
Some of the material in this text is adapted from my textbook EfJicient C
Programming: A Practical Approach (Prentice-Hall, 1995) and is used with
permission of the publisher. I have included end-of-chapter references where
appropriate.
My World Wide Web page, http:/ /www. cs . f iu .edu/-weiss,will
contain updated source code, an errata list, and a link for receiving bug
reports.
M. A. W
Miami, Florida
September, 1999
Part I
Objects and C++
Chapter 1
Arrays, Pointers, and Structures

In this chapter we discuss three features contained in many programming


languages: arrays, pointers, and structures. Sophisticated C++ programming
makes heavy use of pointers to access objects. Arrays and structures store
several objects in one collection. An array stores only one type of object, but
a structure can hold a collection of several distinct types.
In this chapter, we show:

why these features are important;


how the v e c t o r is used to implement arrays in C++;
how the s t r i n g is used to implement strings in C++;
how basic pointer syntax and dynamic memory allocation are used;
and
how pointers, arrays, and structures are passed as parameters to
functions.

1.I What Are Pointers, Arrays, and Structures?


A pointer is an object that can be used to access another object. A pointer
provides indirect access rather than direct access to an object. People use
pointers in real-life situations all the time. Let us look at some examples.

When a professor says, "Do Problem 1.1 in the textbook," the actual
homework assignment is being stated indirectly.
A classic example of indirect access is looking up a topic in the index
of a book. The index tells you where you can find a full description.
A street address is a pointer. It tells you where someone resides. A
forwarding address is a pointer to a pointer.
-- -- -- -

~ p ~ r r a y Pomters,
~ , and Structures

A unform resource locator (URL), such as http : / /www . cnn.corn,is


a pointer. The URL tells you where a target Web page is. If the target
Web page moves, the URL becomes stale, and points to a page that no
longer exists.

A pointer stores an In all these cases a piece of information is given out indirectly by providing
address where other a pointer to the information. In C++ a pointer is an object that stores an
data reside.
address (i.e., a location in memory) where other data are stored. An address
is expected to be an integer, so a pointer object can usually be represented
internally as an (unsigned)int.1What makes a pointer object more than
just a plain integer is that we can access the datum being pointed at. Doing
so is known as dereferencing the pointer.
An aggregate is a An aggregate is a collection of objects stored in one unit. The array is the
collection of objects basic mechanism for storing a collection of identically-typed objects. A differ-
stored in one unit.
ent type of aggregate type is the structure, which stores a collection of objects
An array stores a that need not be of the same type. As a somewhat abstract example, consider
collection of the layout of an apartment building. Each floor might have a one-bedroom
identically-typed
objects.
unit, a two-bedroom unit, a three-bedroom unit, and a laundry room. Thus
each floor is stored as a structure, and the building is an array of floors.

1.2 Arrays and Strings


In C++ we can declare and use arrays in two basic ways. The primitive method
is to use the built-in array. The alternative is to use a vector.The syntax for
both methods is more or less the same; however, the vector is much easier
and slightly safer to use than the primitive array and is preferred for most appli-
cations. The major philosophical difference between the two is that the vector
behaves as a first-class type (even though it is implemented in a library),
whereas the primitive array is a second-class type. Similarly, C++ provides
primitive strings (which are simply primitive arrays of char) and the much-
preferred string.In this section we examine what is meant by first-class and
second-class types and show you how to use the vector and string.

1.2.1 First-Class Versus Second-Class Objects


First-class objects Computer Scientists who study programming languages often designate cer-
can be manipulated in tain language constructs as being $first-class objects or second-class objects.
all the "usual ways"
without special cases
The exact definition of these terms is somewhat imprecise, but the general
and exceptions. idea is that first-class objects can be manipulated in all the "usual ways"

1. This fact is of little use in normal programming practice and in languages besides C. C++, and
low-level assembly languages. It is used (often dangerously) by old-style C++ programmers.
without special cases and exceptions, whereas second-class objects can be
manipulated in only certain restricted ways.
What are the "usual ways?" In the specific case of C++, they might Primitive arrays and
include things like copying. Recall that an array stores a collection of strings are not first-
class objects.
objects. We would expect a copy of an array to copy the entire collection;
this is not the case for the primitive array. We might also expect an array to
know how many objects are in its collection. In other words, we would
expect that the size of the array is part of its being. Again, this is not true for
primitive arrays. (The reason for this is that arrays in C++ are little more
than pointer variables, rather than their own first-class type.) We might also
expect that when allocated arrays are no longer needed (for instance the
function in which they are declared returns), then the memory that these
arrays consumes is automatically reclaimed. This is true sometimes and
false at other times for arrays, making for tricky coding.
The primitive string may be considered even lower than a second-class
object because it suffers all the second-class behavior of arrays. In addition,
its comparison operators (for instance, == and <) do not do what we would
normally expect them to do and thus have to be handled as a special case.
Throughout the text, we use a vector and a string to provide first- Throughout the text,
class treatment for arrays and string^.^ The vector and string classes are we use a v e c t o r and
a string to provide
now part of the Standard Library and thus are part of C++. However, many first-class treatment
compilers do not yet support them. We provide our own versions of vector for arrays and strings.
i Section 3.4.2) and string (Section 2.6), and in the process, illustrate how
their second-class counterparts are manipulated. Our vector and string
are implemented by wrapping the second-class behavior of the built-in types
in a class.3 This implementation is an acceptable use of the second-class
type because the complicated second-class implementation details are hid-
den and never seen by the user of the first-class objects. As we demonstrate
in Chapter 2, the class allows us to define new types. Included in these types
are functions that can be applied to objects of the new type.
The vector and string classes in the Standard Library treat arrays
and strings as first-class objects. A vector knows how large it is. Two
string objects can be compared with ==, <, and so on. Both vector and

2 . The vector class contains the basic primitive array operations plus additional features.
Thus it behaves more like a data structure than a simple array. However, its use is much
safer than the primitive C++ array. The vector is part of the Standard Template Library
(STL).
3. Appendix D contains further discussion of primitive arrays and strings if you want to see
these details early. However, you must read Section 1.3 first. A less detailed discussion is
given in Sections 2.6 and 3.4.2, which contain descriptions that are sufficient to show how
the string and vector are implemented.
Arrays, Pointers, and Structures

string can be copied with =. Except in special cases, you should avoid
using the built-in C++ array and string.
The string is a class, or the library type used for first-class strings.
The vector is a class template, or the library type used for first-class
arrays. We discuss classes in Chapter 2 and class templates in Chapter 3. A
recurring theme in this text is that using a library routine does not require
knowing anything about its underlying implementation. However, you
may need to know how the second-class counterparts are manipulated
because occasionally you must resort to the primitive versions. It turns out
that both string and vector are implemented by providing an interface
that hides the second-class behavior of the built-in types.

1.2.2 Using the vector


To use the standard vector,your program must include a library header file
with

A using directive may be needed if one has not already been provided.
The array indexing Just as a variable must be declared before it is used in an expression and
operator 11 provGes initialized before its value is used. so must an array. A vecto; is declared
access to any object
in the array. by giving it a name, in accordance with the usual identifier rules, and by tell-
ing the compiler what type the elements are. A size can also be provided; if it
is not, the size is zero, but vector will need to be resized later.
Each object in the collection of objects that an array denotes can be
accessed by use of the array indexing operator [ I . We say that the [ 1
operator indexes the array, meaning that it specifies which of the objects is to
be accessed.
Arrays are indexed In C++, arrays are always indexed starting at zero. Thus the declaration
starting at zero.
vectorcintl a ( 3 ) ; / / 3 int objects: a [ O l , a [ l l , and a [ 2 1

sets aside space to store three integers-namely, a [ 0 1 , a [ 11,and a [ 2 1 ; no


index range checking is performed in the Standard Library's vector,so an
access out of the array index bounds is not caught by the compiler (in this
case, the legal array indices range from 0 to 2, inclusive). Although no
explicit run-time error may be generated, undefined and occasionally myste-
rious behavior would occur. The vector that we implement in Section 3.4.2
allows the programmer to turn on index range checking so that this error
causes the program to terminate immediately with a message. (Range check-
ing can be done by using a t ; a . a t ( i ) is the same as a [ i ] , except that an
error is signalled if i is out-of-bounds.)
Arrays and Strings

The size of the vector can always be obtained with the size function. The size of the
For the preceding code fragment example, a . size ( ) returns 3 . Note the vector can always
be obtained with the
syntax: The dot operator is used to call the vector's size function. size operator.
The size of a vector can always be changed by calling resize. Thus
an alternative declaration for the vector a could have been

vector<int> a; / / 0 int objects


a.resize( 3 ) ; / / 3 int objects: a[O], a[l], and a[2]

Figure 1.1 illustrates the use of the vector. The program in Figure 1.1
repeatedly chooses numbers between 1 and 100, inclusive. The output is the
number of times that each number has o ~ c u r r e d . ~
Line 17 declares an array of integers that count the occurrences of each You must always be
number. Because arrays are indexed starting at zero, the + 1 is crucial if we the
correct array size.
want to access the item in position DIFFERENT-NUMBERS. Without it we Off-by-one errors are
would have an array whose indexible range was 0 to 99, and thus any access common and very
to index 100 might~beto memory that was assigned to another object. Incor- difficult to spot.
rect results could occur, depending on the implementation details of
vector; we might find that the program would work perfectly on some plat-
forms but would give wrong answers on others.
The rest of the program is relatively straightforward.The routine rand,
declared in stdlib. h, gives a (somewhat) random number; the manipula-
tion at line 25 places it in the range 1 to 100, inclusive. The results are output
at lines 28 to 30.
The C++ standard specifies that the scope of i on line 20 ends with the
for loop. (In other words, i should not be visible at line 24). This is differ-
cnt from the original language specification, and some older compilers (and
even some newer compilers) see i as being in scope at line 24. Thus we use
different names for the loop counters.5

1.2.3 Resizing a vector


One limitation of primitive arrays is that, once they have been declared, their
iize can never change. Often this is a significant restriction. We know, how-
sver, that we can use resi ze to change the size of a vector. The technique
used illustrates some of the efficiency issues that we address in this text.

The using directive, shown at line 4, is a recent addition to C++ and is discussed in Appen-
dix A.5. Other significant additions are presented in Section A.6.
! Sote also that the STL vector has an initialization shorthand that we have not used. We
could have written
-'ector<int> numbers( DIFFERENT-NUMBERS + 1, 0 ) ;
ro initialize all entries to zero and thus avoided the first for loop.
Arrays, Pointers, and Structures

1 #include <stdlib.h>
2 #include <iostream>
3 #include <vector>
4 using namespace std;
5
6 / / Generate numbers (from 1-100).
7 / / Print number of occurrences of each number.
8 int main( )
9 {
10 const int DIFFERENT-NUMBERS = 100;
11
12 / / Prompt for and read number of games.
13 int totalNumbers;
14 cout << "How many numbers to generate?: " ;
15 cin >> totalNumbers;
16
17 vector<int> numbers( DIFFERENT-NUMBERS + 1 ) ;
18
19 / / Initialize the vector to zeros.
20 for( int i = 0; i < numbers.size( ) ; i++ )
21 numbers[ i ] = 0;
22
23 / / Generate the numbers.
24 for( int j = 0; j < totalNumbers; j++ )
25 numbers[ rand( ) % DIFFERENT-NUMBERS + 1 I + + ;
26
27 / / Output the summary.
28 for( int k = 1; k <= DIFFERENT-NUMBERS; k++ )
29 cout << k << " occurs " << numbers[ k I
30 << I' time(s)\ n " ;
31
32 return 0;
33 }

Figure 1.1 Simple demonstration of arrays.

What happens is that pointers (which we discuss later in this chapter) are
used to give the illusion of an array that can be resized. To understand the
algorithm does not require any knowledge of C++: all this detail is hidden
inside the implementation of vector.
The basic idea is shown in Figure 1.2. There, arr is representing a 10-
element vector.Somewhere, buried in the implementation then, memory is
allocated for 10 elements. Suppose that we would like to expand this mem-
ory to 12 elements. The problem is that array elements must be stored in
contiguous memory and that the memory immediately following arr might
already be taken. So we do the following:
Arrays and Strings

arr

arr

original
(b)

arr

original
(c)

arr

original W
Figure 1.2 Array expansion, internally: (a) At the starting point, arr represents
10 integers; (b) after step 1, original represents the same 10
integers; (c) after steps 2 and 3, arr represents 12 integers, the first
10 of which are copied from original;and (d) after step 4, the
10 integers are freed.

1 . We remember where the memory for the 10-element array is (the


purpose of original).
2. We create a new 12-element array and have arr use it.
3. We copy the 10 elements from original to arr; the two extra
elments in the new arr have some default value.
4. We inform the system that the 10-element array can be reused as it
sees fit.

.A moment's thought will convince you that this is an expensive operation Always expand the
because we copy all the elements from the originally allocated array to the array a size that is
some multiplicative
newly allocated array. If, for instance, this array expansion is in response to con,tant times as
reading input, expanding every time we read a few elements would be ineffi- large. Doubling is a
cient. ~ h u iwhen
, array expansion is implemented, we always make it some good choice. -
constant times as large. For instance, we might expand to
t?l~~lriplicative
m x G r s , and Structures

make it twice as large. In this way, when we expand the array from N items
to 2N items, the cost of the N copies can be apportioned over the next N
items that can be inserted into the array without an expansion. As a result,
this dynamic expansion is only negligibly more expensive than starting with
a fixed size, but it is much more flexible.
To make things more concrete, Figure 1.3 shows a program that reads an
unlimited number of integers from the standard input and stores the result in a
dynamically expanding array. The function declaration for getInts tells us
that the vector is the parameter. The & in the function declaration before
array specifies that it is a reference to the actual parameter, rather than a copy

1 #include <iostream>
2 #include <vector>
3 using namespace std;
4
5 / / Read an unlimited number of ints with no attempts at error
6 / / recovery; fill the vector parameter with the data; its size
7 / / after the return tells how many items were read.
8 void getInts( vector<int> & array )
9 {
10 int itemsRead = 0;
11 int inputVal;
12
13 cout << "Enter any number of integers: ";
14 while( cin >> inputVal )
15 {
16 if( itemsRead == array.size( ) )
17 array.resize( array.size( ) * 2 + 1 );
18 array[ itemsRead++ ] = inputVal;
19 }
20 array.resize( itemsRead ) ;
21 1
22
23 int main( )
24 {
25 vector<int> array;
26
27 getInts( array ) ;
28 for( int i = 0; i < array.size( ); i++ )
29 cout < < array[ i ] << endl;
30
31 return 0;
32 1
Figure 1.3 Code to read an unlimited number of ints and write them out,
using array-doubling.
Arrays and Strings

of it. Thus all changes in the formal parameter are reflected in the actual argu-
ment. We discuss reference parameters in more detail in Section 1.5.
At the start of getrnts, itemsRead is set to 0.We repeatedly read
new items at line 14. If the array is full, as indicated by a successful test at
line 16, then the array is expanded at line 17. We resize to roughly twice
the size of the old. We add 1 so that the initial doubling converts an array
of 0 size to an array of size 1 . At line 18 the actual input item is assigned to
the array, and the number of items read is incremented. At line 20 we
resize the array to match the number of items that were read. An alterna-
tive is to have itemsRead be an additional reference parameter that is even-
tually set to the new array size. When the input fails (for whatever reason),
we merely return. The main routine calls getInts,passing a vector.The
initial size of this vector happens to be 0.

1.2.4 push-back: size and capacity


The technique used in Figure 1.3 is so common that the vector has built-in
functionality to mimic it. The basic idea is that the vector maintains not
only a size, but also a capacity; the capacity is the amount of memory that it
has reserved. The capacity of the vector is really an internal detail, not
something that you need worry about.
The push-back function increases the size by one, and adds a new item The push-back
into the array at the appropriate position. This is a trivial operation if capacity increases
the size by 1, adds a
has not been reached. If it has, the capacity is automatically expanded, using new item to the array
the strategy described in Section 1.2.3.6Typically, we start the vector with a at the appropriate
size of 0. position, expanding
capacity if needed.
The code in Figure 1.4 shows how push-back is used in getInts;it is
clearly much simpler than the getInts function in Figure 1.3. Line 13
resizes the vector to no elements. This may or may not reduce its capacity,
depending on the internal implementation of vector.Note that if we do not
resize, then new items will be placed at the end of the vector;thus items
that were in the vector when getInts was called will still be there.

1.2.5 Parameter-Passing Mechanisms


Suppose that we want to pass a vector to a routine that finds the maximum
\ alue in the array. The natural declaration for the routine would be

6. Some compilers do not double the capacity. but instead expand by a small constant
amount, thereby causing poor performance.
--
m - ~ r r a p , Pointers, and Structures

1 #include <stdlib.h>
2 #include <iostream>
3 #include <vector>
4 using namespace std;
5
6 / / Read an unlimited number of ints with no attempts at error
7 / / recovery; fill the vector parameter with the data; its size
8 / / after the return tells how many items were read.
9 void getInts( vector<int> & array )
10 {
11 int inpu tVal ;
12
13 array.resize( 0 ) ;
14 cout << "Enter any number of integers: ";
15 while( cin >> inputVal )
16 array.push-back( inputVal ) ;
17 1

Figure 1.4 Code to read an unlimited number of i n t s and write them out using
push-back.

Call by value is the This function declaration has a fundamental problem: The default parameter-
default parameter- passing mechanism is call by value, whose semantics dictate that a copy be
passing mechanism.
The actual argument
made of the actual argument and used as the formal parameter for every call
is copied into the to f i n d M a x . Because a could be large,
- this operation is expensive, so call
formal parameter. by value is unsuitable. An alternative is to pass the parameter using call by
reference:

int findMax( vector<int> & a 1;

The call by reference Now we can avoid the overhead of a copy. This routine is still not perfect,
parameter-passing however, because the declaration tells the reader, and also the compiler, that
mechanism avoids a
copy. However, it the actual argument might be changed as result of the call to f i n d M a x .
allowschangestothe When the parameter was passed by value, we were guaranteed that the
parameters. actual parameter would not be altered. To obtain equivalent behavior, we use
a third form of parameter passing, call by constant reference:

int findMax( const vector<int> & a );

The call by constant The constant reference guarantees that


reference parameter-
passing mechanism
avoids a copy and
the overhead of a copy is avoided and that
guarantees that the the actual parameter is unchanged by the function call.
actual parameter will
not be changed.
Arrays and Strings

Choosing a parameter-passing mechanism is an easily overlooked chore


of the programmer. After all, the program is often correct no matter which
mechanism is used. Nevertheless, in C++ choosing a parameter-passing
mechanism carefully is important for efficiency, readability, and program
maintenance alike.

Call by reference is required for objects that may be altered by the


function.
Call by value is appropriate for small objects that should not be
altered by the function.
Call by constant reference is appropriate for large objects that should not
be altered by the function.

As we show later, in some more complex cases call by value must be


avoided. The program can fail to compile if a wrong decision is made.
Because s t r i n g and vector represent large objects, call by value is
generally inappropriate. Instead, when these objects are parameters to a
function, they are usually passed by reference or constant reference, depend-
ing on whether the function is expected to alter the value of the parameter.

1.2.6 Primitive Arrays of Constants


Occasionally, we revert to primitive arrays when we have global constants.
The reason is a convenient notational shorthand, illustrated by the following
declaration of DAYS-IN-MONTH:

zonst int DAYS-IN-MONTH[ ] = { 31, 28, 31, 30, 31, 30,


31, 31, 3 0 , 31, 30, 31 ) ;

Here, the size of the primitive array is automatically initialized, and its size
is deduced by the number of initializers that are present. If this array is glo-
bal, the number of items can be determined by dividing the amount of
memory used by the primitive array s i zeof ( DAYS-IN-MONTH) by the
amount of memory used by one item in the primitive array sizeof
i DAYS-IN-MONTH [ 0 ] ) , as in

const int NUM-MONTHS = sizeof(DAYS-IN-MONTH) /


sizeof(DAYS-IN-MONTH[O]);
Arrays, Pointers, and Structures

1.2.7 Multidimensional Arrays


A multidimensional Sometimes access to arrays needs to be based on more than one index. A
array is an array that multidimensional array is an array that is accessed by more than one
is accessed by more
than one index. A index, and its primitive version is second-class. There is no first-class ver-
matrix class can be sion in the STL. In Section 3.5, we implement a two-dimensional array with
used to implement first-class behavior, called a matrix.The sizes of its indices are specified,
two-dimensional
arrays.
and each element is accessed by placing each index in its own pair of brack-
ets. For example, the declaration

matrix<int> x( 2 , 3 ); / / x has two rows and three columns

defines the two-dimensional array x, with the first index ranging from 0 to 1
and the second index ranging from 0 to 2 (for a total of six objects). The
m a t r i x sets aside six memory locations for these objects: x [ 0 1 [ 0 I ,
x [ o l [ ~ I , X [ [O2 I1 , x [ 1 1[ O I , x [ 1 1 [ l l , a n d x [ l ] [21.

1.2.8 The Standard Library string Type


To use the Standard Library s t r i n g type, you must have the include
directive:

As the s t r i n g is a first-class object, input, output, copying, and com-


parisons work as you would expect. Thus s t r l = = s t r 2is t r u e if and only
if the values of the strings are the same.
Each character of the s t r i n g can be accessed by using the array index-
ing operator (as usual, indices start at zero). The s t r i n g provides many
useful functions.
.
s length ( ) returns If s is a s t r i n g , then s . l e n g t h ( ) returns its length (i.e., the number
the length of s; + of characters in its representation), and s . c-str ( ) returns a primitive
and += perform string
concatenation. string. A primitive string is occasionally needed to interact with other parts
of the libraries. For instance, to open a file, a primitive string must be passed.
Finally, the + and + = operators for s t r i n g s are defined to perform string
concatenation (one string is tacked onto the end of another). Figure 1.5 illus-
trates these operations.
Exploring the Variety of Random
Documents with Different Content
INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.

1.F.5. Some states do not allow disclaimers of certain implied


warranties or the exclusion or limitation of certain types of damages.
If any disclaimer or limitation set forth in this agreement violates the
law of the state applicable to this agreement, the agreement shall be
interpreted to make the maximum disclaimer or limitation permitted
by the applicable state law. The invalidity or unenforceability of any
provision of this agreement shall not void the remaining provisions.

1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation,


the trademark owner, any agent or employee of the Foundation,
anyone providing copies of Project Gutenberg™ electronic works in
accordance with this agreement, and any volunteers associated with
the production, promotion and distribution of Project Gutenberg™
electronic works, harmless from all liability, costs and expenses,
including legal fees, that arise directly or indirectly from any of the
following which you do or cause to occur: (a) distribution of this or
any Project Gutenberg™ work, (b) alteration, modification, or
additions or deletions to any Project Gutenberg™ work, and (c) any
Defect you cause.

Section 2. Information about the Mission


of Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new computers.
It exists because of the efforts of hundreds of volunteers and
donations from people in all walks of life.

Volunteers and financial support to provide volunteers with the


assistance they need are critical to reaching Project Gutenberg™’s
goals and ensuring that the Project Gutenberg™ collection will
remain freely available for generations to come. In 2001, the Project
Gutenberg Literary Archive Foundation was created to provide a
secure and permanent future for Project Gutenberg™ and future
generations. To learn more about the Project Gutenberg Literary
Archive Foundation and how your efforts and donations can help,
see Sections 3 and 4 and the Foundation information page at
www.gutenberg.org.

Section 3. Information about the Project


Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-profit
501(c)(3) educational corporation organized under the laws of the
state of Mississippi and granted tax exempt status by the Internal
Revenue Service. The Foundation’s EIN or federal tax identification
number is 64-6221541. Contributions to the Project Gutenberg
Literary Archive Foundation are tax deductible to the full extent
permitted by U.S. federal laws and your state’s laws.

The Foundation’s business office is located at 809 North 1500 West,


Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up
to date contact information can be found at the Foundation’s website
and official page at www.gutenberg.org/contact

Section 4. Information about Donations to


the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission of
increasing the number of public domain and licensed works that can
be freely distributed in machine-readable form accessible by the
widest array of equipment including outdated equipment. Many
small donations ($1 to $5,000) are particularly important to
maintaining tax exempt status with the IRS.

The Foundation is committed to complying with the laws regulating


charities and charitable donations in all 50 states of the United
States. Compliance requirements are not uniform and it takes a
considerable effort, much paperwork and many fees to meet and
keep up with these requirements. We do not solicit donations in
locations where we have not received written confirmation of
compliance. To SEND DONATIONS or determine the status of
compliance for any particular state visit www.gutenberg.org/donate.

While we cannot and do not solicit contributions from states where


we have not met the solicitation requirements, we know of no
prohibition against accepting unsolicited donations from donors in
such states who approach us with offers to donate.

International donations are gratefully accepted, but we cannot make


any statements concerning tax treatment of donations received from
outside the United States. U.S. laws alone swamp our small staff.

Please check the Project Gutenberg web pages for current donation
methods and addresses. Donations are accepted in a number of
other ways including checks, online payments and credit card
donations. To donate, please visit: www.gutenberg.org/donate.

Section 5. General Information About


Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could be
freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose network of
volunteer support.
Project Gutenberg™ eBooks are often created from several printed
editions, all of which are confirmed as not protected by copyright in
the U.S. unless a copyright notice is included. Thus, we do not
necessarily keep eBooks in compliance with any particular paper
edition.

Most people start at our website which has the main PG search
facility: www.gutenberg.org.

This website includes information about Project Gutenberg™,


including how to make donations to the Project Gutenberg Literary
Archive Foundation, how to help produce our new eBooks, and how
to subscribe to our email newsletter to hear about new eBooks.

You might also like