Unit 1
Unit 1
at(i): Return the element of V with index ‘i’; an error condition occurs if ‘i’ is out of
range.
set(i,e): Replace the element at index ‘i’ with e; an error condition occurs if ‘i’ is out
of range.
insert(i,e): Insert a new element e into V to have index ‘i’; an error condition occurs
if ‘i’ is out of range. erase(i): Remove from V the element at index ‘i’; an error
condition occurs if ‘i’ is out of range.
Example
A Simple Array-Based
Implementation
An obvious choice for implementing the vector ADT is to use a fixed size array A, where A[i] stores
the element at index ‘i’.
We choose the size ‘N’ of array ‘A’ to be sufficiently large, and we maintain the number n < N of
elements in the vector in a member variable.
To implement the at(i) operation, for example, we just return A[i].
The implementations of the functions insert(i,e) and erase(i) are given in Code Fragment 6.1.
Algorithm insert(i,e):
for j = n−1,n−2,...,i do
A[ j +1] ← A[ j] {make room for the new element}
A[i] ← e
n ← n+1
Algorithm erase(i):
for j = i+1,i+2,...,n−1 do
A[ j −1] ← A[ j] {fill in for the removed element}
n ← n−1
The member variable ‘n’ stores the number of elements. An important (and time-consuming) part of
this implementation involves the shifting of elements up or down to keep the occupied cells in the
The Performance of a Simple Array-
Based Implementation
• The worst case for insert(i,e) operation occurs when i = 0, since
all the existing n elements have to be shifted forward.
• Erase(i), which runs in O(n) time, because we have to shift
backward n−1 elements in the worst case (i = 0).
• In fact, assuming that each possible index is equally likely to be
passed as an argument to these operations, their average
running time is O(n) because we have to shift n/2 elements on
average.
An Extendable Array
Implementation
• A major weakness of the simple array implementation for the vector ADT requires advance
specification of a fixed capacity, N, for the total number of elements that may be stored in the
vector.
• If the actual number of elements, n, of the vector is much smaller than N, then this
implementation will waste space.
• Worse, if n increases past N, then this implementation will crash.
• Instead, when an overflow occurs, that is, when n = N and function insert is called, we perform
the following steps: 1. Allocate a new array B of capacity N 2. Copy A[i] to B[i], for i = 0,...,N
−1 3. Deallocate A and reassign A to point to the new array B This array replacement strategy
is known as an extendable array, for it can be viewed as extending the end of the underlying
array to make room for more elements.
An Extendable Array
Implementation
Let V be a vector implemented by means of an extendable array A, as described above. The total time to perform a series of n
push operations in V , starting from V being empty and A having size N = 1, is O(n).
•First Push: You add an item to the vector. Since the array has space, it just goes in. This takes
constant time, or O(1) .
•Second Push: You want to add another item, but now the array is full. So, you need to resize the
array. Usually, this means doubling the size of the array (from 1 to 2). After resizing, you copy the
existing item to the new array and then add the new item. This resizing and copying take some
extra time.
•Third Push and Onwards: As you keep adding more items, sometimes the array will fill up again,
and you'll need to double its size and copy everything over to the new array.
•Final Result
So, even though resizing happens occasionally and can be costly, the total time for all n pushes is
Standard Template Library (STL)
STL Vectors
We refer to the type of individual elements as the vector’s base type. Each element is initialized to the base type’s
default value, which for integers is zero.
•As with arrays, individual elements of a vector object can be indexed using the usual index operator (“[ ]”). Elements can also be
accessed by a member function called at. The advantage of this member function over the index operator is that it performs range
checking and generates an error exception if the index is out of bounds.
•Unlike C++ arrays, STL vectors can be dynamically resized, and new elements may be efficiently appended or removed from the end
of an array.
•When an STL vector of class objects is destroyed, it automatically invokes the destructor for each of its elements. (With C++ arrays, it
is the obligation of the programmer to do this explicitly.)
vector(n): Construct a vector with space for n elements; if no argument is given, create an empty vector
reserve(n): Request that the allocated storage space be large enough to hold n elements.
at(i): Same as V [i], but throw an out of range exception if i is out of bounds, that is, if i < 0 or i ≥
V.size().
push back(e): Append a copy of the element e to the end of V , thus increasing its size by one.
pop back(): Remove the last element of V , thus reducing its size by one.
STL Containers
The C++ Standard Template Library (STL) provides several container classes to handle collections of objects. These containers are categorized
based on their internal structure and usage patterns. Here's a summary of the main STL containers:
1. Sequence Containers
These containers store elements in a linear sequence and provide various methods for accessing and modifying them.
•std::vector:
• Description: A dynamic array that supports random access.
• Features: Fast access to elements by index, efficient appending, and removal at the end.
• Example: std::vector<int> v = {1, 2, 3};
•std::deque:
• Description: A double-ended queue that allows fast insertions and deletions at both ends.
• Features: Supports random access and efficient operations at both the front and back.
• Example: std::deque<int> d = {1, 2, 3};
•std::list:
• Description: A doubly linked list that allows bidirectional traversal.
• Features: Efficient insertions and deletions at any position, but no random access.
• Example: std::list<int> l = {1, 2, 3};
•std::forward_list:
• Description: A singly linked list that allows forward traversal.
• Features: More memory efficient than std::list but only supports forward traversal.
• Example: std::forward_list<int> fl = {1, 2, 3};
•std::array:
• Description: A fixed-size array wrapper that provides compile-time size.
• Features: Supports static allocation and efficient access, but size is fixed.
• Example: std::array<int, 3> arr = {1, 2, 3};
STL Containers
Container Adapters
These provide a different interface to underlying sequence containers.
•std::stack:
• Description: A stack (LIFO) adapter that provides push, pop, and top
operations.
• Underlying Container: Typically uses std::deque or std::vector.
• Example: std::stack<int> s; s.push(1); s.push(2);
•std::queue:
• Description: A queue (FIFO) adapter that provides enqueue and dequeue
operations.
• Underlying Container: Typically uses std::deque or std::list.
• Example: std::queue<int> q; q.push(1); q.push(2);
•std::priority_queue:
• Description: A priority queue adapter that provides access to the largest (or
smallest) element.
• Underlying Container: Typically uses std::vector and a heap structure.
• Example: std::priority_queue<int> pq; pq.push(1); pq.push(2);
Node-Based Operations and
Iterators
Node-based operations and iterators are concepts commonly associated with linked data
structures like linked lists, trees, and graphs. These structures are composed of "nodes,"
where each node contains data and references (or pointers) to other nodes.
Iterators
An iterator is an object that enables traversal through the elements of a data structure
without exposing the underlying structure details. Iterators are particularly useful for node-
based structures.
List ADT
The List Abstract Data Type (List ADT) is a fundamental data structure that represents a
collection of elements, typically in a specific order.
A position is always defined in a relative manner, that is, in terms of its neighbors.
Unless it is the first or last of the container, a position q is always “after”
some position p and “before” some position r (see Figure 6.4).
Key Characteristics of the List
ADT
1.Ordered Collection: The elements in a list are ordered, meaning that each element
has a specific position (index) in the list.
2.Dynamic Size: Lists can grow or shrink dynamically as elements are added or
removed.
3.Homogeneous Elements: Typically, all elements in a list are of the same type,
though some implementations may allow mixed types.
4.Positional Access: Elements can be accessed, inserted, or removed based on their
position in the list.
Common Operations in List ADT
#include <list>
using std::list; // make list accessible
list<float> myList; // an empty list of floats
Advantages of Implementation
•Dynamic Size: A doubly linked list allows the sequence to grow or shrink as needed.
•Flexible Access: Users can access elements either by position or index.
•Efficient Modifications: Insertions and deletions remain efficient due to the linked list structure.
Implementing a Sequence with an Array
1. Overview
•A sequence can be implemented by storing each element e of the sequence S in an
array A at index i.
•This approach allows for efficient indexed access to elements.
2. Position Object
•Define a position object p that holds:
• An index i representing the position of the element in the array.
• A reference to the array A.