Presentation is loading. Please wait.

Presentation is loading. Please wait.

Data structures in C++.

Similar presentations


Presentation on theme: "Data structures in C++."— Presentation transcript:

1 Data structures in C++

2 Coding data structures in C++
So far we’ve seen only theory To be useful, must implement these algorithms and data structures in code All data structures implemented in the textbook Will consider hashtables with chaining here as example

3 Hashing with chaining Hashtable implemented with an array of linked lists Would like to be able to store any data type in the hashtable Need to use templates to do this Consider first how to implement a linked list template in C++

4 Linked lists Recall a linked list is a chain of nodes
Each node has two parts: data pointer to next node Data part can store any data type Need template to implement this

5 Empty list List pointer NULL Data Next Head node

6 List with one data node List pointer Data Next NULL Head node Data

7 Inserting data node List pointer Data Next NULL Head node Data Next
Create new node using dynamic allocation New node

8 Inserting data node List pointer Data Next NULL Head node Data Next
Connect Next pointer from new node FIRST New node

9 Inserting data node List pointer Data Next NULL Head node Data Next
Then redirect existing pointer to point to new node New node

10 C++ list template Will present code for basic list template
Only include data fields and Insert method Other methods can be added See textbook for details (chapter 10)

11 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Template takes one parameter: data type to be stored in list

12 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Data fields are protected rather than private, since list will be inherited.

13 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); A ‘struct’ in C++ is the same as a class, except data fields are public by default.

14 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); ListNode contains the data and pointer fields for a node in the list

15 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Element is the data node. Its data type is the template parameter Type.

16 List template Next is the pointer to the next node in the list.
template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Next is the pointer to the next node in the list.

17 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); The default constructor initializes the pointer to NULL (0).

18 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Two-parameter constructor takes data and a ListNode pointer for the Next pointer.

19 List template The main list class has a pointer to the Head node.
template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); The main list class has a pointer to the Head node.

20 List template Default constructor for list just creates the Head node.
template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Default constructor for list just creates the Head node.

21 List template template <class Type> class list { protected: struct ListNode Type Element; ListNode *Next; ListNode() : Next(0) {} ListNode(Type Data, ListNode *Node = 0) : Element(Data), Next(Node) {} }; ListNode *Head; public: list() : Head(new ListNode) {} virtual void Insert(const Type& NewElement); Insert() method inserts a new node at the end of the list. Note NewElement uses template parameter as data type.

22 Insert() method // Adds NewElement to the end of the list template <class Type> void list<Type>::Insert(const Type& NewElement) { for(ListNode *Marker = Head; Marker->Next; Marker = Marker->Next); Marker->Next = new ListNode(NewElement, Marker->Next); } Locate the end of the list. The last node in the list has a NULL Next pointer. NULL can be used as ‘false’ in a logical statement, so we test for Marker->Next being NULL.

23 Insert() method // Adds NewElement to the end of the list template <class Type> void list<Type>::Insert(const Type& NewElement) { for(ListNode *Marker = Head; Marker->Next; Marker = Marker->Next); Marker->Next = new ListNode(NewElement, Marker->Next); } Create and insert the new element in the correct place. Recall the ListNode constructor connects the Next pointer of the new node. Here we set Marker->Next to point to new node, so it is linked into the list correctly at both ends.

24 Lists for hashing A list in a hashtable must be searchable
Need to add in a Search() method to our list template Can use inheritance for this

25 Searching a list template <class Type> class chainList : public list<Type> { public: chainList() : list<Type>() {} BOOL Search(const Type& SearchElement) const; BOOL Search(const Type& SearchElement, Type& FoundElement) const; }; chainList is a template that inherits the list template.

26 Searching a list Constructor just calls the base class constructor.
template <class Type> class chainList : public list<Type> { public: chainList() : list<Type>() {} BOOL Search(const Type& SearchElement) const; BOOL Search(const Type& SearchElement, Type& FoundElement) const; }; Constructor just calls the base class constructor.

27 Searching a list template <class Type> class chainList : public list<Type> { public: chainList() : list<Type>() {} BOOL Search(const Type& SearchElement) const; BOOL Search(const Type& SearchElement, Type& FoundElement) const; }; First version of Search() just looks for SearchElement and returns true or false depending on whether it was found.

28 Searching a list template <class Type> class chainList : public list<Type> { public: chainList() : list<Type>() {} BOOL Search(const Type& SearchElement) const; BOOL Search(const Type& SearchElement, Type& FoundElement) const; }; Second version also searches for SearchElement, but returns the element as FoundElement. Note this is passed by reference.

29 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } Create a Marker to step through the list.

30 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } Initialize the Marker to the first data node (the one following the head node).

31 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } Termination condition is in 2 parts. First we must see if we have reached the end of the list. If we have, Marker will be NULL.

