CS 261 DATA STRUCTURES COMPLETED EXAM 2024, Exams of Data Structures and Algorithms

CS 261 DATA STRUCTURES COMPLETED EXAM 2024CS 261 DATA STRUCTURES COMPLETED EXAM 2024CS 261 DATA STRUCTURES COMPLETED EXAM 2024

Typology: Exams

2023/2024

Available from 12/25/2023

VanBosco
VanBosco 🇺🇸

3.7

(7)

1.1K documents

1 / 22

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CS 261
Data Structures
COMPLETED EXAM
2024
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16

Partial preview of the text

Download CS 261 DATA STRUCTURES COMPLETED EXAM 2024 and more Exams Data Structures and Algorithms in PDF only on Docsity!

CS 261

Data Structures

COMPLETED EXAM

  1. What is an abstract data type (ADT) and what are its advantages over concrete data types? An ADT is a data type that is defined by its operations and behavior, rather than by its implementation or representation. The advantages of ADTs are that they provide a high level of abstraction, hiding the details of how the data is stored and manipulated, and that they allow for multiple implementations of the same ADT, as long as they satisfy the same specifications.
  2. What are some examples of ADTs and their corresponding concrete data types in common programming languages? Some examples of ADTs are stacks, queues, lists, sets, maps, trees, graphs, etc. Some corresponding concrete data types are arrays, linked lists, hash tables, binary trees, adjacency lists or matrices, etc.
  3. What is the difference between a stack and a queue ADT? A stack ADT is a linear collection of data elements that follows the last-in first-out (LIFO) principle, meaning that the last element added to the stack is the first one to be removed. A queue ADT is a linear collection of data elements that follows the first-in first-out (FIFO) principle, meaning that the first element added to the queue is the first one to be removed.
  4. How can you implement a stack ADT using an array or a linked list? To implement a stack ADT using an array, you need to keep track of the index of the top element of the stack, and use the array operations of insertion and deletion at that index. To implement a stack ADT using a linked list, you need to keep track of the pointer to the head node of the list, and use the linked list operations of insertion and deletion at that node.
  5. How can you implement a queue ADT using an array or a linked list? To implement a queue ADT using an array, you need to keep track of the indices of the front and rear elements of the queue, and use the array operations of insertion and deletion at those indices. To implement a queue ADT using a linked list, you need to keep track of the pointers to the head and tail nodes of the list, and use the linked list operations of insertion and deletion at those nodes.

How do you create a dynamic array in C++? What are some advantages and disadvantages of using dynamic arrays in C++? To create a dynamic array in C++, you can use the new operator to allocate memory for the array on the heap, and store the pointer to the array in a variable. For example, int* arr = new int[10]; creates a dynamic array of 10 integers. Alternatively, you can use a container class such as std::vector that provides a wrapper around a dynamic array and offers some additional features and functionalities. Some advantages of using dynamic arrays in C++ are that they can grow or shrink as needed, they can be passed to functions without specifying their size, and they can be returned from functions. Some disadvantages are that they require manual memory management (using delete or delete[] to free the memory), they may cause memory leaks or dangling pointers if not handled properly, and they may have performance issues due to fragmentation or reallocation. What is the difference between a shallow copy and a deep copy of a dynamic array? When would you use each one? A shallow copy of a dynamic array is when you copy only the pointer to the array, not the elements of the array. This means that both copies point to the same memory location and share the same data. A deep copy of a dynamic array is when you copy both the pointer and the elements of the array, creating a new independent copy of the data. This means that both copies have their own memory location and do not affect each other. You would use a shallow copy when you want to pass or return a reference to an existing array without modifying it, or when you want to save memory and avoid duplication. You would use a deep copy when you want to create a new independent copy of an array that you can modify without affecting the original, or when you want to avoid aliasing or dangling pointer problems. What is the difference between an array and a vector in C++? When would you prefer one over the other? An array is a built-in data type in C++ that represents a fixed-size sequence of elements of the same type. A vector is a container class in C++ that represents a dynamic-size sequence of elements of the same type, implemented as a wrapper around a dynamic array. An array has some advantages over a vector, such as faster access time, less memory usage, and compatibility with C functions. A vector has some advantages over an array, such as automatic memory management, resizing capabilities, bounds checking, and iterator support. You would prefer an array when you know the size of the sequence at compile time, when you need maximum performance and efficiency, or when you need to interoperate with C code. You would prefer a vector when you need flexibility and convenience, when you do not know the size of the sequence at run time, or when you need to use STL algorithms or containers.

