170 likes | 191 Views
6.4 The Deque 6.5 Simulating Waiting Lines Using Queues. Chapter 6 – Queues and Deques. Attendance Quiz #20. Tip #21: Constness. What does it mean for a member function to be const? Bitwise constness (also known as physical constness ).
E N D
6.4 The Deque 6.5 Simulating Waiting Lines Using Queues Chapter 6 – Queues and Deques
Attendance Quiz #20 Queues / Deques (21)
Tip #21: Constness Queues / Deques (21) • What does it mean for a member function to be const? • Bitwise constness (also known as physical constness). • A member function is const if and only if it doesn't modify any of the object's data members (excluding static members.) • Easy for the compiler to detect violations - just look for assignments to data members. • Logical constness. • A member function that modifies what a pointer points to is bitwise constness but not logical constness. • Sometimes there is requirement to modify one or more data members of class/struct by a const function even though you don’t want the function to update other members of class. • The solution is simple: take advantage of C++'s const-related wiggle room storage class specifier know as mutable. • Adding the keyword mutable before an object variable declaration allows a const function to change the object member.
Reporting Expression Errors Queues / Deques (21) Expression: 3 $ 3 Infix: Illegal Operator at 2 Expression: - Infix: Missing Operand at 1 Expression: 21 + Infix: Missing Operand at 3 Expression: + 7 1 Infix: Missing Operand at 1 Expression: 4 % 2 5 - Infix: Missing Operator at 4 Expression: 43 + 2 * 19 + Infix: Missing Operand at 7 Expression: ( 43 + + 2 * 19 Infix: Unbalanced at 1 Expression: ( 43 + + 2 ) * 19 20 Infix: Missing Operand at 4 Expression: { { 2 + 4 } Infix: Unbalanced at 7 Expression: 3 % { 7 - ( 2 / [ 5 - 81 ] } + 1 ) Infix: Unbalanced at 14 1st Check for Balance 2nd Return 1st occurrence of an error.
6.4 The Deque Specification of the Deque Implementing the Deque Using a Circular Array The Standard Library Implementation of the Deque 6.4, pgs. 376-380
Deque ADT Queues / Deques (21) • A deque(double-ended queue) is an abstract data type that generalizes a queue, for which elements can be added to or removed from either the front (head) or back (tail). • A dequediffers from the queue abstract data type or First-In-First-Out List (FIFO), where elements can only be added to one end (EIEO). • Restricted dequesare of two types: • An input-restricted deque (IRDeque) is one where deletion can be made from both ends, but insertion can be made at one end only. • An output-restricted deque (ORDeque) is one where insertion can be made at both ends, but deletion can be made from one end only. • The C++ standard library defines the class std::dequeto be a sequence that, like the std::vector, that supports random-access iterators (not supported by either the stackor the queue) in addition to constant-time insertion and removal from either end.
Specification of the Deque Queues / Deques (21)
STL Implementation of the Deque Queues / Deques (21) • There are at least three common ways to efficiently implement a deque: • A doubly linked list. • A circular array. • A modified dynamic array. • The modified dynamic array approach uses a variant of a dynamic array that can grow from both ends, sometimes called array deques. • These array deques have all the properties of a dynamic array, • constant-time random access, • good locality of reference, • inefficient insertion/removal in the middle, • And with the addition of amortized constant-time insertion/removal at both ends, instead of just one end.
STL Implementation of the Deque Queues / Deques (21) • Efficient array implementations of a deque: • Store the deque contents in a common circular buffer, and only resize when the buffer becomes full. • This decreases the frequency of resizings. • Allocate deque contents from the center of the underlying array and resize the underlying array when either end is reached. • This approach may require more frequent resizings and waste more space, particularly when elements are only inserted at one end. • Store contents in multiple smaller arrays, allocating additional arrays at the beginning or end as needed. • Indexing is implemented by keeping a dynamic array containing pointers to each of the smaller arrays.
Circular Array Deque Queues / Deques (21) • CArray class supports arrays that are like C arrays, but can dynamically shrink and grow as necessary. • A specialization of a CArray is part of the standard deque implementation. • A circular array makes random access straight forward: /** Returns a reference to an item in the deque. */ Item_Type& operator[](size_ti) { return the_data[(i + front_index) % capacity]; }
Dynamic Circular Array Deque Queues / Deques (21) • The standard library implementation circular array contains pointers to fixed-size, dynamically allocated arrays that contain the data. • The first data item is located at offset. • The last data item is located at index (offset + num_items – 1) % BLOCK_SIZE in the last data block.
STL Implementation of the Deque Queues / Deques (21) • The original designers chose this rather elaborate implementation rather than simply using a circular array because of the cost of reallocation. • Even though we amortize the cost of the reallocation so that each push_front or push_back is a constant-time operation, the reallocation can take a significant amount of time. • Storing pointers to single objects in the circular array could work, but dynamically allocating small/single objects has a significant space overhead. • By storing only pointers in the circular array, the cost of reallocation is significantly reduced, because copying a pointer is a simple operation. • Thus, by allocating an array of objects, we minimize this space overhead and minimize the cost of the reallocation. • For large collections of large objects, the dequecan be used instead of the vector to minimize space overhead and the cost of reallocation.
The Data Fields for the Deque Queues / Deques (21) /** Returns a reference to an item referenced by an index. @parami the index @return A reference to deque[i] */ template<typenameItem_Type> Item_Type& deque<Item_Type>::operator[](size_ti) { if (i >= num_items) throw std::out_of_range("Invalid index deque::operator[]"); size_tblock_index = (offset + i) / BLOCK_SIZE; size_tdata_index = (offset + i) % BLOCK_SIZE; return the_data[block_index][data_index]; }
The push_back Function Queues / Deques (21) /** Pushes an item onto the back of the deque. @param item The item to be inserted. */ template<typenameItem_Type> void deque<Item_Type>::push_back(const Item_Type& item) { size_t capacity = the_data.size() * BLOCK_SIZE; // Determine if the capacity needs to be increased. if ((num_items + offset) == capacity) { the_data.push_back(new Item_Type[BLOCK_SIZE]); } // Use index operator to insert item num_items++; (*this)[num_items - 1] = item; }
The pop_front Function Queues / Deques (21) /** Removes the front item from the deque. */ template<typenameItem_Type> void deque<Item_Type>::pop_front() { offset++; if (offset == BLOCK_SIZE) { delete[] the_data.front(); the_data.pop_front(); offset = 0; } num_items--; }
/** Returns a reference to an item referenced by an index. @parami the index @return A reference to deque[i] */ template<typenameItem_Type> Item_Type& deque<Item_Type>::operator[](size_ti) { size_t block_index = (offset + i) / BLOCK_SIZE; size_tdata_index = (offset + i) % BLOCK_SIZE; return the_data[block_index][data_index]; } What is the value of myDeque[13]? What is the value of myDeque.back()? What is the value of myDeque.front()?