32 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } If Marker is not NULL, test its data field to see if it matches SearchElement. Note that this test must work for all data types (including user defined ones). What problem could arise?

33 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } The != operator must be defined for any data type stored in the list. This may require writing an overloaded operator.

34 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } If we haven’t found the element yet, go to the next list element.

35 Simple Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); return (Marker ? TRUE : FALSE); } If Marker is NULL after the loop ends, we reached the end of the list without finding SearchElement, so we return false; otherwise return true.

36 Second Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement, Type& FoundElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); if (Marker) { FoundElement = Marker->Element; return TRUE; } else { FoundElement = SearchElement; return FALSE; } The second search method uses the same technique to locate SearchElement

37 Second Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement, Type& FoundElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); if (Marker) { FoundElement = Marker->Element; return TRUE; } else { FoundElement = SearchElement; return FALSE; } If Marker is not NULL, we have found SearchElement, so set FoundElement equal to the element where the loop quit

38 Second Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement, Type& FoundElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); if (Marker) { FoundElement = Marker->Element; return TRUE; } else { FoundElement = SearchElement; return FALSE; } Suppose we wanted to change the value stored in the list. Will changing FoundElement do this?

39 Second Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement, Type& FoundElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); if (Marker) { FoundElement = Marker->Element; return TRUE; } else { FoundElement = SearchElement; return FALSE; } No it won’t. The = operator creates a copy of Marker->Element in FoundElement so the two are independent of each other. (Remember this for lab 4!)