How do you implement a dynamic array in Java? What are some advantages and disadvantages of using dynamic arrays in Java? To implement a dynamic array in Java, you can use an array object with an initial size and resize it as needed using the Arrays.copyOf method. For example, int[] arr = new int[10]; arr = Arrays.copyOf(arr, 20); creates and resizes a dynamic array of integers. Alternatively, you can use an ArrayList class that provides a wrapper around an array object and offers some additional features and functionalities. Some advantages of using dynamic arrays in Java are that they can store any type of objects (including primitives), they can grow or shrink as needed, and they can be converted to regular arrays using the toArray method. Some disadvantages are that they may waste memory if not resized properly, they may have performance issues due to copying or resizing operations, and they may not support some operations such as sorting or searching efficiently. What are some common operations on dynamic arrays? How do you implement them in pseudocode? Some common operations on dynamic arrays are:

  • Insertion: adding an element at a given position or at the end of the array.
  • Deletion: removing an element at a given position or at the end of the array.
  • Access: retrieving an element at a given position or iterating over all elements.
  • Search: finding an element that matches a given value or condition.
  • Sort: arranging the elements in ascending or descending order according to some criteria. Here is some pseudocode for implementing these operations on a dynamic array: // Assume that arr is a dynamic array of size n and capacity c // Assume that x is the element to be inserted, deleted, accessed, or searched // Assume that i is the position to be inserted, deleted, or accessed // Insertion at position i if i < 0 or i > n then return error // invalid position else if n == c then resize arr to double its capacity // allocate more memory end if for j = n-1 down to i do arr[j+1] = arr[j] // shift elements to the right end for arr[i] = x // insert x at position i n = n + 1 // increment size end if // Insertion at the end if n == c then resize arr to double its capacity // allocate more memory end if arr[n] = x // insert x at the end n = n + 1 // increment size

end for end for What is a linked list and what are its advantages and disadvantages over an array? A linked list is a linear data structure that consists of a sequence of nodes, each containing some data and a pointer to the next node in the list. The advantages of a linked list over an array are that it can grow or shrink dynamically, it can insert or delete elements at any position without shifting other elements, and it does not require a contiguous block of memory. The disadvantages of a linked list over an array are that it has a higher overhead for storing pointers, it does not allow random access to elements, and it may be more difficult to implement some algorithms that require traversal or sorting. What are the different types of linked lists and how are they different from each other? The different types of linked lists are singly linked lists, doubly linked lists, circular linked lists, and skip lists. A singly linked list has only one pointer per node, pointing to the next node in the list. A doubly linked list has two pointers per node, pointing to the previous and the next node in the list. A circular linked list is a singly or doubly linked list where the last node points back to the first node, forming a loop. A skip list is a probabilistic data structure that consists of multiple levels of linked lists, where each level contains a subset of the elements in the lower level, and the pointers skip over some nodes to allow faster search.

. How do you reverse a singly linked list in place? To reverse a singly linked list in place, you need to keep track of three pointers: the current node, the previous node, and the next node. You start from the head of the list and iterate until the current node is null. At each step, you save the next node, set the current node's pointer to the previous node, and update the previous and current nodes. At the end, you return the previous node as the new head of the list. . How do you detect and remove a cycle in a linked list? To detect a cycle in a linked list, you can use a fast and slow pointer technique, also known as Floyd's cycle detection algorithm. You start with two pointers, one moving one step at a time and the other moving two steps at a time, from the head of the list. If there is a cycle, they will eventually meet at some node. To find the start of the cycle, you reset one pointer to the head of the list and move both pointers one step at a time until they meet again. To remove the cycle, you set the pointer that reached the start of the cycle to null.

