Document Sample

通訊軟體人才培訓班 C++ 程式設計與資料結構 顏嗣鈞 台大電機系 E-mail: yen@ee.ntu.edu.tw http://www.ee.ntu.edu.tw/~yen 顏嗣鈞 l 學歷 博士 Univ. of Texas at Austin (電腦) 1986 碩士 交大計算機工程研究所 1982 學士 台大電機系 1980 l 經歷 台大電機系 教授 1991 -- present 台大電機系 副教授 1990 -- 1991 美國Iowa State Univ.電腦系助理教授 1986-1990 l 專長 資料結構, 演算法, 計算理論, 通訊協定工程 2 Life Cycle of Software Development Probl em S pecifi cati on Form al Interpre tation Description appropri ate a ssu mpti ons Abstracti on Ideas, Data structures M odeli ng and desi gn Al gorithm Anal ysis o f the techni ques Desi gn Probl em Problem rep resent at ion, p rop ert ies of t he p roblem compl exi ty; Al gorithm Not satisfi ed correctness Anal ysi s S a ti sfied DONE O .K. Al gorithm Program Impl em entatio n Verifi ca ti on Not O .K. Fai thful codi ng 3 Parti al correctness, Te rmi nati on Goal l Learn to write efficient and elegant software n How to choose between two algorithms – Which to use? bubble-sort, insertion-sort, merge- sort n How to choose appropriate data structures – Which to use? array, vector, linked list, binary tree 4 Why should you care? l Complex data structures and algorithms are used in every real program n Data compression uses trees: MP3, Gif, etc… n Networking uses graphs: Routers and telephone networks n Security uses complex math algorithms: GCD and large decimals n Operating systems use queues and stacks: Scheduling and recursion l Many problems can only be solved using complex data structures and algorithms 5 The Big Idea l Definition of Abstract Data Type n A collection of data along with specific operations that manipulate that data n Has nothing to do with a programming language! l Two fundamental goals of algorithm analysis n Correctness: Prove that a program works as expected n Efficiency: Characterize the run-time of an algorithm 6 Machine Languages, Assembly Languages, and High-level Languages l Three types of programming languages n Machine languages – Strings of numbers giving machine specific instructions – Example: +1300042774 +1400593419 +1200274027 n Assembly languages – English-like abbreviations representing elementary computer operations (translated via assemblers) – Example: LOAD BASEPAY ADD OVERPAY STORE GROSSPAY 7 Machine Languages, Assembly Languages, and High-level Languages n High-level languages – Similar to everyday English, use mathematical notations (translated via compilers) – Example: grossPay = basePay + overTimePay 8 The History of C++ l Roots in Unix: n UNIX developed at AT&T Bell Labs in 1969 by Ken Thompson n Dennis Ritchie writes the first C compiler for UNIX n 1973: Thompson and Ritchie rewrite UNIX in C code n UNIX becomes popular because C makes it platform independent –C becomes the standard programming language of UNIX 9 The History of C++ (continued) l From C to C++ n In the Late 70’s a project began at Bell Labs: –Purpose was to add Object Technology to the C language –C++ made available to programmers in the early 80’s 10 Other High-level Languages l Other high-level languages n FORTRAN – Used in scientific and engineering applications n COBOL – Used to manipulate large amounts of data n Pascal – Used to teach structured programming 11 What is this Object ? l There is no real answer to the question, but we’ll call it a “thinking cap”. l The plan is to describe a thinking cap by telling you what actions can be done to it. 12 Using the Object’s Slots l You may put a piece of paper in each of the two slots (green and red), with a sentence written on each. l You may push the green button and the thinking cap will speak the sentence from the green slot’s paper. l And same for the red button. 13 Example 14 Example That test was a breeze ! 15 Example I should study harder ! 16 Thinking Cap Implementation l We can implement class ThinkingCap the thinking cap { using a data type called a class. ... }; 17 Thinking Cap Implementation l The class will have two class ThinkingCap components called { green_string and ... red_string. These char green_string[50]; compnents are strings char red_string[50]; which hold the information that is }; placed in the two slots. l Using a class permits two new features . . . 18 Thinking Cap Implementation Ê The two components class ThinkingCap will be private member { variables. This ... ensures that nobody private: can directly access this char green_string[50]; information. The only char red_string[50]; access is through }; functions that we provide for the class. 19 Thinking Cap Implementation Ë In a class, the class ThinkingCap functions which { manipulate the public: class are also listed. ... private: char green_string[50]; char red_string[50]; Prototypes for the }; thinking cap functions go here, after the word public: 20 Thinking Cap Implementation Ë In a class, the class ThinkingCap functions which { manipulate the public: class are also listed. ... private: char green_string[50]; char red_string[50]; Prototypes for the }; thinking cap member functions go here 21 Thinking Cap Implementation Our thinking cap has at least three member functions: class ThinkingCap { public: void slots(char new_green[ ], char new_red[ ]); void push_green( ) const; void push_red( ) const; private: char green_string[50]; char red_string[50]; }; 22 Thinking Cap Implementation The keyword const appears after two prototypes: class ThinkingCap { public: void slots(char new_green[ ], char new_red[ ]); void push_green( ) const; void push_red( ) const; private: char green_string[50]; char red_string[50]; }; 23 Files for the Thinking Cap l The ThinkingCap class definition, which we have just seen, is placed with Documentation documentation in a file called thinker.h, outlined here. l The implementations of the three member functions will be Class definition: • ThinkingCap class placed in a separate file called definition which we thinker.cxx, which we will have already seen examine in a few minutes. 24 Using the Thinking Cap l A program that #include <iostream.h> wants to use #include <stdlib.h> the thinking #include "thinker.h" cap must ... include the thinker header file (along with its other header inclusions). 25 Using the Thinking Cap l Just for fun, the #include <iostream.h> example program #include <stdlib.h> #include "thinker.h" will declare two ThinkingCap int main( ) variables named { ThinkingCap student: student and fan. ThinkingCap fan; 26 Using the Thinking Cap l Just for fun, the #include <iostream.h> example program #include <stdlib.h> #include "thinker.h" will declare two ThinkingCap int main( ) objects named { ThinkingCap student; student and fan. ThinkingCap fan; 27 Using the Thinking Cap l The program #include <iostream.h> starts by #include <stdlib.h> #include "thinker.h" calling the slots member int main( ) function for { ThinkingCap student; student. ThinkingCap fan; student.slots( "Hello", "Goodbye"); 28 Using the Thinking Cap l The program #include <iostream.h> starts by #include <stdlib.h> #include "thinker.h" activating the slots member int main( ) function for { ThinkingCap student: student. ThinkingCap fan; . student slots( "Hello", "Goodbye"); 29 Using the Thinking Cap Ê The member function int main( ) activation { consists of four ThinkingCap student; parts, starting ThinkingCap fan; with the object . student slots( "Hello", "Goodbye"); name. 30 Using the Thinking Cap Ë The instance name is int main( ) followed by a { period. ThinkingCap student; ThinkingCap fan; . student slots( "Hello", "Goodbye"); 31 Using the Thinking Cap Ì After the period is the name of int main( ) { the member ThinkingCap student; function that ThinkingCap fan; you are . student slots( "Hello", "Goodbye"); activating. 32 Using the Thinking Cap Í Finally, the #include "thinker.h" arguments for the member function. int main( ) { In this example ThinkingCap student; the first argument ThinkingCap fan; (new_green) is . student slots( "Hello", "Goodbye"); "Hello" and the second argument (new_red) is "Goodbye". 33 A Quiz How would you activate student's push_green int main( ) member function ? { ThinkingCap student; What would be the ThinkingCap fan; output of student's . student slots( "Hello", "Goodbye"); push_green member function at this point in the program ? 34 A Quiz Notice that the push_green member function int main( ) { has no arguments. ThinkingCap student; ThinkingCap fan; At this point, . student slots( "Hello", "Goodbye"); student.push_green( ); activating student.push_green will print the string Hello. 35 A Quiz Trace through this program, and tell int main( ) me the complete { ThinkingCap student; output. ThinkingCap fan; student.slots( "Hello", "Goodbye"); fan.slots( "Go Cougars!", "Boo!"); student.push_green( ); fan.push_green( ); student.push_red( ); ... 36 A Quiz Hello Go Cougars! int main( ) { Goodbye ThinkingCap student; ThinkingCap fan; student.slots( "Hello", "Goodbye"); fan.slots( "Go Cougars!", "Boo!"); student.push_green( ); fan.push_green( ); student.push_red( ); ... 37 The Key Software Trend: Object Technology l Objects n Reusable software components that model real world items n Meaningful software units – Date objects, time objects, paycheck objects, invoice objects, audio objects, video objects, file objects, record objects, etc. – Any noun can be represented as an object n More understandable, better organized and easier to maintain than procedural programming n Favor modularity 38 Information Hiding l Hiding the details of a function or data structure with the goal of controlling access to the details of a module or structure. PURPOSE: To prevent high-level designs from depending on low-level design details that may be changed. Two Approaches to Building Manageable Modules FUNCTIONAL OBJECT-ORIENTED DECOMPOSITION DESIGN Divides the problem Identifies various into more easily handled objects composed of subtasks, until the data and operations, functional modules that can be used (subproblems) can together to solve be coded. the problem. FOCUS ON: processes FOCUS ON: data objects Functional Design Modules Main Prepare Find Print File for Get Data Print Data Weighted Weighted Reading Average Average Print Heading Object-Oriented Design A technique for developing a program in which the solution is expressed in terms of objects -- self- contained entities composed of data and operations on that data. cin cout >> << get Private data setf Private data . . . . . . ignore OCD: Object-Centered Design l 1. Identify the objects in the problem's specification and their types. l 2. Identify the operations needed to solve the problem. l 3. Arrange the operations in a sequence of steps, called an algorithm, which, when applied to the objects, will solve the problem. 43 More about OOD l Languages supporting OOD include: C++, Java, Smalltalk, Eiffel, and Object-Pascal. l A class is a programmer-defined data type and objects are variables of that type. l In C++, cin is an object of a data type (class) named istream, and cout is an object of a class ostream. Header files iostream.h and fstream.h contain definitions of stream classes. Procedural vs. Object-Oriented Code “Read the specification of the software you want to build. Underline the verbs if you are after procedural code, the nouns if you aim for an object-oriented program.” Brady Gooch, “What is and Isn’t Object Oriented Design,” 1989. Objects l Objects are: n Building blocks and tools that interact to produce an outcome l Objects Have: n Attributes – These define the object n Actions – These are the tasks the object can perform 46 Objects (continued) Example: Oven Object Attributes: Size, temperature level. heat source (top=broil, bottom = bake) Actions: Turn the oven on or off Select the heat source (bake, broil) Set the temperature level 47 Algorithm (演算法) Algorithm: Sequence of instructions leading to a solution of a problem in a finite amount of time. Problem Algorithm Solution 48 Algorithm Efficiency What to measure? Space utilization: amount of memory required Time efficiency: amount of time required to process the data. Depends on many factors: • size of input • speed of machine • quality of source code • quality of compiler These factors vary from one machine/compiler (platform) to another Count the number of times instructions are executed So, measure computing time as T(n) = computing time of an algorithm for input of size n 49 Best, Worst, and Average-Case 50 表示演算法效率的用語 l 計算機科學界喜歡用「big-O notation」 來表示函數的成長速率。例如說 f O(g) 表示存在兩個定數 c > 0 和 n0 0，使得 對所有n n0 ，我們可以得到 f(n) c g(n) 51 Asymptotic Notation l A theoretical means of ordering functions l Goal: to simplify analysis by getting rid of unneeded information (like “rounding” 1,000,001≈1,000,000) l We want to say in a formal way 3n2 ≈ n2 l Compares relative growth rates of functions - not the functional values l “Big-Oh” notation expresses a less-than-or-equal-to relation between two functions n given functions f(n) and g(n), we say that f(n) is O(g(n) ) if and only if there are positive constants c and n0 such that f(n)≤ c g(n) for n ≥ n0 52 Other Common Asymptotic Notations l - “Big Omega” n If T(n) is (f(n)) then T(n) is greater-than-or-equal-to f(n) l - “Big Theta” n If T(n) is (f(n) )then T(n) is equal-to f(n) l o – “Little-Oh” n If T(n) is o(f(n)) then T(n) is strictly less-than f(n) 53 Big-O 54 Big-O Notation的例子 55 Common Growth Rates Name Big Oh Notation Constant O(1) Logarithmic O(log N) Log-squared O(log2 N) Linear O(N) O(N log N) Quadratic O(N2) Cubic O(N3) Exponential O(2N) 56 Table of Common Functions Growth Rates n log n n^.5 n n log n^2 n^3 2^n n 2 1 1.4 2 2 4 8 4 4 2 2 4 8 16 64 16 8 3 2.8 8 24 64 512 256 16 4 4 16 64 256 4096 65536 32 5 5.7 32 160 1024 32768 429496729 6 64 6 8 64 384 4096 262144 1.84E19 128 7 11 128 896 16384 2097152 3.4E38 256 8 16 256 2048 65536 16777216 1.15E77 512 9 23 512 4608 262144 13421772 1.34E154 57 8 Polynomial and Intractable Algorithms l Polynomial Time complexity n An algorithm is said to be polynomial if it is O( nd ) for some integer d n Polynomial algorithms are said to be efficient – They solve problems in reasonable times! l Intractable algorithms n Algorithms for which there is no known polynomial time algorithm 58 Analysing an Algorithm l Simple statement sequence s1; s2; …. ; sk n O(1) as long as k is constant l Simple loops for(i=0;i<n;i++) { s; } where s is O(1) n Time complexity is n O(1) or O(n) This part is l Nested loops O(n) for(i=0;i<n;i++) for(j=0;j<n;j++) { s; } n Complexity is n O(n) or O(n2) 59 Analysing an Algorithm l Loop index doesn’t vary linearly h = 1; while ( h <= n ) { s; h = 2 * h; } n h takes values 1, 2, 4, … until it exceeds n n There are 1 + log2n iterations n Complexity O(log n) 60 Analysing an Algorithm l Loop index depends on outer loop index for(j=0;j<n;j++) for(k=0;k<j;k++){ s; } n Inner loop executed Distinguish this case - – 1, 2, 3, …., n times where the iteration count n n(n+1) increases (decreases) by a S i = constant ç O(nk) i=1 2 from the previous one - where it changes by a factor Complexity O(n2) ç O(log n) 61 Program Verification l Program Verification is the process of determining the degree to which a software product fulfills its specifications. SPECIFICATIONS Inputs Outputs Processing Requirements PROGRAM Assumptions Testing, Execution, and Debugging n Validation: "Are we building the right product?" – check that documents, program modules, etc. match the customer's requirements. n Verification: : "Are we building the product right?" – check that products are correct, complete, consistent with each other and with those of the preceding phases. 63 Program Testing l Testing is the process of executing a program with various data sets designed to discover errors. DATA SET 1 DATA SET 2 DATA SET 3 DATA SET 4 ... Data Abstraction l Separation of a data type’s logical properties from its implementation. LOGICAL PROPERTIES IMPLEMENTATION What are the possible values? How can this be done in C++? What operations will be needed? How can data types be used? 65 Data Encapsulation l is the separation of the representation of data from the applications that use the data at a logical level; a programming language feature that enforces information hiding. APPLICATION REPRESENTATION int y; y = 25; 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 66 Encapsulated C++ Data Type int TYPE int Value range: Representation of INT_MIN . . INT_MAX int Operations: + prefix as 16 bits two’s - prefix (inside) complement + infix - infix + * infix / infix Implementation of % infix Operations Relational Operators infix 67 Abstract Data Type (ADT) l A data type whose properties (domain and operations) are specified independently of any particular implementation. 68 Data from 3 different levels l Application (or user) level: modeling real-life data in a specific context. l Logical (or ADT) level: abstract view of the domain and operations. WHAT l Implementation level: specific representation of the structure to hold the data items, and the coding for operations. HOW 69 Viewing a library from 3 different levels l Application (or user) level: Library of Congress, or Baltimore County Public Library. l Logical (or ADT) level: domain is a collection of books; operations include: check book out, check book in, pay fine, reserve a book. l Implementation level: representation of the structure to hold the “books”, and the coding for operations. 70 Composite Data Type A composite data type is a type which l stores a collection of individual data components under one variable name, l and allows the individual data components to be accessed. 71 Basic Kinds of ADT Operations l Constructor -- creates a new instance (object) of an ADT. l Transformer -- changes the state of one or more of the data values of an instance. l Observer -- allows us to observe the state of one or more of the data values without changing them. l Iterator -- allows us to process all the components in a data structure sequentially. 72 Two Forms of Composite Data Types UNSTRUCTURED STRUCTURED Components are not The organization organized with respect to determines method used one another. to access individual data components. EXAMPLES: EXAMPLES: arrays classes and structs 73 C++ Built-In Data Types Simple Composite Integral Floating array struct union class char short int long enum float double long double Address pointer reference 74 Records A record is a composite data type made up of a finite collection of not necessarily homogeneous elements called members or fields. For example . . . thisCar at Base Address 6000 .year 1999 .maker ‘h’ ‘o’ ‘n’ ‘d’ ‘a’ ‘\0’ ... .price 18678.92 75 struct CarType struct CarType { int year ; char maker[10]; float price ; } ; CarType thisCar; //CarType variables CarType myCar; 76 Accessing struct members The member selection operator (period . ) is used between the variable name and the member identifier to access individual members of a record (struct or class) type variable. EXAMPLES myCar.year thisCar.maker[4] 77 Valid struct operations l Operations valid on an entire struct type variable: assignment to another struct variable of same type, pass as a parameter to a function (either by value or by reference), return as the value of a function. 78 Pass-by-value sends a copy of the contents of the actual parameter CALLING FUNCTION BLOCK CALLED SO, the actual parameter cannot be changed by the function. 79 Pass-by-reference sends the location (memory address) of the actual parameter CALLING BLOCK FUNCTION CALLED can change value of actual parameter 80 Using struct type Reference Parameter to change a member void AdjustForInflation(CarType& car, float perCent) // Increases price by the amount specified in perCent { car.price = car.price * perCent + car.price; }; SAMPLE CALL AdjustForInflation(myCar, 0.03); 81 Using struct type Value Parameter to examine a member bool LateModel(CarType car, int date) // Returns true if the car’s model year is later than or // equal to date; returns false otherwise. { return ( car.year >= date ) ; }; SAMPLE CALL if ( LateModel(myCar, 1995) ) cout << myCar.price << endl ; 82 One-Dimensional Array at the Logical Level A one-dimensional array is a structured composite data type made up of a finite, fixed size (known at compile time) collection of homogeneous (all of the same data type) elements having relative positions and to which there is direct access (any element can be accessed immediately). Array operations (creation, storing a value, retrieving a value) are performed using a declaration and indexes. 83 Implementation Example This ACCESSING FUNCTION gives position of values[Index] Address(Index) = BaseAddress + Index * SizeOfElement float values[5]; // assume element size is 4 bytes Base Address 7000 7004 7008 7012 7016 values[0] values[1] values[2] values[3] values[4] Indexes 84 One-Dimensional Arrays in C++ l The index must be of an integral type (char, short, int, long, or enum). l The index range is always 0 through the array size minus 1. l Arrays cannot be assigned, and cannot be the return type of a function. 85 Another Example This ACCESSING FUNCTION gives position of name[Index] Address(Index) = BaseAddress + Index * SizeOfElement char name[10]; // assume element size is 1 byte Base Address 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 name[0] name[1] name[2] name[3] name[4] . . . . . name[9] 86 Passing Arrays as Parameters l In C++, arrays are always passed by reference, and & is not used with the formal parameter type. l Whenever an array is passed as a parameter, its base address is sent to the called function. 87 const array parameter Because arrays are always passed as reference parameters, you can protect the actual parameter from unintentional changes by using const in formal parameter list and function prototype. FOR EXAMPLE . . . // prototype float SumValues( const float values[ ], int numOfValues ); 88 float SumValues (const float values[ ], int numOfValues ) // Pre: values[ 0] through values[numOfValues-1] // have been assigned // Returns the sum of values[0] through // values[numOfValues-1] { float sum = 0; for ( int index = 0; index < numOfValues; index++ ) { sum += values [ index ] ; } return sum; 89 } Two-Dimensional Array at the Logical Level A two-dimensional array is a structured composite data type made up of a finite, fixed size collection of homogeneous elements having relative positions and to which there is direct access. Array operations (creation, storing a value, retrieving a value) are performed using a declaration and a pair of indexes (called row and column) representing the component’s position in each dimension. 90 EXAMPLE -- To keep monthly high temperatures for 50 states in a two-dimensional array. const int NUM_STATES = 50 ; const int NUM_MONTHS = 12 ; int stateHighs [ NUM_STATES ] [ NUM_MONTHS ] ; [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [0] [1] [ 2 ] 66 64 72 78 85 90 99 115 98 90 88 80 row 2, . col 7 might be . stateHighs [2] [7] Arizona’s . high for [ 48 ] August [ 49 ] 91 Finding the average high temperature for Arizona int total = 0 ; int month ; int average ; for ( month = 0 ; month < NUM_MONTHS ; month ++ ) total = total + stateHighs [ 2 ] [ month ] ; average = int ( total / 12.0 + 0.5 ) ; 92 const int NUM_STATES = 50 ; const int NUM_MONTHS = 12 ; int stateHighs [ NUM_STATES ] [ NUM_MONTHS ] ; rows columns STORAGE l In memory, C++ stores arrays in row order. The first row is followed by the second row, etc. Base Address 8000 8024 8048 ... 12 highs for state 0 12 highs for state 1 etc. Alabama Alaska first row second row 93 Implementation Level View stateHighs[ 0 ] [ 0 ] Base Address 8000 stateHighs[ 0 ] [ 1 ] stateHighs[ 0 ] [ 2 ] stateHighs[ 0 ] [ 3 ] To locate an element such as stateHighs[ 0 ] [ 4 ] stateHighs [ 2 ] [ 7] stateHighs[ 0 ] [ 5 ] stateHighs[ 0 ] [ 6 ] the compiler needs to know stateHighs[ 0 ] [ 7 ] that there are 12 columns stateHighs[ 0 ] [ 8 ] in this two-dimensional array. stateHighs[ 0 ] [ 9 ] stateHighs[ 0 ] [10 ] stateHighs[ 0 ] [11 ] stateHighs[ 1 ] [ 0 ] At what address will stateHighs[ 1 ] [ 1 ] stateHighs[ 1 ] [ 2 ] stateHighs [ 2 ] [ 7 ] be found? stateHighs[ 1 ] [ 3 ] . Assume 2 bytes for type int. . 94 Two-Dimensional Array Parameters l Just as with a one-dimensional array, when a two- (or higher) dimensional array is passed as a parameter, the base address of the actual array is sent to the function. l The size of all dimensions except the first must be included in the function heading and prototype. l The sizes of those dimensions for the formal parameter must be exactly the same as in the actual array. 95 Use the two-dimensional stateHighs array to fill a one-dimensional stateAverages array const int NUM_STATES = 50 ; const int NUM_MONTHS = 12 ; int stateHighs [ NUM_STATES ] [ NUM_MONTHS ] ; int stateAverages [ NUM_STATES ] ; [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [0] Alaska ? [1] 43 42 50 55 60 78 79 80 77 72 63 40 Arizona ? [2] 66 64 72 78 85 90 99 115 98 90 88 80 . . . [ 48 ] [ 49 ] 96 void findAverages ( const int stateHighs [ ] [ NUM_MONTHS] , int stateAverages [ ] ) // Pre: stateHighs[ 0..NUM_STATES-1] [ 0..NUM_MONTHS-1] assigned // Post: stateAverages[ 0..NUM_STATES-1 ] contains rounded average // high temperature for each state { int state; int month; int total; for ( state = 0 ; state < NUM_STATES; state++ ) { total = 0 ; for ( month = 0 ; month < NUM_MONTHS ; month++ ) total += stateHighs [ state ] [ month ] ; stateAverages [ state ] = int ( total / 12.0 + 0.5 ) ; } } 97 Using typedef with arrays helps eliminate the chances of size mismatches between formal and actual parameters. FOR EXAMPLE, typedef int StateHighsType [ NUM_STATES ] [ NUM_MONTHS ] ; typedef int StateAveragesType [ NUM_STATES ] ; void findAverages( const StateHighsType stateHighs , StateAveragesType stateAverages ) { . . . } 98 Declaring Multidimensional Arrays EXAMPLE USING TYPEDEF const int NUM_DEPTS = 5 ; // mens, womens, childrens, electronics, linens const int NUM_MONTHS = 12 ; const int NUM_STORES = 3 ; // White Marsh, Owings Mills, Towson typedef long MonthlySalesType [NUM_DEPTS] [NUM_MONTHS] [NUM_STORES]; MonthlySalesType monthlySales; 99 const int NUM_DEPTS = 5 ; // mens, womens, childrens, electronics, linens const int NUM_MONTHS = 12 ; const int NUM_STORES = 3 ; // White Marsh, Owings Mills, Towson typedef long MonthlySalesType [NUM_DEPTS] [NUM_MONTHS] [NUM_STORES] ; MonthlySalesType monthlySales; monthlySales[3][7][0] sales for electronics in August at White Marsh 5 DEPTS rows 100 12 MONTHS columns Structs vs. Classes Similarities 1. Essentially the same syntax 2. Both are used to model objects with different attributes (characteristics) represented as data members (also called fields or instance or attribute variables). Thus, both are used to process non-homogeneous data sets. 101 Structs vs. Classes Differences 1. C does not provide classes; C++ provides both structs and classes. 2. Members of a struct by default are public (can be accessed outside the struct by using the dot operator. In C++ they can be declared to be private (cannot be accessed outside the struct. 3. Members of a class by default are private (cannot be accessed outside the class) but can be explicitly declared to be public. 102 C Structs vs. C++ Classes (& Structs) ("traditional" vs "OOP") Structs have: Attributes (characteristics) represented as data members and, C++ structs and classes can also have: Operations (behaviors) represented as function members (also called methods). Operations This leads to a whole new style of programming: Function object-oriented. Objects are self-contained, Members possessing their own operations — commonly Data called the I can do it myself principle — Members rather than being passed as a parameter to an external function that operates on them and sends Attributes them back. 103 C++ class data type l A class is an unstructured type that encapsulates a fixed number of data components (data members) with the functions (called member functions) that manipulate them. l The predefined operations on an instance of a class are whole assignment and component access. 104 class DateType Specification // SPECIFICATION FILE ( datetype.h ) class DateType // declares a class data type { public : // 4 public member functions void Initialize ( int newMonth , int newDay , int newYear ) ; int YearIs( ) const ; // returns year int MonthIs( ) const ; // returns month int DayIs( ) const ; // returns day private : // 3 private data members int year ; int month ; int day ; }; 105 Use of C++ data type class l Variables of a class type are called objects (or instances) of that particular class. l Software that declares and uses objects of the class is called a client. l Client code uses public member functions (called methods in OOP) to handle its class objects. l Sending a message means calling a public member function. 106 Client Code Using DateType #include “datetype.h” // includes specification of the class #include “bool.h” int main ( void ) { DateType startDate ; // declares 2 objects of DateType DateType endDate ; bool retired = false ; startDate.Initialize ( 6, 30, 1998 ) ; endDate.Initialize ( 10, 31, 2002 ) ; cout << startDate.MonthIs( ) << “/” << startDate.DayIs( ) << “/” << startDate.YearIs( ) << endl; while ( ! retired ) { finishSomeTask( ) ; . . . } 107 } Separate files generally used for class type // SPECIFICATION FILE ( datetype .h ) // Specifies the data and function members. class DateType { public: . . . private: . . . }; // IMPLEMENTATION FILE ( datetype.cpp ) // Implements the DateType member functions. . . . 108 DateType Class Instance Diagrams startDate endDate Private data: Private data: Initialize Initialize year 1998 year 2002 YearIs YearIs month 6 month 10 MonthIs MonthIs day 30 day 31 DayIs DayIs 109 Implementation of DateType member functions // IMPLEMENTATION FILE (datetype.cpp) #include “datetype.h” // also must appear in client code void DateType :: Initialize ( int newMonth, int newDay, int newYear ) // Post: year is set to newYear. // month is set to newMonth. // day is set to newDay. { year = newYear ; month = newMonth ; day = newDay ; } 110 int DateType :: MonthIs ( ) const // Accessor function for data member month { return month ; } int DateType :: YearIs ( ) const // Accessor function for data member year { return year ; } int DateType :: DayIs ( ) const // Accessor function for data member day { return day ; } 111 Familiar Class Instances and Member Functions l The member selection operator ( . ) selects either data members or member functions. l Header files iostream.h and fstream.h declare the istream, ostream,and ifstream, ofstream I/O classes. l Both cin and cout are class objects and get and ignore are member functions. cin.get (someChar) ; cin.ignore (100, ‘\n’) ; l These statements declare myInfile as an instance of class ifstream and invoke member function open. ifstream myInfile ; myInfile.open ( “A:\\mydata.dat” ) ; 112 Scope Resolution Operator ( :: ) l C++ programs typically use several class types. l Different classes can have member functions with the same identifer, like Write( ). l Member selection operator is used to determine the class whose member function Write( ) is invoked. currentDate .Write( ) ; // class DateType numberZ .Write( ) ; // class ComplexNumberType l In the implementation file, the scope resolution operator is used in the heading before the member function’s name to specify its class. void DateType :: Write ( ) const { . . . } 113 Information Hiding Class implementation details are hidden from the client’s view. This is called information hiding. Public functions of a class provide the interface between the client code and the class objects. client specification implementation code 114 // SPECIFICATION FILE ( strtype.h ) #include <fstream.h> #include <iostream.h> const int MAX_CHARS = 200 ; enum RelationType { LESS, EQUAL, GREATER } ; enum InType { ALPHA_NUM, ALPHA, NON_WHITE, NOT_NEW } ; class StrType // declares class data type { public : // 7 public member functions void MakeEmpty ( ) ; void GetString ( bool skip, InType charsAllowed ) ; void GetStringFile ( bool skip, InType charsAllowed, ifstream& inFile ) ; void PrintToScreen ( bool newLine ) const ; void PrintToFile ( bool newLine, ofstream& outFile) const ; int LengthIs( ) const ; void CopyString( StrType& newString ) const ; private : // 1 private data member char letters [MAX_CHARS + 1 ] ; 115 }; StrType Class Interface Diagram StrType class MakeEmpty GetString Private data: GetStringFile letters ‘c’ ’a’ ’t’ ’\0’ ... PrintToScreen PrintToFile LengthIs CopyString 116 // IMPLEMENTATION FILE (strtype.cpp) #include “strtype.h” // also appears in client code #include “string.h” void StrType :: MakeEmpty ( ) // Post: letters is empty string. { letters[0] = ‘\0’ ; } ... int StrType :: LengthIs ( ) const // Returns length of letters string. { return strlen ( letters ) ; } 117 ADTs Unsorted List and Sorted List 118 Abstract Data Type (ADT) l A data type whose properties (domain and operations) are specified independently of any particular implementation. 119 Data from 3 different levels l Application (or user) level: modeling real-life data in a specific context. l Logical (or ADT) level: abstract view of the domain and operations. WHAT l Implementation level: specific representation of the structure to hold the data items, and the coding for operations. HOW 120 Basic Kinds of ADT Operations l Constructor -- creates a new instance (object) of an ADT. l Transformer -- changes the state of one or more of the data values of an instance. l Observer -- allows us to observe the state of one or more of the data values of an instance without changing them. l Iterator -- allows us to process all the components in a data structure sequentially. 121 What is a List? l A list is a homogeneous collection of elements, with a linear relationship between elements. l That is, each list element (except the first) has a unique predecessor, and each element (except the last) has a unique successor. 122 Sorted and Unsorted Lists UNSORTED LIST SORTED LIST Elements are placed List elements are in an into the list in order that is sorted in no particular order. some way -- either numerically or alphabetically by the elements themselves, or by a component of the element (called a KEY member) . 123 ADT Unsorted List Operations Transformers n MakeEmpty change state n InsertItem n DeleteItem Observers n IsFull n LengthIs observe state n RetrieveItem Iterators n ResetList process all n GetNextItem 124 What is a Generic Data Type? A generic data type is a type for which the operations are defined but the types of the items being manipulated are not defined. One way to simulate such a type for our UnsortedList ADT is via a user-defined class ItemType with member function ComparedTo having enumerated type value LESS, GREATER, or EQUAL. 125 // SPECIFICATION FILE ( unsorted.h ) #include “ItemType.h” class UnsortedType // declares a class data type { public : // 8 public member functions void MakeEmpty ( ) ; bool IsFull ( ) const ; int LengthIs ( ) const ; // returns length of list void RetrieveItem ( ItemType& item, bool& found ) ; void InsertItem ( ItemType item ) ; void DeleteItem ( ItemType item ) ; void ResetList ( ); void GetNextItem ( ItemType& item ) ; private : // 3 private data members int length ; ItemType info[MAX_ITEMS] ; int currentPos ; }; 126 Class Interface Diagram UnsortedType class MakeEmpty IsFull Private data: length LengthIs info [0] RetrieveItem [1] [2] InsertItem DeleteItem [MAX_ITEMS-1] ResetList currentPos GetNextItem 127 // IMPLEMENTATION FILE ARRAY-BASED LIST ( unsorted.cpp ) #include “itemtype.h” void UnsortedType::MakeEmpty ( ) // Pre: None. // Post: List is empty. { length = 0 ; } void UnsortedType::InsertItem ( ItemType item ) // Pre: List has been initialized. List is not full. item is not in list. // Post: item is in the list. { info[length] = item ; length++ ; } 128 Before Inserting Hsing into an Unsorted List length 3 The item will be placed into the length location, info [0] Maxwell and length will be incremented. [1] Bradley [2] Asad [3] . . . [MAX_ITEMS-1] 129 After Inserting Hsing into an Unsorted List length 4 info [0] Maxwell [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 130 void UnsortedType::LengthIs ( ) const // Pre: List has been inititalized. // Post: Function value == ( number of elements in list ). { return length ; } bool UnsortedType::IsFull ( ) const // Pre: List has been initialized. // Post: Function value == ( list is full ). { return ( length == MAX_ITEMS ) ; } 131 void UnsortedType::RetrieveItem ( ItemType& item, bool& found ) // Pre: Key member of item is initialized. // Post: If found, item’s key matches an element’s key in the list and a copy // of that element has been stored in item; otherwise, item is unchanged. { bool moreToSearch ; int location = 0 ; found = false ; moreToSearch = ( location < length ) ; while ( moreToSearch && !found ) { switch ( item.ComparedTo( info[location] ) ) { case LESS : case GREATER : location++ ; moreToSearch = ( location < length ) ; case EQUAL : found = true ; item = info[ location ] ; break ; } } } 132 Retrieving Ivan from an Unsorted List length 4 moreToSearch: true found: false info [0] Maxwell location: 0 [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 133 Retrieving Ivan from an Unsorted List length 4 moreToSearch: true found: false info [0] Maxwell location: 1 [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 134 Retrieving Ivan from an Unsorted List length 4 moreToSearch: true found: false info [0] Maxwell location: 2 [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 135 Retrieving Ivan from an Unsorted List length 4 moreToSearch: true found: false info [0] Maxwell location: 3 [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 136 Retrieving Ivan from an Unsorted List length 4 moreToSearch: false found: false info [0] Maxwell location: 4 [1] Bradley [2] Asad [3] Hsing . . . [MAX_ITEMS-1] 137 void UnsortedType::DeleteItem ( ItemType item ) // Pre: item’s key has been inititalized. // An element in the list has a key that matches item’s. // Post: No element in the list has a key that matches item’s. { int location = 0 ; while (item.ComparedTo (info [location] ) != EQUAL ) location++; // move last element into position where item was located info [location] = info [length - 1 ] ; length-- ; } 138 Deleting Bradley from an Unsorted List length 4 location: 0 info [0] Maxwell [1] Bradley [2] Asad Key Bradley has not been matched. [3] Hsing . . . [MAX_ITEMS-1] 139 Deleting Bradley from an Unsorted List length 4 location: 1 info [0] Maxwell [1] Bradley [2] Asad Key Bradley has been matched. [3] Hsing . . . [MAX_ITEMS-1] 140 Deleting Bradley from an Unsorted List length 4 location: 1 info [0] Maxwell [1] Hsing [2] Asad Placed copy of last list element [3] Hsing into the position . where the key Bradley . was before. . [MAX_ITEMS-1] 141 Deleting Bradley from an Unsorted List length 3 location: 1 info [0] Maxwell [1] Hsing [2] Asad Decremented length. [3] Hsing . . . [MAX_ITEMS-1] 142 void UnsortedType::ResetList ( ) // Pre: List has been inititalized. // Post: Current position is prior to first element in list. { currentPos = -1 ; } void UnsortedType::GetNextItem ( ItemType& item ) // Pre: List has been initialized. Current position is defined. // Element at current position is not last in list. // Post: Current position is updated to next position. // item is a copy of element at current position. { currentPos++ ; item = info [currentPos] ; } 143 Specifying class ItemType // SPECIFICATION FILE ( itemtype.h ) const int MAX_ITEM = 5 ; enum RelationType { LESS, EQUAL, GREATER } ; class ItemType // declares class data type { public : // 3 public member functions RelationType ComparedTo ( ItemType ) const ; void Print ( ) const ; void Initialize ( int number ) ; private : // 1 private data member int value ; // could be any different type }; 144 // IMPLEMENTATION FILE ( itemtype.cpp ) // Implementation depends on the data type of value. #include “itemtype.h” #include <iostream.h> RelationType ComparedTo ( ItemType otherItem ) const { if ( value < otherItem.value ) return LESS ; else if ( value > otherItem.value ) return GREATER ; else return EQUAL ; } void Print ( ) const { cout << value << endl ; } void Initialize ( int number ) { value = number ; } ItemType Class Interface Diagram class ItemType ComparedTo Private data Print value Initialize 146 SortedType Class Interface Diagram SortedType class MakeEmpty IsFull Private data: length LengthIs info [0] RetrieveItem [1] [2] InsertItem DeleteItem [MAX_ITEMS-1] ResetList currentPos GetNextItem 147 Member functions Which member function specifications and implementations must change to ensure that any instance of the Sorted List ADT remains sorted at all times? n InsertItem n DeleteItem 148 InsertItem algorithm for SortedList ADT l Find proper location for the new element in the sorted list. l Create space for the new element by moving down all the list elements that will follow it. l Put the new element in the list. l Increment length. 149 Implementing SortedType member function InsertItem // IMPLEMENTATION FILE (sorted.cpp) #include “itemtype.h” // also must appear in client code void SortedType :: InsertItem ( ItemType item ) // Pre: List has been initialized. List is not full. item is not in list. // List is sorted by key member using function ComparedTo. // Post: item is in the list. List is still sorted. { . . . } 150 void SortedType :: InsertItem ( ItemType item ) { bool moreToSearch ; int location = 0 ; // find proper location for new element moreToSearch = ( location < length ) ; while ( moreToSearch ) { switch ( item.ComparedTo( info[location] ) ) { case LESS : moreToSearch = false ; break ; case GREATER : location++ ; moreToSearch = ( location < length ) ; break ; } } // make room for new element in sorted list for ( int index = length ; index > location ; index-- ) info [ index ] = info [ index - 1 ] ; info [ location ] = item ; length++ ; } DeleteItem algorithm for SortedList ADT l Find the location of the element to be deleted from the sorted list. l Eliminate space occupied by the item being deleted by moving up all the list elements that follow it. l Decrement length. 152 Implementing SortedType member function DeleteItem // IMPLEMENTATION FILE continued (sorted.cpp) void SortedType :: DeleteItem ( ItemType item ) // Pre: List has been initialized. Key member of item is initialized. // Exactly one element in list has a key matching item’s key. // List is sorted by key member using function ComparedTo. // Post: No item in list has key matching item’s key. // List is still sorted. { . . . } 153 void SortedType :: DeleteItem ( ItemType item ) { int location = 0 ; // find location of element to be deleted while ( item.ComparedTo ( info[location] ) != EQUAL ) location++ ; // move up elements that follow deleted item in sorted list for ( int index = location + 1 ; index < location ; index++ ) info [ index - 1 ] = info [ index ] ; length-- ; } 154 Improving member function RetrieveItem Recall that with the Unsorted List ADT we examined each list element beginning with info[ 0 ], until we either found a matching key, or we had examined all the elements in the Unsorted List. How can the searching algorithm be improved for Sorted List ADT? 155 Retrieving Eliot from a Sorted List length 4 The sequential search for Eliot can stop when Hsing has been info [0] Asad examined. [1] Bradley [2] Hsing [3] Maxwell . . . [MAX_ITEMS-1] 156 Binary Seach in a Sorted List l Examines the element in the middle of the array. Is it the sought item? If so, stop searching. Is the middle element too small? Then start looking in second half of array. Is the middle element too large? Then begin looking in first half of the array. l Repeat the process in the half of the list that should be examined next. l Stop when item is found, or when there is nowhere else to look and item has not been found. 157 void SortedType::RetrieveItem ( ItemType& item, bool& found ) // Pre: Key member of item is initialized. // Post: If found, item’s key matches an element’s key in the list and a copy // of that element has been stored in item; otherwise, item is unchanged. { int midPoint ; int first = 0; int last = length - 1 ; bool moreToSearch = ( first <= last ) ; found = false ; while ( moreToSearch && !found ) { midPoint = ( first + last ) / 2 ; // INDEX OF MIDDLE ELEMENT switch ( item.ComparedTo( info [ midPoint ] ) ) { case LESS : . . . // LOOK IN FIRST HALF NEXT case GREATER : . . . // LOOK IN SECOND HALF NEXT case EQUAL : . . . // ITEM HAS BEEN FOUND } } } Trace of Binary Search item = 45 15 26 38 57 62 78 84 91 108 119 info[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] first midPoint last LESS last = midPoint - 1 15 26 38 57 62 78 84 91 108 119 info[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] first midPoint last GREATER first = midPoint + 1 159 Trace continued item = 45 15 26 38 57 62 78 84 91 108 119 info[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] first, last midPoint GREATER first = midPoint + 1 15 26 38 57 62 78 84 91 108 119 info[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] first, midPoint, last LESS last = midPoint - 1 160 Trace concludes item = 45 15 26 38 57 62 78 84 91 108 119 info[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] last first first > last found = false 161 void SortedType::RetrieveItem ( ItemType& item, bool& found ) // ASSUMES info ARRAY SORTED IN ASCENDING ORDER { int midPoint ; int first = 0; int last = length - 1 ; bool moreToSearch = ( first <= last ) ; found = false ; while ( moreToSearch && !found ) { midPoint = ( first + last ) / 2 ; switch ( item.ComparedTo( info [ midPoint ] ) ) { case LESS : last = midPoint - 1 ; moreToSearch = ( first <= last ) ; break ; case GREATER : first = midPoint + 1 ; moreToSearch = ( first <= last ) ; break ; case EQUAL : found = true ; item = info[ midPoint ] ; break ; } } } Order of Magnitude of a Function The order of magnitude, or Big-O notation, of a function expresses the computing time of a problem as the term in a function that increases most rapidly relative to the size of a problem. 163 Names of Orders of Magnitude O(1) bounded (by a constant) time O(log2N) logarithmic time O(N) linear time O(N*log2N) N*log2N time O(N2) quadratic time O( 2N ) exponential time 164 N log2N N*log2N N2 2N 1 0 0 1 2 2 1 2 4 4 4 2 8 16 16 8 3 24 64 256 16 4 64 256 65,536 32 5 160 1024 4,294,967,296 64 6 384 4096 128 7 896 16,384 Big-O Comparison of List Operations OPERATION UnsortedList SortedList RetrieveItem O(N) O(N) linear search O(log2N) binary search InsertItem Find O(1) O(N) search Put O(1) O(N) moving down Combined O(1) O(N) DeleteItem Find O(N) O(N) search Put O(1) swap O(N) moving up Combined O(N) O(N) Two Forms of Composite Data Types UNSTRUCTURED STRUCTURED Components are not The organization organized with respect to determines method used one another. to access individual data components. EXAMPLES: EXAMPLES: arrays classes and structs 167 // SPECIFICATION FILE ( sorted.h ) #include “ItemType.h” class SortedType { public : SortedType ( ) ; // Default constructor SortedType ( ItemType initialValue ) ; // Parameterized constr. void MakeEmpty ( ) ; // OTHER MEMBER FUNCTIONS HERE . . . private : // private data members int length ; ItemType info[MAX_ITEMS] ; int currentPos ; }; SortedType with 2 constructors SortedType class SortedType SortedType Private data: length MakeEmpty info [0] IsFull [1] [2] LengthIs RetrieveItem [MAX_ITEMS-1] . . currentPos . GetNextItem 169 Class Constructor A special member function of a class that is implicitly invoked when a class object is defined. 170 Class Constructor Rules 1 A constructor cannot return a function value, and has no return value type. 2 A class may have several constructors. The compiler chooses the appropriate constructor by the number and types of parameters used. 3 Constructor parameters are placed in a parameter list in the declaration of the class object. 4 The parameterless constructor is the default constructor. 5 If a class has at least one constructor, and an array of class objects is declared, then one of the constructors must be the default constructor, which is invoked for each element in the array. 171 Default Constructor // IMPLEMENTATION FILE (sorted.cpp) SortedType :: SortedType ( ) // Pre: None // Post: length is initialized to 0. { length = 0 ; } 172 Parameterized Constructor // IMPLEMENTATION FILE (sorted.cpp) SortedType :: SortedType ( ItemType initialValue ) // Pre: initialValue has been assigned a value. // Post: length is initialized to 0. Each element of list is initialized // to initialValue. { length = 0 ; for ( int counter = 0 ; counter < MAX_ITEMS ; counter++ ) info [ counter ] = initialValue ; } 173 // SPECIFICATION FILE ( strtype.h ) const int MAX_CHARS = 200 ; enum InType { ALPHA_NUM, ALPHA, NON_WHITE, NOT_NEW } ; class StrType { public : StrType ( ) ; // DEFAULT CONSTRUCTOR void MakeEmpty ( ) ; void GetString ( bool skip, InType charsAllowed ) ; void PrintToScreen ( bool newLine ) const ; . . . // OVERLOADED OPERATORS bool operator< (StrType otherString ) const ; bool operator== (StrType otherString ) const ; private : char letters [MAX_CHARS + 1 ] ; }; StrType Class Interface Diagram StrType class StrType MakeEmpty Private data: GetString letters ‘c’ ’a’ ’t’ ’\0’ ... PrintToScreen . . . operator< operator== 175 class StrType Default Constructor // IMPLEMENTATION FILE (strtype.cpp) #include “strtype.h” // also appears in client code StrType :: StrType( ) // DEFAULT CONSTRUCTOR // Pre: None. // Post: letters is empty string. { letters[0] = ‘\0’ ; } 176 // IMPLEMENTATION FILE continued (strtype.cpp) // operator< OVERLOADED bool StrType :: operator< ( StrType otherString ) const // Pre: self is initialized. otherString is initialized. // Post: Returns true if self precedes otherString // lexicographically. Otherwise, returns false. { int result ; result = strcmp ( letters, otherString.letters ) ; if ( result < 0 ) return true; else return false ; } // IMPLEMENTATION FILE continued (strtype.cpp) // operator== OVERLOADED bool StrType :: operator==( StrType otherString ) const // Pre: self is initialized. otherString is initialized. // Post: Returns true if self is identical to otherString // lexicographically. Otherwise, returns false. { int result ; result = strcmp ( letters, otherString.letters ) ; if ( result == 0 ) return true; else return false ; } ADTs Stack and Queue 179 Stacks of Coins and Bills 180 What is a Stack? l Logical (or ADT) level: A stack is an ordered group of homogeneous items (elements), in which the removal and addition of stack items can take place only at the top of the stack. l A stack is a LIFO “last in, first out” structure. 181 Stacks of Boxes and Books TOP OF THE STACK TOP OF THE STACK 182 Stack ADT Operations l MakeEmpty -- Sets stack to an empty state. l IsEmpty -- Determines whether the stack is currently empty. l IsFull -- Determines whether the stack is currently full. l Push (ItemType newItem) -- Adds newItem to the top of the stack. l Pop (ItemType& item) -- Removes the item at the top of the stack and returns it in item. 183 ADT Stack Operations Transformers n MakeEmpty change state n Push n Pop Observers n IsEmpty observe state n IsFull 184 //---------------------------------------------------------- // SPECIFICATION FILE (stack.h) //---------------------------------------------------------- #include "bool.h" #include "ItemType.h" // for MAX_ITEMS and // class ItemType definition class StackType { public: StackType( ); // Default constructor. // POST: Stack is created and empty. void MakeEmpty( ); // PRE: None. // POST: Stack is empty. bool IsEmpty( ) const; // PRE: Stack has been initialized. // POST: Function value = (stack is empty) 185 // SPECIFICATION FILE continued (Stack.h) bool IsFull( ) const; // PRE: Stack has been initialized. // POST: Function value = (stack is full) void Push( ItemType newItem ); // PRE: Stack has been initialized and is not full. // POST: newItem is at the top of the stack. void Pop( ItemType& item ); // PRE: Stack has been initialized and is not empty. // POST: Top element has been removed from stack. // item is a copy of removed element. private: int top; ItemType items[MAX_ITEMS]; // array of ItemType }; 186 ItemType Class Interface Diagram class ItemType ComparedTo Private data Print value Initialize 187 //------------------------------------------------------- // IMPLEMENTATION FILE (Stack.cpp) //------------------------------------------------------ // Private data members of class: // int top; // ItemType items[MAX_ITEMS]; //------------------------------------------------------- #include “bool.h” #include “ItemType.h” StackType::StackType( ) //------------------------------------------------ // Default Constructor //------------------------------------------------ { top = -1; } 188 // IMPLEMENTATION FILE continued (Stack.cpp) //---------------------------------------------------------- void StackType::MakeEmpty( ) //--------------------------------------------------- // PRE: None. // POST: Stack is empty. //--------------------------------------------------- { top = -1; } 189 // IMPLEMENTATION FILE continued (Stack.cpp) //---------------------------------------------------------- bool StackType::IsEmpty( ) const //--------------------------------------------------- // PRE: Stack has been initialized. // POST: Function value = (stack is empty) //--------------------------------------------------- { return ( top == -1 ); } bool StackType::IsFull( ) const //--------------------------------------------------- // PRE: Stack has been initialized. // POST: Function value = (stack is full) //--------------------------------------------------- { return ( top == MAX_ITEMS-1 ); } 190 // IMPLEMENTATION FILE continued (Stack.cpp) //------------------------------------------------------------- void StackType::Push ( ItemType newItem ) //------------------------------------------------------ // PRE: Stack has been initialized and is not full. // POST: newItem is at the top of the stack. //------------------------------------------------------ { top++; items[top] = newItem; } 191 // IMPLEMENTATION FILE continued (Stack.cpp) //------------------------------------------------------------- void StackType::Pop ( ItemType& item ) //------------------------------------------------------ // PRE: Stack has been initialized and is not empty. // POST: Top element has been removed from stack. // item is a copy of removed element. //------------------------------------------------------ { item = items[top]; top--; } 192 Class Interface Diagram StackType class StackType Private data: top MakeEmpty [MAX_ITEMS-1] IsEmpty . . . IsFull [2] Push [1] Pop items [0] 193 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] charStack.Push(‘K’); [1] while (!charStack.IsEmpty( )) items [ 0 ] charStack.Pop(letter); 194 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top -1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] charStack.Push(‘K’); [1] while (!charStack.IsEmpty( )) items [ 0 ] charStack.Pop(letter); 195 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 0 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] charStack.Push(‘K’); [1] while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 196 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 197 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 2 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘S’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 198 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 2 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘S’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 199 letter ‘S’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘S’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 200 letter ‘S’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 2 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 201 letter ‘S’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 2 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 202 letter ‘K’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 203 letter ‘K’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 204 letter ‘C’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 0 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 205 letter ‘C’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top 0 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 206 letter ‘V’ Tracing Client Code char letter = ‘V’; Private data: StackType charStack; top -1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 207 letter ‘V’ End of Trace char letter = ‘V’; Private data: StackType charStack; top -1 charStack.Push(letter); charStack.Push(‘C’); [MAX_ITEMS-1] . charStack.Push(‘S’); . . if ( !charStack.IsEmpty( )) charStack.Pop(letter); [2] ‘K’ charStack.Push(‘K’); [1] ‘C’ while (!charStack.IsEmpty( )) items [ 0 ] ‘V’ charStack.Pop(letter); 208 What is a Class Template? l A class template allows the compiler to generate multiple versions of a class type by using type parameters. l The formal parameter appears in the class template definition, and the actual parameter appears in the client code. Both are enclosed in pointed brackets, < >. 209 ACTUAL PARAMETER StackType<int> numStack; top 3 [MAX_ITEMS-1] . . . [3] 789 [2] -56 [1] 132 items [0] 5670 210 ACTUAL PARAMETER StackType<float> myStack; top 3 [MAX_ITEMS-1] . . . [3] 3456.8 [2] -90.98 [1] 98.6 items [0] 167.87 211 ACTUAL PARAMETER StackType<StrType> nameStack; top 3 [MAX_ITEMS-1] . . . [3] Bradley [2] Asad [1] Rodrigo items [0] Max 212 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION AND MEMBER FUNCTIONS //-------------------------------------------------------- #include "bool.h" #include "ItemType.h" // for MAX_ITEMS and ItemType template<class ItemType> // formal parameter list class StackType { public: StackType( ); void MakeEmpty( ); bool IsEmpty( ) const; bool IsFull( ) const; void Push( ItemType item ); void Pop( ItemType& item ); private: int top; ItemType items[MAX_ITEMS]; }; 213 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION AND MEMBER FUNCTIONS cont’d //-------------------------------------------------------- // member function definitions for class StackType template<class ItemType> // formal parameter list StackType<ItemType>::StackType( ) { top = -1; } . . . template<class ItemType> // formal parameter list void StackType<ItemType>::Push ( ItemType newItem ) { top++; items[top] = newItem; // STATIC ARRAY IMPLEMENTATION } 214 Using class templates l The actual parameter to the template is a data type. Any type can be used, either built-in or user-defined. l When using class templates, both the specification and implementation should be located in the same file, instead of in separate .h and .cpp files. 215 Recall that . . . char msg [ 8 ]; msg is the base address of the array. We say msg is a pointer because its value is an address. It is a pointer constant because the value of msg itself cannot be changed by assignment. It “points” to the memory location of a char. 6000 ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’ msg [0] [1] [2] [3] [4] [5] [6] [7] 216 Addresses in Memory l When a variable is declared, enough memory to hold a value of that type is allocated for it at an unused memory location. This is the address of the variable. int x; float number; char ch; 2000 2002 2006 x number ch 217 Obtaining Memory Addresses l The address of a non-array variable can be obtained by using the address-of operator &. int x; float number; char ch; cout << “Address of x is “ << &x << endl; cout << “Address of number is “ << &number << endl; cout << “Address of ch is “ << &ch << endl; 218 What is a pointer variable? l A pointer variable is a variable whose value is the address of a location in memory. l To declare a pointer variable, you must specify the type of value that the pointer will point to. For example, int* ptr; // ptr will hold the address of an int char* q; // q will hold the address of a char 219 Using a pointer variable int x; 2000 x = 12; 12 x int* ptr; 3000 ptr = &x; 2000 ptr NOTE: Because ptr holds the address of x, we say that ptr “points to” x 220 Unary operator * is the deference (indirection) operator int x; 2000 x = 12; 12 x int* ptr; 3000 ptr = &x; 2000 ptr cout << *ptr; NOTE: The value pointed to by ptr is denoted by *ptr 221 Using the dereference operator int x; 2000 x = 12; 12 5 x int* ptr; 3000 ptr = &x; 2000 ptr *ptr = 5; // changes the value // at adddress ptr to 5 222 Another Example char ch; 4000 ch = ‘A’; A Z ch char* q; 5000 6000 q = &ch; 4000 4000 *q = ‘Z’; q p char* p; p = q; // the right side has value 4000 // now p and q both point to ch 223 C++ Data Types Simple Structured Integral Floating array struct union class char short int long enum float double long double Address pointer reference 224 The NULL Pointer There is a pointer constant 0 called the “null pointer” denoted by NULL in stddef.h But NULL is not memory address 0. NOTE: It is an error to dereference a pointer whose value is NULL. Such an error may cause your program to crash, or behave erratically. It is the programmer’s job to check for this. while (ptr != NULL) { . . . // ok to use *ptr here } 225 Allocation of memory STATIC DYNAMIC ALLOCATION ALLOCATION Static allocation Dynamic is the allocation allocation is the of memory space allocation of at compile time. memory space at run time by using operator new. 226 3 Kinds of Program Data l STATIC DATA: memory allocation exists throughout execution of program. static long SeedValue; l AUTOMATIC DATA: automatically created at function entry, resides in activation frame of the function, and is destroyed when returning from function. l DYNAMIC DATA: explicitly allocated and deallocated during program execution by C++ instructions written by programmer using unary operators new and delete 227 Using operator new If memory is available in an area called the free store (or heap), operator new allocates the requested object or array, and returns a pointer to (address of ) the memory allocated. Otherwise, the null pointer 0 is returned. The dynamically allocated object exists until the delete operator destroys it. 228 Dynamically Allocated Data 2000 char* ptr; ptr ptr = new char; *ptr = ‘B’; cout << *ptr; 229 Dynamically Allocated Data 2000 char* ptr; ptr ptr = new char; *ptr = ‘B’; cout << *ptr; NOTE: Dynamic data has no variable name 230 Dynamically Allocated Data 2000 char* ptr; ptr ptr = new char; *ptr = ‘B’; ‘B’ cout << *ptr; NOTE: Dynamic data has no variable name 231 Dynamically Allocated Data 2000 char* ptr; ? ptr ptr = new char; *ptr = ‘B’; cout << *ptr; NOTE: Delete deallocates delete ptr; the memory pointed to by ptr. 232 Using operator delete The object or array currently pointed to by the pointer is deallocated, and the pointer is considered unassigned. The memory is returned to the free store. Square brackets are used with delete to deallocate a dynamically allocated array of classes. 233 Some C++ pointer operations Precedence Higher -> Select member of class pointed to Unary: ++ -- ! * new delete Increment, Decrement, NOT, Dereference, Allocate, Deallocate + - Add Subtract < <= > >= Relational operators == != Tests for equality, inequality Lower = Assignment Dynamic Array Allocation char *ptr; // ptr is a pointer variable that // can hold the address of a char ptr = new char[ 5 ]; // dynamically, during run time, allocates // memory for 5 characters and places into // the contents of ptr their beginning address 6000 6000 ptr 235 Dynamic Array Allocation char *ptr ; ptr = new char[ 5 ]; strcpy( ptr, “Bye” ); ptr[ 1 ] = ‘u’; // a pointer can be subscripted cout << ptr[ 2] ; 6000 ‘u’ 6000 ‘B’ ‘y’ ‘e’ ‘\0’ ptr 236 Dynamic Array Deallocation char *ptr ; ptr = new char[ 5 ]; strcpy( ptr, “Bye” ); ptr[ 1 ] = ‘u’; delete ptr; // deallocates array pointed to by ptr // ptr itself is not deallocated, but // the value of ptr is considered unassigned ? ptr 237 What happens here? int* ptr = new int; *ptr = 3; 3 ptr ptr = new int; // changes value of ptr *ptr = 4; 3 ptr 4 238 Memory Leak A memory leak occurs when dynamic memory (that was created using operator new) has been left without a pointer to it by the programmer, and so is inaccessible. 8 int* ptr = new int; ptr *ptr = 8; int* ptr2 = new int; -5 *ptr2 = -5; ptr2 How else can an object become inaccessible? 239 Causing a Memory Leak int* ptr = new int; 8 *ptr = 8; ptr int* ptr2 = new int; *ptr2 = -5; -5 ptr2 ptr = ptr2; // here the 8 becomes inaccessible 8 ptr -5 ptr2 240 A Dangling Pointer l occurs when two pointers point to the same object and delete is applied to one of them. int* ptr = new int; 8 *ptr = 8; ptr int* ptr2 = new int; *ptr2 = -5; -5 ptr = ptr2; ptr2 FOR EXAMPLE, 241 Leaving a Dangling Pointer int* ptr = new int; 8 *ptr = 8; ptr int* ptr2 = new int; *ptr2 = -5; -5 ptr = ptr2; ptr2 delete ptr2; // ptr is left dangling ptr2 = NULL; 8 ptr NULL ptr2 242 DYNAMIC ARRAY IMPLEMENTATION class StackType StackType Private Data: ~StackType top 2 50 items [0] Push maxStack 5 43 items [1] items Pop 80 items [2] . . items [3] . items [4] 243 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION AND MEMBER FUNCTIONS #include "ItemType.h" // for ItemType template<class ItemType> class StackType { public: StackType( ); StackType( int max ); // PARAMETERIZED CONSTRUCTOR ~StackType( ) ; // DESTRUCTOR . . . bool IsFull( ) const; void Push( ItemType item ); void Pop( ItemType& item ); private: int top; int maxStack; ItemType* items; // DYNAMIC ARRAY IMPLEMENTATION }; 244 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION AND MEMBER FUNCTIONS cont’d //-------------------------------------------------------- template<class ItemType> StackType<ItemType>::StackType( ) //DEFAULT CONSTRUCTOR { maxStack = 500; top = -1; items = new ItemType[500]; // dynamically allocates array } template<class ItemType> StackType<ItemType>::StackType( int max ) // PARAMETERIZED { maxStack = max; top = -1; items = new ItemType[max]; // dynamically allocates array } 245 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION AND MEMBER FUNCTIONS cont’d //-------------------------------------------------------- template<class ItemType> StackType<ItemType>::~StackType( ) { delete [ ] items; // deallocates array } . . . template<class ItemType> bool StackType<ItemType>::IsFull( ) { return (top == maxStack - 1) } 246 The N-Queens Problem l Suppose you have 8 chess queens... l ...and a chess board 247 The N-Queens Problem Can the queens be placed on the board so that no two queens are attacking each other ? 248 The N-Queens Problem Two queens are not allowed in the same row... 249 The N-Queens Problem Two queens are not allowed in the same row, or in the same column... 250 The N-Queens Problem Two queens are not allowed in the same row, or in the same column, or along the same diagonal. 251 The N-Queens Problem The number of N Queens queens, and the size of the board can vary. N columns 252 The N-Queens Problem We will write a program which tries to If you can run ega or find a way to place N vga graphics, queens on an N x N you can double click on chess board. this icon with the left mouse button: 253 How the program works The program uses a stack to keep track of where each queen is placed. 254 How the program works Each time the program decides to place a queen on the board, the position of the new queen is stored in a record which is placed in ROW 1, COL 1 the stack. 255 How the program works We also have an integer variable to keep track of how many rows have been filled so far. ROW 1, COL 1 filled 1 256 How the program works Each time we try to place a new queen in the next row, we start by ROW 2, COL 1 placing the queen in the ROW 1, COL 1 first column... filled 1 257 How the program works ...if there is a conflict with another queen, then we shift the new queen ROW 2, COL 2 to the next column. ROW 1, COL 1 filled 1 258 How the program works If another conflict occurs, the queen is shifted rightward ROW 2, COL 3 again. ROW 1, COL 1 filled 1 259 How the program works When there are no conflicts, we stop and add one to the value of filled. ROW 2, COL 3 ROW 1, COL 1 filled 2 260 How the program works Let's look at the third row. The first position we ROW 3, COL 1 try has a conflict... ROW 2, COL 3 ROW 1, COL 1 filled 2 261 How the program works ...so we shift to column 2. But another conflict ROW 3, COL 2 arises... ROW 2, COL 3 ROW 1, COL 1 filled 2 262 How the program works ...and we shift to the third column. ROW 3, COL 3 Yet another conflict arises... ROW 2, COL 3 ROW 1, COL 1 filled 2 263 How the program works ...and we shift to column 4. There's still a ROW 3, COL 4 conflict in column 4, so ROW 2, COL 3 we try to shift rightward ROW 1, COL 1 again... filled 2 264 How the program works ...but there's nowhere else to go. ROW 3, COL 4 ROW 2, COL 3 ROW 1, COL 1 filled 2 265 How the program works When we run out of room in a row: l pop the stack, ROW 2, COL 3 l reduce filled by 1 l and continue ROW 1, COL 1 working on the previous row. filled 1 266 How the program works Now we continue working on row 2, shifting the queen to the ROW 2, COL 4 right. ROW 1, COL 1 filled 1 267 How the program works This position has no conflicts, so we can increase filled by 1, and ROW 2, COL 4 move to row 3. ROW 1, COL 1 filled 2 268 How the program works In row 3, we start again at the first ROW 3, COL 1 column. ROW 2, COL 4 ROW 1, COL 1 filled 2 269 What is a Queue? l Logical (or ADT) level: A queue is an ordered group of homogeneous items (elements), in which new elements are added at one end (the rear), and elements are removed from the other end (the front). l A queue is a FIFO “first in, first out” structure. 270 Queue ADT Operations l MakeEmpty -- Sets queue to an empty state. l IsEmpty -- Determines whether the queue is currently empty. l IsFull -- Determines whether the queue is currently full. l Enqueue (ItemType newItem) -- Adds newItem to the rear of the queue. l Dequeue (ItemType& item) -- Removes the item at the front of the queue and returns it in item. 271 ADT Queue Operations Transformers n MakeEmpty change state n Enqueue n Dequeue Observers n IsEmpty observe state n IsFull 272 DYNAMIC ARRAY IMPLEMENTATION class QueType QueType Private Data: front 1 ~QueType rear 4 Enqueue maxQue 5 ‘C’ ‘X’ ‘J’ Dequeue items . . items [0] [1] [2] [3] [4] . 273 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION FOR CIRCULAR QUEUE #include "ItemType.h" // for ItemType template<class ItemType> class QueType { public: QueType( ); QueType( int max ); // PARAMETERIZED CONSTRUCTOR ~QueType( ) ; // DESTRUCTOR . . . bool IsFull( ) const; void Enqueue( ItemType item ); void Dequeue( ItemType& item ); private: int front; int rear; int maxQue; ItemType* items; // DYNAMIC ARRAY IMPLEMENTATION }; 274 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION FOR CIRCULAR QUEUE cont’d //-------------------------------------------------------- template<class ItemType> QueType<ItemType>::QueType( int max ) // PARAMETERIZED { maxQue = max + 1; front = maxQue - 1; rear = maxQue - 1; items = new ItemType[maxQue]; // dynamically allocates } template<class ItemType> bool QueType<ItemType>::IsEmpty( ) { return ( rear == front ) } 275 //-------------------------------------------------------- // CLASS TEMPLATE DEFINITION FOR CIRCULAR QUEUE cont’d //-------------------------------------------------------- template<class ItemType> QueType<ItemType>::~QueType( ) { delete [ ] items; // deallocates array } . . . template<class ItemType> bool QueType<ItemType>::IsFull( ) { // WRAP AROUND return ( (rear + 1) % maxQue == front ) } 276 Linked Structures 277 Definition of Stack l Logical (or ADT) level: A stack is an ordered group of homogeneous items (elements), in which the removal and addition of stack items can take place only at the top of the stack. l A stack is a LIFO “last in, first out” structure. 278 Stack ADT Operations l MakeEmpty -- Sets stack to an empty state. l IsEmpty -- Determines whether the stack is currently empty. l IsFull -- Determines whether the stack is currently full. l Push (ItemType newItem) -- Adds newItem to the top of the stack. l Pop (ItemType& item) -- Removes the item at the top of the stack and returns it in item. 279 ADT Stack Operations Transformers n MakeEmpty change state n Push n Pop Observers n IsEmpty observe state n IsFull 280 Another Stack Implementation l One advantage of an ADT is that the kind of implementation used can be changed. l The dynamic array implementation of the stack has a weakness -- the maximum size of the stack is passed to the constructor as parameter. l Instead we can dynamically allocate the space for each stack element as it is pushed onto the stack. 281 class StackType<char> StackType MakeEmpty IsEmpty Private data: IsFull topPtr ‘C’ ‘V’ Push Pop ~StackType 282 class StackType<float> StackType MakeEmpty IsEmpty Private data: IsFull topPtr 23.4 -7.9 Push Pop ~StackType 283 class StackType<StrType> StackType MakeEmpty IsEmpty Private data: IsFull topPtr cat dog Push Pop ~StackType 284 letter ‘V’ Tracing Client Code char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 285 letter ‘V’ Tracing Client Code Private data: topPtr NULL char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 286 letter ‘V’ Tracing Client Code Private data: topPtr ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 287 letter ‘V’ Tracing Client Code Private data: topPtr ‘C’ ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 288 letter ‘V’ Tracing Client Code Private data: topPtr ‘S’ ‘C’ ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 289 letter ‘V’ Tracing Client Code Private data: topPtr ‘S’ ‘C’ ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 290 letter ‘S’ Tracing Client Code Private data: topPtr ‘C’ ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 291 letter ‘S’ Tracing Client Code Private data: topPtr ‘K’ ‘C’ ‘V’ char letter = ‘V’; StackType< char > myStack; myStack.Push(letter); myStack.Push(‘C’); myStack.Push(‘S’); if ( !myStack.IsEmpty( ) ) myStack.Pop( letter ); myStack.Push(‘K’); 292 Dynamically Linked Implementation of Stack // DYNAMICALLY LINKED IMPLEMENTATION OF STACK #include "bool.h" #include "ItemType.h" // for ItemType template<class ItemType> struct NodeType { ItemType info; NodeType<ItemType>* next; } ‘A’ 6000 . info . next 293 // DYNAMICALLY LINKED IMPLEMENTATION OF STACK continued template<class ItemType> class StackType { public: StackType( ); // constructor // Default constructor. // POST: Stack is created and empty. void MakeEmpty( ); // PRE: None. // POST: Stack is empty. bool IsEmpty( ) const; // PRE: Stack has been initialized. // POST: Function value = (stack is empty) bool IsFull( ) const; // PRE: Stack has been initialized. // POST: Function value = (stack is full) 294 // DYNAMICALLY LINKED IMPLEMENTATION OF STACK continued void Push( ItemType item ); // PRE: Stack has been initialized. // Stack is not full. // POST: newItem is at the top of the stack. void Pop( ItemType& item ); // PRE: Stack has been initialized. // Stack is not empty. // POST: Top element has been removed from stack. // item is a copy of removed element. ~StackType( ); // destructor // PRE: Stack has been initialized. // POST: Memory allocated for nodes has been // deallocated. private: NodeType<ItemType>* topPtr ; }; 295 // DYNAMICALLY LINKED IMPLEMENTATION OF STACK continued // member function definitions for class StackType template<class ItemType> StackType<ItemType>::StackType( ) // constructor { topPtr = NULL; } template<class ItemType> void StackType<ItemType>::IsEmpty( ) const // Returns true if there are no elements // on the stack; false otherwise { return ( topPtr == NULL ); } 296 Using operator new If memory is available in an area called the free store (or heap), operator new allocates the requested object, and returns a pointer to the memory allocated. The dynamically allocated object exists until the delete operator destroys it. 297 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ 298 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ location 299 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ location 300 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ location ‘B’ 301 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ location ‘B’ 302 newItem ‘B’ Adding newItem to the stack newItem = ‘B’; NodeType<char>* location; location = new NodeType<char>; location->info = newItem; location->next = topPtr; topPtr = location; topPtr ‘X’ ‘C’ ‘L’ location ‘B’ 303 Implementing Push template<class ItemType> void StackType<ItemType>::Push ( ItemType newItem ) // Adds newItem to the top of the stack. { NodeType<ItemType>* location; location = new NodeType<ItemType>; location->info = newItem; location->next = topPtr; topPtr = location; } 304 Using operator delete The object currently pointed to by the pointer is deallocated, and the pointer is considered unassigned. The memory is returned to the free store. 305 item Deleting item from the stack NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘B’ ‘X’ ‘C’ ‘L’ tempPtr 306 item ‘B’ Deleting item from the stack NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘B’ ‘X’ ‘C’ ‘L’ tempPtr 307 item ‘B’ Deleting item from the stack NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘B’ ‘X’ ‘C’ ‘L’ tempPtr 308 item ‘B’ Deleting item from the stack NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘B’ ‘X’ ‘C’ ‘L’ tempPtr 309 item ‘B’ Deleting item from the stack NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; topPtr ‘X’ ‘C’ ‘L’ tempPtr 310 Implementing Pop template<class ItemType> void StackType<ItemType>::Pop ( ItemType& item ) // Removes element at the top of the stack and // returns it in item. { NodeType<ItemType>* tempPtr; item = topPtr->info; tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; } 311 template<class ItemType> bool StackType<ItemType>::IsFull( ) const // Returns true if there is no room for // another NodeType node on the free store; // false otherwise. { location = new NodeType<ItemType>; if ( location == NULL ) return true; else { delete location; return false; } } 312 Why is a destructor needed? When a local stack variable goes out of scope, the memory space for data member topPtr is deallocated. But the nodes that topPtr points to are not automatically deallocated. A class destructor is used to deallocate the dynamic memory pointed to by the data member. 313 template<class ItemType> void StackType<ItemType>::MakeEmpty( ) // Post: Stack is empty; all elements deallocated. { NodeType<ItemType>* tempPtr;; while ( topPtr != NULL ) { tempPtr = topPtr; topPtr = topPtr->next; delete tempPtr; } } template<class ItemType> StackType<ItemType>::~StackType( ) // destructor { MakeEmpty( ); } 314 What is a Queue? l Logical (or ADT) level: A queue is an ordered group of homogeneous items (elements), in which new elements are added at one end (the rear), and elements are removed from the other end (the front). l A queue is a FIFO “first in, first out” structure. 315 Queue ADT Operations l MakeEmpty -- Sets queue to an empty state. l IsEmpty -- Determines whether the queue is currently empty. l IsFull -- Determines whether the queue is currently full. l Enqueue (ItemType newItem) -- Adds newItem to the rear of the queue. l Dequeue (ItemType& item) -- Removes the item at the front of the queue and returns it in item. 316 ADT Queue Operations Transformers n MakeEmpty change state n Enqueue n Dequeue Observers n IsEmpty observe state n IsFull 317 class QueType<char> QueType Private Data: ~QueType qFront ‘C’ ‘Z’ ‘T’ Enqueue qRear Dequeue . . . 318 // DYNAMICALLY LINKED IMPLEMENTATION OF QUEUE #include "ItemType.h" // for ItemType template<class ItemType> class QueType { public: QueType( ); // CONSTRUCTOR ~QueType( ) ; // DESTRUCTOR bool IsEmpty( ) const; bool IsFull( ) const; void Enqueue( ItemType item ); void Dequeue( ItemType& item ); void MakeEmpty( ); private: NodeType<ItemType>* qFront; NodeType<ItemType>* qRear; }; 319 // DYNAMICALLY LINKED IMPLEMENTATION OF QUEUE continued // member function definitions for class QueType template<class ItemType> QueType<ItemType>::QueType( ) // CONSTRUCTOR { qFront = NULL; qRear = NULL; } template<class ItemType> bool QueType<ItemType>::IsEmpty( ) const { return ( qFront == NULL ) } 320 template<class ItemType> void QueType<ItemType>::Enqueue( ItemType newItem ) // Adds newItem to the rear of the queue. // Pre: Queue has been initialized. // Queue is not full. // Post: newItem is at rear of queue. { NodeType<ItemType>* ptr; ptr = new NodeType<ItemType>; ptr->info = newItem; ptr->next = NULL; if ( qRear == NULL ) qFront = ptr; else qRear->next = ptr; qRear = ptr; } 321 template<class ItemType> void QueType<ItemType>::Dequeue( ItemType& item ) // Removes element from from front of queue // and returns it in item. // Pre: Queue has been initialized. // Queue is not empty. // Post: Front element has been removed from queue. // item is a copy of removed element. { NodeType<ItemType>* tempPtr; tempPtr = qFront; item = qFront->info; qFront = qFornt->next; if ( qFront == NULL ) qRear = NULL; delete tempPtr; } 322 What is a List? l A list is a homogeneous collection of elements, with a linear relationship between elements. l That is, each list element (except the first) has a unique predecessor, and each element (except the last) has a unique successor. 323 ADT Unsorted List Operations Transformers n MakeEmpty change state n InsertItem n DeleteItem Observers n IsFull n LengthIs observe state n RetrieveItem Iterators n ResetList process all n GetNextItem 324 #include “ItemType.h” // unsorted.h . . . template <class ItemType> class UnsortedType { public : // LINKED LIST IMPLEMENTATION UnsortedType ( ) ; ~UnsortedType ( ) ; void MakeEmpty ( ) ; bool IsFull ( ) const ; int LengthIs ( ) const ; void RetrieveItem ( ItemType& item, bool& found ) ; void InsertItem ( ItemType item ) ; void DeleteItem ( ItemType item ) ; void ResetList ( ); void GetNextItem ( ItemType& item ) ; private : NodeType<ItemType>* listData; int length; NodeType<ItemType>* currentPos; }; 325 class UnsortedType<char> UnsortedType Private data: MakeEmpty length 3 ~UnsortedType listData ‘X’ ‘C’ ‘L’ RetrieveItem InsertItem currentPos DeleteItem . . . GetNextItem 326 // LINKED LIST IMPLEMENTATION ( unsorted.cpp ) #include “itemtype.h” template <class ItemType> UnsortedType<ItemType>::UnsortedType ( ) // constructor // Pre: None. // Post: List is empty. { length = 0 ; listData = NULL; } template <class ItemType> int UnsortedType<ItemType>::LengthIs ( ) const // Post: Function value = number of items in the list. { return length; } 327 template <class ItemType> void UnsortedType<ItemType>::RetrieveItem( ItemType& item, bool& found ) // Pre: Key member of item is initialized. // Post: If found, item’s key matches an element’s key in the list and a copy // of that element has been stored in item; otherwise, item is unchanged. { bool moreToSearch ; NodeType<ItemType>* location ; location = listData ; found = false ; moreToSearch = ( location != NULL ) ; while ( moreToSearch && !found ) { if ( item == location->info ) // match here { found = true ; item = location->info ; } else // advance pointer { location = location->next ; moreToSearch = ( location != NULL ) ; } } } 328 template <class ItemType> void UnsortedType<ItemType>::InsertItem ( ItemType item ) // Pre: list is not full and item is not in list. // Post: item is in the list; length has been incremented. { NodeType<ItemType>* location ; // obtain and fill a node location = new NodeType<ItemType> ; location->info = item ; location->next = listData ; listData = location ; length++ ; } 329 Inserting ‘B’ into an Unsorted List Private data: length 3 listData ‘X’ ‘C’ ‘L’ currentPos 330 ‘B’ location = new NodeType<ItemType>; item location Private data: length 3 listData ‘X’ ‘C’ ‘L’ currentPos 331 ‘B’ location->info = item ; item location ‘B’ Private data: length 3 listData ‘X’ ‘C’ ‘L’ currentPos 332 ‘B’ location->next = listData ; item location ‘B’ Private data: length 3 listData ‘X’ ‘C’ ‘L’ currentPos 333 ‘B’ listData = location ; item location ‘B’ Private data: length 3 listData ‘X’ ‘C’ ‘L’ currentPos 334 ‘B’ length++ ; item location ‘B’ Private data: length 4 listData ‘X’ ‘C’ ‘L’ currentPos 335 class SortedType<char> SortedType Private data: MakeEmpty length 3 ~SortedType listData ‘C’ ‘L’ ‘X’ RetrieveItem InsertItem currentPos DeleteItem . . . GetNextItem 336 InsertItem algorithm for Sorted Linked List l Find proper position for the new element in the sorted list using two pointers predLoc and location, where predLoc trails behind location. l Obtain a node for insertion and place item in it. l Insert the node by adjusting pointers. l Increment length. 337 Implementing SortedType member function InsertItem // LINKED LIST IMPLEMENTATION (sorted.cpp) #include “ItemType.h” template <class ItemType> void SortedType<ItemType> :: InsertItem ( ItemType item ) // Pre: List has been initialized. List is not full. item is not in list. // List is sorted by key member. // Post: item is in the list. List is still sorted. { . . . } 338 Inserting ‘S’ into a Sorted List predLoc location Private data: length 3 listData ‘C’ ‘L’ ‘X’ currentPos moreToSearch 339 Finding proper position for ‘S’ predLoc location NULL Private data: length 3 listData ‘C’ ‘L’ ‘X’ currentPos moreToSearch true 340 Finding proper position for ‘S’ predLoc location Private data: length 3 listData ‘C’ ‘L’ ‘X’ currentPos moreToSearch true 341 Finding proper position for ‘S’ predLoc location Private data: length 3 listData ‘C’ ‘L’ ‘X’ currentPos moreToSearch false 342 Inserting ‘S’ into proper position predLoc location Private data: length 4 listData ‘C’ ‘L’ ‘X’ currentPos ‘S’ moreToSearch false 343 Lists Plus 344 ADT Sorted List Operations Transformers n MakeEmpty change state n InsertItem n DeleteItem Observers n IsFull n LengthIs observe state n RetrieveItem Iterators n ResetList process all n GetNextItem class SortedType<char> SortedType Private data: MakeEmpty length 3 ~SortedType listData ‘C’ ‘L’ ‘X’ RetrieveItem InsertItem currentPos DeleteItem . . . GetNextItem 346 What is a Circular Linked List? l A circular linked list is a list in which every node has a successor; the “last” element is succeeded by the “first” element. listData ‘B’ ‘C’ ‘L’ ‘T’ ‘V’ ‘Y’ 347 What is a Doubly Linked List? l A doubly linked list is a list in which each node is linked to both its successor and its predecessor. listData ‘A’ ‘C’ ‘T’ ‘F’ ‘Z’ 348 Each node contains two pointers template< class ItemType > struct NodeType { ItemType info; // Data member NodeType<ItemType>* back; // Pointer to predecessor NodeType<ItemType>* next; // Pointer to successor }; 3000 ‘A’ NULL . back . info . next 349 What are Header and Trailer Nodes? l A Header Node is a node at the beginning of a list that contains a key value smaller than any possible key. l A Trailer Node is a node at the end of a list that contains a key larger than any possible key. l Both header and trailer are placeholding nodes used to simplify list processing. listData INT_MIN 5 8 13 INT_MAX 350 Recall Definition of Stack l Logical (or ADT) level: A stack is an ordered group of homogeneous items (elements), in which the removal and addition of stack items can take place only at the top of the stack. l A stack is a LIFO “last in, first out” structure. 351 Stack ADT Operations l MakeEmpty -- Sets stack to an empty state. l IsEmpty -- Determines whether the stack is currently empty. l IsFull -- Determines whether the stack is currently full. l Push (ItemType newItem) -- Adds newItem to the top of the stack. l Pop (ItemType& item) -- Removes the item at the top of the stack and returns it in item. 352 class StackType<int> StackType MakeEmpty IsEmpty Private data: IsFull topPtr 20 30 Push Pop ~StackType 353 What happens . . . l When a function is called that uses pass by value for a class object like our dynamically linked stack? StackType MakeEmpty IsEmpty Private data: IsFull 20 30 topPtr Push Pop ~StackType 354 Passing a class object by value // FUNCTION CODE template<class ItemType> void MyFunction( StackType<ItemType> SomeStack ) // Uses pass by value { . . . . } 355 Pass by value makes a shallow copy StackType<int> MyStack; // CLIENT CODE . . . MyFunction( MyStack ); // function call MyStack SomeStack Private data: 7000 6000 Private data: topPtr 7000 topPtr 7000 20 30 shallow copy 356 Shallow Copy vs. Deep Copy l A shallow copy copies only the class data members, and does not copy any pointed-to data. l A deep copy copies not only the class data members, but also makes separately stored copies of any pointed-to data. 357 What’s the difference? l A shallow copy shares the pointed to data with the original class object. l A deep copy stores its own copy of the pointed to data at different locations than the data in the original class object. 358 Making a deep copy MyStack Private data: 7000 6000 topPtr 7000 20 30 SomeStack Private data: 5000 2000 topPtr 5000 20 30 deep copy 359 Suppose MyFunction Uses Pop // FUNCTION CODE template<class ItemType> void MyFunction( StackType<ItemType> SomeStack ) // Uses pass by value { ItemType item; SomeStack.Pop(item); . . . } WHAT HAPPENS IN THE SHALLOW COPY SCENARIO? 360 MyStack.topPtr is left dangling StackType<int> MyStack; // CLIENT CODE . . . MyFunction( MyStack ); MyStack SomeStack Private data: 7000 6000 Private data: topPtr 7000 topPtr 6000 ? 30 shallow copy 361 MyStack.topPtr is left dangling NOTICE THAT NOT JUST FOR THE SHALLOW COPY, BUT ALSO FOR ACTUAL PARAMETER MyStack, THE DYNAMIC DATA HAS CHANGED! MyStack SomeStack Private data: 7000 6000 Private data: topPtr 7000 topPtr 6000 ? 30 shallow copy 362 As a result . . . l This default method used for pass by value is not the best way when a data member pointer points to dynamic data. l Instead, you should write what is called a copy constructor, which makes a deep copy of the dynamic data in a different memory location. 363 More about copy constructors l When there is a copy constructor provided for a class, the copy constructor is used to make copies for pass by value. l You do not call the copy constructor. l Like other constructors, it has no return type. l Because the copy constructor properly defines pass by value for your class, it must use pass by reference in its definition. 364 Copy Constructor l Copy constructor is a special member function of a class that is implicitly called in these three situations: n passing object parameters by value, n initializing an object variable in a declaration, n returning an object as the return value of a function. 365 // DYNAMICALLY LINKED IMPLEMENTATION OF STACK template<class ItemType> class StackType { public: StackType( ); // Default constructor. // POST: Stack is created and empty. StackType( const StackType<ItemType>& anotherStack ); // Copy constructor. // Implicitly called for pass by value. . . . ~StackType( ); // Destructor. // POST: Memory for nodes has been deallocated. private: NodeType<ItemType>* topPtr ; }; 366 Classes with Data Member Pointers Need CLASS CONSTRUCTOR CLASS COPY CONSTRUCTOR CLASS DESTRUCTOR 367 template<class ItemType> // COPY CONSTRUCTOR StackType<ItemType>:: StackType( const StackType<ItemType>& anotherStack ) { NodeType<ItemType>* ptr1 ; NodeType<ItemType>* ptr2 ; if ( anotherStack.topPtr == NULL ) topPtr = NULL ; else // allocate memory for first node { topPtr = new NodeType<ItemType> ; topPtr->info = anotherStack.topPtr->info ; ptr1 = anotherStack.topPtr->next ; ptr2 = topPtr ; while ( ptr1 != NULL ) // deep copy other nodes { ptr2->next = new NodeType<ItemType> ; ptr2 = ptr2->next ; ptr2->info = ptr1->info ; ptr1 = ptr1->next ; } ptr2->next = NULL ; } } 368 What about the assignment operator? l The default method used for assignment of class objects makes a shallow copy. l If your class has a data member pointer to dynamic data, you should write a member function to overload the assignment operator to make a deep copy of the dynamic data. 369 // DYNAMICALLY LINKED IMPLEMENTATION OF STACK template<class ItemType> class StackType { public: StackType( ); // Default constructor. StackType( const StackType<ItemType>& anotherStack ); // Copy constructor. void operator= ( StackType<ItemType> ); // Overloads assignment operator. . . . ~StackType( ); // Destructor. private: NodeType<ItemType>* topPtr ; }; 370 C++ Operator Overloading Guides 1 All operators except these :: . sizeof ?: may be overloaded. 2 At least one operand must be a class instance. 3 You cannot change precedence, operator symbols, or number of operands. 4 Overloading ++ and -- requires prefix form use by default, unless special mechanism is used. 5 To overload these operators = ( ) [ ] member functions (not friend functions) must be used. 6 An operator can be given multiple meanings if the data types of operands differ. 371 Using Overloaded Binary operator+ When a Member Function was defined myStack + yourStack myStack.operator+(yourStack) When a Friend Function was defined myStack + yourStack operator+(myStack, yourStack) 372 Composition (containment) l Composition (or containment) means that an internal data member of one class is defined to be an object of another class type. A FAMILIAR EXAMPLE . . . 373 ItemType Class Interface Diagram class ItemType ComparedTo Private data Print value Initialize 374 Sorted list contains an array of ItemType SortedType class MakeEmpty IsFull Private data: length LengthIs info [0] RetrieveItem [1] [2] InsertItem DeleteItem [MAX_ITEMS-1] ResetList currentPos GetNextItem 375 Inheritance l Inheritance is a means by which one class acquires the properties--both data and operations--of another class. l When this occurs, the class being inherited from is called the Base Class. l The class that inherits is called the Derived Class. AN EXAMPLE . . . 376 Recall Definition of Queue l Logical (or ADT) level: A queue is an ordered group of homogeneous items (elements), in which new elements are added at one end (the rear), and elements are removed from the other end (the front). l A queue is a FIFO “first in, first out” structure. 377 Queue ADT Operations l MakeEmpty -- Sets queue to an empty state. l IsEmpty -- Determines whether the queue is currently empty. l IsFull -- Determines whether the queue is currently full. l Enqueue (ItemType newItem) -- Adds newItem to the rear of the queue. l Dequeue (ItemType& item) -- Removes the item at the front of the queue and returns it in item. 378 class QueType<char> QueType Private Data: ~QueType qFront ‘C’ ‘Z’ ‘T’ Enqueue qRear Dequeue . . . 379 // DYNAMICALLY LINKED IMPLEMENTATION OF QUEUE #include "ItemType.h" // for ItemType template<class ItemType> class QueType { public: QueType( ); // CONSTRUCTOR ~QueType( ) ; // DESTRUCTOR bool IsEmpty( ) const; bool IsFull( ) const; void Enqueue( ItemType item ); void Dequeue( ItemType& item ); void MakeEmpty( ); private: NodeType<ItemType>* qFront; NodeType<ItemType>* qRear; }; 380 SAYS ALL PUBLIC MEMBERS OF QueType CAN BE INVOKED FOR OBJECTS OF TYPE CountedQue // DERIVED CLASS CountedQue FROM BASE CLASS QueType template<class ItemType> class CountedQue : public QueType<ItemType> { public: CountedQue( ); void Enqueue( ItemType newItem ); void Dequeue( ItemType& item ); int LengthIs( ) const; // Returns number of items on the counted queue. private: int length; }; 381 class CountedQue<char> CountedQue QueType Private Data: LengthIs ~QueType qFront ‘C’ ‘Z’ ‘T’ Enqueue qRear Enqueue Dequeue . . Dequeue . . . Private Data: . length 3 382 // Member function definitions for class CountedQue template<class ItemType> CountedQue<ItemType>::CountedQue( ) : QueType<ItemType>( ) { length = 0 ; } template<class ItemType> int CountedQue<ItemType>::LengthIs( ) const { return length ; } 383 template<class ItemType> void CountedQue<ItemType>::Enqueue( ItemType newItem ) // Adds newItem to the rear of the queue. // Increments length. { length++; QueType<ItemType>::Enqueue( newItem ); } template<class ItemType> void CountedQue<ItemType>::Dequeue(ItemType& item ) // Removes item from the rear of the queue. // Decrements length. { length--; QueType<ItemType>::Dequeue( item ); } 384 Programming with Recursion 385 Recursive Function Call l A recursive call is a function call in which the called function is the same as the one making the call. l In other words, recursion occurs when a function calls itself! l We must avoid making an infinite sequence of function calls (infinite recursion). 386 Finding a Recursive Solution l Each successive recursive call should bring you closer to a situation in which the answer is known. l A case for which the answer is known (and can be expressed without recursion) is called a base case. l Each recursive algorithm must have at least one base case, as well as the general (recursive) case 387 General format for many recursive functions if (some condition for which answer is known) // base case solution statement else // general case recursive function call SOME EXAMPLES . . . 388 Writing a recursive function to find n factorial DISCUSSION The function call Factorial(4) should have value 24, because that is 4 * 3 * 2 * 1 . For a situation in which the answer is known, the value of 0! is 1. So our base case could be along the lines of if ( number == 0 ) return 1; 389 Writing a recursive function to find Factorial(n) Now for the general case . . . The value of Factorial(n) can be written as n * the product of the numbers from (n - 1) to 1, that is, n * (n - 1) * . . . * 1 or, n * Factorial(n - 1) And notice that the recursive call Factorial(n - 1) gets us “closer” to the base case of Factorial(0). 390 Recursive Solution int Factorial ( int number ) // Pre: number is assigned and number >= 0. { if ( number == 0) // base case return 1 ; else // general case return number + Factorial ( number - 1 ) ; } 391 Three-Question Method of verifying recursive functions l Base-Case Question: Is there a nonrecursive way out of the function? l Smaller-Caller Question: Does each recursive function call involve a smaller case of the original problem leading to the base case? l General-Case Question: Assuming each recursive call works correctly, does the whole function work correctly? 392 Another example where recursion comes naturally l From mathematics, we know that 20 = 1 and 25 = 2 * 24 l In general, x0 = 1 and xn = x * xn-1 for integer x, and integer n > 0. l Here we are defining xn recursively, in terms of xn-1 393 // Recursive definition of power function int Power ( int x, int n ) // Pre: n >= 0. x, n are not both zero // Post: Function value = x raised to the power n. { if ( n == 0 ) return 1; // base case else // general case return ( x * Power ( x , n-1 ) ) ; } Of course, an alternative would have been to use looping instead of a recursive call in the function body. 394 struct ListType struct ListType { int length ; // number of elements in the list int info[ MAX_ITEMS ] ; }; ListType list ; 395 Recursive function to determine if value is in list PROTOTYPE bool ValueInList( ListType list , int value , int startIndex ) ; 74 36 ... 95 75 29 47 ... list[0] [1] [startIndex] [length -1] Already searched index Needs to be searched of current element to examine 396 bool ValueInList ( ListType list , int value , int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ) { if ( list.info[startIndex] == value ) // one base case return true ; else if (startIndex == list.length -1 ) // another base case return false ; else // general case return ValueInList( list, value, startIndex + 1 ) ; } 397 “Why use recursion?” Those examples could have been written without recursion, using iteration instead. The iterative solution uses a loop, and the recursive solution uses an if statement. However, for certain problems the recursive solution is the most natural solution. This often occurs when pointer variables are used. 398 struct ListType struct NodeType { int info ; NodeType* next ; } class SortedType { public : . . . // member function prototypes private : NodeType* listData ; }; 399 RevPrint(listData); listData A B C D E FIRST, print out this section of list, backwards THEN, print this element 400 Base Case and General Case A base case may be a solution in terms of a “smaller” list. Certainly for a list with 0 elements, there is no more processing to do. Our general case needs to bring us closer to the base case situation. That is, the number of list elements to be processed decreases by 1 with each recursive call. By printing one element in the general case, and also processing the smaller remaining list, we will eventually reach the situation where 0 list elements are left to be processed. In the general case, we will print the elements of the smaller remaining list in reverse order, and then print the current pointed to element. 401 Using recursion with a linked list void RevPrint ( NodeType* listPtr ) // Pre: listPtr points to an element of a list. // Post: all elements of list pointed to by listPtr have been printed // out in reverse order. { if ( listPtr != NULL ) // general case { RevPrint ( listPtr-> next ) ; // process the rest cout << listPtr->info << endl ; // then print this element } // Base case : if the list is empty, do nothing } 402 Function BinarySearch( ) l BinarySearch takes sorted array info, and two subscripts, fromLoc and toLoc, and item as arguments. It returns false if item is not found in the elements info[fromLoc…toLoc]. Otherwise, it returns true. l BinarySearch can be written using iteration, or using recursion. 403 found = BinarySearch(info, 25, 0, 14 ); item fromLoc toLoc indexes 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 info 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 16 18 20 22 24 26 28 24 26 28 24 NOTE: denotes element examined 404 // Recursive definition template<class ItemType> bool BinarySearch ( ItemType info[ ] , ItemType item , int fromLoc , int toLoc ) // Pre: info [ fromLoc . . toLoc ] sorted in ascending order // Post: Function value = ( item in info [ fromLoc . . toLoc] ) { int mid ; if ( fromLoc > toLoc ) // base case -- not found return false ; else { mid = ( fromLoc + toLoc ) / 2 ; if ( info [ mid ] == item ) // base case-- found at mid return true ; else if ( item < info [ mid ] ) // search lower half return BinarySearch ( info, item, fromLoc, mid-1 ) ; else // search upper half return BinarySearch( info, item, mid + 1, toLoc ) ; } } 405 When a function is called... l A transfer of control occurs from the calling block to the code of the function. It is necessary that there be a return to the correct place in the calling block after the function code is executed. This correct place is called the return address. l When any function is called, the run-time stack is used. On this stack is placed an activation record (stack frame) for the function call. 406 Stack Activation Frames l The activation record stores the return address for this function call, and also the parameters, local variables, and the function’s return value, if non-void. l The activation record for a particular function call is popped off the run-time stack when the final closing brace in the function code is reached, or when a return statement is reached in the function code. l At this time the function’s return value, if non- void, is brought back to the calling block return address for use there. 407 // Another recursive function int Func ( int a, int b ) // Pre: a and b have been assigned values // Post: Function value = ?? { int result; if ( b == 0 ) // base case result = 0; else if ( b > 0 ) // first general case result = a + Func ( a , b - 1 ) ) ; // instruction 50 else // second general case result = Func ( - a , - b ) ; // instruction 70 return result; } 408 Run-Time Stack Activation Records x = Func(5, 2); // original call is instruction 100 FCTVAL ? original call result ? at instruction 100 b 2 pushes on this record a 5 for Func(5,2) Return Address 100 409 Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100 FCTVAL ? call in Func(5,2) code result ? at instruction 50 b 1 pushes on this record a 5 for Func(5,1) Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 record for Func(5,2) a 5 Return Address 100 410 Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100 FCTVAL ? call in Func(5,1) code result ? at instruction 50 b 0 pushes on this record a 5 for Func(5,0) Return Address 50 FCTVAL ? result 5+Func(5,0) = ? b 1 record for Func(5,1) a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 record for Func(5,2) a 5 Return Address 100 411 Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100 FCTVAL 0 result 0 b 0 record for Func(5,0) a 5 is popped first Return Address 50 with its FCTVAL FCTVAL ? result 5+Func(5,0) = ? b 1 record for Func(5,1) a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 record for Func(5,2) a 5 Return Address 100 412 Run-Time Stack Activation Records x = Func(5, 2); // original call at instruction 100 FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 record for Func(5,1) a 5 is popped next Return Address 50 with its FCTVAL FCTVAL ? result 5+Func(5,1) = ? b 2 record for Func(5,2) a 5 Return Address 100 413 Run-Time Stack Activation Records x = Func(5, 2); // original call at line 100 FCTVAL 10 result 5+Func(5,1) = 5+5 b 2 record for Func(5,2) a 5 is popped last Return Address 100 with its FCTVAL 414 Show Activation Records for these calls x = Func( - 5, - 3 ); x = Func( 5, - 3 ); What operation does Func(a, b) simulate? 415 Tail Recursion l The case in which a function contains only a single recursive call and it is the last statement to be executed in the function. l Tail recursion can be replaced by iteration to remove recursion from the solution as in the next example. 416 // USES TAIL RECURSION bool ValueInList ( ListType list , int value , int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ) { if ( list.info[startIndex] == value ) // one base case return true ; else if (startIndex == list.length -1 ) // another base case return false ; else // general case return ValueInList( list, value, startIndex + 1 ) ; } 417 // ITERATIVE SOLUTION bool ValueInList ( ListType list , int value , int startIndex ) // Searches list for value between positions startIndex // and list.length-1 // Pre: list.info[ startIndex ] . . list.info[ list.length - 1 ] // contain values to be searched // Post: Function value = // ( value exists in list.info[ startIndex ] . . list.info[ list.length - 1 ] ) { bool found = false ; while ( !found && startIndex < list.length ) { if ( value == list.info[ startIndex ] ) found = true ; else startIndex++ ; } return found ; } 418 Use a recursive solution when: l The depth of recursive calls is relatively “shallow” compared to the size of the problem. l The recursive version does about the same amount of work as the nonrecursive version. l The recursive version is shorter and simpler than the nonrecursive solution. SHALLOW DEPTH EFFICIENCY CLARITY 419 Using quick sort algorithm A..Z A..L M..Z A..F G..L M..R S..Z 420 Before call to function Split splitVal = 9 GOAL: place splitVal in its proper position with all values less than or equal to splitVal on its left and all larger values on its right 9 20 6 10 14 3 60 11 values[first] [last] 421 After call to function Split splitVal = 9 smaller values larger values 6 3 9 10 14 20 60 11 values[first] [splitPoint] [last] 422 // Recursive quick sort algorithm template <class ItemType > void QuickSort ( ItemType values[ ] , int first , int last ) // Pre: first <= last // Post: Sorts array values[ first. .last ] into ascending order { if ( first < last ) // general case { int splitPoint ; Split ( values, first, last, splitPoint ) ; // values [ first ] . . values[splitPoint - 1 ] <= splitVal // values [ splitPoint ] = splitVal // values [ splitPoint + 1 ] . . values[ last ] > splitVal QuickSort( values, first, splitPoint - 1 ) ; QuickSort( values, splitPoint + 1, last ); } } 423 Binary Search Trees 424 Jake’s Pizza Shop Owner Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len 425 A Tree Has a Root Node Owner ROOT NODE Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len 426 Leaf nodes have no children Owner Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len LEAF NODES 427 A Tree Has Levels Owner LEVEL 0 Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len 428 Level One Owner Jake Manager Chef LEVEL 1 Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len 429 Level Two Owner Jake Manager Chef Brad Carol LEVEL 2 Waitress Waiter Cook Helper Joyce Chris Max Len 430 A Subtree Owner Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len LEFT SUBTREE OF ROOT NODE 431 Another Subtree Owner Jake Manager Chef Brad Carol Waitress Waiter Cook Helper Joyce Chris Max Len RIGHT SUBTREE OF ROOT NODE 432 Binary Tree A binary tree is a structure in which: Each node can have at most two children, and in which a unique path exists from the root to every other node. The two children of a node are called the left child and the right child, if they exist. 433 A Binary Tree V Q L E T A K S 434 How many leaf nodes? V Q L E T A K S 435 How many descendants of Q? V Q L E T A K S 436 How many ancestors of K? V Q L E T A K S 437 Implementing a Binary Tree with Pointers and Dynamic Data V Q L E T A K S 438 Each node contains two pointers template< class ItemType > struct TreeNode { ItemType info; // Data member TreeNode<ItemType>* left; // Pointer to left child TreeNode<ItemType>* right; // Pointer to right child }; NULL ‘A’ 6000 . left . info . right 439 // BINARY SEARCH TREE SPECIFICATION template< class ItemType > class TreeType { public: TreeType ( ); // constructor ~TreeType ( ); // destructor bool IsEmpty ( ) const; bool IsFull ( ) const; int NumberOfNodes ( ) const; void InsertItem ( ItemType item ); void DeleteItem (ItemType item ); void RetrieveItem ( ItemType& item, bool& found ); void PrintTree (ofstream& outFile) const; . . . private: TreeNode<ItemType>* root; }; 440 TreeType<char> CharBST; TreeType ‘J’ ~TreeType Private data: root IsEmpty ‘E’ ‘S’ InsertItem RetrieveItem ‘A’ ‘H’ PrintTree . . . 441 A Binary Search Tree (BST) is . . . A special kind of binary tree in which: 1. Each node contains a distinct data value, 2. The key values in the tree can be compared using “greater than” and “less than”, and 3. The key value of each node in the tree is less than every key value in its right subtree, and greater than every key value in its left subtree. 442 Shape of a binary search tree . . . Depends on its key values and their order of insertion. Insert the elements ‘J’ ‘E’ ‘F’ ‘T’ ‘A’ in that order. The first value to be inserted is put into the root node. ‘J’ 443 Inserting ‘E’ into the BST Thereafter, each value to be inserted begins by comparing itself to the value in the root node, moving left it is less, or moving right if it is greater. This continues at each level until it can be inserted as a new leaf. ‘J’ ‘E’ 444 Inserting ‘F’ into the BST Begin by comparing ‘F’ to the value in the root node, moving left it is less, or moving right if it is greater. This continues until it can be inserted as a leaf. ‘J’ ‘E’ ‘F’ 445 Inserting ‘T’ into the BST Begin by comparing ‘T’ to the value in the root node, moving left it is less, or moving right if it is greater. This continues until it can be inserted as a leaf. ‘J’ ‘E’ ‘T’ ‘F’ 446 Inserting ‘A’ into the BST Begin by comparing ‘A’ to the value in the root node, moving left it is less, or moving right if it is greater. This continues until it can be inserted as a leaf. ‘J’ ‘E’ ‘T’ ‘A’ ‘F’ 447 What binary search tree . . . is obtained by inserting the elements ‘A’ ‘E’ ‘F’ ‘J’ ‘T’ in that order? ‘A’ 448 Binary search tree . . . obtained by inserting the elements ‘A’ ‘E’ ‘F’ ‘J’ ‘T’ in that order. ‘A’ ‘E’ ‘F’ ‘J’ ‘T’ 449 Another binary search tree ‘J’ ‘E’ ‘T’ ‘A’ ‘H’ ‘M’ ‘K’ ‘P’ Add nodes containing these values in this order: ‘D’ ‘B’ ‘L’ ‘Q’ ‘S’ ‘V’ ‘Z’ 450 Is ‘F’ in the binary search tree? ‘J’ ‘E’ ‘T’ ‘A’ ‘H’ ‘M’ ‘V’ ‘D’ ‘K’ ‘P’ ‘Z’ ‘B’ ‘L’ ‘Q’ ‘S’ 451 // BINARY SEARCH TREE SPECIFICATION template< class ItemType > class TreeType { public: TreeType ( ) ; // constructor ~TreeType ( ) ; // destructor bool IsEmpty ( ) const ; bool IsFull ( ) const ; int NumberOfNodes ( ) const ; void InsertItem ( ItemType item ) ; void DeleteItem (ItemType item ) ; void RetrieveItem ( ItemType& item , bool& found ) ; void PrintTree (ofstream& outFile) const ; . . . private: TreeNode<ItemType>* root ; }; 452 // SPECIFICATION (continued) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // RECURSIVE PARTNERS OF MEMBER FUNCTIONS template< class ItemType > void PrintHelper ( TreeNode<ItemType>* ptr, ofstream& outFile ) ; template< class ItemType > void InsertHelper ( TreeNode<ItemType>*& ptr, ItemType item ) ; template< class ItemType > void RetrieveHelper ( TreeNode<ItemType>* ptr, ItemType& item, bool& found ) ; template< class ItemType > void DestroyHelper ( TreeNode<ItemType>* ptr ) ; 453 // BINARY SEARCH TREE IMPLEMENTATION // OF MEMBER FUNCTIONS AND THEIR HELPER FUNCTIONS // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template< class ItemType > TreeType<ItemType> :: TreeType ( ) // constructor { root = NULL ; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template< class ItemType > bool TreeType<ItemType> :: IsEmpty( ) const { return ( root == NULL ) ; } 454 template< class ItemType > void TreeType<ItemType> :: RetrieveItem ( ItemType& item, bool& found ) { RetrieveHelper ( root, item, found ) ; } template< class ItemType > void RetrieveHelper ( TreeNode<ItemType>* ptr, ItemType& item, bool& found) { if ( ptr == NULL ) found = false ; else if ( item < ptr->info ) // GO LEFT RetrieveHelper( ptr->left , item, found ) ; else if ( item > ptr->info ) // GO RIGHT RetrieveHelper( ptr->right , item, found ) ; else { item = ptr->info ; found = true ; } 455 } template< class ItemType > void TreeType<ItemType> :: InsertItem ( ItemType item ) { InsertHelper ( root, item ) ; } template< class ItemType > void InsertHelper ( TreeNode<ItemType>*& ptr, ItemType item ) { if ( ptr == NULL ) { // INSERT item HERE AS LEAF ptr = new TreeNode<ItemType> ; ptr->right = NULL ; ptr->left = NULL ; ptr->info = item ; } else if ( item < ptr->info ) // GO LEFT InsertHelper( ptr->left , item ) ; else if ( item > ptr->info ) // GO RIGHT InsertHelper( ptr->right , item ) ; } 456 Search Example I Successful findElement(76) 76>44 76<88 76>65 76<82 l A successful search traverses a path starting at the root and ending at an internal node 457 l How about findAllelements(k)? Search Example II Unsuccessful findElement(25) 25<44 25>17 25<32 25<28 leaf node l An unsuccessful search traverses a path starting at the root and ending at an external node 458 Insertion l To perform insertItem(k, e), let w be the node returned by TreeSearch(k, T.root()) l If w is external, we know that k is not stored in T. We call expandExternal(w) on T and store (k, e) in w 459 Insertion II l If w is internal, we know another item with key k is stored at w. We call the algorithm recursively starting at T.rightChild(w) or T.leftChild(w) 460 Removal I l We locate the node w where the key is stored with algorithm TreeSearch l If w has an external child z, we remove w and z with removeAboveExternal(z) 461 Removal II l If w has an no external children: n find the internal node y following w in inorder n move the item at y into w n perform removeAboveExternal(x), where x is the left child of y (guaranteed to be external) 462 Time Complexity l A search, insertion, or removal, visits the nodes along a root-to leaf path, plus possibly the siblings of such nodes l Time O(1) is spent at each node l The running time of each operation is O(h), where h is the height of the tree l The height of binary serch tree is in n in the worst case, where a binary search tree looks like a sorted sequence l To achieve good running time, we need to keep the tree balanced, i.e., with O(logn) height. l Various balancing schemes will be explored in the next lectures 463 Traversal of Trees l Preorder: Process the node, then recursively process the left and right subtrees. l Inorder: Process the left subtree, the node, and the right subtree. l Postorder: Process the left subtree, the right subtree, and the node. l Levelorder: top-to-bottom, left-to-right order 464 Tree Traversal We've mentioned In Order and Level Order. In Order is easily described recursively: •Visit left subtree (if there is one) In Order •Visit root •Visit right subtree (if there is one) In Order 465 Tree Traversal: PreOrder Another common traversal is PreOrder. It goes as deep as possible (visiting as it goes) then left to right. More precisely: •Visit root •Visit left subtree in PreOrder •Visit right subtree in PreOrder 466 Tree Traversal: PostOrder PostOrder traversal also goes as deep as possible, but only visits internal nodes during backtracking. More precisely: •Visit left subtree in PostOrder •Visit right subtree in PostOrder •Visit root 467 Inorder Traversal: A E H J M T Y Print second tree ‘J’ ‘ ‘ T’ ‘ E’ ‘ ‘ A’ H’ ‘ Y’ M’ Print left subtree first Print right subtree last 468 // INORDER TRAVERSAL template< class ItemType > void TreeType<ItemType> :: PrintTree ( ofstream& outFile ) const { PrintHelper ( root, outFile ) ; } template< class ItemType > void PrintHelper ( TreeNode<ItemType>* ptr, ofstream& outFile ) { if ( ptr != NULL ) { PrintHelper( ptr->left , outFile ) ; // Print left subtree outFile << ptr->info ; PrintHelper( ptr->right, outFile ) ; // Print right subtree } } 469 Preorder Traversal: J E A H T M Y Print first tree ‘J’ ‘ ‘ T’ ‘ E’ ‘ ‘ A’ H’ ‘ Y’ M’ Print left subtree second Print right subtree last 470 Postorder Traversal: A H E M Y T J Print last tree ‘J’ ‘ ‘ T’ ‘ E’ ‘ ‘ A’ H’ ‘ Y’ M’ Print left subtree first Print right subtree second 471 template< class ItemType > TreeType<ItemType> :: ~TreeType ( ) // DESTRUCTOR { DestroyHelper ( root ) ; } template< class ItemType > void DestroyHelper ( TreeNode<ItemType>* ptr ) // Post: All nodes of the tree pointed to by ptr are deallocated. { if ( ptr != NULL ) { DestroyHelper ( ptr->left ) ; DestroyHelper ( ptr->right ) ; delete ptr ; } } 472 Preorder Traversal + + * + g a * b c * f d e Preorder traversal yields: (+ (+ a (* b c)) (* (+ (* d e) f) g)) 473 Inorder Traversal + + * + g a * b c * f d e Inorder traversal yields: (a + (b * c)) + (((d * e) + f) * g) 474 Postorder Traversal + + * + g a * b c * f d e Postorder traversal yields: a b c * + d e * f + g * + 475 Constant-Space Scanning 476 477 Trees Plus 478 A Binary Expression Tree is . . . A special kind of binary tree in which: 1. Each leaf node contains a single operand, 2. Each nonleaf node contains a single binary operator, and 3. The left and right subtrees of an operator node represent subexpressions that must be evaluated before applying the operator at the root of the subtree. 479 A Two-Level Binary Expression treePtr ‘-’ ‘8’ ‘5’ INORDER TRAVERSAL: 8 - 5 has value 3 PREORDER TRAVERSAL: - 8 5 POSTORDER TRAVERSAL: 8 5 - 480 Levels Indicate Precedence When a binary expression tree is used to represent an expression, the levels of the nodes in the tree indicate their relative precedence of evaluation. Operations at higher levels of the tree are evaluated later than those below them. The operation at the root is always the last operation performed. 481 A Binary Expression Tree ‘*’ ‘+’ ‘3’ ‘4’ ‘2’ What value does it have? ( 4 + 2 ) * 3 = 18 482 A Binary Expression Tree ‘*’ ‘+’ ‘3’ ‘4’ ‘2’ What infix, prefix, postfix expressions does it represent? 483 A Binary Expression Tree ‘*’ ‘+’ ‘3’ ‘4’ ‘2’ Infix: ((4+2)*3) Prefix: * + 4 2 3 Postfix: 4 2 + 3 * has operators in order used 484 Inorder Traversal: (A + H) / (M - Y) Print second tree ‘/’ ‘- ‘ ’ ‘ + ‘ ‘ A’ ’ H’ ‘ Y’ M’ Print left subtree first Print right subtree last 485 Preorder Traversal: / + A H - M Y Print first tree ‘/’ ‘ ‘ - ‘ + ‘ ’ ‘ A’ ’ H’ ‘ Y’ M’ Print left subtree second Print right subtree last 486 Postorder Traversal: A H + M Y - / Print last tree ‘/’ ‘ ‘ - ‘ + ‘ ’ ‘ A’ ’ H’ ‘ Y’ M’ Print left subtree first Print right subtree second 487 Evaluate this binary expression tree ‘*’ ‘-’ ‘/’ ‘8’ ‘5’ ‘+’ ‘3’ ‘4’ ‘2’ What infix, prefix, postfix expressions does it represent? 488 A binary expression tree ‘*’ ‘-’ ‘/’ ‘8’ ‘5’ ‘+’ ‘3’ ‘4’ ‘2’ Infix: ((8-5)*((4+2)/3)) Prefix: *-85 /+423 Postfix: 8 5 - 4 2 + 3 / * has operators in order used 489 InfoNode has 2 forms enum OpType { OPERATOR, OPERAND } ; struct InfoNode { OpType whichType; union // ANONYMOUS union { char operation ; int operand ; } }; OPERATOR ‘+’ OPERAND 7 . whichType . operation . whichType . operand 490 Each node contains two pointers struct TreeNode { InfoNode info ; // Data member TreeNode* left ; // Pointer to left child TreeNode* right ; // Pointer to right child }; NULL OPERAND 7 6000 . whichType . operand . left . info . right 491 int Eval ( TreeNode* ptr ) // Pre: ptr is a pointer to a binary expression tree. // Post: Function value = the value of the expression represented // by the binary tree pointed to by ptr. { switch ( ptr->info.whichType ) { case OPERAND : return ptr->info.operand ; case OPERATOR : switch ( tree->info.operation ) { case ‘+’ : return ( Eval ( ptr->left ) + Eval ( ptr->right ) ) ; case ‘-’ : return ( Eval ( ptr->left ) - Eval ( ptr->right ) ) ; case ‘*’ : return ( Eval ( ptr->left ) * Eval ( ptr->right ) ) ; case ‘/’ : return ( Eval ( ptr->left ) / Eval ( ptr->right ) ) ; } } 492 } class ExprTree ExprTree ‘*’ ~ExprTree private: root Build ‘+’ ‘3’ Evaluate . ‘4’ ‘2’ . . 493 A full binary tree A full binary tree is a binary tree in which all the leaves are on the same level and every non leaf node has two children. SHAPE OF A FULL BINARY TREE 494 A complete binary tree A complete binary tree is a binary tree that is either full or full through the next-to-last level, with the leaves on the last level as far to the left as possible. SHAPE OF A COMPLETE BINARY TREE 495 What is a Heap? A heap is a binary tree that satisfies these special SHAPE and ORDER properties: n Its shape must be a complete binary tree. n For each node in the heap, the value stored in that node is greater than or equal to the value in each of its children. 496 Are these both heaps? treePtr C 50 A T 20 30 18 10 497 Is this a heap? tree 70 60 12 40 30 8 10 498 Where is the largest element in a heap always found? tree 70 60 12 40 30 8 499 We can number the nodes left to right by level this way tree 70 0 60 12 1 2 40 30 8 3 4 5 500 Binary Tree Implementation A B C D E F G 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 501 And use the numbers as array indexes to store the tree tree.nodes [0] tree 70 [1] 60 70 0 [2] 12 60 12 [3] 40 1 2 [4] 30 40 30 8 [5] 3 4 5 8 [6] 502 // HEAP SPECIFICATION // Assumes ItemType is either a built-in simple data type // or a class with overloaded realtional operators. template< class ItemType > struct HeapType { void ReheapDown ( int root , int bottom ) ; void ReheapUp ( int root, int bottom ) ; ItemType* elements ; // ARRAY to be allocated dynamically int numElements ; }; 503 ReheapDown // IMPLEMENTATION OF RECURSIVE HEAP MEMBER FUNCTIONS template< class ItemType > void HeapType<ItemType>::ReheapDown ( int root, int bottom ) // Pre: root is the index of the node that may violate the heap // order property // Post: Heap order property is restored between root and bottom { int maxChild ; int rightChild ; int leftChild ; leftChild = root * 2 + 1 ; rightChild = root * 2 + 2 ; 504 if ( leftChild <= bottom ) // ReheapDown continued { if ( leftChild == bottom ) maxChild = leftChld ; else { if (elements [ leftChild ] <= elements [ rightChild ] ) maxChild = rightChild ; else maxChild = leftChild ; } if ( elements [ root ] < elements [ maxChild ] ) { Swap ( elements [ root ] , elements [ maxChild ] ) ; ReheapDown ( maxChild, bottom ) ; } } } 505 // IMPLEMENTATION continued template< class ItemType > void HeapType<ItemType>::ReheapUp ( int root, int bottom ) // Pre: bottom is the index of the node that may violate the heap // order property. The order property is satisfied from root to // next-to-last node. // Post: Heap order property is restored between root and bottom { int parent ; if ( bottom > root ) { parent = ( bottom - 1 ) / 2; if ( elements [ parent ] < elements [ bottom ] ) { Swap ( elements [ parent ], elements [ bottom ] ) ; ReheapUp ( root, parent ) ; } } 506 } Priority Queue A priority queue is an ADT with the property that only the highest-priority element can be accessed at any time. 507 ADT Priority Queue Operations Transformers n MakeEmpty change state n Enqueue n Dequeue Observers n IsEmpty observe state n IsFull 508 // CLASS PQTYPE DEFINITION AND MEMBER FUNCTIONS //-------------------------------------------------------- #include "bool.h" #include "ItemType.h" // for ItemType template<class ItemType> class PQType { public: PQType( int ); ~PQType ( ); void MakeEmpty( ); bool IsEmpty( ) const; bool IsFull( ) const; void Enqueue( ItemType item ); void Dequeue( ItemType& item ); private: int numItems; HeapType<ItemType> items; int maxItems; }; 509 class PQType<char> Private Data: numItems ‘X’ [0] ‘C’ [1] PQType 3 ‘J’ [2] [3] maxItems [4] ~PQType [5] 10 [6] Enqueue [7] items [8] Dequeue [9] . . . .elements .numElements Sorting and Searching Algorithms 511 Sorting means . . . l The values stored in an array have keys of a type for which the relational operators are defined. (We also assume unique keys.) l Sorting rearranges the elements into either ascending or descending order within the array. (We’ll use ascending order.) 512 Straight Selection Sort values [ 0 ] Divides the array into two 36 parts: already sorted, and [1] not yet sorted. 24 [2] On each pass, finds the 10 smallest of the unsorted elements, and swaps it into [3] 6 its correct place, thereby increasing the number of [4] 12 sorted elements by one. 513 Selection Sort: Pass One values [ 0 ] 36 U [1] N 24 S [2] O 10 R [3] 6 T E [4] D 12 514 Selection Sort: End Pass One values [ 0 ] 6 SORTED [1] U 24 N [2] S 10 O [3] R 36 T [4] E 12 D 515 Selection Sort: Pass Two values [ 0 ] 6 SORTED [1] U 24 N [2] S 10 O [3] R 36 T [4] E 12 D 516 Selection Sort: End Pass Two values [ 0 ] 6 SORTED [1] 10 [2] U 24 N S [3] O 36 R T [4] E 12 D 517 Selection Sort: Pass Three values [ 0 ] 6 SORTED [1] 10 [2] U 24 N S [3] O 36 R T [4] E 12 D 518 Selection Sort: End Pass Three values [ 0 ] 6 S O [1] R 10 T [2] E 12 D [3] 36 UNSORTED [4] 24 519 Selection Sort: Pass Four values [ 0 ] 6 S O [1] R 10 T [2] E 12 D [3] 36 UNSORTED [4] 24 520 Selection Sort: End Pass Four values [ 0 ] 6 S [1] O 10 [2] R 12 T [3] 24 E D [4] 36 521 Selection Sort: How many comparisons? values [ 0 ] 6 4 compares for values[0] [1] 10 3 compares for values[1] [2] 12 2 compares for values[2] [3] 1 compare for values[3] 24 [4] = 4 + 3 + 2 + 1 36 522 For selection sort in general l The number of comparisons when the array contains N elements is Sum = (N-1) + (N-2) + . . . + 2 + 1 523 Notice that . . . Sum = (N-1) + (N-2) + . . . + 2 + 1 + Sum = 1 + 2 + . . . + (N-2) + (N-1) 2* Sum = N + N + ... + N + N 2 * Sum = N * (N-1) Sum = N * (N-1) 2 524 For selection sort in general l The number of comparisons when the array contains N elements is Sum = (N-1) + (N-2) + . . . + 2 + 1 Sum = N * (N-1) /2 Sum = .5 N2 - .5 N Sum = O(N2) 525 template <class ItemType > int MinIndex ( ItemType values [ ] , int start , int end ) // Post: Function value = index of the smallest value in // values [start] . . values [end]. { int indexOfMin = start ; for ( int index = start + 1 ; index <= end ; index++ ) if ( values [ index ] < values [ indexOfMin ] ) indexOfMin = index ; return indexOfMin; } 526 template <class ItemType > void SelectionSort ( ItemType values [ ] , int numValues ) // Post: Sorts array values[0 . . numValues-1 ] into ascending // order by key { int endIndex = numValues - 1 ; for ( int current = 0 ; current < endIndex ; current++ ) Swap ( values [ current ] , values [ MinIndex ( values, current, endIndex ) ] ) ; } 527 Bubble Sort Compares neighboring values [ 0 ] 36 pairs of array elements, starting with the last array [1] element, and swaps 24 neighbors whenever they [2] are not in correct order. 10 [3] On each pass, this causes 6 the smallest element to [4] “bubble up” to its correct 12 place in the array. 528 template <class ItemType > void BubbleUp ( ItemType values [ ] , int start , int end ) // Post: Neighboring elements that were out of order have been // swapped between values [start] and values [end], // beginning at values [end]. { for ( int index = end ; index > start ; index-- ) if (values [ index ] < values [ index - 1 ] ) Swap ( values [ index ], values [ index - 1 ] ) ; } 529 template <class ItemType > void BubbleSort ( ItemType values [ ] , int numValues ) // Post: Sorts array values[0 . . numValues-1 ] into ascending // order by key { int current = 0 ; while ( current < numValues - 1 ) BubbleUp ( values , current , numValues - 1 ) ; current++ ; } 530 Insertion Sort values [ 0 ] One by one, each as yet 36 unsorted array element is [1] inserted into its proper 24 place with respect to the already sorted elements. [2] 10 On each pass, this causes [3] 6 the number of already sorted elements to increase [4] 12 by one. 531 Insertion Sort Works like someone who “inserts” one more card at a time into a hand of cards that are already sorted. To insert 12, we need to make room for it by moving first 36 and then 24. 532 Insertion Sort Works like someone who “inserts” one more card at a time into a hand of cards that are already sorted. To insert 12, we need to make room for it by moving first 36 and then 24. 533 Insertion Sort Works like someone who “inserts” one more card at a time into a hand of cards that are already sorted. To insert 12, we need to make room for it by moving first 36 and then 24. 534 Insertion Sort Works like someone who “inserts” one more card at a time into a hand of cards that are already sorted. To insert 12, we need to make room for it by moving first 36 and then 24. 535 template <class ItemType > void InsertItem ( ItemType values [ ] , int start , int end ) // Post: Elements between values [start] and values [end] // have been sorted into ascending order by key. { bool finished = false ; int current = end ; bool moreToSearch = ( current != start ) ; while ( moreToSearch && !finished ) { if (values [ current ] < values [ current - 1 ] ) { Swap ( values [ current ], values [ current - 1 ] ) ; current-- ; moreToSearch = ( current != start ); } else finished = true ; } } 536 template <class ItemType > void InsertionSort ( ItemType values [ ] , int numValues ) // Post: Sorts array values[0 . . numValues-1 ] into ascending // order by key { for ( int count = 0 ; count < numValues ; count++ ) InsertItem ( values , 0 , count ) ; } 537 Sorting Algorithms and Average Case Number of Comparisons Simple Sorts n Straight Selection Sort n Bubble Sort O(N2) n Insertion Sort More Complex Sorts n Quick Sort n Merge Sort O(N*log N) n Heap Sort 538 Recall that . . . A heap is a binary tree that satisfies these special SHAPE and ORDER properties: n Its shape must be a complete binary tree. n For each node in the heap, the value stored in that node is greater than or equal to the value in each of its children. 539 The largest element in a heap is always found in the root node root 70 60 12 40 30 8 10 540 The heap can be stored in an array values [0] root 70 [1] 60 70 0 [2] 12 60 12 [3] 40 1 2 [4] 30 40 30 8 10 [5] 3 4 5 6 8 [6] 10 541 Heap Sort Approach First, make the unsorted array into a heap by satisfying the order property. Then repeat the steps below until there are no more unsorted elements. l Take the root (maximum) element off the heap by swapping it into its correct place in the array at the end of the unsorted elements. l Reheap the remaining unsorted elements. (This puts the next-largest element into the root position). 542 After creating the original heap values [0] root 70 [1] 60 70 0 [2] 12 60 12 [3] 40 1 2 [4] 30 40 30 8 10 [5] 3 4 5 6 8 [6] 10 543 Swap root element into last place in unsorted array values [0] root 70 [1] 60 70 0 [2] 12 60 12 [3] 40 1 2 [4] 30 40 30 8 10 [5] 3 4 5 6 8 [6] 10 544 After swapping root element into its place values [0] root 10 [1] 60 10 0 [2] 12 60 12 [3] 40 1 2 [4] 30 40 30 8 70 [5] 3 4 5 6 8 [6] 70 NO NEED TO CONSIDER AGAIN 545 After reheaping remaining unsorted elements values [0] root 60 [1] 40 60 0 [2] 12 40 12 [3] 10 1 2 [4] 30 10 30 8 70 [5] 3 4 5 6 8 [6] 70 546 Swap root element into last place in unsorted array values [0] root 60 [1] 40 60 0 [2] 12 40 12 [3] 10 1 2 [4] 30 10 30 8 70 [5] 3 4 5 6 8 [6] 70 547 After swapping root element into its place values [0] root 8 [1] 40 8 0 [2] 12 40 12 [3] 10 1 2 [4] 30 10 30 60 70 [5] 3 4 5 6 60 [6] 70 NO NEED TO CONSIDER AGAIN 548 After reheaping remaining unsorted elements values [0] root 40 [1] 30 40 0 [2] 12 30 12 [3] 10 1 2 [4] 6 10 6 60 70 [5] 3 4 5 6 60 [6] 70 549 Swap root element into last place in unsorted array values [0] root 40 [1] 30 40 0 [2] 12 30 12 [3] 10 1 2 [4] 6 10 6 60 70 [5] 3 4 5 6 60 [6] 70 550 After swapping root element into its place values [0] root 6 [1] 30 6 0 [2] 12 30 12 [3] 10 1 2 [4] 40 10 40 60 70 [5] 3 4 5 6 60 [6] 70 NO NEED TO CONSIDER AGAIN 551 After reheaping remaining unsorted elements values [0] root 30 [1] 10 30 0 [2] 12 10 12 [3] 6 1 2 [4] 40 6 40 60 70 [5] 3 4 5 6 60 [6] 70 552 Swap root element into last place in unsorted array values [0] root 30 [1] 10 30 0 [2] 12 10 12 [3] 6 1 2 [4] 40 6 40 60 70 [5] 3 4 5 6 60 [6] 70 553 After swapping root element into its place values [0] root 6 [1] 10 6 0 [2] 12 10 12 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 NO NEED TO CONSIDER AGAIN 554 After reheaping remaining unsorted elements values [0] root 12 [1] 10 12 0 [2] 6 10 6 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 555 Swap root element into last place in unsorted array values [0] root 12 [1] 10 12 0 [2] 6 10 6 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 556 After swapping root element into its place values [0] root 6 [1] 10 6 0 [2] 12 10 12 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 NO NEED TO CONSIDER AGAIN 557 After reheaping remaining unsorted elements values [0] root 10 [1] 6 10 0 [2] 12 6 12 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 558 Swap root element into last place in unsorted array values [0] root 10 [1] 6 10 0 [2] 12 6 12 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 559 After swapping root element into its place values [0] root 6 [1] 10 6 0 [2] 12 10 12 [3] 30 1 2 [4] 40 30 40 60 70 [5] 3 4 5 6 60 [6] 70 ALL ELEMENTS ARE SORTED 560 template <class ItemType > void HeapSort ( ItemType values [ ] , int numValues ) // Post: Sorts array values[ 0 . . numValues-1 ] into ascending // order by key { int index ; // Convert array values[ 0 . . numValues-1 ] into a heap. for ( index = numValues/2 - 1 ; index >= 0 ; index-- ) ReheapDown ( values , index , numValues - 1 ) ; // Sort the array. for ( index = numValues - 1 ; index >= 1 ; index-- ) { Swap ( values [0] , values [index] ); ReheapDown ( values , 0 , index - 1 ) ; } } 561 ReheapDown template< class ItemType > void ReheapDown ( ItemType values [ ], int root, int bottom ) // Pre: root is the index of a node that may violate the heap // order property // Post: Heap order property is restored between root and bottom { int maxChild ; int rightChild ; int leftChild ; leftChild = root * 2 + 1 ; rightChild = root * 2 + 2 ; 562 if ( leftChild <= bottom ) // ReheapDown continued { if ( leftChild == bottom ) maxChild = leftChild; else { if (values [ leftChild ] <= values [ rightChild ] ) maxChild = rightChild ; else maxChild = leftChild ; } if ( values [ root ] < values [ maxChild ] ) { Swap ( values [ root ] , values [ maxChild ] ) ; ReheapDown ( maxChild, bottom ) ; } } } 563 Heap Sort: How many comparisons? In reheap down, an element root is compared with its 2 children (and swapped 24 with the larger). But 0 only one element at each level makes 60 12 this comparison, and a complete 1 2 binary tree with 30 40 8 10 N nodes has only O(log2N) 3 4 5 6 levels. 15 6 18 70 7 8 9 10 564 Heap Sort of N elements: How many comparisons? (N/2) * O(log N) compares to create original heap (N-1) * O(log N) compares for the sorting loop = O ( N * log N) compares total 565 566 Quick-Sort l To understand quick-sort, let’s look at a high-level description of the algorithm 1) Divide : If the sequence S has 2 or more elements, select an element x from S to be your pivot. Any arbitrary element, like the last, will do. Remove all the elements of S and divide them into 3 sequences: L, holds S’s elements less than x E, holds S’s elements equal to x G, holds S’s elements greater than x 2) Recurse: Recursively sort L and G 3) Conquer: Finally, to put elements back into S in order, first inserts the elements of L, then those of E, and those of G. Here are some pretty diagrams.... 567 Idea of Quick Sort 1) Select: pick an element 2) Divide: rearrange elements so that x goes to its final position E 3) Recurse and Conquer: recursively sort 568 Quick-Sort Tree 569 Quick-Sort Tree 570 Quick-Sort Tree 571 Quick-Sort Tree 572 Quick-Sort Tree 573 Quick-Sort Tree 574 Quick-Sort Tree 575 Quick-Sort Tree 576 Quick-Sort Tree 577 Quick-Sort Tree 578 Quick-Sort Tree 579 Quick-Sort Tree Skipping ... 580 ... Finally 581 // Recursive quick sort algorithm template <class ItemType > void QuickSort ( ItemType values[ ] , int first , int last ) // Pre: first <= last // Post: Sorts array values[ first . . last ] into ascending order { if ( first < last ) // general case { int splitPoint ; Split ( values, first, last, splitPoint ) ; // values [ first ] . . values[splitPoint - 1 ] <= splitVal // values [ splitPoint ] = splitVal // values [ splitPoint + 1 ] . . values[ last ] > splitVal QuickSort( values, first, splitPoint - 1 ) ; QuickSort( values, splitPoint + 1, last ); } }; 582 Quick Sort of N elements: How many splits can occur? It depends on the order of the original array elements! If each split divides the subarray approximately in half, there will be only log2N splits, and QuickSort is O(N*log2N). But, if the original array was sorted to begin with, the recursive calls will split up the array into parts of unequal length, with one part empty, and the other part containing all the rest of the array except for split value itself. In this case, there can be as many as N-1 splits, and QuickSort is O(N2). 583 Before call to function Split splitVal = 9 GOAL: place splitVal in its proper position with all values less than or equal to splitVal on its left and all larger values on its right 9 20 26 18 14 53 60 11 values[first] [last] 584 After call to function Split splitVal = 9 no smaller values larger values empty left part in right part with N-1 elements 9 20 26 18 14 53 60 11 values[first] [last] splitVal in correct position 585 Merge Sort 586 Merge Sort Algorithm Cut the array in half. Sort the left half. Sort the right half. Merge the two sorted halves into one sorted array. 74 36 ... 95 75 29 ... 52 [first] [middle] [middle + 1] [last] 36 74 ... 95 29 52 ... 75 587 // Recursive merge sort algorithm template <class ItemType > void MergeSort ( ItemType values[ ] , int first , int last ) // Pre: first <= last // Post: Array values[ first . . last ] sorted into ascending order. { if ( first < last ) // general case { int middle = ( first + last ) / 2 ; MergeSort ( values, first, middle ) ; MergeSort( values, middle + 1, last ) ; // now merge two subarrays // values [ first . . . middle ] with // values [ middle + 1, . . . last ]. Merge( values, first, middle, middle + 1, last ) ; } } 588 Using Merge Sort Algorithm with N = 16 16 8 8 4 4 4 4 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 589 Merge Sort of N elements: How many comparisons? The entire array can be subdivided into halves only log2N times. Each time it is subdivided, function Merge is called to re-combine the halves. Function Merge uses a temporary array to store the merged elements. Merging is O(N) because it compares each element in the subarrays. Copying elements back from the temporary array to the values array is also O(N). MERGE SORT IS O(N*log2N). 590 Searching 591 Function BinarySearch( ) l BinarySearch takes sorted array info, and two subscripts, fromLoc and toLoc, and item as arguments. It returns false if item is not found in the elements info[fromLoc…toLoc]. Otherwise, it returns true. l BinarySearch is O(log2N). 592 found = BinarySearch(info, 25, 0, 14 ); item fromLoc toLoc indexes 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 info 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 16 18 20 22 24 26 28 24 26 28 24 NOTE: denotes element examined 593 template<class ItemType> bool BinarySearch ( ItemType info[ ] , ItemType item , int fromLoc , int toLoc ) // Pre: info [ fromLoc . . toLoc ] sorted in ascending order // Post: Function value = ( item in info [ fromLoc . . toLoc] ) { int mid ; if ( fromLoc > toLoc ) // base case -- not found return false ; else { mid = ( fromLoc + toLoc ) / 2 ; if ( info [ mid ] == item ) // base case-- found at mid return true ; else if ( item < info [ mid ] ) // search lower half return BinarySearch ( info, item, fromLoc, mid-1 ) ; else // search upper half return BinarySearch( info, item, mid + 1, toLoc ) ; } } 594 HashTable 595 Dictionary l A collection of data that is accessed by “key” values n The keys may be ordered or unordered n Multiple key values may/may-not be allowed l Supports the following fundamental methods n void put(Object key, Object data) – Inserts data into the dictionary using the specified key n Object get(Object key) – Returns the data associated with the specified key – An error occurs if the specified key is not in the dictionary n Object remove(Object key) – Removes the data associated with the specified key and returns the data. – An error occurs if the specified key is not in the dictionary 596 What is a Hashtable? l A hashtable is an unordered dictionary that uses an array to store data n Each data element is associated with a key n Each key is mapped into an array index using a hash function n The key AND the data are then stored in the array l Hashtables are commonly used in the construction of compiler symbol tables. 597 Dictionaries AVL Trees vs. Hashtables AVL Hashtable Method Worst Average Worst Average Not Bad Astounding! put O(Log N) O(Log N) O(N) O(1) get O(Log N) O(Log N) O(N) O(1) remove O(Log N) O(Log N) O(N) O(1) 598 Simple Example Insert data into the hashtable using characters as keys 0 The hashtable is an array of “items” The hashtables’ capacity is 7 1 The hash function must take a character as input and 2 convert it into a number between 0 and 6. 3 Use the following hash function: Let P be the position of the character in the English alphabet (starting with 1). The 4 hash function h(K) = P 5 The function must be normalized in order to map into the appropriate range (0-6). The normalized hash function is 6 h(K) % 7. 599 Example put(B2, Data1) 0 (N14, Data4) This is called a collision put(S19, Data2) 1 Collisions are handled via a “collision put(J10, Data3) 2 (B2, Data1) resolution policy” put(N14, Data4) 3 (J10, Data3) (X24, Data5) ??? put(X24, Data5) put(W23, Data6) 4 put(B2, Data7) 5 (S19, Data2) get(X24) 6 get(W23) 600 From Keys to Indices l The mapping of keys to indices of a hash table is called a hash function l A hash function is usually the composition of two maps, a hash code map and a compression map. n An essential requirement of the hash function is to map equal keys to equal indices n A “good” hash function minimizes the probability of collisions 601 Popular Hash-Code Maps l Integer cast: for numeric types with 32 bits or less, we can reinterpret the bits of the number as an int l Component sum: for numeric types with more than 32 bits (e.g., long and double), we can add the 32-bit components. l Polynomial accumulation: for strings of a natural language, combine the character values (ASCII or Unicode) a0a1 ... an-1 by viewing them as the coefficients of a polynomial: a0 + a1x + ...+ xn-1an-1 -The polynomial is computed with Horner’s rule, ignoring overflows, at a fixed value x: a0 + x (a1 +x (a2+ ... x (an-2+ x an-1) ... )) -The choice x = 33, 37, 39, or 41gives at most 6 collisions on a vocabulary of 50,000 English words 602 l Why is the component-sum hash code bad for strings? Popular Compression Maps l Division: h(k) = |k| mod N n the choice N = 2k is bad because not all the bits are taken into account n the table size N is usually chosen as a prime number n certain patterns in the hash codes are propagated l Multiply, Add, and Divide (MAD): h(k) = |ak + b| mod N 603 Details and Definitions •Various means of “collision resolution” can be used. The collision resolution policy determines what is done when two keys map to the same array index. –Open Addressing: look for an open slot –Separate Chaining: keep a list of key/value pairs in a slot l Load factor is the size of the table divided by the capacity of the table 604 Open Addressing: When a collision occurs, probe for an empty slot. In this case, use linear probing Example (looking “down”) until an empty slot is found. put(B2, Data1) 0 (N14, Data4) put(S19, Data2) 1 (X24, Data5) put(J10, Data3) 2 (B2, Data1) put(N14, Data4) 3 (J10, Data3) (X24, Data5) ??? put(X24, Data5) put(W23, Data6) 4 get(X24) 5 (S19, Data2) get(W23) 6 (W23, Data7) 605 Open Addressing l Uses a “probe sequence” to look for an empty slot to use l The first location examined is the “hash” address l The sequence of locations examined when locating data is called the “probe sequence” l The probe sequence {s(0), s(1), s(2), … } can be described as follows: s(i) = norm(h(K) + p(i)) n where h(K) is the “hash function” mapping K to an integer n p(i) is a “probing function” returning an offset for the ith probe n norm is the “normalizing function” (usually division modulo capacity) 606 Open Addressing l Linear probing n use p(i) = i n The probe sequence becomes {norm(h(k)), norm(h(k)+1), norm(h(k)+2), …} l Quadratic probing n use p(i) = i2 n The probe sequence becomes {norm(h(k)), norm(h(k)+1), norm(h(k)+4),…} n Must be careful to allow full coverage of “empty” array slots n A theorem states that this method will find an empty slot if the table is not more that ½ full. 607 Linear Probing l If the current location is used, try the next table location linear_probing_insert(K) if (table is full) error probe = h(K) while (table[probe] occupied) probe = (probe + 1) mod M table[probe] = K l Lookups walk along table until the key or an empty slot is found l Uses less memory than chaining. (Don’t have to store all those links) l Slower than chaining. (May have to walk along table for a long way.) l Deletion is more complex. (Either mark the deleted slot or fill in the slot by shifting some elements down.) 608 Linear Probing Example l h(k) = k mod 13 l Insert keys: 31 73 44 32 41 18 44 59 32 22 31 73 609 Linear Probing Example (cont.) 610 Linear probing N-1 0 h N-2 1 (h(key) + 4) mod N Keys 611 Quadratic probing N-1 0 h N-2 1 h(key) (h(key) + 144) mod N Keys N = 17 (prime) 612 Collisions Given N people in a room, what are the odds that at least two of them will have the same birthday? •Table capacity of 365 •After N insertions what are the odds of at least one collision? Who wants to be a Millionaire? Assume N = 23 (load factor is therefore 23/365 = 6.3%). What are the approximate odds that two of these people have the same birthday? 10% 75% 25% 90% 50% 99% 613 Collisions Let Q(n) be the probability that when n people are in a room, nobody has the same birthday. Let P(n) be the probability that when n people are in a room, at least two of them have the same birthday. P(n) = 1 – Q(n) Consider that: Q(1) = 1 Q(2) = Odds that Q(1) don’t collide times the odds of one more person not “colliding” Q(2) = Q(1) * 364/365 Q(3) = Q(2) * 363/365 Q(4) = Q(3) * 362/365 … Q(n) = (365/365) * (364/365) * (363/365) * … * ((365-n+1)/365) Q(n) = 365! / (365n * (365-n)!) 614 Collisions Odds of N Collision Odds of a collision 5 2.7% 10 11.7% 15 25.3% 23 50.7% 30 70.1% 40 89.1% 45 94.1% 100 99.9999% Number of people Collisions are more frequent than you might expect, even for low load factors! 615 Hashcodes and table size l Hashcodes should be fast/easy to compute l Keys should evenly distribute across the table l Hashtable capacities are usually kept at prime- values to avoid problems with probe sequences n Consider inserting into the table below using quadratic probing and a key object that hashes to index 2 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 616 We need to have a little talk l How to remove an item from a hashtable that uses open addressing? l Consider a table of size 11 with the following sequence of operations using h(k) = K%11 and linear probing (p(i) = i) n put(36, D1) n put(23, D2) n put(4, D3) n put(46, D4) n put(1, D5) n remove(23) n remove(36) n get(1) 617 Removal l If an item is removed from the table, it could mess up gets on other items in the table. l Fix the problem by using a “tombstone” marker to indicate that while the item has been removed from the array slot, the slot should be considered “occupied” for purposes of later gets. 618 Double Hashing l Another probing strategy is to use “double hashing” l The probe sequence becomes s(k,i) = norm(h(k) + i*h2(k)) l The hash value is determined by “two” hash functions and is typically better than linear or quadratic probing. 619 Double Hashing Example l h1(K) = K mod 13 l h2 (K) = 8 - K mod 8 l we want h2 to be an offset to add 620 Double Hashing Example (cont.) 621 Separate Chaining l A way to “avoid” collisions l Each array slot contains a list of data elements l The fundamental methods then become: n PUT: hash into array and add to list n GET: hash into array and search the list n REMOVE: hash into array and remove from list l The built-in HashMap and Hashtable classes use separate chaining 622 Chaining Example put(B2, Data1) 0 (N14, Data4) put(S19, Data2) 1 put(J10, Data3) 2 (B2, Data1) put(N14, Data4) 3 (J10, Data3) (X24, Data5) ??? put(X24, Data5) put(W23, Data6) 4 put(B2, Data7) 5 (S19, Data2) get(X24) 6 get(W23) 623 Chaining Example put(B2, Data1) 0 (N14, Data4) put(S19, Data2) 1 put(J10, Data3) 2 (B2, Data1) put(N14, Data4) 3 (J10, Data3) (X24, Data5) put(X24, Data5) put(W23, Data6) 4 I’m so put(B2, Data7) 5 (S19, Data2) relieved! get(X24) 6 get(W23) 624 Theoretical Results •Let = N/M the load factor: average number of keys per array index •Analysis is probabilistic, rather than worst-case Expected Number of Probes Not found found 625 Expected Number of Probes vs. Load Factor 626 Summary l Dictionaries may be ordered or unordered n Unordered can be implemented with – lists (array-based or linked) – hashtables (best solution) n Ordered can be implemented with – lists (array-based or linked) – trees (avl (best solution), splay, bst) 627 More on Search Trees l AVL Trees l Splay Trees l 2-3 Trees 628 AVL 樹 l G. M. Adel’son-Vel’skii and E. M. Landis, “An Algorithm for the Organization of Information,” Soviet Math. Doklady 3 (1962), pp. 1259— 1262. l AVL樹是二元搜尋樹，並具有以下的特性：對 樹裡任何一個節點來說，右子樹的高度減左子 樹的高度等於負1或0或正1。 629 AVL Tree l AVL trees are 4 44 balanced. 2 3 l An AVL Tree is a 17 78 binary search tree 1 2 1 32 50 88 such that for every 1 1 internal node v of T, 48 62 the heights of the children of v can differ by at most 1. An example of an AVL tree where the heights are shown next to the nodes: 630 Height of an AVL Tree l Proposition: The height of an AVL tree T storing n keys is O(log n). l Justification: The easiest way to approach this problem is to find n(h): the minimum number of internal nodes of an AVL tree of height h. l We see that n(1) = 1 and n(2) = 2 l For n ≥ 3, an AVL tree of height h contains the root node, one AVL subtree of height n-1 and the other AVL subtree of height n- 2. l i.e. n(h) = 1 + n(h-1) + n(h-2) 631 Height of an AVL Tree (cont) l Knowing n(h-1) > n(h-2), we get n(h) > 2n(h-2) n(h) > 2n(h-2) n(h) > 4n(h-4) … n(h) > 2in(h-2i) l Solving the base case we get: n(h) ≥ 2 h/2-1 l Taking logarithms: h < 2log n(h) +2 l Thus the height of an AVL tree is O(log n) 632 Example 633 AVL樹：如何新增 l 注意：AVL樹的每一個節點都要存左右子樹 的高度。（存高度差就可以了） 1. 當做是平常的二元搜尋樹來做新增。 2. 從新增的樹葉一步一步走回樹根檢查每一 個節點是否有違反AVL樹的特性，如果有 違反的地方，用以下介紹的方法修正。 634 Case 1 635 Case 2 636 Case 3 l 假設 A 是第一個碰到的有問題的節點。 做完可以 不用再往 上看了。 637 Case 4 l 假設 A 是第一個碰到的有問題的節點。 做完可以 不用再往 上看了。 638 Restructuring l The four ways to rotate nodes in an AVL tree, graphically represented -Single Rotations: a =z single rotation b =y b =y a =z c=x c=x T0 T3 T1 T3 T0 T1 T2 T2 c=z single rotation b =y b =y a =x c=z a =x T3 T3 T0 T2 T2 T1 T0 639 T1 Restructuring (contd.) l double rotations: a=z double rotation b=x c=y a=z c=y b=x T0 T2 T2 T3 T0 T1 T3 T1 c=z double rotation b=x a=y a=y c=z b=x T0 T2 T3 T2 T3 T1 T0 T1 640 Insertion (contd.) unbalanced... 5 44 2 z 64 17 78 7 3 2 y 1 1 32 1 50 4 88 1 2 x 48 1 3 62 5 54 T3 T0 T2 ...balanced 4 44 3 4 x 2 17 62 2y z 6 1 2 2 32 1 50 3 78 1 5 7 1 1 48 54 88 T2 T0 T1 T 641 3 AVL樹：如何刪除 l 當做是平常的二元搜尋樹來做刪除。 l 從被刪除的節點一步一步走回樹根，遇到 有違反AVL性質的節點，用以下的方法調 整。（假設A是有問題的節點。） 做完還要繼續往上檢查。 未完成 642 Removal (contd.) l example of deletion from an AVL tree: 4 Oh no, unbalanced! 44 1 y 3 17 62 x 2 2 50 78 1 1 0 1 T0 48 54 88 T2 32 T1 T3 y 4 62 3 z x 2 44 78 1 2 0 1 Whew, 17 1 50 1 88 balanced! 48 54 T2 T0 643 T3 Removal (contd.) l example of deletion from an AVL tree: z 4 44 1 y 3 17 62 2 x 2 Oh no, 50 78 T0 1 1 0 1 unbalanced! 48 54 88 32 T1 T2 T3 4 x 50 z 2 44 y 62 3 Whew, 1 17 1 48 1 54 78 2 balanced! 0 1 88 T0 644 T1 T2 AVL樹的例子 l 原來是空的AVL樹，新增0，1，2，3，4 ，5，6，7，8，9以後AVL樹變成什麼樣 子？ 645 Example Continued 646 Example Continued l 再刪除4，8以後AVL樹變成什麼樣子？ 647 Splay Trees l Binary search trees. l Search, insert, delete, and split have amortized complexity O(log n) & actual complexity O(n). l Actual and amortized complexity of join is O(1). l Priority queue and double-ended priority queue versions outperform heaps, deaps, etc. over a sequence of operations. l Two varieties. n Bottom up. n Top down. Bottom-Up Splay Trees l Search, insert, delete, and join are done as in an unbalanced binary search tree. l Search, insert, and delete are followed by a splay operation that begins at a splay node. l When the splay operation completes, the splay node has become the tree root. l Join requires no splay (or, a null splay is done). l For the split operation, the splay is done in the middle (rather than end) of the operation. 649 Splaying l Given x, an internal node of the tree, we splay x by moving x to the root of T thru a sequence of restructurings. l The specific restructurings chosen depend upon the relative positions of x, its parent y, and (if it exists) x’s grandparent z. l We consider three possible cases: 650 Possible Substep 1 zig-zig: The node x and its parent are both left (or right) children. then replace z by x, maintaining inorder relationships z x 10 30 y y 20 20 x T4 T1 z 30 10 T2 T3 T3 T4 T1 T2 before after 651 Possible Substep 2 zig-zag: One of x and y is a left child and the other is a right child. Then replace z by x, x having y and z as children and maintaining inorder. z 10 x 20 y 30 z y T1 x 10 30 20 T4 T2 T3 T1 T2 T3 T4 before after 652 Possible Substep 3 zig: x does not have a grandparent. Then rotate x over y, maintaining inorder relationships y 10 x 20 x 20 y w T1 w 10 30 30 T2 T3 T4 T1 T2 T3 T4 before after 653 A Splaying Step l For a given x, start performing zig-zig or zig-zag when it has a grandparent, and zig when it does not, until x becomes the root of T. l x’s depth: n decreases by 2 after each zig-zig/zig-zag n decreases by 1 after each zig 654 When to splay l When searching for key k: one of n if k is found in node x, splay x n otherwise splay the external node where search ends l When inserting key k: n splay the newly created internal node where k gets inserted 655 When to splay 2 l When deleting a key k: n splay the parent of the node w that gets removed (either the node containing k or one of its descendants). l Time for performing each search, insertion or deletion proportional to the associated splay time l We can see that so far, worst case can be (n) - so this is not a good data structure from a worst-case point of view 656 Per Operation Actual Complexity l Start with an empty splay tree and insert pairs with keys 1, 2, 3, …, in this order. 1 1 2 2 1 657 Per Operation Actual Complexity l Start with an empty splay tree and insert pairs with keys 1, 2, 3, …, in this order. 3 3 2 2 2 4 1 3 1 1 658 Per Operation Actual Complexity l Worst-case height = n. l Actual complexity of search, insert, delete, and split is O(n). 659 2-3樹 l 所有的樹葉的深度都一樣。 l 一個節點可以有一個值（兩個子樹）或兩 個值（三個子樹）。 l 是搜尋樹。 l 是滿的樹。 660 例子 l 如何搜尋？ 661 2-3樹的新增 l 找到該新增的節點。把新的值放在那個節點。 n 如果是 D1 D2 則停止; n 如果是 D1 D2 D3 則 從該節點一步一步依照 以下的調整方法把樹調 整成合法的 2-3 樹。 662 Case 1 663 Case 2 664 Case 3 665 2-3 樹的刪除 l 如果要刪除的值在樹葉，直接刪掉。不然 刪掉比它小的最大的（一定在樹葉）。 l 然後依照以下的方法調整成合法的 2-3 樹 。 666 Case 1:（鄰近的兄弟節點有3節 點） 667 Case 2:（鄰近的兄弟節點是2節 點） l 如果同時合Case 1和Case 2：用Case 1。 668 Case 3: 669 2-3 樹的例子 l 原來是空的2-3樹，新增0，1，2，3，4，5，6，7，8 ，9以後樹變成什麼樣子？ 670 Example Continued 671 Example Continued l 再刪除4，8以後樹變成什麼樣子？ 672 刪除4，再刪除8 673 Graphs l Definitions l Examples l The Graph ADT PVD LAX STL HNL DFW FTL 674 What is a Graph? l A graph G = (V,E) is composed of: V: set of vertices E: set of edges connecting the vertices in V l An edge e = (u,v) is a pair of vertices l Example: a b V= {a,b,c,d,e} E= {(a,b),(a,c),(a,d), c (b,e),(c,d),(c,e), (d,e)} d e 675 Applications X l electronic circuits start find the path of least resistance to X l networks (roads, flights, communications) PVD LAX STL HNL DFW 676 FTL Graph Terminology l adjacent vertices: vertices connected by an edge 3 2 l degree (of a vertex): # of adjacent vertices 3 NOTE: The sum of the degrees of all vertices is twice the number 3 3 of edges. Why? Since adjacent vertices each a b a b count the adjoining edge, it will be counted twice c c l path: sequence of vertices d e d e v1,v2,. . .vk such that consecutive abedc bedc vertices vi and vi+1 are adjacent. 677 More Graph Terminology a b l simple path: no repeated vertices bec c d e l cycle: simple path, except that the last vertex is the same as the first vertex a b acda c d e 678 Even More Terminology •connected graph: any two vertices are connected by some path connected not connected l subgraph: subset of vertices and edges forming a graph l connected component: maximal connected subgraph. E.g., the graph below has 3 connected components. 679 Another Terminology Slide l (free) tree - connected graph without cycles l forest - collection of trees tree tree forest tree tree 680 Connectivity l Let n = #vertices, and m = #edges l A complete graph: one in which all pairs of vertices are adjacent l How many total edges in a complete graph? n Each of the n vertices is incident to n-1 edges, however, we would have counted each edge twice!!! Therefore, intuitively, m = n(n -1)/2. l Therefore, if a graph is not complete, m < n(n -1)/2 n5 m (5 2 1 681 More Connectivity n = #vertices m = #edges n5 l For a tree m = n - 1 m4 If m < n - 1, G is not connected n5 m3 682 Spanning Tree l A spanning tree of G is a subgraph which is a tree and which contains all vertices of G G spanning tree of G l Failure on any edge disconnects system (least fault tolerant) 683 Roberto wants to call the TA’s to suggest an extension for the next program... TA TA But Plant-Ops ‘accidentally’ cuts a phone cable!!! TA In the previous graph, one fault will TA TA disconnect part of graph!! A cycle would be more fault tolerant and only requires n edges 684 Euler and the Bridges of Koenigsberg Gilligan’s Isle? C Pregal River A D B Can one walk across each bridge exactly once and return at the starting point? l Consider if you were a UPS driver, and you didn’t want to retrace your steps. l In 1736, Euler proved that this is not possible 685 Graph Model(with parallel edges) Eulerian Tour: path that l traverses every edge C exactly once and returns to the first vertex l Euler’s Theorem: A graph has a Eulerian A D Tour if and only if all vertices have even degree B 686 The Graph ADT l The Graph ADT is a positional container whose positions are the vertices and the edges of the graph. -size() Return the number of vertices plus the number of edges of G. -isEmpty() -elements() -positions() -swap() -replaceElement() Notation: Graph G; Vertices v, w; Edge e; Object o -numVertices() Return the number of vertices of G. -numEdges() Return the number of edges of G. -vertices() Return an enumeration of the vertices of G. -edges() Return an enumeration of the edges of G. 687 The Graph ADT (contd.) -directedEdges() Return an enumeration of all directed edges in G. -undirectedEdges() Return an enumeration of all undirected edges in G. -incidentEdges(v) Return an enumeration of all edges incident on v. -inIncidentEdges(v) Return an enumeration of all the incoming edges to v. -outIncidentEdges(v) Return an enumeration of all the outgoing edges from v. -opposite(v, e) Return an endpoint of e distinct from v -degree(v) Return the degree of v. -inDegree(v) Return the in-degree of v. -outDegree(v) Return the out-degree of v. 688 More Methods ... -adjacentVertices(v) Return an enumeration of the vertices adjacent to v. -inAdjacentVertices(v) Return an enumeration of the vertices adjacent to v along incoming edges. -outAdjacentVertices(v) Return an enumeration of the vertices adjacent to v along outgoing edges. -areAdjacent(v,w) Return whether vertices v and w are adjacent. -endVertices(e) Return an array of size 2 storing the end vertices of e. -origin(e) Return the end vertex from which e leaves. -destination(e) Return the end vertex at which e arrives. -isDirected(e) Return true iff e is directed. 689 Update Methods -makeUndirected(e) Set e to be an undirected edge. -reverseDirection(e) Switch the origin and destination vertices of e. -setDirectionFrom(e, v) Sets the direction of e away from v, one of its end vertices. -setDirectionTo(e, v) Sets the direction of e toward v, one of its end vertices. -insertEdge(v, w, o) Insert and return an undirected edge between v and w, storing o at this position. -insertDirectedEdge(v, w, o) Insert and return a directed edge between v and w, storing o at this position. -insertVertex(o) Insert and return a new (isolated) vertex storing o at this position. -removeEdge(e) Remove edge e. 690 Graph Representations There are two main ways of representing graphs in a computer: • The adjacency matrix representation. • The adjacency list representation. 691 Graph Representations The adjacency matrix representation: 1 if (v, w) E M(v, w) = 0 otherwise A B C D E F A 0 1 0 1 0 0 B C B 1 0 1 0 0 0 A C 0 1 0 1 1 0 F D 1 0 1 0 1 0 D E E 0 0 1 1 0 0 F 0 0 0 0 0 6920 Graph Representations The adjacency matrix representation: Space: 1 if (v, w) E M(v, w) = |V|2 bits 0 otherwise A B C D E F A 0 1 0 1 0 0 B C B 1 0 1 0 0 0 A C 0 1 0 1 1 0 F D 1 0 1 0 1 0 D E E 0 0 1 1 0 0 F 0 0 0 0 0 6930 Graph Representations The adjacency list representation: L(v) = list of w such that (v, w) E, for v V A B D B C B A C A C B D E F D A C E D E E C D F 694 Graph Representations The adjacency list representation: How much space: ? A B D B C B A C A C B D E F D A C E D E E C D F 695 Graph Representations The adjacency list representation: Space: a |V| + 2 b |E| a b A B D B C B A C A C B D E F D A C E D E E C D F 696 Graph Representations The adjacency matrix representation, again, this time representing a directed graph. A B C D E F A 0 1 0 1 0 0 B C B 0 0 1 0 0 0 A C 0 0 0 0 1 0 F D 0 0 1 0 0 0 D E E 0 0 0 1 0 0 F 0 0 0 0 0 6970 Graph Representations The adjacency list representation, again, this time representing a directed graph. A B D B C B C A C E F D C D E E D F 698 Graph Representations The adjacency list representation, again, this time representing a directed graph. How much space? A B D B C B C A C E F D C D E E D F 699 Graph Representations The adjacency list representation, again, this time representing a directed graph. Space: a |V| + b |E| a b A B D B C B C A C E F D C D E E D F 700 Graphs - Kruskal’s Algorithm l Calculate the minimum spanning tree n Put all the vertices into single node trees by themselves n Put all the edges in a priority queue n Repeat until we’ve constructed a spanning tree – Extract cheapest edge – If it forms a cycle, ignore it else add it to the forest of trees (it will join two trees into a larger tree) n Return the spanning tree 701 Graphs - Kruskal’s Algorithm in C Forest MinimumSpanningTree( Graph g, int n, double **costs ) Initial Forest: single vertex trees { Forest T; Queue q; P Queue of edges Edge e; T = ConsForest( g ); q = ConsEdgeQueue( g, costs ); for(i=0;i<(n-1);i++) { do { e = ExtractCheapestEdge( q ); } while ( !Cycle( e, T ) ); AddEdge( T, e ); } return T; } 702 ` Forest MinimumSpanningTree( Graph g, int n, double **costs ) { Forest T; Queue q; We need n-1 edges Edge e; to fully connect (span) T = ConsForest( g ); n vertices q = ConsEdgeQueue( g, costs ); for(i=0;i<(n-1);i++) { do { e = ExtractCheapestEdge( q ); } while ( !Cycle( e, T ) ); AddEdge( T, e ); } return T; } 703 Graphs - Kruskal’s Algorithm in C Forest MinimumSpanningTree( Graph g, int n, double **costs ) { Forest T; Queue q; Edge e; Try the cheapest edge T = ConsForest( g ); q = ConsEdgeQueue( g, costs ); for(i=0;i<(n-1);i++) { do { e = ExtractCheapestEdge( q ); } while ( !Cycle( e, T ) ); AddEdge( T, e ); } Until we find one that doesn’t return T; form a cycle } ... and add it to the forest 704 Kruskal’s Algorithm Forest MinimumSpanningTree( Graph g, int n, double **costs ) { Forest T; Queue q; Edge e; T = ConsForest( g ); q = ConsEdgeQueue( g, costs ); for(i=0;i<(n-1);i++) { do { e = ExtractCheapestEdge( q ); But how do } while ( !Cycle( e, T ) ); we detect a AddEdge( T, e ); cycle? } return T; } 705 Kruskal’s Algorithm in operation Each vertex is its own representative All the vertices are in single element trees 706 Kruskal’s Algorithm in operation Add it to the forest, The cheapest edge joining h and g into a is h-g 2-element tree All the vertices are in single element trees 707 Kruskal’s Algorithm in operation The cheapest edge is h-g Add it to the forest, Choose g as its joining h and g into a representative 2-element tree 708 Kruskal’s Algorithm in operation Add it to the forest, joining c and i into a 2-element tree Choose c as its representative Our forest now has 2 two-element trees and 5 single vertex ones The next cheapest edge is c-i 709 Kruskal’s Algorithm in operation Add it to the forest, joining a and b into a 2-element tree Choose b as its representative Our forest now has 3 two-element trees and 4 single vertex ones The next cheapest edge is a-b 710 Kruskal’s Algorithm in operation Add it to the forest, merging two 2-element trees Choose the rep of one as its representative The next cheapest edge is c-f 711 Kruskal’s Algorithm in operation The rep of g is c The rep of i is also c g-i forms a cycle It’s clearly not needed! The next cheapest edge is g-i 712 Kruskal’s Algorithm in operation The rep of c is c The rep of d is d c-d joins two trees, so we add it .. and keep c as the representative The next cheapest edge is c-d 713 Kruskal’s Algorithm in operation The rep of h is c The rep of i is c h-i forms a cycle, so we skip it The next cheapest edge is h-i 714 Kruskal’s Algorithm in operation The rep of a is b The rep of h is c a-h joins two trees, and we add it The next cheapest edge is a-h 715 Kruskal’s Algorithm in operation But b-c forms a cycle So add d-e instead ... and we now have a spanning tree The next cheapest edge is b-c 716 Prim's Algorithm Select an arbitrary vertex to start. While (there are fringe vertices) select minimum weight edge between tree and fringe add the selected edge and vertex to the tree l The main loop of the algorithm is executed n-1 times; each iteration takes O(n) time. Thus Prim's algorithm takes O(n2) time. l Compare the above two algorithm according to the density of the graph G = (V, E). l What happens to the above two algorithms if we allow edges with negative lengths? 717 Example 718 Example of Prim's Algorithm 719 Example of Prim's Algorithm 720 Graph Algorithms: Shortest Path We are given a weighted, directed graph G = (V, E), with weight function 1 w: E R mapping edges to real valued weights. 5 10 1 8 3 2 3 4 1 1 1 3 6 4 6 5 2 721 Graph Algorithms: Shortest Path 1 The weight of a path 5 10 p = (v , v , . . ., v ) 1 1 2 k is k-1 2 8 3 3 4 S w(v i , vi+1). i=1 1 The weight of the path 1 1 3 6 4 along the red edges is 1 + 6 + 1 + 4 = 12. 6 5 2 722 Graph Algorithms: Shortest Path 1 The weight of a path 5 10 p = (v , v , . . ., v ) 1 1 2 k is k-1 2 8 3 3 4 S w(v i , vi+1). i=1 1 Single source shortest path 1 1 3 6 4 problem: given a vertex s, for 6 every vertex v V find a 5 2 shortest path from s to v. 723 Graph Algorithms: Shortest Path Single source shortest path problem: given vertex s, 1 for every vertex v inV find a 10 5 shortest path from s to v. 1 8 3 2 3 4 Dijkstra’s algorithm solves this problem efficiently for the 1 1 1 3 case in which all weights are 6 4 nonnegative (as in the 6 5 example graph). 2 724 Graph Algorithms: Shortest Path Dijkstra’s algorithm maintains a set S 1 of vertices whose final shortest path 5 weights have already been determined. 10 1 8 3 2 3 4 It also maintains, for each 1 vertex v not in S, an upper 1 1 3 bound d[v] on the weight 6 4 of a shortest path from 6 source s to v. 5 2 725 Graph Algorithms: Shortest Path 1 It also maintains, for each 5 vertex v not in S, an upper 10 1 bound d[v] on the weight 8 3 of a shortest path from 2 3 4 source s to v. 1 The algorithm repeatedly selects 1 1 3 6 4 the vertex u V – S with minimum bound d[v], inserts u into S, 6 2 5 and relaxes all edges leaving 726 u. Graph Algorithms: Shortest Path Suppose vertex 1 is the source. s 1 Set S = { } initially. 5 10 1 v 1 2 3 4 5 6 8 3 2 3 4 d 0 1 1 1 3 6 4 Also initialize a queue with all 6 the vertices and their upper 5 2 bounds. 727 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 S={} 5 10 1 v 1 2 3 4 5 6 8 3 2 3 4 d 0 1 1 3 Select the vertex u V – S with 1 6 4 minimum bound d[v], insert 6 u into S, . . . 5 2 728 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 (here we keep the bound S= 5 0 with the vertex in S) 10 1 v 2 3 4 5 6 8 3 2 3 4 d 1 . . . remove it from the 1 1 3 6 4 queue, insert it in S,. . . 6 5 2 729 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 S= 5 0 10 1 v 2 3 4 5 6 8 3 2 3 4 d 10 1 5 1 . . . and relax the edges from 1 1 3 6 4 this vertex. 6 5 2 730 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 S= 5 0 10 1 v 3 4 2 5 6 8 3 2 3 4 d 1 5 10 1 . . . reordering the queue 1 1 3 6 4 according to the new upper 6 bounds. 5 2 731 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 S= 5 0 10 1 v 3 4 2 5 6 8 3 2 3 4 d 1 5 10 1 Repeat . . . 1 1 3 6 4 6 5 2 732 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 S= 5 0 1 10 1 v 4 2 5 6 8 3 2 3 4 d 5 10 1 . . . remove from queue and 1 1 3 6 4 put in S 6 5 2 733 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 S= 5 0 1 10 1 v 4 2 5 6 8 3 2 3 4 d 4 9 2 1 . . . relax the edges . . . 1 1 3 6 4 6 5 2 734 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 S= 5 0 1 10 1 v 5 4 2 6 8 3 2 3 4 d 2 4 9 1 . . . and reorder the queue . . . 1 1 3 6 4 6 5 2 735 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 S= 5 0 1 10 1 v 5 4 2 6 8 3 2 3 4 d 2 4 9 1 Repeat . . . 1 1 3 6 4 6 5 2 736 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 5 S= 5 0 1 2 10 1 v 4 2 6 8 3 2 3 4 d 4 9 1 . . . remove from queue and 1 1 3 6 4 put in S 6 5 2 737 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 5 S= 5 0 1 2 10 1 v 4 2 6 8 3 2 3 4 d 4 9 4 1 . . . relax the edges . . . 1 1 3 6 4 6 5 2 738 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 5 S= 5 0 1 2 10 1 v 4 6 2 8 3 2 3 4 d 4 4 9 1 . . . and reorder the queue . . . 1 1 3 6 4 6 5 2 739 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 5 S= 5 0 1 2 10 1 v 4 6 2 8 3 2 3 4 d 4 4 9 1 Repeat . . . 1 1 3 6 4 6 5 2 740 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 S= 5 0 1 4 2 10 1 v 6 2 8 3 2 3 4 d 4 9 1 . . . remove from queue and 1 1 3 6 4 put in S 6 5 2 741 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 S= 5 0 1 4 2 10 1 v 6 2 8 3 2 3 4 d 4 9 1 . . . relax the edges (no change 1 1 3 6 4 in this case) . . . 6 5 2 742 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 S= 5 0 1 4 2 10 1 v 6 2 8 3 2 3 4 d 4 9 1 . . . and reorder the queue 1 1 3 6 4 (no change in this case) . . . 6 5 2 743 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 S= 5 0 1 4 2 10 1 v 6 2 8 3 2 3 4 d 4 9 1 Repeat . . . 1 1 3 6 4 6 5 2 744 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 6 S= 5 0 1 4 2 4 10 1 v 2 8 3 2 3 4 d 9 1 . . . remove from queue and 1 1 3 6 4 put in S 6 5 2 745 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 6 S= 5 0 1 4 2 4 10 1 v 2 8 3 2 3 4 d 9 1 . . . relax the edges (no change 1 1 3 6 4 in this case) . . . 6 5 2 746 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 3 4 5 6 S= 5 0 1 4 2 4 10 1 v 2 8 3 2 3 4 d 9 1 Repeat . . . 1 1 3 6 4 6 5 2 747 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 1 2 3 4 5 6 S= 5 0 9 1 4 2 4 10 1 v 8 3 2 3 4 d 1 Done! 1 1 3 6 4 6 5 2 748 Graph Algorithms: Shortest Path Suppose vertex 1 Dijkstra’s algorithm maintains a set S is the source. of vertices whose final shortest path s weights have already been determined. 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 8 3 2 3 4 The result is the bottom row 1 which contains the length of 1 1 3 6 4 the shortest path from s to the vertex above it. 6 5 2 749 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 To compute the corresponding 1 paths, we augment the data 1 1 3 6 4 structure with an additional attribute, p(v), which is the 6 vertex that precedes v in a 5 2 shortest path. 750 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 Using the predecessor 1 attribute, p(v), it’s easy to 1 1 3 construct the path to v, working 6 4 backwards from v to s. 6 5 2 751 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 E.g., v = 6. 1 1 1 3 6 4 6 5 2 752 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 E.g., v = 6. 1 p(6) = 5, 1 1 3 6 4 6 5 2 753 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 E.g., v = 6. 1 p(6) = 5, 1 1 3 p(5) = 3, 6 4 6 5 2 754 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 E.g., v = 6. 1 p(6) = 5, 1 1 3 p(5) = 3, 6 4 p(3) = 1. 6 5 2 755 Graph Algorithms: Shortest Path s 1 v 1 2 3 4 5 6 S= 5 d 0 9 1 4 2 4 10 1 p 3 1 3 3 5 8 3 2 3 4 E.g., v = 6. 1 p(6) = 5, 1 1 3 p(5) = 3, 6 4 p(3) = 1. 6 5 Path: 1, 3, 5, 6. 2 756 Weight: 4. Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed how many times? 757 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. 758 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed how many times? 759 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed |E| times. • Total time = |V| T Delete_min + |E| T Decrease_key 760 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed |E| times. • Total time = |V| T Delete_min + |E| TDecrease_key Priority queue T T Decrease_key Total time Delete_min Array Binary heap 761 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed |E| times. • Total time = |V| T Delete_min + |E| TDecrease_key Priority queue T T Decrease_key Total time Delete_min Array O(|V|) O(1) Binary heap 762 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed |E| times. • Total time = |V| T Delete_min + |E| TDecrease_key Priority queue T T Decrease_key Total time Delete_min 2 Array O(|V|) O(1) O(|V| ) Binary heap O(log |V|) O(log |V|) 763 Graph Algorithms: Shortest Path Computing time analysis: look at different implementations of the priority queue, with different costs for the queue operations. • Delete_min executed |V| times. • Decrease_key executed |E| times. • Total time = |V| T Delete_min + |E| TDecrease_key Priority queue T T Total time Delete_min Decrease_key Unsorted Array O(|V|) O(1) O(|V| 2 ) Binary heap O(log |V|) O(log |V|) O(E log |V|) 764

DOCUMENT INFO

Shared By:

Categories:

Tags:

Stats:

views: | 12 |

posted: | 3/25/2012 |

language: | |

pages: | 764 |

Docstoc is the premier online destination to start and grow small businesses. It hosts the best quality and widest selection of professional documents (over 20 million) and resources including expert videos, articles and productivity tools to make every small business better.

Search or Browse for any specific document or resource you need for your business. Or explore our curated resources for Starting a Business, Growing a Business or for Professional Development.

Feel free to Contact Us with any questions you might have.