Data Structure Exam Paper 2019
Data Structure Exam Paper 2019
Asymptotic notations provide a way to describe the running time of an algorithm in terms of input size, n, by focusing on the growth rate of the algorithm's time complexity. The primary types include Big O notation, which gives an upper bound on the growth, indicating the worst-case scenario; Theta notation, which provides a tight bound, showing both upper and lower bounds when the running time grows exactly at this rate; and Omega notation, used to provide a lower bound, indicating the best-case time complexity. These notations help compare algorithms by focusing on their execution time or space requirements in the bounds of large inputs, ignoring lower-order terms and constant factors, thus making it easier to predict performance and choose the optimal algorithm for a problem .
Constructing an AVL tree involves inserting elements from the list one by one while maintaining the tree's balance through specific rotations. Start with an empty tree and insert the first key as the root. For each subsequent key, insert it at the correct position based on binary search tree ordering. After each insertion, check the balance factor of each node (difference in heights of the left and right subtrees). If a node becomes unbalanced (balance factor exceeds ±1), perform rotations to restore balance, such as single Right or Left rotations, or double rotations (Right-Left or Left-Right) for complex cases. This iterative balancing ensures that the AVL tree remains height-balanced, thus maintaining logarithmic search, insertion, and deletion times .
Insertion sort is an iterative, comparison-based sorting algorithm. It builds the sorted array one element at a time by repeatedly taking the next element and inserting it into its correct position among the already sorted elements. The algorithm proceeds as follows: Assume the first element is sorted; pick the next element and compare it with elements in the sorted sub-array, shifting those greater than the element one position to the right; insert the element at the correct position. Continue this process with each subsequent element. Insertion sort has a time complexity of O(n^2) in the worst and average cases due to its nested comparisons. However, it performs well on small or partially sorted data, providing an average advantage with adaptations for incremental sorting .
A circular queue differs from a linear queue in that it wraps around to the beginning of the queue when the end of the queue is reached. This is achieved using an array and two pointers, front and rear. When rear reaches the end of the queue, it wraps around to the beginning if there is space, thus utilizing the empty space left by dequeued elements at the front. The main advantage of a circular queue over a linear one is that it optimizes space, avoiding wasted memory by reusing space of dequeued elements. This configuration is particularly beneficial in scenarios like resource scheduling where bounded environments need efficient use of storage .
Linked lists provide several advantages over arrays, including dynamic size allocation, allowing efficient insertions and deletions without the need for shifting elements as required in arrays. They offer flexibility in memory usage as they don't need a contiguous block of memory, important in cases where memory reallocation is costly. Linked lists are also more suitable for implementations like queues, stacks, and dynamic collections like hash tables, due to their ability to grow and shrink as needed without predefined sizes .
A height-balanced tree is a binary tree where the height difference between the left and right subtrees of any node is at most one, ensuring balanced operations. The concept primarily involves two rotations to maintain balance: Right Rotation (RR) and Left Rotation (RL). Right Rotation (RR) occurs when a left subtree becomes heavier, causing an extended height. Similarly, Left Rotation (RL) corrects balance when the right subtree of the left child needs rebalancing. In a Right-Right case (heavy on right), a Left Rotation directly fixes imbalance, while a Left-Right case requires a Right Rotation first on the left child, followed by a Left Rotation. These rotations are performed recursively along the tree where imbalance occurs, ensuring optimized search time operations .
To convert an infix expression to a postfix expression using a stack, follow these steps: 1) Initialize an empty stack and an empty result string. 2) Iterate over each character in the infix expression. 3) If the character is an operand, append it to the result. 4) If the character is '(', push it onto the stack. 5) When encountering ')', pop from the stack to the result until '(' is encountered at the top of the stack, which is then discarded. 6) If an operator is encountered, pop from the stack to the result string until the stack is empty or a lower or equal precedence operator is at the top of the stack. Push the current operator onto the stack. 7) After processing the input, pop all remaining operators in the stack to the result. The result is then the postfix expression of the given infix expression .
An adjacency matrix is a 2D array used to represent a graph, where the rows and columns correspond to vertices, and the presence of an edge between two vertices is indicated by a non-zero value at the matrix cell intersecting those vertices. Strengths of the adjacency matrix include its straightforward implementation that provides quick access to check if an edge exists between any two vertices, making it effective for dense graphs. However, its weaknesses include inefficient space usage for sparse graphs, as it occupies O(V^2) space regardless of the number of edges, and edges may be minimally present .
The primary difference between a stack and a linked list lies in their access constraints and structural organization. A stack is a linear data structure that follows the Last In, First Out (LIFO) principle, allowing insertion and deletion only at one end, referred to as the top of the stack. Conversely, a linked list is a collection of nodes that are not confined to sequential memory, allowing insertion and deletion at any position. Stacks are commonly used for their constraint of accessing elements, which makes them suitable for algorithms like depth-first search and for managing function calls, whereas linked lists provide more flexibility for dynamic memory allocation and efficient insertions and deletions provided you have a reference to the nodes involved .
A priority queue is a data structure where each element has a priority, and elements are served based on priority rather than just order in the queue, typically implemented using a heap structure. If two elements have the same priority, they are served according to their order in the queue. A common application in computing is task scheduling in operating systems, where processes with higher priority are executed before others, ensuring timely task management and system resource allocation. The priority queue helps in scenarios requiring dynamic and flexible priority determination, such as Dijkstra's shortest path algorithm .