How do you merge two sorted linked lists into one sorted linked list? To merge two sorted linked lists into one sorted linked list, you can use a recursive or iterative approach. The recursive approach is to compare the data of the first nodes of each list and choose the smaller one as the new head of the merged list. Then, recursively merge the rest of that list with the other list and return the new head. The iterative approach is to use a dummy node as a placeholder for the new head of the merged list and maintain a tail pointer that points to the last node added to the merged list. Then, iterate through both lists and compare their data, adding the smaller one to the tail pointer and updating it accordingly. At the end, return the dummy node's next pointer as the new head. What is the difference between a tree and a graph? Give an example of a real-world problem that can be modeled by each data structure. A tree is a special kind of graph that has no cycles and has a unique path between any two nodes. A graph is a more general data structure that can have cycles and multiple paths between nodes. A real-world problem that can be modeled by a tree is the hierarchical structure of an organization or a file system. A real-world problem that can be modeled by a graph is the network of roads or flights between cities. What are the advantages and disadvantages of using an adjacency matrix versus an adjacency list to represent a graph? Which representation would you choose for a sparse graph and why? An adjacency matrix is a two-dimensional array that stores the presence or absence of an edge between every pair of nodes in the graph. An adjacency list is a collection of lists that stores the neighbors of each node in the graph. The advantages of using an adjacency matrix are that it is easy to check if there is an edge between two nodes, and it is easy to perform matrix operations on the graph. The disadvantages are that it takes O(n^2) space, where n is the number of nodes, and it is inefficient to iterate over the edges or neighbors of a node. The advantages of using an adjacency list are that it takes O(m+n) space, where m is the number of edges, and it is efficient to iterate over the edges or neighbors of a node. The disadvantages are that it is harder to check if there is an edge between two nodes, and it is harder to perform matrix operations on the graph. For a sparse graph, which has few edges compared to the number of nodes, I would choose an adjacency list representation because it saves space and allows faster traversal. What are some common algorithms for traversing a tree or a graph? What are their time and space complexities? How do they differ in terms of order and strategy? Some common algorithms for traversing a tree or a graph are depth-first search (DFS), breadth-first search (BFS), and topological sort. DFS visits the nodes in a depth-first manner, meaning it explores as far as possible along each branch before backtracking. BFS visits the nodes in a breadth-first manner, meaning it explores all the nodes at the same level before moving to the next level. Topological sort visits the nodes in a linear order such that for every directed edge from u to v, u comes before v in the order. The time

What is the difference between a binary tree and a binary search tree? Explain with examples. A binary tree is a tree data structure where each node has at most two children, left and right. A binary search tree is a special type of binary tree where the nodes are ordered according to a key value, such that for any node, all the nodes in its left subtree have smaller keys and all the nodes in its right subtree have larger keys. For example, the following is a binary tree but not a binary search tree: 5 /
3 7 / \ /
2 6 4 8 The following is a binary search tree: 5 /
3 7 / \ /
2 4 6 8 What are the advantages and disadvantages of using a binary search tree over other data structures such as arrays, linked lists, or hash tables? Some advantages of using a binary search tree are:

  • It allows fast search, insertion, and deletion operations in O(log n) time on average, where n is the number of nodes in the tree.
  • It can be used to implement other abstract data types such as sets, maps, or priority queues.
  • It can support range queries and ordered traversal of the elements in O(n) time. Some disadvantages of using a binary search tree are:
  • It requires extra space for storing pointers to the children nodes.
  • It can become unbalanced and degrade to O(n) time for search, insertion, and deletion operations if the keys are not randomly distributed or if the tree is not rebalanced periodically.
  • It is not suitable for dynamic data that changes frequently.

