Data Structures Notes for NEP 2020
Data Structures Notes for NEP 2020
A binary search tree (BST) enhances data searching and sorting by ensuring that each node's left subtree contains values less than the node, and the right subtree contains values greater, which facilitates efficient searching operations with a time complexity of O(log n) for balanced trees. This characteristic allows for in-order traversal to yield sorted data inherently . However, BSTs can become unbalanced in operations like insertion, leading to degraded search performance up to O(n) in the worst case, similar to that of a linear list. This can happen if data is inserted in a sorted order, requiring balancing operations like AVL or Red-Black trees to maintain efficiency .
Using a fixed-size array to implement a stack can lead to issues such as stack overflow if the stack grows beyond its array capacity and the inefficiency of memory usage as preallocation might leave significant unused space. Additionally, resizing the array is costly in terms of time complexity . A linked list implementation addresses these issues by dynamically allocating memory, allowing the stack to grow and shrink as needed without the predefined size, thus preventing overflow and allowing efficient use of memory. This eliminates the need for restructuring and resizing arrays, making linked lists more suitable for cases with uncertain stack sizes .
A linked list can effectively implement a stack or a queue by using nodes to dynamically allocate memory and store elements sequentially, ensuring efficient use of memory. Using a node-based approach allows for potentially unlimited size, as elements are allocated in memory as needed, avoiding the fixed size constraint of array implementations . For a stack, insertion and deletion at the head of the list support efficient push and pop operations. In a queue, using a linked list allows enqueuing at the tail and dequeuing at the head, maintaining O(1) time complexity for both operations, which translates to efficient management of resources, especially in applications requiring dynamic sizes .
A priority queue differs from other types of queues in that it dequeues elements based on their priority rather than their order of insertion . Implementation of priority queues can use binary heaps for efficient access to the highest (or lowest) priority element, resulting in O(log n) time complexity for insertion and deletion. Alternatively, balanced trees or unordered lists can be used with varying efficiencies. Priority queues are utilized in applications such as operating systems for job scheduling, where tasks are executed based on priority, or in algorithmic implementations like Dijkstra’s shortest path and Huffman coding .
Linear search benefits from its simplicity and ability to operate on unsorted datasets, making it a straightforward option for small datasets or when preprocessing for sorting (a requirement for binary search) is not feasible. Its major limitation is the time complexity of O(n), rendering it inefficient for large datasets . Linear search is preferred over binary search when the dataset is small or unsorted, as binary search requires data to be sorted beforehand and is optimal for sorted large datasets with a complexity of O(log n).
The main difference between stack and queue data structures lies in their operation principles and application areas. A stack follows the LIFO (Last In First Out) principle, allowing operations such as push to add an element to the top, pop to remove the top element, peek to view the top element without removing it, and isEmpty to check if the stack is empty. Stacks are used in recursion, expression evaluation, undo mechanisms, and backtracking . On the other hand, a queue follows FIFO (First In First Out) operations with enqueue adding elements at the rear and dequeue removing the front element. Applications of queues include job scheduling in operating systems, network packet management, and printer queues .
Binary trees structure data hierarchically, where each node has at most two children. This structure is significant in many applications, such as storing hierarchical data, efficient searching (Binary Search Trees), or managing sorted data . The traversal techniques include inorder, preorder, and postorder traversals. Inorder traversal (Left, Root, Right) is particularly significant in BSTs for producing nodes in non-decreasing order. Preorder traversal (Root, Left, Right) is used to make a prefix expression of data and is useful in scenarios like copying trees. Postorder traversal (Left, Right, Root) is crucial for deleting trees node by node and for applications like calculating postfix expressions .
A queue follows the FIFO principle where the first element added is the first to be removed. Types of queues include the simple queue, where operations are restricted at both ends; the circular queue, where the rear connects back to the front, resolving the limitation of wasted space encountered in simple queues when the array becomes full but still has available space at its beginning; the deque allowing insertions and deletions from both ends; and the priority queue where elements are dequeued based on priority rather than order . Applications include job scheduling in operating systems using simple queues, network packet management utilizing priority queues, and printer job handling with circular queues to efficiently manage the queue's fixed memory .
Linked lists offer significant advantages in dynamic memory allocation over arrays due to their ability to dynamically adjust size and facilitate easier insertions and deletions since each node points to the next . This flexibility allows for efficient use of memory without the need for predefined size limits as in arrays. However, linked lists have disadvantages, such as no random access capabilities, meaning elements can only be accessed sequentially (O(n) time complexity), and they require extra memory for storing pointers for each element, which could lead to increased memory overhead .
Circular linked lists are particularly useful in use cases such as round-robin scheduling, where each node is equally important and needs periodic access, as the last node connects back to the first, providing a natural loop without the need for additional control mechanisms . Compared to singly linked lists, circular lists handle operations requiring circular data access more naturally and efficiently, particularly in applications like playlist management or cyclic buffer implementation. They are more memory-efficient than doubly linked lists, which require two pointers per element. In scenarios requiring bidirectional traversal or deletion, doubly linked lists are more appropriate .