40 Second Search() method
template <class Type> BOOL chainList<Type>:: Search(const Type& SearchElement, Type& FoundElement) const { ListNode *Marker; for (Marker = Head->Next; Marker && Marker->Element != SearchElement; Marker = Marker->Next); if (Marker) { FoundElement = Marker->Element; return TRUE; } else { FoundElement = SearchElement; return FALSE; } If we didn’t find SearchElement, we could just leave FoundElement undefined, but here we assign it to SearchElement and return FALSE.

41 Code for the hashtable Hashtable is an array of lists
Need two methods: Store() to store an item in the table Retrieve() to search for and retrieve an item Both methods require a hash function Hash function depends on the data type

42 Hash functions Won’t know what hash function to use until we know the data type For a template this can be anything Require the user to specify the function when they use the template Make HashFunction() an abstract method in the table class

43 Defining a hashtable class
Must inherit chainTable class to obtain a usable hashtable class Must provide a HashFunction() method tailored to the data type being stored

44 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; chainTable is a template. The parameter Type is the data type stored in the table

45 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; Bucket is a pointer to an array of chainLists, each of which stores data of type Type.

46 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; We allow the size of the table to be specified when it is declared.

47 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; HashFunc() is declared as an abstract method (= 0). This means the class must be inherited and a definition for HashFunc() must be provided.

48 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; Specify the table size in the constructor (default size is 1000).

49 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; Store() stores Item in the table by using HashFunc() to calculate its location in the table, and then adding it to the list at that location.

50 chainTable base class template <class Type> class chainTable { protected: chainList<Type> *Bucket; int TableSize; virtual int HashFunc(const Type& Item) const = 0; public: chainTable(int tablesize = 1000); virtual ~chainTable(); virtual BOOL Store(const Type& Item); virtual BOOL Retrieve(const Type& SearchItem, Type& FoundItem) const; }; Retrieve uses HashFunc() to look up the location of SearchItem, and stores a copy of it in FoundItem if it is found.

51 chainTable constructor
template <class Type> chainTable<Type>::chainTable(int tablesize) : TableSize(tablesize), Bucket(new chainList<Type>[tablesize]) {} Constructor creates a dynamic array of chainLists

52 chainTable Store() method
template <class Type> BOOL chainTable<Type>::Store(const Type& Item) { int index = HashFunc(Item); if (Bucket[index].Search(Item)) return FALSE; Bucket[index].Insert(Item); return TRUE; } The array index in the Bucket array is found using HashFunc() on Item.

53 chainTable Store() method
template <class Type> BOOL chainTable<Type>::Store(const Type& Item) { int index = HashFunc(Item); if (Bucket[index].Search(Item)) return FALSE; Bucket[index].Insert(Item); return TRUE; } This version searches to see if Item is already in the table. If so, it returns false without storing the new Item. This may not be what you want – e.g. in lab 4 you need to change the value of an existing entry or add a new entry.

54 chainTable Store() method
template <class Type> BOOL chainTable<Type>::Store(const Type& Item) { int index = HashFunc(Item); if (Bucket[index].Search(Item)) return FALSE; Bucket[index].Insert(Item); return TRUE; } If Item is not already in the table, call the Insert() method of the list class to insert it into the table at that point.

55 chainTable Retrieve() method
template <class Type> BOOL chainTable<Type>:: Retrieve(const Type& SearchItem, Type& FoundItem) const { int index = HashFunc(SearchItem); return Bucket[index].Search(SearchItem, FoundItem) ? TRUE : FALSE; } As with Store(), use HashFunc() to find where SearchItem would be if it is in the table.

56 chainTable Retrieve() method
template <class Type> BOOL chainTable<Type>:: Retrieve(const Type& SearchItem, Type& FoundItem) const { int index = HashFunc(SearchItem); return Bucket[index].Search(SearchItem, FoundItem) ? TRUE : FALSE; } Use the second Search() method in chainList to look for SearchItem. Recall Search() returns TRUE if the item is present, and in this case the item will be copied into FoundItem.

57 Using the chainTable class
Must inherit chainTable class to obtain a usable hashtable class Derived class must provide implementation of HashFunc() This depends on the data type being stored E.g. if we store ints, can use int value modulo table size

58 Hashtable for long ints
class chainInt : public chainTable<long> { private: int HashFunc(const long& Item) const; public: chainInt(int tablesize = 1000) : chainTable<long>(tablesize) {} }; Define a class that inherits chainTable, and sets Type to ‘long’. Note this is a real class, not a template

59 Hashtable for long ints
class chainInt : public chainTable<long> { private: int HashFunc(const long& Item) const; public: chainInt(int tablesize = 1000) : chainTable<long>(tablesize) {} }; Must provide a version of HashFunc() that works for longs. This must have the same signature as the abstract method in the base class.

60 Hashtable for long ints
class chainInt : public chainTable<long> { private: int HashFunc(const long& Item) const; public: chainInt(int tablesize = 1000) : chainTable<long>(tablesize) {} }; Constructor just calls the base class constructor with the given data type.

61 HashFunc() for chainInt
int chainInt::HashFunc(const long& Item) const { return Item % TableSize; } A simple hash function for an integer data type takes its value modulo the table size. Other data types would need a customized hash function. E.g. for text, could use the sum of the ASCII values modulo the table size.

62 Using the chainInt hashtable
Having created a hashtable class for long ints, we can use it in ‘real’ code Use Store() and Retrieve() to manage the contents of the table

63 Using a chainInt hashtable
void main() { chainInt InTable(100); long NewItem, GetItem, GotItem; for (int i = 0; i < 10; i++) { cout << "Enter integer to insert in table: "; cin >> NewItem; if (InTable.Store(NewItem)) cout << "Item stored.\n"; else cout << "Item already in table.\n"; } for (i = 0; i < 10; i++) { cout << "Enter integer to retrieve from table: "; cin >> GetItem; if (InTable.Retrieve(GetItem, GotItem)) cout << "Item " << GotItem << " found.\n"; cout << "Item not found.\n"; Create the hashtable with a table size of 100.

64 Using a chainInt hashtable
void main() { chainInt InTable(100); long NewItem, GetItem, GotItem; for (int i = 0; i < 10; i++) { cout << "Enter integer to insert in table: "; cin >> NewItem; if (InTable.Store(NewItem)) cout << "Item stored.\n"; else cout << "Item already in table.\n"; } for (i = 0; i < 10; i++) { cout << "Enter integer to retrieve from table: "; cin >> GetItem; if (InTable.Retrieve(GetItem, GotItem)) cout << "Item " << GotItem << " found.\n"; cout << "Item not found.\n"; Create some variables for storing data

65 Using a chainInt hashtable
void main() { chainInt InTable(100); long NewItem, GetItem, GotItem; for (int i = 0; i < 10; i++) { cout << "Enter integer to insert in table: "; cin >> NewItem; if (InTable.Store(NewItem)) cout << "Item stored.\n"; else cout << "Item already in table.\n"; } for (i = 0; i < 10; i++) { cout << "Enter integer to retrieve from table: "; cin >> GetItem; if (InTable.Retrieve(GetItem, GotItem)) cout << "Item " << GotItem << " found.\n"; cout << "Item not found.\n"; Enter a long int and use Store() to try to store it. If already in the table, Store() returns false, otherwise item is stored.

66 Using a chainInt hashtable
void main() { chainInt InTable(100); long NewItem, GetItem, GotItem; for (int i = 0; i < 10; i++) { cout << "Enter integer to insert in table: "; cin >> NewItem; if (InTable.Store(NewItem)) cout << "Item stored.\n"; else cout << "Item already in table.\n"; } for (i = 0; i < 10; i++) { cout << "Enter integer to retrieve from table: "; cin >> GetItem; if (InTable.Retrieve(GetItem, GotItem)) cout << "Item " << GotItem << " found.\n"; cout << "Item not found.\n"; Ask user to enter some data values and try to look them up in the table. If Retrieve() returns true, item was found, otherwise it’s not in the table.


Download ppt "Data structures in C++."

Similar presentations


Ads by Google