代码改变世界

Adaptive Container: stack and queue

2011-08-14 22:53  Daniel Zheng  阅读(315)  评论(0编辑  收藏  举报

The standard template library (STL) features containers that adapt others to simulate stack and queue behavior. Such containers that internally use another and present a distinct behavior are called adaptive containers.

Using the STL stack Class

The STL stack is a generic class that allows insertions and removal of elements at the top, and dose not permit any access or inspection of elements at the middle. In that sense, the std::stack is quite similar in behavior to a stack of plates.

Instantiating the Stack

std::stack is defined by some impementations of STL  as  template<class elementType, class Container = deque<Type> > class stack;

The parameter elementType is the type of object that is collected by the stack. The second template parameter Container is the stack’s default underlying container implementation class. std::deque is the default for the stack’s internal data storage, and can be replaced by the vector and the list respectively, when the user explicitly instantiates the stack template class with the appropriate second template parameter.

#include <stack>
#include
<vector>

int main ()
{
using namespace std;

// A stack of integers
stack <int> stackIntegers;

// A stack of doubles
stack <double> stackDoubles;

// A stack of doubles contained in a vector
stack <double, vector <double> > stackDoublesInVector;

return 0;
}

  

Stack Member Functions

The stack, which adapts another container such as the deque, list, or vector, implements its functionality by restricting the manner in which elements can be inserted or removed, to supply a behavior that is expected strictly from a stack-like mechanism.

#include <stack>
#include
<iostream>

int main ()
{
using namespace std;

// A stack of integers
stack <int> stackIntegers;

// Push sample values to the top of the stack
cout << "Pushing numbers {25, 10, -1, 5} into the stack:" << endl;

// push = insert at top of the container
stackIntegers.push (25);
stackIntegers.push (
10);
stackIntegers.push (
-1);
stackIntegers.push (
5);
// So, 25 is at the bottom and 5 is at the top!

cout
<< "The stack contains " << stackIntegers.size () << " elements";
cout
<< endl;

// pop = remove the topmost element
cout << endl << "Popping them one after another..." << endl;

while (stackIntegers.size () != 0)
{
cout
<< "The element at the top is: " << stackIntegers.top();
cout
<< endl << "Removing it from the stack!" << endl;

// Remove the topmost element
stackIntegers.pop ();
}

if (stackIntegers.empty ())
cout
<< endl << "The stack is now empty!";

return 0;
}

  

Using the STL queue Class

It is a generic class that allows insertion only at the end and removal of elements only at the front. A queue does not permit any access or inspection of elements at the middle; however, elements at the beginning and the end can be accessed. In a sense, the std::queue is quite similar in behavior to a queue of people at the cashier in a supermarket!

Instantiating the Queue

#include <queue>
#include
<list>

int main ()
{
using namespace std;

// A queue of integers
queue <int> qIntegers;

// A queue of doubles
queue <double> qDoubles;

// A queue of doubles stored internally in a list
queue <double, list <double> > qDoublesInList;

return 0;
}

  

Member Functions of a queue

As is the case with the std::stack, the std::queue also bases its implementation on an STL container such as the vector, list, or deque. The queue exposes a few member functions that implement the behavioral characteristics of a queue.

#include <queue>
#include
<iostream>

int main ()
{
using namespace std;

// A queue of integers
queue <int> qIntegers;

cout
<< "Inserting {10, 5, -1, 20} into the queue" << endl;

// elements pushed into the queue are inserted at the end
qIntegers.push (10);
qIntegers.push (
5);
qIntegers.push (
-1);
qIntegers.push (
20);
// the elements in the queue now are {20, -1, 5, 10} in that order

cout
<< "The queue contains " << qIntegers.size ();
cout
<< " elements" << endl;
cout
<< "Element at the front: " << qIntegers.front() << endl;
cout
<< "Element at the back: " << qIntegers.back ();
cout
<< endl << endl;

cout
<< "Removing them one after another..." << endl;
while (qIntegers.size () != 0)
{
cout
<< "Deleting element " << qIntegers.front () << endl;

// Remove the element at the front of the queue
qIntegers.pop ();
}

cout
<< endl;

// Test if the queue is empty
if (qIntegers.empty ())
cout
<< "The queue is now empty!";

return 0;
}

  

Using the STL Priority Queue

The STL priority_queue is different from the queue in that the element of the highest value (or the value deemed as highest by a binary predicate) is available at the front of the queue, and queue operations are restricted to the front.

Instantiating the priortity_queue Class

std::priority_queue is defined as template<class elementType, class Container = vector<Type>, class Compare = less<typename Container::value_type>

#include <queue>

int main ()
{
using namespace std;

// A priority queue of integers sorted using std::less <> (default)
priority_queue <int> pqIntegers;

// A priority queue of doubles
priority_queue <double> pqDoubles;

// A priority queue of integers sorted using std::greater <>
priority_queue <int, deque <int>, greater <int> > pqIntegers_Inverse;

return 0;
}

  

Member Functions of priority_queue

The member functions front() and back(), available in the queue, are not available in the priority_queue.

#include <queue>
#include
<iostream>

int main ()
{
using namespace std;

priority_queue
<int> pqIntegers;
cout
<< "Inserting {10, 5, -1, 20} into the priority_queue" << endl;

// elements get push-ed into the p-queue
pqIntegers.push (10);
pqIntegers.push (
5);
pqIntegers.push (
-1);
pqIntegers.push (
20);

cout
<< "The queue contains " << pqIntegers.size () << " elements";
cout
<< endl;
cout
<< "Element at the top: " << pqIntegers.top () << endl << endl;

while (!pqIntegers.empty ())
{
cout
<< "Deleting the topmost element: " << pqIntegers.top ();
cout
<< endl;

pqIntegers.pop ();
}

return 0;
}

  

The next sample demonstrates the instantiation of a priority_queue with std::greater <int> as the predicate. This predicate results in the queue evaluating the smallest number as the element with greatest value, which is then available at the front of the priority queue.

#include <queue>
#include
<iostream>

int main ()
{
using namespace std;

// Define a priority_queue object with greater <int> as predicate
// So, numbers of smaller magnitudes are evaluated as greater in value
priority_queue <int, vector <int>, greater <int> > pqIntegers;

cout
<< "Inserting {10, 5, -1, 20} into the priority queue" << endl;

// elements get push-ed into the p-queue
pqIntegers.push (10);
pqIntegers.push (
5);
pqIntegers.push (
-1);
pqIntegers.push (
20);

cout
<< "The queue contains " << pqIntegers.size () << " elements";
cout
<< endl;
cout
<< "Element at the top: " << pqIntegers.top () << endl << endl;

while (!pqIntegers.empty ())
{
cout
<< "Deleting the topmost element " << pqIntegers.top ();
cout
<< endl;

// delete the number at the 'top'
pqIntegers.pop ();
}

return 0;
}