DSA-Chapter-3.1-2024 (1)
DSA-Chapter-3.1-2024 (1)
The internal details of an ADT are hidden from the user, and only the public interface
(operations) is exposed.
Each ADT has its own key operations regardless of the data structure used to implement it.
Key Operations:
Key Operations:
Key Operations:
Key Operations:
Key Operations:
Key Operations:
Key Operations:
• enqueue(element, priority): Inserts an element with a given priority into the queue.
• dequeue(): Removes and returns the element with the highest priority.
• peek(): Returns the element with the highest priority without removing it.
• isEmpty(): Checks if the priority queue is empty.
• size(): Returns the number of elements in the queue.
1. Stack
• Array: Fixed-size or dynamically resizable array.
• Linked List: Singly linked list or doubly linked list.
• Deque (Double-Ended Queue): Can be implemented using a doubly linked list or a
dynamic array.
2. Queue
• Array: Fixed-size or circular array.
• Linked List: Singly linked list or doubly linked list.
• Circular Buffer (Ring Buffer): A fixed-size buffer that overwrites the oldest data with
new data when full.
• Deque (Double-Ended Queue): Can be implemented using a doubly linked list or a
dynamic array.
3. List
• Array: A fixed-size or dynamically resizable array.
• Linked List: A sequence of nodes where each node points to the next node.
o Singly linked list
o Doubly linked list
o Circular linked list
4. String
a. Array: A fixed-size or dynamically resizable array of characters.
b. Linked list: Singly linked list or doubly linked list.
c. Rope: A balanced binary tree where each leaf node contains a substring. Useful for
efficient concatenation and splitting.
d. Suffix Tree/Array: Specialized data structures for efficient string operations like
substring search and pattern matching.
5. Tree
a. Binary Tree
b. Binary Search Tree (BST)
c. AVL Tree:
d. Red-Black Tree:
e. B-Tree:
f. Trie (Prefix Tree):
6. Graph
a. Adjacency List
b. Adjacency Matrix
c. Edge List
7. Set
a. Hash Table
b. Hash Set
c. Balanced Binary Search Tree
8. Map
a. Hash Table
b. Hash Map
c. Balanced Binary Search Tree
d. Trie
9. Priority Queue
a. Binary Heap
b. Binomial Heap
c. Fibonacci Heap
Note:
The choice of data structure to implement an Abstract Data Type (ADT) can significantly impact
the time complexity of operations, space efficiency, and ease of use. Different data structures
have different strengths and weaknesses, and these affect how efficiently they can perform the
operations required by the ADT.
The C++ Standard Library
The Standard Library in C++ includes a robust set of tools that are incredibly useful. It provides:
• Templated Containers: These are classes like vector, list, map, set etc., which are generic
so they can work with any data type. This eliminates the need to write a new linked list or
stack class for every different type of element you want to store.
• Algorithms: The library comes with a wide array of pre-written algorithms like sorting (sort),
searching (find), and many more. These are optimized for performance, reducing the risk of
errors and enhancing efficiency.
• Iterators: These provide a way to traverse through the elements of containers in a
standardized manner, which is critical for using many of the standard algorithms.
The Standard Library uses advanced C++ features, especially templates (see Chapter 3.0), which
can present a steep learning curve. However, mastery of these features is invaluable for enhancing
code quality and development speed.
Containers
The Standard Library offers a variety of container classes tailored for various applications. These
containers can be broadly classified into three main types:
int main() {
// std::array example: Size must be a compile-time constant
std::array<int, 5> arr = { 1, 2, 3, 4, 5 };
return 0;
}
int main() {
std::stack<int> stack;
stack.push(10);
stack.push(20);
stack.push(30);
stack.pop();
std::cout << "After pop: ";
while (!stack.empty()) {
std::cout << stack.top() << " ";
stack.pop();
}
std::cout << '\n';
return 0;
}
Example for std::list
#include <iostream>
#include <list>
int main() {
std::list<int> myList;
myList.push_back(10);
myList.push_back(20);
myList.push_back(30);
myList.push_front(5);
myList.remove(20);
std::cout << "The elements in the list after removing 20 are: ";
printList(myList);
std::cout << "The size of the list is: " << myList.size() << '\n';
myList.clear();
if (myList.empty()) {
std::cout << "The list is now empty." << '\n';
}
else {
std::cout << "The list is not empty." << '\n';
}
return 0;
}
int main() {
std::queue<std::string> myQueue;
std::string input;
std::string_view inputView;
std::cout << "Enter elements to enqueue (type 'done' without quotes to finish)\n";
// Loop to read input and add to the queue until "done" is entered
do {
std::getline(std::cin, input);
// only add the input to queue if entered string is not empty or not "done"
if (!input.empty() && toLower(std::string(inputView)) != "done") {
myQueue.push(input);
}
} while (toLower(std::string(inputView)) != "done");
if (myQueue.empty()) {
std::cout << "Front element after pop: none\n";
}
else {
std::cout << "Front element after pop: " << myQueue.front() << '\n';
}
}
return 0;
}
std::string_view (which lives in the <string_view> header) provides read-only access to
an existing string (a C-style string, a std::string, or another std::string_view) without making a copy.
It does not allocate memory and simply references the underlying string.
Note:
std::string is slow and expensive to initialize (or copy). Prefer std::string_view over std::string when
you need a read-only string, especially for function parameters.
However, it is essential to learn how to implement basic data structures to gain a deeper
understanding and improve algorithmic thinking. Knowing how the underlying mechanisms work
enables writing more efficient and robust code when necessary.
Implementing ADTs and data structures from scratch provides a clearer understanding of
time and space complexity. For example, understanding why certain operations on a std::vector
might be O(n) (e.g., insert at the beginning), whereas they’re O(1) for a linked list.
It also gives the ability to implement data structures in environments where standard
libraries are unavailable or not optimized enough, such as the following examples:
Operating Systems: In kernel programming, standard library support is typically absent, so custom
data structures must be written with careful attention to memory management and real-time
constraints.