containers in c++ and java (contd.) questionspammann/332/ppt/kak/slides5b.pdf · deque a dequehas...
TRANSCRIPT
Containers in C++ and Java (contd.)
Questions:
1
1. What’s the technically correct way to
complete the following partial sentence:
"The primary advantage of using an array
as a container is that it gives you ......"
2
2. Complete the following partial sentence:
"The primary disadvantage of an array is
that you have to know its ..........."
3
3. What’s that part of the C++ Standard Libraray
called that has all the container classes
defined in it?
4
4. What’s that part of Java called that has all the
container classes defined in it?
5
5. Name the different container classes in C++.
6
6. Are vector, list, and deque called sequence
containers because their elements are stored in
a contiguous block of memory?
7
7. Considering that a vector is allocated contiguous
memory that comes optionally with some extra space
at the end;
that a deque is allocated contiguous memory that comes
optionally with extra spaces at both ends; and
that a list is stored basically as a linked list;
which of the following statements are true?
a) The efficieny of inserting/deleting
items at the front of a vector is
O(N)
b) The efficiency of inserting/deleting
at the end of a vector is
O(1)+
c) The efficiency of array-like access
for both a vector and a deque is
O(1)
d) The efficiency of a array-like access
in a list is
O(N)
8
8. What does the notation
O(1)+
stand for?
9
9. Why does it not make it any sense to write
functions that have pointers to vectors or to
vector elements?
10
10. Does the following make sense?
vector<int> vec(100, 5);
vector<int>::iterator p = vec.begin();
vec.insert( vec.begin(), 10 );
cout << *p << endl;
11
11. Is there anything wrong with the following
program fragment:
vector<int> vec;
vector<int>::iterator p;
p = vec.begin();
12
12. For C++/STL containers, what’s the difference
between what’s returned by the function begin()
and end() on the one hand and by the functions
front() and back() on the other?
13
13. To reduce the overhead associated with incremental
memory allocation, you can use resize() to increase the
size of an existing vector by any desired amount.
vector<string> vec;
vec.push_back( "hello" );
vec.resize( 1000 );
Is this additional memory initialized? Also, what will
be returned by
vec.size();
and where exactly will the following additional element
go?
vec.push_back( "jello" );
14
14. How would you appropriate memory for a vector without
changing its size? More specifically, how would you
appropriate memory for a vector without changing
what is returned by size()?
15
Deque
A deque has all the functionality of a vector and then some.
A vector is inefficient for insert/delete operations at the front of the
sequence, because if you insert a new element at the front, you’d need to
shuffle all the other elements in the memory to their next location.
On the other hand, in a deque the insert/delete operations at the front
are just as efficient as they are at the back.
So, whereas a vector provides us with the efficient push back and pop back
operations at the back, a deque has these two and also push front and
pop front for equally efficient operations at the front.
16
//DequeFront.cc
#include <string>
#include <deque>
#include <algorithm> // for sort, find
void print( deque<string> );
int main()
{
deque<string> animals;
animals.push_back( "yak" );
animals.push_back( "zebra" );
animals.push_front( "cat" );
animals.push_front( "canary" );
print(animals); // canary cat yak zebra
animals.pop_front();
animals.pop_back();
print(animals); // cat yak
animals.erase( find( animals.begin(), animals.end(), "cat" ) );
print(animals); // yak
animals.insert( animals.begin(), "canary" );
print(animals); // canray yak
17
int sz = animals.size(); // 2
animals.resize( 5 ); // size() will now return 5
animals[sz] = "fox"; // animals[2] = "fox"
animals[sz+1] = "elephant"; // animals[3] = "elephant"
animals[sz+2] = "cat"; // animals[4] = "cat"
print( animals ); // canary yak fox elephant cat
animals.erase( animals.begin() + 2 );
// remove "fox"
print( animals ); // canary yak elephant cat
sort( animals.begin(), animals.end() );
print( animals ); // canary cat elephant yak
}
void print( deque<string> d )
{
typedef deque<string>::const_iterator CI;
cout << "The number of items in the deque: " << d.size() << endl;;
for ( CI iter = d.begin(); iter != d.end(); iter++ )
cout << *iter << " ";
cout << endl << endl;
}
18
List
If your application requires frequent insertions of new data items anywhere
– front, back, or anywhere else in the middle – in a sequence and array-like
indexing for accessing the data items is not important, then you need to
use a list.
19
#include <string>
#include <list>
void print( list<string>& );
int main()
{
list<string> animals;
animals.push_back( "cheetah" );
animals.push_back( "lion" );
animals.push_back( "cat" );
animals.push_back( "fox" );
animals.push_back( "elephant" );
animals.push_back( "cat" ); //<<<<< duplicate
print( animals ); // cheetah lion cat fox elephant cat
animals.pop_back();
print( animals ); // cheetah lion cat fox elephant
animals.remove( "lion" ); // first occurrence of "lion"
print( animals ); // cheetah cat fox elephant
animals.push_front( "lion" ); // lion cheetah cat fox elephant
print( animals );
animals.pop_front( );
print( animals ); // cheetah cat fox elephant
animals.insert( animals.end(), "cat" );
print( animals ); // cheetah cat fox elephant cat
20
animals.sort();
print( animals ); // cat cat cheetah elephant fox
animals.unique();
print( animals ); // cat cheetah elephant fox
list<string> pets;
pets.push_back( "cat" );
pets.push_back( "dog" );
pets.push_back( "turtle" );
pets.push_back( "bird" );
animals.splice( animals.begin(), pets, pets.begin() );
print( animals ); // cat cat cheetah elephant fox
print( pets ); // dog turtle bird
pets.sort(); // bird dog turtle
animals.merge( pets );
cout << pets.empty() << endl; // true
print( animals ); // bird cat cat cheetah dog elephant
// fox turtle
}
21
void print( list<string>& li ) {
typedef list<string>::const_iterator CI;
cout << "The number of items in the list: "
<< li.size() << endl;;
for ( CI iter = li.begin(); iter != li.end(); iter++ )
cout << *iter << " ";
cout << endl << endl;
}
22
Stack
A stack works on the principle of “last in, first out” (LIFO).
push pop
......
23
An STL Stack is the first of the sequence container adapters.
A container adapter restricts the public interface of a specified sequence
container.
24
//StackOps.cc
#include <string>
#include <stack>
#include <vector>
int main()
{
stack< string, vector<string> > s;
s.push( "me" );
s.push( "to" );
s.push( "talk" );
while ( !s.empty() ) {
cout << s.top() << " ";
s.pop();
}
}
25
Queue
.....pop from queue(pop_front)
back ofcontainer
front ofcontainer
push into queue (push_back)
26
The queue adapter can adapt to any underlying container that supports
push back, pop front, front and size, back, size, and empty.
The queue itself provides to the user the function push, pop, front,
back, size, and empty.
The push of queue invokes push back of the underlying container and
the pop of queue invokes pop front of the underlying container. The
rest of the functions of queue directly invoke functions of the same name
on the underlying container.
27
//QueueOps.cc
#include <string>
#include <queue>
int main()
{
queue<string> q;
q.push( "roses" );
q.push( "are" );
q.push( "red" );
while ( !q.empty() ) {
cout << q.front() << " ";
q.pop();
}
}
28
Priority Queue
A priority queue works very much like a queue except that the item
that will be popped off next is one with the highest-priority.
So whenever anything is pushed into or popped off a priority queue,
the item with the highest priority is brought to the front of the queue.
The priority of an item is usually established on the basis of a comparison
criterion for the queue items, the criterion being supplied by the program-
mer.
If the programmer does not supply a comparison criterion, the system will
try to use either the < operator if defined for the items in the queue or, if
29
applicable, the less function object from the functional header file of
the C++ Standard Library.
30
//PriorityQueueOps.cc
#include <string>
#include <queue>
class Prioritize {
public:
int operator() ( const pair<string, unsigned int>& p1,
const pair<string, unsigned int>& p2 ) {
return p1.second < p2.second;
}
};
int main()
{
priority_queue< pair< string, unsigned int >,
vector <pair< string, unsigned int > >, Prioritize > pq;
pq.push( pair<string, int>( "go to lunch", 2) );
pq.push( pair<string, int>( "go to bathroom", 10 ) );
pq.push( pair<string, int>( "take a nap", 1 ) );
while ( !pq.empty() ) {
cout << pq.top().first << endl;
pq.pop();
}
31
return 0;
}
32
Map
A C++ map is a sequence of <key, value> pairs in which every key is
unique.
So a phone book in which every name appeared only once could be repre-
sented by a map – each distinct name would serve as a key and the phone-
number associated with that name would be the corresponding value.
A map can be thought of as a mapping from the keys to the values.
All the <key, value> pairs in a map are stored in a sorted ascending
order and the order is maintained as new pairs are added to the container.
33
As one would expect, this requires that the container have access to a
less-than operation for the key type. This would ordinarily be provided
by overloading the < operator for the data type of the keys.
34
//MapHist.cc
#include <string>
#include <map> //(A)
#include <fstream>
int main()
{
map<string, int> hist;
ifstream in( "inFile" );
string word;
while ( in >> word )
hist[ word ]++;
in.close();
typedef map<string, int>::const_iterator CI;
for ( CI iter = hist.begin(); iter != hist.end(); ++iter )
cout << iter->first << ’\t’ << iter->second << endl;
return 0;
}
35
Set
Each object can appear only once in a set – no duplicate elements allowed.
For example, the names of all of your friends would constitute a set –
assuming that the same name was not shared by two or more friends.
36
//SetOps.cc
#include <string>
#include <set> //(A)
int main()
{
set<string> animals; //(B)
animals.insert( "cheetah" ); //(C)
animals.insert( "lion" ); //(D)
animals.insert( "cat" ); //(E)
animals.insert( "elephant" ); //(F)
animals.insert( "cat" ); //attempting a duplicate
cout << animals.size() << endl;; // output: 4 //(G)
typedef set<string>::const_iterator CI;
for ( CI iter = animals.begin(); //(H)
iter != animals.end();
iter++ )
cout << *iter << " "; // output: cat cheetah
// elephant lion
animals.erase( "lion" ); //(I)
cout << animals.size() << endl;; // output: 3
for ( CI iter = animals.begin();
iter != animals.end();
iter++ )
cout << *iter << " "; // output: cat cheetah elephant
37
return 0;
}
38
Generic Algorithms
In addition to the containers, STL also provides us with algorithms that
can be used with the container classes for searching, sorting, counting,
merging, filling, comparing, swapping, deleting, partitioning, and much
more.
The most significant thing to note about the algorithms is that they only
require iterators for their arguments and that they do not need to know
about the container directly.
39
There are 60 different algorithms.
Of these, 23 are non-mutating algorithms because they do not alter the
contents of a container.
Examples of non-mutating algorithms are min element that returns an
iterator that points to the minimum element in a sequence; find that
returns an iterator which points to the first occurrence of a value in a
sequence; binary search that performs a binary search for a given value
in an ordered container, etc.
Examples of the mutating algorithms are fill for assigning values to
specified elements in a sequence; sort for in-place sorting of the elements
within a specified range in a container, etc.
40
With regard to the sorting algorithms provided by STL, although you
have already seen examples of sorting in some of the example code we
have shown in this section, Chapter 12 will present in greater detail how
the contents of a C++ container can be sorted. For the sorting of class
type objects, there are basically two approaches and they both require
operator overloading.
41
Containers in Java
Java containers are based on a hierarchy of interfaces:
Collection
SetList
SortedSet
Map
SortedMap
42
Interface Implementation Retrofitted Implementation
Set HashSet
SortedSet TreeSet
List ArrayList LinkedList Vector Stack
Map HashMap HashTable
SortedMap TreeMap
43
Set
As with a C++ set, a Java Set cannot contain duplicate objects.
Set serves as a general abstraction for manipulating Java sets.
One uses either a TreeSet or a HashSet for actual storage of objects;
both of these are sub-types of Set.
44
A HashSet uses a hashing function to store the objects. For most data,
it will therefore exhibit superior object retrieval performance.
A TreeSet stores data in an ascending order in a balanced binary tree
data structure.
45
import java.util.*;
class SetDemo {
public static void main( String[] args )
{
Set animals = new TreeSet(); //(B)
animals.add( "cheetah" ); //(C)
animals.add( "lion" ); //(D)
animals.add( "cat" ); //(E)
animals.add( "elephant" ); //(F)
animals.add( "cat" ); //<<<<< duplicate to (E)
System.out.println("Number of animals in the set:" +
animals.size() ); //(G)
System.out.println( animals ); //(H)
animals.remove( "lion" ); //(I}
System.out.println("Number of animals in the set:" +
animals.size() ); //(J)
Iterator iter = animals.iterator(); //(K)
while ( iter.hasNext() ) //(L)
System.out.println( iter.next() ); //(M)
}
}
46
List
A List is a sequence of items stored either contiguously in memory or in
the form of a linked list.
The contiguous memory version of a List is ArrayList.
The linked list version of List is LinkedList.
Think of ArrayList as a modern version of Vector.
47
import java.util.*;
class ListDemo {
public static void main( String[] args )
{
List animals = new ArrayList(); //(A)
animals.add( "cheetah" ); //(B)
animals.add( "lion" ); //(C)
animals.add( "cat" ); //(D)
animals.add( "fox" ); //(E)
animals.add( "elephant" ); //(F)
animals.add( "cat" ); //<<<<< duplicate //(G)
System.out.println( animals );
animals.remove( "lion" ); //(H)
System.out.println( "\nAfter remove:" );
System.out.println( animals );
animals.add( 0, "lion" ); //(I)
System.out.println( "\nAfter front insertion:" );
System.out.println( animals );
animals.add( 3, "racoon" ); //(J)
System.out.println( "\nAfter fourth pos insertion:" );
System.out.println( animals );
animals.remove(3); //(K)
System.out.println("\nAfter fourth element removal:");
System.out.println( animals );
Collections.sort( animals ); //(L)
48
System.out.println("\nAfter sorting:");
System.out.println( animals );
List pets = new LinkedList(); //(M)
pets.add( "cat" );
pets.add( "dog" );
pets.add( "turtle" );
pets.add( "bird" );
System.out.println("\npets, a new list stored as a linked list:");
System.out.println( pets );
animals.addAll( 3, pets ); //(N)
System.out.println("\nAfter inserting pets list at fourth position in animals:");
System.out.println( animals );
System.out.println("\nList printed out via its iterator:" );
ListIterator iter = animals.listIterator(); //(P)
while ( iter.hasNext() )
System.out.println( iter.next() );
}
}
49
Map
The Map container in Java acts pretty much like the map container in
C++: it stores a sequence of <Key, Value> pairs.
However, there is one big difference with respect to how things are stored:
Both the keys and the values must be class type objects.
50
In Java, one usually uses one of the following two kinds of Maps: a HashMap
or a TreeMap.
A HashMap is stored in the form of a hash table. This provides for very
fast access to the keys, provided the hashing function used is effective for
the keys.
A TreeMap, on the other hand, is stored as a balanced binary tree. which
guarantees a key-order storage for the <key, value> pairs. This makes
for slower retrieval, but gives the advantage of maintaining a key-order on
the entries.
51
import java.io.*;
import java.util.*;
public class WordHistogram {
public static void main (String args[]) throws IOException
{
String allChars = getAllChars( args[0] ); //(A)
Map map = new TreeMap(); //(B)
StringTokenizer st = new StringTokenizer( allChars ); //(C)
while ( st.hasMoreTokens() ) { //(D)
String word = st.nextToken(); //(E)
Integer count = (Integer) map.get( word ); //(F)
map.put( word, ( count==null ? new Integer(1)
: new Integer( count.intValue() + 1 ) ) ); //(G)
}
System.out.println( "Total number of DISTINCT words: " + map.size() );
//(H)
System.out.println( map ); //(I)
}
static String getAllChars( String filename ) throws IOException
{
String str = "";
int ch;
Reader input = new FileReader( filename );
while ( ( ch = input.read() ) != -1 )
52
str += (char) ch;
input.close();
return str;
}
}
53
Interface Implementation Retrofitted Implementation
Set HashSet
SortedSet TreeSet
List ArrayList LinkedList Vector Stack
Map HashMap HashTable
SortedMap TreeMap
54