Big O Notation
Computational Complexity
Algorithm Analysis
Asymptotic Analysis
Mathematical Proofs

n log n is On?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Understanding algorithmic complexity is crucial for computer science and software development, especially when it comes to sorting operations, data structures, and other performance-critical tasks. Within this context, it's common to encounter complexity expressions like nlog⁡nn \log n and O(n)O(n). This article will delve into why nlog⁡nn \log n is considered O(n2)O(n^2) but not O(n)O(n), exploring its meaning, implications, and applications.

Asymptotic Notation

Asymptotic notation provides a way to describe the efficiency and performance of an algorithm in terms of its time or space complexity, particularly as the input size grows indefinitely. The three most frequently used asymptotic notations are:

  • Big O (OO-notation): Provides an upper bound on the time complexity, indicating the worst-case scenario.
  • Big Omega (Ω\Omega-notation): Offers a lower bound, showing the best-case scenario.
  • Big Theta (Θ\Theta-notation): Describes a tight bound, representing the average or expected scenario.

Big O Notation: O(n)O(n)

Big O notation, O(f(n))O(f(n)), provides an upper bound for the growth rate of a function. If T(n)T(n) is the time complexity of an algorithm, then T(n)T(n) is O(f(n))O(f(n)) if there exist constants c>0c > 0 and n0≥0n_0 \geq 0 such that for all n≥n0n \geq n_0, T(n)≤c⋅f(n)T(n) \leq c \cdot f(n).

Understanding nlog⁡nn \log n

The term nlog⁡nn \log n is frequently encountered in algorithms such as Merge Sort, Quick Sort, and Heap Sort, which have average-case time complexities of O(nlog⁡n)O(n \log n). Here, the function log⁡n\log n often refers to log⁡2n\log_2 n, the binary logarithm, which is common in computer science contexts where binary data is processed.

Why nlog⁡nn \log n is Not O(n)O(n)

To understand why nlog⁡nn \log n is not O(n)O(n), consider the relationship between these two functions:

  1. Growth Rate: The growth rate of nlog⁡nn \log n is faster than nn for large values of nn. While log⁡n\log n grows very slowly compared to linear or polynomial functions, when multiplied by nn, the combined function nlog⁡nn \log n grows more quickly than nn.
  2. Proof by Contradiction: Let's attempt to prove that nlog⁡nn \log n is O(n)O(n). It implies there exist constants c>0c > 0 and n0≥0n_0 \geq 0 such that for all n≥n0n \geq n_0, nlog⁡n≤c⋅nn \log n \leq c \cdot n. Simplifying, we get log⁡n≤c\log n \leq c. Since log⁡n\log n grows indefinitely as nn increases, no such constant cc can exist, thus proving nlog⁡nn \log n is not O(n)O(n).

n log n in the Hierarchy of Functions

To visualize this, consider the following hierarchy of growth rates:

  • Constant: O(1)O(1)
  • Logarithmic: O(log⁡n)O(\log n)
  • Linear: O(n)O(n)
  • Linearithmic: O(nlog⁡n)O(n \log n)
  • Quadratic: O(n2)O(n^2)
  • Cubic: O(n3)O(n^3)
  • Exponential: O(2n)O(2^n)

Practical Example

Consider a Merge Sort algorithm, which efficiently sorts an array of nn elements. The algorithm divides the array in half, sorts each half recursively, and then merges the sorted halves. This divide-and-conquer approach has a time complexity of O(nlog⁡n)O(n \log n). While it is significantly better than O(n2)O(n^2) algorithms like Bubble Sort for large nn, it is still not as efficient as linear time algorithms like Counting Sort, which are feasible when certain conditions are met.

Summary Table

FunctionDescriptionGrowth Relative to nn
O(1)O(1)Constant timeSame
O(log⁡n)O(\log n)Logarithmic timeSlower
O(n)O(n)Linear timeBaseline
O(nlog⁡n)O(n \log n)Linearithmic timeFaster
O(n2)O(n^2)Quadratic timeMuch Faster

Conclusion

While nlog⁡nn \log n often appears in algorithm analysis as a desirable and efficient time complexity, particularly in sorting and other divide-and-conquer algorithms, it is strictly not O(n)O(n). Understanding these distinctions allows developers to make informed choices about algorithm selection and performance optimization. Recognizing that nlog⁡nn \log n grows more rapidly than linear time but less so than quadratic time helps calibrate expectations about algorithm performance, especially with large data sets.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms