Primitive data types are system-defined, like integers or characters. User-defined data types such as stacks or heaps, which are built using primitives. Abstract data types, or ADTs, which are defined by the operations they support rather than how they’re implemented internally. For example, a Stack
Data structures are broadly classified into linear and non-linear structures. Linear data structures store elements in a sequential manner, such as arrays, linked lists, stacks, and queues. Non-linear data structures represent hierarchical or network-like relationships, where elements are connected through edges, like trees and graphs.
Static memory allocation happens at compile time and typically stored on the stack. The size is fixed and cannot change during runtime. Dynamic memory allocation happens at runtime, allocated on the heap. This allows data structures like linked lists to grow or shrink dynamically based on program needs.
Algorithm efficiency is measured with respect to the input size, usually denoted by N. Big-O for the worst case, Omega for the best case, and Theta for the average case. Space complexity accounts for the input data, local variables, and any additional space used by recursion.
O(1) is constant, O(log N) reduces input each step, O(N) scans once, O(N log N) divides and processes, and higher orders like O(2ⁿ) grow exponentially and don’t scale.
Lists can store mixed data types but are slower for comparisons. Arrays store elements of the same type and provide fast indexed access.
A linked list is a collection of nodes where each node stores data and a pointer to the next node. Linked lists do not require contiguous memory and allow efficient insertion and deletion without shifting elements. However, they do not support random access, and binary search is not possible.
Save: No constant-time middle access.
Stacks follow the LIFO principle, where elements are added and removed from the top. They are commonly used for undo-redo operations and expression parsing.
Queues follow the FIFO principle, where insertion happens at the rear and deletion at the front. They are used in task scheduling and I/O buffering.
A priority queue processes elements based on priority rather than order. A circular queue prevents unused gaps in memory. Deques allow insertion and deletion from both ends, with variants limiting operations to one end.