Comprehensive Data Structures Notes
Comprehensive Data Structures Notes
Trees, hierarchical data structures with a single root and connected nodes, are notably used for organizing hierarchical data like file systems, allowing efficient traversal and operations like searching, as they impose constraints where cycles and multiple parent nodes are not allowed . Graphs are more generalized non-linear structures allowing multiple connections and cycles, suited for complex relational datasets like social networks or logistics networks . The absence of strict hierarchy in graphs allows more versatile modeling of relationships, but trees offer clarity and efficiency in structured data organization .
Merge sort has a time complexity of O(n log n) consistently for all cases, while quicksort has an average time complexity of O(n log n), but can degrade to O(n²) in the worst case when the pivot selection is poor . Merge sort is stable and preferred in scenarios where consistent performance is required and when handling large datasets that don't fit into memory. Quicksort is preferred for in-place sorting with better average-case performance and when memory usage is a concern .
BFS uses a queue to explore nodes level-by-level from a source node, which is suitable for finding the shortest path in unweighted graphs due to its level-order visiting nature . DFS employs a stack or recursion to explore as deeply as possible along branches before backtracking, making it useful for scenarios requiring exhaustive exploration like topological sorting or detecting cycles . The iterative broad exploration characteristic of BFS contrasts with DFS's deep path preference .
Dijkstra’s Algorithm finds the shortest path from a given source node to all other nodes in a weighted graph by iteratively selecting the node with the smallest tentative distance and updating its neighboring nodes' distances . It uses a priority queue to efficiently retrieve the next node to process. However, it does not efficiently handle negative weight edges, as negative cycles could cause the algorithm to incorrectly determine paths . It's suitable for graphs where edge weights are non-negative, such as road networks .
When the initial data is unsorted or incomplete knowledge about data order exists, linear search is appropriate as it checks each element sequentially, with O(n) time complexity, without any prerequisite on data order . Binary search, requiring sorted data, offers O(log n) time complexity, and becomes favorable in scenarios where data maintenance in sorted form is feasible. If recorded data is dynamic and changes order frequently or maintains substantial unsorted portions, linear search remains applicable where binary search is impractical .
A stack is a linear data structure operated on the LIFO (Last In First Out) principle, where elements are added and removed from the same end called the 'top.' Its applications include expression evaluation and recursion handling . In contrast, a queue operates on the FIFO (First In First Out) principle, where elements are added at the rear and removed from the front, commonly used in CPU scheduling and data buffering .
A BST is efficient because it maintains the property that the left child node is less than the parent, and the right child node is greater, allowing binary search operations that consistently halve the search space, typically offering O(log n) complexity for search, insertion, and deletion . However, if not balanced correctly, such as through frequent sequential insertions, the tree can degenerate into a linked list, losing its logarithmic time complexity and resulting in O(n) operations, necessitating mechanisms like AVL or red-black tree adjustments to retain balanced structure .
The implementation of a stack using an array involves a fixed-size data structure where elements are added or removed from the top, managed by a 'top' index. This implementation is simple and provides efficient access time, but it lacks flexibility due to the fixed size, leading to wasted space or overflow issues . Conversely, using a linked list allows dynamic memory allocation, so the stack can grow as needed, eliminating the fixed size limitation . However, it involves additional memory overhead due to node pointers and may result in slower access time and more complex memory management .
The self-balancing property of AVL trees ensures that the height difference (balance factor) between left and right subtrees of every node is at most 1, maintaining O(log n) time complexity for insertion, deletion, and search operations . This contrasts with standard binary search trees, where unbalanced trees can degrade to linked lists with O(n) time complexity for these operations. The self-balancing nature of AVL trees makes them particularly useful in applications requiring consistent time performance .
A priority queue differs from a standard queue in that elements are served based on priority rather than their arrival time, enabling elements with higher priority to be dequeued first . This is advantageous in real-world applications such as CPU task scheduling, where processes must be prioritized based on urgency or importance, and networking protocols that manage data packets by priority .