How can you check if a given binary tree is a valid binary search tree? One way to check if a given binary tree is a valid binary search tree is to perform an in-order traversal of the tree and verify that the keys are in sorted order. Alternatively, one can use a recursive function that checks if each node satisfies the binary search tree property with respect to its left and right subtrees, using minimum and maximum values as parameters to keep track of the valid range for each node. What are some common operations that can be performed on a binary search tree? How would you implement them? Some common operations that can be performed on a binary search tree are:

  • Search: To search for a key in a binary search tree, start from the root node and compare the key with the node's key. If they are equal, return the node. If the key is smaller, go to the left child. If the key is larger, go to the right child. Repeat until either the key is found or the node is null.
  • Insertion: To insert a key in a binary search tree, start from the root node and compare the key with the node's key. If they are equal, do nothing or update the node's value. If the key is smaller, go to the left child. If the key is larger, go to the right child. If the child is null, create a new node with the key and attach it as the child. Repeat until either the key is inserted or the node is null.
  • Deletion: To delete a key from a binary search tree, start from the root node and compare the key with the node's key. If they are equal, delete the node by replacing it with either its left or right child if one of them is null, or with its in-order successor (the smallest node in its right subtree) or predecessor (the largest node in its left subtree) if both of them are not null. If the key is smaller, go to the left child. If the key is larger, go to the right child. Repeat until either the key is deleted or the node is null. What are some ways to balance a binary search tree? Explain with examples. Some ways to balance a binary search tree are:
  • Rotation: A rotation is an operation that changes the structure of a subtree without changing its in-order traversal order. There are two types of rotations: left rotation and right rotation. A left rotation on a node x means to make its right child y as the new root of the subtree, and make x as the left child of y. A right rotation on a node x means to make its left child y as the new root of the subtree, and make x as the right child of y. For example: x y / \ /
    A y => x C / \ /
    B C A B A rotation can be used to reduce the height of a subtree by moving nodes from one side to another.
  • Self-balancing algorithms: A self-balancing algorithm is an algorithm that maintains the balance of a
  • Splay tree: A splay tree is a self-balancing binary search tree that performs a splay operation on every access (search, insertion, or deletion) of a node. A splay operation is a sequence of rotations that moves the accessed node to the root of the tree, making it easier to access in the future. Splay trees have good amortized performance and can adapt to different access patterns.
  • B-tree: A B-tree is a balanced multi-way search tree where each node has between d and 2d children (except for the root), where d is a positive integer called the minimum degree of the tree. Each node stores up to 2d-1 keys in sorted order and optionally values associated with them. The keys in each node act as separators that divide its children into subranges. B-trees are commonly used to store large amounts of data on disk or other external memory devices. How can you implement a binary search tree using an array? What are the advantages and disadvantages of this approach? One way to implement a binary search tree using an array is to use the following formula to calculate the index of each node's children and parent:
  • Left child index = 2 * parent index + 1
  • Right child index = 2 * parent index + 2
  • Parent index = (child index - 1) / 2 For example, if the root node is stored at index 0, then its left child will be at index 1, its right child will be at index 2, its parent will be at index - 1 (invalid), and so on. Some advantages of this approach are:
  • It saves space by eliminating pointers to the children nodes.
  • It allows random access to any node in O(1) time. Some disadvantages of this approach are:
  • It wastes space if the tree is sparse or unbalanced, as some array elements will be unused or null.
  • It limits the size of the tree by the size of the array.
  • It requires shifting elements when inserting or deleting nodes.

What is a hash function and what are its properties? Explain with an example. A hash function is a function that maps a key to an index in a hash table. A hash function should have the following properties:

  • It should be deterministic, meaning that the same key always produces the same index.
  • It should be uniform, meaning that it distributes the keys evenly across the hash table to avoid collisions.
  • It should be efficient, meaning that it can be computed quickly. An example of a hash function is the division method, where the index is computed as h(k) = k mod m, where k is the key and m is the size of the hash table. What is a collision and how can it be resolved in a hash table? Explain with an example. A collision occurs when two or more keys are mapped to the same index in a hash table. A collision can be resolved by using one of the following methods:
  • Chaining: Each index in the hash table points to a linked list of entries that have the same hash value. To insert or search for a key, we traverse the corresponding list until we find or insert the entry.
  • Open addressing: Each index in the hash table contains either an entry or a special value indicating that it is empty. To insert or search for a key, we probe the hash table using a sequence of indices until we find or insert the entry or reach an empty slot. An example of a collision is when we use the division method with m = 10 and insert the keys 15 and 25. Both keys have the same hash value of 5, so they collide. We can resolve this collision by using chaining or open addressing. What are the advantages and disadvantages of chaining and open addressing? The advantages and disadvantages of chaining and open addressing are as follows:
  • Chaining: The advantage of chaining is that it can handle any number of collisions and does not require resizing the hash table. The disadvantage of chaining is that it requires extra space for the linked lists and may have poor cache performance due to random memory access.
  • Open addressing: The advantage of open addressing is that it does not require extra space and may have better cache performance due to sequential memory access. The disadvantage of open addressing is that it has a limited load factor (the ratio of entries to slots) and requires resizing the hash table when it becomes full or too sparse. What are some common probing strategies for open addressing? Explain with an example. Some common probing strategies for open addressing are as follows:
  • Linear probing: The probe sequence is h(k), h(k) + 1, h(k) + 2, ..., wrapping around the hash table if necessary. This strategy is simple but may suffer from clustering, where consecutive slots are occupied by colliding keys.
  • Quadratic probing: The probe sequence is h(k), h(k) + 1^2, h(k) + 2^2, ..., wrapping around the hash table if necessary. This strategy avoids primary clustering but may suffer from secondary clustering, where keys

