SVVRL IM NTU ArrayBased Implementations The ADT Bag
SVVRL @ IM. NTU Array-Based Implementations The ADT Bag as an Example Yih-Kuen Tsay Dept. of Information Management National Taiwan University Based on [Carrano and Henry 2013] With Contributions by Ling-Chieh Kung 1 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 2 / 70
SVVRL @ IM. NTU The ADT Bag n We want to implement an ADT “Bag” of items whose types are “Item. Type: ” q q q q n n +get. Current. Size(): integer +is. Empty(): boolean +add(new. Entry: Item. Type): boolean // duplicates are allowed +remove(an. Entry: Item. Type): boolean // remove only one copy +clear(): void +get. Frequency. Of(an. Entry: Item. Type): integer +contains(an. Entry: Item. Type): boolean +print(): void Specifications indicate what the operations do, not how they are implemented. Let’s begin with a bag of C++ strings. Yih-Kuen Tsay DS 2017: Array-Based Implementations 3 / 70
SVVRL @ IM. NTU Implementing the ADT Bag (1/4) n Implementing the ADT as a C++ class provides ways to enforce a wall: q This prevents one from accessing the data without using the defined operations. Source: Figure 3 -1 [Carrano and Henry 2015] Yih-Kuen Tsay DS 2017: Array-Based Implementations 4 / 70
SVVRL @ IM. NTU Implementing the ADT Bag (2/4) n The abstract class Bag. Interface defines the behaviors of the ADT. q In many cases, no member variable is needed for the abstract class Bag. Interface { public: virtual int get. Current. Size() const = 0; virtual bool is. Empty() const = 0; virtual bool add(const string& new. Entry) = 0; virtual bool remove(const string& an. Entry) = 0; virtual void clear() = 0; virtual int get. Frequency. Of(const string& an. Entry) const = 0; virtual bool contains(const string& an. Entry) const = 0; virtual void print() const = 0; }; Yih-Kuen Tsay DS 2017: Array-Based Implementations 5 / 70
SVVRL @ IM. NTU Implementing the ADT Bag (3/4) n To implement the ADT, we write a (concrete) class to inherit Bag. Interface and implement all the operations. Yih-Kuen Tsay class Array. Bag : public Bag. Interface { private: //. . . public: Array. Bag(); int get. Current. Size() const; bool is. Empty() const; bool add(const string& new. Entry); bool remove(const string& an. Entry); void clear(); bool contains(const string& an. Entry) const; int get. Frequency. Of(const string& an. Entry) const; void print() const; }; DS 2017: Array-Based Implementations 6 / 70
SVVRL @ IM. NTU Implementing the ADT Bag (4/4) n n Now it is time to choose a data structure. For the ADT Bag, we will try two different data structures: q n An array and a linked list. Let’s use a fixed-size (static) array first. q q In a fixed-size array, each item occupies one entry of the array. These items are unsorted. A one-dimensional unsorted array will be used. Source: Figure 3 -2 [Carrano and Henry 2015] Yih-Kuen Tsay DS 2017: Array-Based Implementations 7 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 8 / 70
Using a Fixed-Size Array n n What else should we keep track of when we use a fixed-size array? q The maximum size of the array. q The number of items currently stored. We add member variable declarations to the private section. Yih-Kuen Tsay SVVRL @ IM. NTU class Array. Bag : public Bag. Interface { private: static const int DEFAULT_CAPACITY = 6; string items[DEFAULT_CAPACITY]; int item. Count; int max. Items; // may have something else. . . public: // those member functions. . . }; DS 2017: Array-Based Implementations 9 / 70
SVVRL @ IM. NTU Implementing Member Functions n n Some member functions are pretty straightforward. q Note that these should be constant member functions. How would you add a constructor to choose a maximum number of items? Yih-Kuen Tsay Array. Bag: : Array. Bag() : item. Count(0), max. Items(DEFAULT_CAPACITY) {} int Array. Bag: : get. Current. Size() const { return item. Count; } bool Array. Bag: : is. Empty() const { return item. Count == 0; } void Array. Bag: : print() const { for(int i = 0; i < item. Count; i++) cout << items[i] << " "; cout << endl; } DS 2017: Array-Based Implementations 10 / 70
SVVRL @ IM. NTU The Member Function add() (1/2) n For adding an item: q q n If there is room, store the item somewhere in the array (where? ) Return true if there is room, or false otherwise. Let’s put it in the first empty cell. q q If the array has no “hole, ” its index is exactly item. Count. Otherwise, we may need to search from the beginning. Source: Figure 3 -3 [Carrano and Henry 2015]: After adding an item Yih-Kuen Tsay DS 2017: Array-Based Implementations 11 / 70
SVVRL @ IM. NTU The Member Function add() (2/2) n As long as the array has no hole, adding an item is easy. q When we remove an item, we need to maintain this property! bool Array. Bag: : add(const string& new. Entry) { bool has. Room. To. Add = (item. Count < max. Items); if(has. Room. To. Add) { items[item. Count] = new. Entry; item. Count++; } return has. Room. To. Add; } n Why using a constant reference? Why not just string new. Entry? Yih-Kuen Tsay DS 2017: Array-Based Implementations 12 / 70
Testing the Implementations n n n Before we try to implement something more, test your existing member functions. Once you have your add() function, you may test the constructor, is. Empty(), get. Current. Size(), and print(). In fact, print() is to test add() and other member functions. Yih-Kuen Tsay SVVRL @ IM. NTU int main() { Array. Bag bag; bag. add("aaa"); bag. print(); cout << bag. is. Empty(); cout << bag. get. Current. Size(); bag. add("bbb"); bag. print(); cout << bag. is. Empty(); cout << bag. get. Current. Size(); return 0; } DS 2017: Array-Based Implementations 13 / 70
SVVRL @ IM. NTU The Member Function remove() n For removing a given item: q q n Note that we need to determine whether a given item exists. q q n Remove one copy if it exists in the array. Return true if the item exists, or false otherwise. This is exactly the function contains(). Moreover, we need to locate that item. We may enhance modularity (and make the development more efficient) by implementing a member function to be a building block. Yih-Kuen Tsay DS 2017: Array-Based Implementations 14 / 70
SVVRL @ IM. NTU The Member Function get. Index. Of() n Let’s implement a member function get. Index. Of(). q q get. Index. Of(an. Entry: Item. Type): integer Given an item, return the index of its first copy in the array or – 1 otherwise. Source: Figure 3 -4 [Carrano and Henry 2015] n Define things precisely: Returning an array index or a rank of an item? Yih-Kuen Tsay DS 2017: Array-Based Implementations 15 / 70
SVVRL @ IM. NTU The Member Function get. Index. Of() int Array. Bag: : get. Index. Of(const string& target) const { bool found = false; int result = -1; int search. Index = 0; while(!found && (search. Index < item. Count)) { if(items[search. Index] == target) { found = true; result = search. Index; } else search. Index++; } return result; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 16 / 70
Privatizing get. Index. Of() n n The function get. Index. Of() should be private! If it is public, clients will know some details of the private array. q n Data hiding (encapsulation, the “wall”) would be damaged. SVVRL @ IM. NTU class Array. Bag : public Bag. Interface { private: static const int DEFAULT_CAPACITY = 6; string items[DEFAULT_CAPACITY]; int item. Count; int max. Items; int get. Index. Of(const string& target) const; public: // those member functions. . . }; As long as one thing is useless to clients, hide it! Yih-Kuen Tsay DS 2017: Array-Based Implementations 17 / 70
SVVRL @ IM. NTU The Member Function remove() n n With get. Index. Of(), remove() can be easily implemented. How to “remove the item while ensuring no hole? ” Yih-Kuen Tsay remove(an. Entry) { Search the array items for an. Entry if(an. Entry is in the bag at items[index]) { Decrement the counter item. Count remove the item while ensuring no hole return true } else return false } DS 2017: Array-Based Implementations 18 / 70
Ensuring No Hole (Idea 1) SVVRL @ IM. NTU Source: Figure 3 -5 [Carrano and Henry 2015] Yih-Kuen Tsay DS 2017: Array-Based Implementations 19 / 70
Ensuring No Hole (Idea 2) SVVRL @ IM. NTU Source: Figure 3 -6 [Carrano and Henry 2015] Yih-Kuen Tsay DS 2017: Array-Based Implementations 20 / 70
Implementing remove() bool Array. Bag: : remove(const string& an. Entry) { int located. Index = get. Index. Of(an. Entry); bool can. Remove. Item = (located. Index > -1); if(can. Remove. Item) { item. Count--; items[located. Index] = items[item. Count]; } return can. Remove. Item; } Yih-Kuen Tsay SVVRL @ IM. NTU remove(an. Entry) { Search the array items for an. Entry if(an. Entry is in the bag at items[index]) { Decrement the counter item. Count remove the item while ensuring no hole return true } else return false } DS 2017: Array-Based Implementations 21 / 70
SVVRL @ IM. NTU Functions contains() and clear() n The functions contains() is straightforward. bool Array. Bag: : contains(const string& an. Entry) const { return get. Index. Of(an. Entry) > -1; } n How about clear()? Which one is better? void Array. Bag: : clear() { while(!is. Empty()) remove(items[1]); } Yih-Kuen Tsay void Array. Bag: : clear() { item. Count = 0; } DS 2017: Array-Based Implementations 22 / 70
SVVRL @ IM. NTU Member function get. Frequency. Of() returns the number of occurrences of a given item. int Array. Bag: : get. Frequency. Of(const string& an. Entry) const { int frequency = 0; int cur. Index = 0; while(cur. Index < item. Count) { if(items[cur. Index] == an. Entry) frequency++; cur. Index++; } return frequency; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 23 / 70
SVVRL @ IM. NTU Remarks n Before starting the implementation, always “design” the program first. q q q n Design the ADT. In particular, design the operations and behaviors. Write an abstract class to specify the operations. Write a concrete class to inherit the abstract class. Implement the class. For a specific function, pseudocodes are helpful. Test the implementation. Do not forget data hiding: q q If something is not useful for clients, hide it. E. g. , do not let clients know whether you starts at items[0] or items[1]. Yih-Kuen Tsay DS 2017: Array-Based Implementations 24 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 25 / 70
SVVRL @ IM. NTU Recursion n Though not required, some functions can be implemented with recursion. In many cases, a task that needs to go through a data structure can be implemented with recursion. Let’s look at two examples. Yih-Kuen Tsay DS 2017: Array-Based Implementations 26 / 70
SVVRL @ IM. NTU Using recursion for get. Index. Of() int Array. Bag: : get. Index. Of(const string& target, int search. Index) const { // search within items[search. Index. . (item. Count – 1)] int result = -1; if(search. Index < item. Count) { if(items[search. Index] == target) result = search. Index; else result = get. Index. Of(target, search. Index + 1); } return result; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 27 / 70
SVVRL @ IM. NTU Using recursion for get. Frequency. Of() int Array. Bag: : get. Frequency. Of(const string& an. Entry) const { return count. Frequency(an. Entry, 0); } int Array. Bag: : count. Frequency(const string& target, int search. Index) const { // count within items[search. Index. . (item. Count – 1)] int frequency = 0; if (search. Index < item. Count) { if (items[search. Index] == target) frequency = 1 + count. Frequency(target, search. Index + 1); else frequency = count. Frequency(target, search. Index + 1); } return frequency; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 28 / 70
SVVRL @ IM. NTU Using Recursion for the Two Functions n The ways of applying recursion on get. Index. Of() and get. Frequency. Of() are different. q q n We add a second parameter to get. Index. Of(). We create a new function count. Frequency() for get. Frequency. Of(). The key factor determining the difference is their visibility. q q q A private function is only used in the class. Its header can be modified. A public function is called by a client. Its header should remain unchanged. If we add search. Index to the public function header, we reveal some information about the implementation. This violates data hiding. Yih-Kuen Tsay DS 2017: Array-Based Implementations 29 / 70
SVVRL @ IM. NTU Dynamically Adjusting the Array Size n n In the previous implementation, the array size is fixed. With dynamic memory allocation (DMA), we may make it changeable. q E. g. , let’s double the array length when it is full. Yih-Kuen Tsay DS 2017: Array-Based Implementations 30 / 70
SVVRL @ IM. NTU Modifying the Class Definition n To do so, first we change the class definition. q q q items becomes (purely) a pointer rather than a (static) array. When we implement DMA, we need a destructor. All others are unchanged. Yih-Kuen Tsay class Array. Bag : public Bag. Interface { private: static const int DEFAULT_CAPACITY = 6; string* items; int item. Count; int max. Items; int get. Index. Of(const string& target) const; public: Array. Bag(); ~Array. Bag(); // others are not changed }; DS 2017: Array-Based Implementations 31 / 70
SVVRL @ IM. NTU The Constructor and Destructor n The constructor is modified to initialize items. q n It points to a dynamic array. The destructor releases the dynamic array. Yih-Kuen Tsay Array. Bag: : Array. Bag() : item. Count(0), max. Items(DEFAULT_CAPACITY) { items = new string[DEFAULT_CAPACITY]; } Array. Bag: : ~Array. Bag() { delete [] items; } DS 2017: Array-Based Implementations 32 / 70
The Member Function add() is modified: q n When the array is full, double the array length. We use a local pointer old. Array to point to the existing array. q q n SVVRL @ IM. NTU Do this before you use items to point to the new array. Otherwise, you will have memory leak. Then release the old space. Yih-Kuen Tsay bool Array. Bag: : add(const string& new. Entry) { bool has. Room. To. Add = (item. Count < max. Items); if(!has. Room. To. Add) { string* old. Array = items; items = new string[2 * max. Items]; for(int index = 0; index < max. Items; index++) items[index] = old. Array[index]; delete [] old. Array; max. Items = 2 * max. Items; } items[item. Count] = new. Entry; item. Count++; return true; } DS 2017: Array-Based Implementations 33 / 70
SVVRL @ IM. NTU Should We Make the Array Dynamic? n A dynamic array is of course useful. q n Disadvantages: q q n There is no need to worry about whether the array is full. It can hurt efficiency: Every time when the array is full, we need to allocate a new space, copy and paste, and releasing an old space. It can waste spaces (as all static arrays do). Another way to prevent your bag from being full is to use a link-based implementation. Yih-Kuen Tsay DS 2017: Array-Based Implementations 34 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 35 / 70
Items in the ADT Bag n n n Our ADT Bag contains items. We implemented it as a bag of (C++) strings. What if we want to implement it as a bag of integers? Yih-Kuen Tsay SVVRL @ IM. NTU class Array. Bag : public Bag. Interface { private: static const int DEFAULT_CAPACITY = 6; string items[DEFAULT_CAPACITY]; //. . . public: //. . . bool add(const string& new. Entry); bool remove(const string& an. Entry); //. . . }; DS 2017: Array-Based Implementations 36 / 70
Templates (1/2) n We hope that our implementation is “general: ” q q n In a bag, all items will be of a single type. For different bags, the item types can be different. In C++, templates make this possible. q q n SVVRL @ IM. NTU It can be applied on functions and classes. Note: the notion of a template is not unique to objectoriented programming. This is called generic programming. Yih-Kuen Tsay DS 2017: Array-Based Implementations 37 / 70
Templates (2/2) n C++ class templates allow one to pass a datatype argument when: q q n Invoking a function defined with templates, or Creating an object whose class is defined with templates. In our example, objects of Array. Bag can be created with the actual item type passed as an argument. q q n SVVRL @ IM. NTU Array. Bag<string> bag. Of. Strings; Array. Bag<int> bag. Of. Integers; No need to write two implementations! Yih-Kuen Tsay DS 2017: Array-Based Implementations 38 / 70
Template Declaration n SVVRL @ IM. NTU To declare a type parameter, use the keywords template and typename. template<typename T> class The. Class. Name { // T can be treated as a type inside the class definition block }; Some old codes write class instead of typename. Both are fine. We then do this to all member functions: q n template<typename T> T The. Class. Name<T>: : f(T t) { // t is a variable whose type is T }; Yih-Kuen Tsay template<typename T> void The. Class. Name<T>: : f(int i) { // follow the rule even if T is not used }; DS 2017: Array-Based Implementations 39 / 70
Template Invocation n SVVRL @ IM. NTU To instantiate an object, pass a type argument. int main() { The. Class. Name<int> a; The. Class. Name<double> b; The. Class. Name<Another. Class. Name> c; }; n The passed type will then replace all the Ts in the class definition. Yih-Kuen Tsay DS 2017: Array-Based Implementations 40 / 70
SVVRL @ IM. NTU An Example n n Let’s start from an example with no classes. When we invoke f with f<double>, the function is void f(double t) { cout << t; } When we invoke f with f<int>, the function is That is why Yih-Kuen Tsay void f(int t) { cout << t; we }see 1. #include <iostream> using namespace std; template<typename T> void f(T t) { cout << t; } int main() { f<double>(1. 2); // 1. 2 f<int>(1. 2); // 1 return 0; } DS 2017: Array-Based Implementations 41 / 70
SVVRL @ IM. NTU An Example with Two Type Parameters n We may also have multiple type parameters. #include <iostream> using namespace std; template<typename A, typename B> void g(A a, B b) { cout << a + b << endl; } int main() { g<double, int>(1. 2, 1); return 0; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 42 / 70
SVVRL @ IM. NTU An Example with Classes n The syntax of applying templates to classes is very similar. q q q Add the declaration line to the class definition. Add the declaration line to all member function definitions. For each member function definition, specify the type parameter. int main() { C<int> c; cout << c. f() << endl; return 0; } Yih-Kuen Tsay #include <iostream> using namespace std; template<typename T> class C { public: T f(); }; template<typename T> T C<T>: : f() { return 1. 2; } DS 2017: Array-Based Implementations 43 / 70
SVVRL @ IM. NTU Applying Templates to Bag. Interface (1/2) n Before we use a template, Bag. Interface was: class Bag. Interface { public: virtual int get. Current. Size() const = 0; virtual bool is. Empty() const = 0; virtual bool add(const string& new. Entry) = 0; virtual bool remove(const string& an. Entry) = 0; virtual void clear() = 0; virtual int get. Frequency. Of(const string& an. Entry) const = 0; virtual bool contains(const string& an. Entry) const = 0; virtual void print() const = 0; }; Yih-Kuen Tsay DS 2017: Array-Based Implementations 44 / 70
SVVRL @ IM. NTU Applying Templates to Bag. Interface (2/2) n After we use a template, Bag. Interface becomes: template<typename Item. Type> // add this line class Bag. Interface { public: virtual int get. Current. Size() const = 0; virtual bool is. Empty() const = 0; virtual bool add(const Item. Type& new. Entry) = 0; // treat Item. Type as a type virtual bool remove(const Item. Type& an. Entry) = 0; virtual void clear() = 0; virtual int get. Frequency. Of(const Item. Type& an. Entry) const = 0; virtual bool contains(const Item. Type& an. Entry) const = 0; virtual void print() const = 0; }; Yih-Kuen Tsay DS 2017: Array-Based Implementations 45 / 70
SVVRL @ IM. NTU Applying Templates to Array. Bag (1/2) template<typename Item. Type> class Array. Bag : public Bag. Interface<Item. Type> { private: static const int DEFAULT_CAPACITY = 6; Item. Type items[DEFAULT_CAPACITY]; int item. Count; int max. Items; int get. Index. Of(const Item. Type& target) const; public: // others that do not need Item. Type bool add(const Item. Type& new. Entry); bool remove(const Item. Type& an. Entry); bool contains(const Item. Type& an. Entry) const; int get. Frequency. Of(const Item. Type& an. Entry) const; }; Yih-Kuen Tsay DS 2017: Array-Based Implementations 46 / 70
SVVRL @ IM. NTU Applying Templates to Array. Bag (2/2) template<typename Item. Type> // add this even if not used bool Array. Bag<Item. Type>: : is. Empty() const // add this even if not used { return item. Count == 0; } template<typename Item. Type> bool Array. Bag<Item. Type>: : add(const Item. Type& new. Entry) { // Item. Type can be used in the function definition bool has. Room. To. Add = (item. Count < max. Items); if(has. Room. To. Add) { items[item. Count] = new. Entry; item. Count++; } return has. Room. To. Add; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 47 / 70
SVVRL @ IM. NTU Using Array. Bag with Templates n Now we can have bags for different types of items. int main() { Array. Bag<string> bag. Of. Strings; Array. Bag<int> bag. Of. Integers; Array. Bag<My. Class> bag. Special; bag. Of. Strings. add("here"); bag. Of. Integers. add(123); My. Class mc; bag. Special. add(mc); return 0; } Yih-Kuen Tsay DS 2017: Array-Based Implementations 48 / 70
Final Remarks (1/2) n SVVRL @ IM. NTU An operation may need a special definition for a given type. template<typename Item. Type> bool Array. Bag<Item. Type>: : add(const Item. Type& new. Entry) { bool has. Room. To. Add = (item. Count < max. Items); if(has. Room. To. Add) { items[item. Count] = new. Entry; item. Count++; } return has. Room. To. Add; } n What if Item. Type is a class with dynamic memory allocation? Yih-Kuen Tsay DS 2017: Array-Based Implementations 49 / 70
Final Remarks (2/2) n n n What if Item. Type is a class with undefined comparisons? We need to (re)define operations for our classes. We need to do operator overloading. p To be introduced in the next lecture. Yih-Kuen Tsay SVVRL @ IM. NTU template<typename Item. Type> int Array. Bag<Item. Type> : : get. Frequency. Of(const Item. Type& an. Entry) const { int frequency = 0; int cur. Index = 0; while(cur. Index < item. Count) class Ra. Num { { if(items[cur. Index] == an. Entry) private: frequency++; int num; cur. Index++; int deno; } public: return frequency; //. . . } }; DS 2017: Array-Based Implementations 50 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 51 / 70
SVVRL @ IM. NTU Libraries n There are many C++ standard libraries. q n We may also want to define our own libraries. q q q n <iostream>, <climits>, <cmath>, <cctype>, <cstring>, etc. Especially when we collaborate with others. Typically, one implements classes or global functions for others to use. That function can be defined in a self-defined library. A library includes a header file (. h) and a source file (. cpp). q q The header file contains declarations The source file contains definitions/implementations. Yih-Kuen Tsay DS 2017: Array-Based Implementations 52 / 70
SVVRL @ IM. NTU Example n Consider the following program with a single function my. Max(): #include <iostream> using namespace std; int my. Max(int [], int); int main() { int a[5] = {7, 2, 5, 8, 9}; cout << my. Max(a, 5); return 0; } n int my. Max(int a[], int len) { int max = a[0]; for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } Let’s define a constant variable for the array length in a header file. Yih-Kuen Tsay DS 2017: Array-Based Implementations 53 / 70
SVVRL @ IM. NTU Defining Variables in a Library my. Max. h const int LEN = 5; main. cpp #include <iostream> #include "my. Max. h" using namespace std; int my. Max(int [], int); int main() { int a[LEN] = {7, 2, 5, 8, 9}; cout << my. Max (a, LEN); return 0; } Yih-Kuen Tsay int my. Max(int a[], int len) { int max = a[0]; for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } DS 2017: Array-Based Implementations 54 / 70
Including a Header File n When your main program wants to include a selfdefined header file, simply indicate its path and file name. q q n n SVVRL @ IM. NTU #include "my. Max. h" #include "D: /test/my. Max. h" #include "lib/my. Max. h" Using or / does not matter (on Windows). We still compile the main program as usual. Let’s also define functions in our library! q Now we need a source file. Yih-Kuen Tsay DS 2017: Array-Based Implementations 55 / 70
SVVRL @ IM. NTU Defining Functions in a Library my. Max. h my. Max. cpp const int LEN = 5; int my. Max(int [], int); main. cpp #include <iostream> #include "my. Max. h" using namespace std; int main() { int a[LEN] = {7, 2, 5, 8, 9}; cout << my. Max(a, LEN); return 0; } Yih-Kuen Tsay int my. Max(int a[], int len) { int max = a[0]; for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } DS 2017: Array-Based Implementations 56 / 70
SVVRL @ IM. NTU Including a Header and a Source File n When your main program also wants to include a self-defined source file, the include statement needs not be changed. q n We add a source file my. Max. cpp. q q n #include "my. Max. h" In the source file, we implement those functions declared in the header file. The main file names of the header and source files can be different. The two source files (main. cpp and my. Max. cpp) must be compiled together. q Each environment has its own way. Yih-Kuen Tsay DS 2017: Array-Based Implementations 57 / 70
SVVRL @ IM. NTU Defining One More Function (1/2) my. Max. h my. Max. cpp const int LEN = 5; int my. Max (int [], int); void print(int); main. cpp #include <iostream> #include "my. Max. h" using namespace std; int main() { int a[LEN] = {7, 2, 5, 8, 9}; print(my. Max(a, LEN)); return 0; } Yih-Kuen Tsay int my. Max(int a[], int len) { int max = a[0]; for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } void print(int i) { cout << i; // cout undefined! } DS 2017: Array-Based Implementations 58 / 70
SVVRL @ IM. NTU Defining One More Function (2/2) n n #include <iostream> Each source file contains using namespace std; int my. Max(int a[], int len) statements to run. { Each source file must include the int max = a[0]; libraries it needs for its statements. for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } void print(int i) { cout << i; // good! } Yih-Kuen Tsay DS 2017: Array-Based Implementations 59 / 70
The Complete Set of Files my. Max. h my. Max. cpp const int LEN = 5; int my. Max(int [], int); void print(int); main. cpp #include <iostream> #include "my. Max. h" using namespace std; int main() { int a[LEN] = {7, 2, 5, 8, 9}; print(my. Max (a, LEN)); return 0; } Yih-Kuen Tsay SVVRL @ IM. NTU #include <iostream> using namespace std; int my. Max(int a[], int len) { int max = a[0]; for(int i = 1; i < len; i++) { if(a[i] > max) max = a[i]; } return max; } void print(int i) { cout << i; } DS 2017: Array-Based Implementations 60 / 70
SVVRL @ IM. NTU Remarks n In many cases, my. Max. cpp also include my. Max. h. q n E. g. , if LEN is accessed in my. Max. cpp. More will be discussed in further courses. q q main. cpp C++ Standard Libraries my. Max. cpp my. Max. h More than two source files. A header file including another header file. Yih-Kuen Tsay DS 2017: Array-Based Implementations 61 / 70
SVVRL @ IM. NTU Header Files for Array. Bag (1/4) n n First, we put the definition of Bag. Interface into a file Bag. Interface. h. In general, the inclusion relationship can be very complicated. q n One thing may be defined multiple times (which is an error) if one file is included multiple times. #ifndef _BAG_INTERFACE #define _BAG_INTERFACE template<typename Item. Type> class Bag. Interface { // all those member functions }; #endif To avoid this, q q q (Bag. Interface. h) We use #define to define a token. #ifndef checks whether a given token has been defined; #endif labels the end of a block. Yih-Kuen Tsay DS 2017: Array-Based Implementations 62 / 70
SVVRL @ IM. NTU Header Files for Array. Bag (2/4) n n n Second, we put the definition of Array. Bag into Array. Bag. h. We still use #define, #ifndef, and #endif to avoid multiple definitions. Because this class needs an implementation, we add an include statement at the end to include the implementation file Array. Bag. cpp. Yih-Kuen Tsay #ifndef _ARRAY_BAG #define _ARRAY_BAG #include "Bag. Interface. h" template<typename Item. Type> class Array. Bag : public Bag. Interface<Item. Type> { // all those member variables and functions }; #include "Array. Bag. cpp" #endif (Array. Bag. h) DS 2017: Array-Based Implementations 63 / 70
SVVRL @ IM. NTU Header Files for Array. Bag (3/4) n n n Third, we put the implementation of Array. Bag into Array. Bag. cpp. In Array. Bag. cpp, we need to include the header file Array. Bag. h. When a standard library is used in an implementation file, we need to include it. #include <iostream> #include "Array. Bag. h" using namespace std; // all other function definitions template<typename Item. Type> void Array. Bag<Item. Type>: : print() const { for(int i = 0; i < item. Count; i++) cout << items[i] << " "; cout << endl; } // all other function definitions (Array. Bag. cpp) Yih-Kuen Tsay DS 2017: Array-Based Implementations 64 / 70
SVVRL @ IM. NTU Header Files for Array. Bag (4/4) n n Now, for any client who uses the class Array. Bag, all it needs to do is to include Array. Bag. h. For those who want to understand how Array. Bag should be used, they only need to read the header file. q q Comments in Array. Bag. h should be understandable to client developers. Implementation details should not be disclosed. Yih-Kuen Tsay #include <iostream> #include <string> #include "Array. Bag. h" using namespace std; int main() { Array. Bag<string> bag; return 0; } DS 2017: Array-Based Implementations (main. cpp) 65 / 70
SVVRL @ IM. NTU Outline n n n The ADT Bag (of Strings) Implementation with an Array Recursion and DMA The (Generic) ADT Bag Self-Defined Header Files The Standard Library <vector> Yih-Kuen Tsay DS 2017: Array-Based Implementations 66 / 70
Displaying Bag Items n n SVVRL @ IM. NTU In the textbook, the implementation of Array. Bag does not contain print(). To allow one to display bag items, a member function to. Vector() and a global function display. Bag() are defined: template<class Item. Type> vector<Item. Type> Array. Bag<Item. Type> : : to. Vector() const { vector<Item. Type> bag. Contents; for(int i = 0; i < item. Count; i++) bag. Contents. push_back(items[i]); return bag. Contents; } Yih-Kuen Tsay void display. Bag(Array. Bag<string>& bag) { cout << "The bag contains " << bag. get. Current. Size() << " items: " << endl; vector<string> bag. Items = bag. to. Vector(); int number. Of. Entries = (int) bag. Items. size(); for (int i = 0; i < number. Of. Entries; i++) cout << bag. Items[i] << " "; cout << endl; } DS 2017: Array-Based Implementations 67 / 70
SVVRL @ IM. NTU The Standard Library <vector> (1/2) n n The class vector with templates is defined and implemented in the standard library <vector>. It is just a “dynamic vector” of any type. q q q It is a class with an embedded one-dimensional dynamic array. It has many useful member functions (including overloaded operators). It is implemented with templates. Yih-Kuen Tsay DS 2017: Array-Based Implementations 68 / 70
SVVRL @ IM. NTU The Standard Library <vector> (2/2) n Four member functions are used in the textbook implementation: q q Constructor: vector<Item. Type> bag. Contents; Element addition: bag. Contents. push_back(items[i]); Assignment operator: vector<string> bag. Items = bag. to. Vector(); Indexing operator: cout << bag. Items[i] << " "; Yih-Kuen Tsay DS 2017: Array-Based Implementations 69 / 70
SVVRL @ IM. NTU Some Questions Regarding vector n Why not just print()? q n Should we have to. Vector() or print()? q n n Using to. Vector() rather than print() completely decouples Array. Bag operations and program I/O (e. g. , displaying bag items on a screen). If it is only used during the development phase, we should remove it after Array. Bag is completed. If we have vector, why should we implement Array. Bag? (Prof. Kung’s suggestion) Try not to use vector unless you are able to implement something with the same capability. Yih-Kuen Tsay DS 2017: Array-Based Implementations 70 / 70
- Slides: 70