collisions.

  • Store the secondary hash tables and their hash functions in another array B of size m.
  • The final hash function is H(k) = h(k) if A[h(k)] = 1, or H(k) = h(k) * A[h(k)] + h_h(k)(k) if A[h(k)] > 1. What is a cryptographic hash function and what are its applications? A cryptographic hash function is a hash function that has the following properties:
  • It is one-way, meaning that it is easy to compute the hash value from the key, but hard to find the key from the hash value.
  • It is collision-resistant, meaning that it is hard to find two keys that have the same hash value.
  • It is pseudorandom, meaning that it produces hash values that are uniformly distributed and unpredictable. Some applications of cryptographic hash functions are as follows:
  • Authentication: Cryptographic hash functions can be used to verify the identity or integrity of a message or a file by comparing its hash value with a known or expected value.
  • Digital signatures: Cryptographic hash functions can be used to generate digital signatures that can prove the authenticity and non-repudiation of a message or a file by using public-key cryptography.
  • Encryption: Cryptographic hash functions can be used to generate encryption keys or initialization vectors for symmetric-key cryptography. What are some examples of cryptographic hash functions and their properties? Some examples of cryptographic hash functions and their properties are as follows:
  • MD5: A 128-bit hash function that was widely used in the past but is now considered insecure due to its vulnerability to collision attacks.
  • SHA-1: A 160-bit hash function that was also widely used in the past but is now considered insecure due to its vulnerability to collision attacks.
  • SHA-2: A family of hash functions that include SHA-224, SHA-256, SHA-384, and SHA-512, with different output sizes. They are considered secure and widely used in various applications.
  • SHA-3: A family of hash functions that include SHA3-224, SHA3-256, SHA3-384, and SHA3-512, with different output sizes. They are based on a different design than SHA-2 and provide an alternative in case SHA-2 is compromised. What are some challenges or limitations of using hash tables in practice? Some challenges or limitations of using hash tables in practice are as follows:
  • Choosing a good hash function: A good hash function should be uniform, efficient, and suitable for the domain of keys. However, finding such a function may not be easy or possible for some types of keys or applications.
  • Handling collisions: Collisions are inevitable in any hashing scheme and require extra space or time to

resolve. Different collision resolution methods have different trade-offs and may not work well for some scenarios or workloads.

  • Resizing the hash table: Resizing the hash table may be necessary to maintain a good load factor and performance. However, resizing may be costly or disruptive as it requires rehashing all the entries or reallocating all the buckets. What is the difference between primary and secondary storage? Provide an example of each. Primary storage is the memory that is directly accessible by the CPU, such as RAM or cache. Secondary storage is the memory that is not directly accessible by the CPU, but can be accessed through input/output operations, such as hard disk or flash drive. An example of primary storage is DDR4 RAM, and an example of secondary storage is SSD. What are the advantages and disadvantages of using RAID (Redundant Array of Independent Disks) for storage management? Explain the different levels of RAID and how they work. RAID is a technique that combines multiple disks into a logical unit to improve performance, reliability, or both. The advantages of using RAID are that it can increase data transfer speed, provide fault tolerance, and reduce the risk of data loss. The disadvantages of using RAID are that it can increase the cost, complexity, and power consumption of the system, and reduce the usable storage capacity. The different levels of RAID are:
  • RAID 0: Striping. Data is split across two or more disks without redundancy. This improves performance but offers no fault tolerance.
  • RAID 1: Mirroring. Data is duplicated on two or more disks. This provides fault tolerance but reduces storage capacity by half.
  • RAID 5: Parity. Data is striped across three or more disks with one disk storing parity information. This provides fault tolerance and performance improvement, but requires more disks and computation.
  • RAID 6: Double parity. Data is striped across four or more disks with two disks storing parity information. This provides higher fault tolerance than RAID 5, but requires more disks and computation.
  • RAID 10: Nested RAID. Data is striped and mirrored across four or more disks. This combines the benefits of RAID 0 and RAID 1, but requires at least four disks and reduces storage capacity by half. What are the benefits and challenges of using cloud storage for data management? Compare and contrast different types of cloud storage services, such as SaaS, PaaS, and IaaS. Cloud storage is a service that allows users to store and access data over the internet, rather than on local devices. The benefits of using cloud storage are that it can provide scalability, flexibility, accessibility,

. What are the differences and similarities between magnetic, optical, and solid-state storage devices? Give an example of each type of device and explain how they work. Magnetic, optical, and solid-state storage devices are different types of secondary storage devices that use different technologies to store and access data. The differences and similarities between them are:

  • Magnetic storage devices use magnetized materials, such as metal disks or tapes, to store data as patterns of magnetic fields. An example of a magnetic storage device is a hard disk drive (HDD), which consists of one or more rotating platters coated with magnetic material and read/write heads that move across the platters to read or write data. Magnetic storage devices have high capacity, low cost, and long durability, but low speed, high power consumption, and high sensitivity to physical damage.
  • Optical storage devices use laser beams, such as infrared or visible light, to store data as patterns of pits and lands on a reflective surface. An example of an optical storage device is a compact disc (CD), which consists of a thin plastic disc with a spiral track of pits and lands that reflect light from a laser beam in a CD- ROM drive to read data. Optical storage devices have moderate capacity, moderate cost, and moderate durability, but low speed, low power consumption, and low sensitivity to physical damage.
  • Solid-state storage devices use electronic circuits, such as transistors or capacitors, to store data as patterns of electric charges. An example of a solid-state storage device is a flash drive, which consists of a small circuit board with flash memory chips that store data as electric charges in cells that can be erased and rewritten by applying voltage. Solid-state storage devices have low capacity, high cost, and low durability, but high speed, low power consumption, and low sensitivity to physical damage. What is the difference between worst-case, best-case and average-case complexity of an algorithm? Give an example of a data structure and an operation that have different complexities for these cases. Answer: The worst-case complexity of an algorithm is the maximum amount of time or space it takes to execute for any input of a given size. The best-case complexity is the minimum amount of time or space it takes to execute for any input of a given size. The average-case complexity is the expected amount of time or space it takes to execute for a random input of a given size. An example of a data structure and an operation that have different complexities for these cases is a binary search tree and searching for an element. The worst-case complexity of searching in a binary search tree is O(n), where n is the number of nodes, if the tree is skewed. The best-case complexity is O(log n), if the tree is balanced. The average-case complexity is O(log n), assuming that the tree is randomly constructed. What is the difference between static and dynamic data structures? Give an example of each type and explain their advantages and disadvantages. Answer: A static data structure is one that has a fixed size and structure at compile time and cannot be modified at run time. A dynamic data structure is one that can change its size and structure at run time according to the needs of the program. An example of a static data structure is an array, which has a fixed number of elements and can be accessed by index. An example of a dynamic data structure is a linked list,

which can grow or shrink by adding or removing nodes and can be accessed by pointers. The advantages of static data structures are that they are easy to implement, have fast access and use less memory overhead. The disadvantages are that they are inflexible, have limited capacity and may waste memory if not fully utilized. The advantages of dynamic data structures are that they are flexible, have unlimited capacity and use memory efficiently. The disadvantages are that they are harder to implement, have slower access and use more memory overhead. What is the difference between linear and nonlinear data structures? Give an example of each type and explain how they are stored in memory. Answer: A linear data structure is one that stores its elements in a sequential order, such as an array, a stack or a queue. A nonlinear data structure is one that stores its elements in a hierarchical or networked order, such as a tree or a graph. Linear data structures are usually stored in contiguous memory locations, where each element has a fixed size and can be accessed by index or pointer arithmetic. Nonlinear data structures are usually stored in non-contiguous memory locations, where each element has a variable size and can be accessed by pointers or references. What is the difference between stack and queue data structures? Give an example of an application that uses each type and explain how they work. Answer: A stack is a linear data structure that follows the last-in first-out (LIFO) principle, where the last element inserted is the first one to be removed. A queue is a linear data structure that follows the first-in first-out (FIFO) principle, where the first element inserted is the first one to be removed. An example of an application that uses a stack is a function call, where the function parameters and return addresses are pushed onto the stack when the function is called and popped off when the function returns. An example of an application that uses a queue is a printer spooler, where the print jobs are enqueued when they are requested and dequeued when they are processed. What is the difference between array and linked list data structures? Give an example of an operation that is faster in one type than the other and explain why. Answer: An array is a static data structure that stores its elements in contiguous memory locations and can be accessed by index. A linked list is a dynamic data structure that stores its elements in non-contiguous memory locations and can be accessed by pointers. An example of an operation that is faster in an array than in a linked list is random access, where any element can be retrieved in constant time by its index. An