mirror of
https://github.com/krahets/hello-algo.git
synced 2026-06-29 09:04:23 +00:00
2218 lines
56 KiB
Markdown
2218 lines
56 KiB
Markdown
---
|
|
comments: true
|
|
---
|
|
|
|
# 2.4 Space Complexity
|
|
|
|
<u>Space complexity</u> measures the growth trend of memory space occupied by an algorithm as the data size increases. This concept is very similar to time complexity, except that "running time" is replaced with "occupied memory space".
|
|
|
|
## 2.4.1 Algorithm-Related Space
|
|
|
|
The memory space used by an algorithm during execution mainly includes the following types.
|
|
|
|
- **Input space**: Used to store the input data of the algorithm.
|
|
- **Temporary space**: Used to store variables, objects, function contexts, and other data during the algorithm's execution.
|
|
- **Output space**: Used to store the output data of the algorithm.
|
|
|
|
In general, the scope of space complexity statistics is "temporary space" plus "output space".
|
|
|
|
Temporary space can be further divided into three parts.
|
|
|
|
- **Temporary data**: Used to save various constants, variables, objects, etc., during the algorithm's execution.
|
|
- **Stack frame space**: Used to save the context data of called functions. The system creates a stack frame at the top of the stack each time a function is called, and the stack frame space is released after the function returns.
|
|
- **Instruction space**: Used to save compiled program instructions, which are usually ignored in actual statistics.
|
|
|
|
When analyzing the space complexity of a program, **we usually consider three parts: temporary data, stack frame space, and output data**, as shown in the following figure.
|
|
|
|
{ class="animation-figure" }
|
|
|
|
<p align="center"> Figure 2-15 Algorithm-related space </p>
|
|
|
|
The related code is as follows:
|
|
|
|
=== "Python"
|
|
|
|
```python title=""
|
|
class Node:
|
|
"""Class"""
|
|
def __init__(self, x: int):
|
|
self.val: int = x # Node value
|
|
self.next: Node | None = None # Reference to the next node
|
|
|
|
def function() -> int:
|
|
"""Function"""
|
|
# Perform some operations...
|
|
return 0
|
|
|
|
def algorithm(n) -> int: # Input data
|
|
A = 0 # Temporary data (constant, usually represented by uppercase letters)
|
|
b = 0 # Temporary data (variable)
|
|
node = Node(0) # Temporary data (object)
|
|
c = function() # Stack frame space (function call)
|
|
return A + b + c # Output data
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title=""
|
|
/* Structure */
|
|
struct Node {
|
|
int val;
|
|
Node *next;
|
|
Node(int x) : val(x), next(nullptr) {}
|
|
};
|
|
|
|
/* Function */
|
|
int func() {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
int algorithm(int n) { // Input data
|
|
const int a = 0; // Temporary data (constant)
|
|
int b = 0; // Temporary data (variable)
|
|
Node* node = new Node(0); // Temporary data (object)
|
|
int c = func(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title=""
|
|
/* Class */
|
|
class Node {
|
|
int val;
|
|
Node next;
|
|
Node(int x) { val = x; }
|
|
}
|
|
|
|
/* Function */
|
|
int function() {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
int algorithm(int n) { // Input data
|
|
final int a = 0; // Temporary data (constant)
|
|
int b = 0; // Temporary data (variable)
|
|
Node node = new Node(0); // Temporary data (object)
|
|
int c = function(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title=""
|
|
/* Class */
|
|
class Node(int x) {
|
|
int val = x;
|
|
Node next;
|
|
}
|
|
|
|
/* Function */
|
|
int Function() {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
int Algorithm(int n) { // Input data
|
|
const int a = 0; // Temporary data (constant)
|
|
int b = 0; // Temporary data (variable)
|
|
Node node = new(0); // Temporary data (object)
|
|
int c = Function(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title=""
|
|
/* Structure */
|
|
type node struct {
|
|
val int
|
|
next *node
|
|
}
|
|
|
|
/* Create node structure */
|
|
func newNode(val int) *node {
|
|
return &node{val: val}
|
|
}
|
|
|
|
/* Function */
|
|
func function() int {
|
|
// Perform some operations...
|
|
return 0
|
|
}
|
|
|
|
func algorithm(n int) int { // Input data
|
|
const a = 0 // Temporary data (constant)
|
|
b := 0 // Temporary data (variable)
|
|
newNode(0) // Temporary data (object)
|
|
c := function() // Stack frame space (function call)
|
|
return a + b + c // Output data
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title=""
|
|
/* Class */
|
|
class Node {
|
|
var val: Int
|
|
var next: Node?
|
|
|
|
init(x: Int) {
|
|
val = x
|
|
}
|
|
}
|
|
|
|
/* Function */
|
|
func function() -> Int {
|
|
// Perform some operations...
|
|
return 0
|
|
}
|
|
|
|
func algorithm(n: Int) -> Int { // Input data
|
|
let a = 0 // Temporary data (constant)
|
|
var b = 0 // Temporary data (variable)
|
|
let node = Node(x: 0) // Temporary data (object)
|
|
let c = function() // Stack frame space (function call)
|
|
return a + b + c // Output data
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title=""
|
|
/* Class */
|
|
class Node {
|
|
val;
|
|
next;
|
|
constructor(val) {
|
|
this.val = val === undefined ? 0 : val; // Node value
|
|
this.next = null; // Reference to the next node
|
|
}
|
|
}
|
|
|
|
/* Function */
|
|
function constFunc() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
function algorithm(n) { // Input data
|
|
const a = 0; // Temporary data (constant)
|
|
let b = 0; // Temporary data (variable)
|
|
const node = new Node(0); // Temporary data (object)
|
|
const c = constFunc(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title=""
|
|
/* Class */
|
|
class Node {
|
|
val: number;
|
|
next: Node | null;
|
|
constructor(val?: number) {
|
|
this.val = val === undefined ? 0 : val; // Node value
|
|
this.next = null; // Reference to the next node
|
|
}
|
|
}
|
|
|
|
/* Function */
|
|
function constFunc(): number {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
function algorithm(n: number): number { // Input data
|
|
const a = 0; // Temporary data (constant)
|
|
let b = 0; // Temporary data (variable)
|
|
const node = new Node(0); // Temporary data (object)
|
|
const c = constFunc(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title=""
|
|
/* Class */
|
|
class Node {
|
|
int val;
|
|
Node next;
|
|
Node(this.val, [this.next]);
|
|
}
|
|
|
|
/* Function */
|
|
int function() {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
int algorithm(int n) { // Input data
|
|
const int a = 0; // Temporary data (constant)
|
|
int b = 0; // Temporary data (variable)
|
|
Node node = Node(0); // Temporary data (object)
|
|
int c = function(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title=""
|
|
use std::rc::Rc;
|
|
use std::cell::RefCell;
|
|
|
|
/* Structure */
|
|
struct Node {
|
|
val: i32,
|
|
next: Option<Rc<RefCell<Node>>>,
|
|
}
|
|
|
|
/* Create Node structure */
|
|
impl Node {
|
|
fn new(val: i32) -> Self {
|
|
Self { val: val, next: None }
|
|
}
|
|
}
|
|
|
|
/* Function */
|
|
fn function() -> i32 {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
fn algorithm(n: i32) -> i32 { // Input data
|
|
const a: i32 = 0; // Temporary data (constant)
|
|
let mut b = 0; // Temporary data (variable)
|
|
let node = Node::new(0); // Temporary data (object)
|
|
let c = function(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title=""
|
|
/* Function */
|
|
int func() {
|
|
// Perform some operations...
|
|
return 0;
|
|
}
|
|
|
|
int algorithm(int n) { // Input data
|
|
const int a = 0; // Temporary data (constant)
|
|
int b = 0; // Temporary data (variable)
|
|
int c = func(); // Stack frame space (function call)
|
|
return a + b + c; // Output data
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title=""
|
|
/* Class */
|
|
class Node(var _val: Int) {
|
|
var next: Node? = null
|
|
}
|
|
|
|
/* Function */
|
|
fun function(): Int {
|
|
// Perform some operations...
|
|
return 0
|
|
}
|
|
|
|
fun algorithm(n: Int): Int { // Input data
|
|
val a = 0 // Temporary data (constant)
|
|
var b = 0 // Temporary data (variable)
|
|
val node = Node(0) // Temporary data (object)
|
|
val c = function() // Stack frame space (function call)
|
|
return a + b + c // Output data
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title=""
|
|
### Class ###
|
|
class Node
|
|
attr_accessor :val # Node value
|
|
attr_accessor :next # Reference to the next node
|
|
|
|
def initialize(x)
|
|
@val = x
|
|
end
|
|
end
|
|
|
|
### Function ###
|
|
def function
|
|
# Perform some operations...
|
|
0
|
|
end
|
|
|
|
### Algorithm ###
|
|
def algorithm(n) # Input data
|
|
a = 0 # Temporary data (constant)
|
|
b = 0 # Temporary data (variable)
|
|
node = Node.new(0) # Temporary data (object)
|
|
c = function # Stack frame space (function call)
|
|
a + b + c # Output data
|
|
end
|
|
```
|
|
|
|
## 2.4.2 Calculation Method
|
|
|
|
The calculation method for space complexity is roughly the same as for time complexity, except that what we measure changes from the "number of operations" to the "amount of space used".
|
|
|
|
Unlike time complexity, **we usually only focus on the worst-case space complexity**. This is because memory space is a hard requirement, and we must ensure that sufficient memory space is reserved for all input data.
|
|
|
|
Observe the following code. Here, "worst case" in worst-case space complexity has two meanings.
|
|
|
|
1. **Based on the worst input data**: When $n < 10$, the space complexity is $O(1)$; but when $n > 10$, the initialized array `nums` occupies $O(n)$ space, so the worst-case space complexity is $O(n)$.
|
|
2. **Based on the peak memory during algorithm execution**: For example, before executing the last line, the program occupies $O(1)$ space; when initializing the array `nums`, the program occupies $O(n)$ space, so the worst-case space complexity is $O(n)$.
|
|
|
|
=== "Python"
|
|
|
|
```python title=""
|
|
def algorithm(n: int):
|
|
a = 0 # O(1)
|
|
b = [0] * 10000 # O(1)
|
|
if n > 10:
|
|
nums = [0] * n # O(n)
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title=""
|
|
void algorithm(int n) {
|
|
int a = 0; // O(1)
|
|
vector<int> b(10000); // O(1)
|
|
if (n > 10)
|
|
vector<int> nums(n); // O(n)
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title=""
|
|
void algorithm(int n) {
|
|
int a = 0; // O(1)
|
|
int[] b = new int[10000]; // O(1)
|
|
if (n > 10)
|
|
int[] nums = new int[n]; // O(n)
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title=""
|
|
void Algorithm(int n) {
|
|
int a = 0; // O(1)
|
|
int[] b = new int[10000]; // O(1)
|
|
if (n > 10) {
|
|
int[] nums = new int[n]; // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title=""
|
|
func algorithm(n int) {
|
|
a := 0 // O(1)
|
|
b := make([]int, 10000) // O(1)
|
|
var nums []int
|
|
if n > 10 {
|
|
nums := make([]int, n) // O(n)
|
|
}
|
|
fmt.Println(a, b, nums)
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title=""
|
|
func algorithm(n: Int) {
|
|
let a = 0 // O(1)
|
|
let b = Array(repeating: 0, count: 10000) // O(1)
|
|
if n > 10 {
|
|
let nums = Array(repeating: 0, count: n) // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title=""
|
|
function algorithm(n) {
|
|
const a = 0; // O(1)
|
|
const b = new Array(10000); // O(1)
|
|
if (n > 10) {
|
|
const nums = new Array(n); // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title=""
|
|
function algorithm(n: number): void {
|
|
const a = 0; // O(1)
|
|
const b = new Array(10000); // O(1)
|
|
if (n > 10) {
|
|
const nums = new Array(n); // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title=""
|
|
void algorithm(int n) {
|
|
int a = 0; // O(1)
|
|
List<int> b = List.filled(10000, 0); // O(1)
|
|
if (n > 10) {
|
|
List<int> nums = List.filled(n, 0); // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title=""
|
|
fn algorithm(n: i32) {
|
|
let a = 0; // O(1)
|
|
let b = [0; 10000]; // O(1)
|
|
if n > 10 {
|
|
let nums = vec![0; n as usize]; // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title=""
|
|
void algorithm(int n) {
|
|
int a = 0; // O(1)
|
|
int b[10000]; // O(1)
|
|
if (n > 10)
|
|
int nums[n] = {0}; // O(n)
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title=""
|
|
fun algorithm(n: Int) {
|
|
val a = 0 // O(1)
|
|
val b = IntArray(10000) // O(1)
|
|
if (n > 10) {
|
|
val nums = IntArray(n) // O(n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title=""
|
|
def algorithm(n)
|
|
a = 0 # O(1)
|
|
b = Array.new(10000) # O(1)
|
|
nums = Array.new(n) if n > 10 # O(n)
|
|
end
|
|
```
|
|
|
|
**In recursive functions, it is necessary to count the stack frame space**. Observe the following code:
|
|
|
|
=== "Python"
|
|
|
|
```python title=""
|
|
def function() -> int:
|
|
# Perform some operations
|
|
return 0
|
|
|
|
def loop(n: int):
|
|
"""Loop has space complexity of O(1)"""
|
|
for _ in range(n):
|
|
function()
|
|
|
|
def recur(n: int):
|
|
"""Recursion has space complexity of O(n)"""
|
|
if n == 1:
|
|
return
|
|
return recur(n - 1)
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title=""
|
|
int func() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
void loop(int n) {
|
|
for (int i = 0; i < n; i++) {
|
|
func();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
void recur(int n) {
|
|
if (n == 1) return;
|
|
recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title=""
|
|
int function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
void loop(int n) {
|
|
for (int i = 0; i < n; i++) {
|
|
function();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
void recur(int n) {
|
|
if (n == 1) return;
|
|
recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title=""
|
|
int Function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
void Loop(int n) {
|
|
for (int i = 0; i < n; i++) {
|
|
Function();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
int Recur(int n) {
|
|
if (n == 1) return 1;
|
|
return Recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title=""
|
|
func function() int {
|
|
// Perform some operations
|
|
return 0
|
|
}
|
|
|
|
/* Loop has space complexity of O(1) */
|
|
func loop(n int) {
|
|
for i := 0; i < n; i++ {
|
|
function()
|
|
}
|
|
}
|
|
|
|
/* Recursion has space complexity of O(n) */
|
|
func recur(n int) {
|
|
if n == 1 {
|
|
return
|
|
}
|
|
recur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title=""
|
|
@discardableResult
|
|
func function() -> Int {
|
|
// Perform some operations
|
|
return 0
|
|
}
|
|
|
|
/* Loop has space complexity of O(1) */
|
|
func loop(n: Int) {
|
|
for _ in 0 ..< n {
|
|
function()
|
|
}
|
|
}
|
|
|
|
/* Recursion has space complexity of O(n) */
|
|
func recur(n: Int) {
|
|
if n == 1 {
|
|
return
|
|
}
|
|
recur(n: n - 1)
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title=""
|
|
function constFunc() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
function loop(n) {
|
|
for (let i = 0; i < n; i++) {
|
|
constFunc();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
function recur(n) {
|
|
if (n === 1) return;
|
|
return recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title=""
|
|
function constFunc(): number {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
function loop(n: number): void {
|
|
for (let i = 0; i < n; i++) {
|
|
constFunc();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
function recur(n: number): void {
|
|
if (n === 1) return;
|
|
return recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title=""
|
|
int function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
void loop(int n) {
|
|
for (int i = 0; i < n; i++) {
|
|
function();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
void recur(int n) {
|
|
if (n == 1) return;
|
|
recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title=""
|
|
fn function() -> i32 {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
fn loop(n: i32) {
|
|
for i in 0..n {
|
|
function();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
fn recur(n: i32) {
|
|
if n == 1 {
|
|
return;
|
|
}
|
|
recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title=""
|
|
int func() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
void loop(int n) {
|
|
for (int i = 0; i < n; i++) {
|
|
func();
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
void recur(int n) {
|
|
if (n == 1) return;
|
|
recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title=""
|
|
fun function(): Int {
|
|
// Perform some operations
|
|
return 0
|
|
}
|
|
/* Loop has space complexity of O(1) */
|
|
fun loop(n: Int) {
|
|
for (i in 0..<n) {
|
|
function()
|
|
}
|
|
}
|
|
/* Recursion has space complexity of O(n) */
|
|
fun recur(n: Int) {
|
|
if (n == 1) return
|
|
return recur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title=""
|
|
def function
|
|
# Perform some operations
|
|
0
|
|
end
|
|
|
|
### Loop has space complexity of O(1) ###
|
|
def loop(n)
|
|
(0...n).each { function }
|
|
end
|
|
|
|
### Recursion has space complexity of O(n) ###
|
|
def recur(n)
|
|
return if n == 1
|
|
recur(n - 1)
|
|
end
|
|
```
|
|
|
|
The time complexity of both functions `loop()` and `recur()` is $O(n)$, but their space complexities are different.
|
|
|
|
- The function `loop()` calls `function()` $n$ times in a loop. In each iteration, `function()` returns and releases its stack frame space, so the space complexity remains $O(1)$.
|
|
- The recursive function `recur()` has $n$ unreturned `recur()` instances existing simultaneously during execution, thus occupying $O(n)$ stack frame space.
|
|
|
|
## 2.4.3 Common Types
|
|
|
|
Let the input data size be $n$. The following figure shows common types of space complexity (arranged from low to high).
|
|
|
|
$$
|
|
\begin{aligned}
|
|
& O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline
|
|
& \text{Constant} < \text{Logarithmic} < \text{Linear} < \text{Quadratic} < \text{Exponential}
|
|
\end{aligned}
|
|
$$
|
|
|
|
{ class="animation-figure" }
|
|
|
|
<p align="center"> Figure 2-16 Common types of space complexity </p>
|
|
|
|
### 1. Constant Order $O(1)$ {data-toc-label="1. Constant Order"}
|
|
|
|
Constant order is common for constants, variables, and objects whose number is independent of the input data size $n$.
|
|
|
|
It should be noted that memory occupied by initializing variables or calling functions in a loop is released when entering the next iteration, so it does not accumulate space, and the space complexity remains $O(1)$:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def function() -> int:
|
|
"""Function"""
|
|
# Perform some operations
|
|
return 0
|
|
|
|
def constant(n: int):
|
|
"""Constant order"""
|
|
# Constants, variables, objects occupy O(1) space
|
|
a = 0
|
|
nums = [0] * 10000
|
|
node = ListNode(0)
|
|
# Variables in the loop occupy O(1) space
|
|
for _ in range(n):
|
|
c = 0
|
|
# Functions in the loop occupy O(1) space
|
|
for _ in range(n):
|
|
function()
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Function */
|
|
int func() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
void constant(int n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const int a = 0;
|
|
int b = 0;
|
|
vector<int> nums(10000);
|
|
ListNode node(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
int c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
func();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Function */
|
|
int function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
void constant(int n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
final int a = 0;
|
|
int b = 0;
|
|
int[] nums = new int[10000];
|
|
ListNode node = new ListNode(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
int c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
function();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Function */
|
|
int Function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
void Constant(int n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
int a = 0;
|
|
int b = 0;
|
|
int[] nums = new int[10000];
|
|
ListNode node = new(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
int c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
Function();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Function */
|
|
func function() int {
|
|
// Perform some operations...
|
|
return 0
|
|
}
|
|
|
|
/* Constant order */
|
|
func spaceConstant(n int) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const a = 0
|
|
b := 0
|
|
nums := make([]int, 10000)
|
|
node := newNode(0)
|
|
// Variables in the loop occupy O(1) space
|
|
var c int
|
|
for i := 0; i < n; i++ {
|
|
c = 0
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for i := 0; i < n; i++ {
|
|
function()
|
|
}
|
|
b += 0
|
|
c += 0
|
|
nums[0] = 0
|
|
node.val = 0
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Function */
|
|
@discardableResult
|
|
func function() -> Int {
|
|
// Perform some operations
|
|
return 0
|
|
}
|
|
|
|
/* Constant order */
|
|
func constant(n: Int) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
let a = 0
|
|
var b = 0
|
|
let nums = Array(repeating: 0, count: 10000)
|
|
let node = ListNode(x: 0)
|
|
// Variables in the loop occupy O(1) space
|
|
for _ in 0 ..< n {
|
|
let c = 0
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for _ in 0 ..< n {
|
|
function()
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Function */
|
|
function constFunc() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
function constant(n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const a = 0;
|
|
const b = 0;
|
|
const nums = new Array(10000);
|
|
const node = new ListNode(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (let i = 0; i < n; i++) {
|
|
const c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (let i = 0; i < n; i++) {
|
|
constFunc();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Function */
|
|
function constFunc(): number {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
function constant(n: number): void {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const a = 0;
|
|
const b = 0;
|
|
const nums = new Array(10000);
|
|
const node = new ListNode(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (let i = 0; i < n; i++) {
|
|
const c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (let i = 0; i < n; i++) {
|
|
constFunc();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Function */
|
|
int function() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
void constant(int n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
final int a = 0;
|
|
int b = 0;
|
|
List<int> nums = List.filled(10000, 0);
|
|
ListNode node = ListNode(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for (var i = 0; i < n; i++) {
|
|
int c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (var i = 0; i < n; i++) {
|
|
function();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Function */
|
|
fn function() -> i32 {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
#[allow(unused)]
|
|
fn constant(n: i32) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const A: i32 = 0;
|
|
let b = 0;
|
|
let nums = vec![0; 10000];
|
|
let node = ListNode::new(0);
|
|
// Variables in the loop occupy O(1) space
|
|
for i in 0..n {
|
|
let c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for i in 0..n {
|
|
function();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Function */
|
|
int func() {
|
|
// Perform some operations
|
|
return 0;
|
|
}
|
|
|
|
/* Constant order */
|
|
void constant(int n) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
const int a = 0;
|
|
int b = 0;
|
|
int nums[1000];
|
|
ListNode *node = newListNode(0);
|
|
free(node);
|
|
// Variables in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
int c = 0;
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (int i = 0; i < n; i++) {
|
|
func();
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Function */
|
|
fun function(): Int {
|
|
// Perform some operations
|
|
return 0
|
|
}
|
|
|
|
/* Constant order */
|
|
fun constant(n: Int) {
|
|
// Constants, variables, objects occupy O(1) space
|
|
val a = 0
|
|
var b = 0
|
|
val nums = Array(10000) { 0 }
|
|
val node = ListNode(0)
|
|
// Variables in the loop occupy O(1) space
|
|
for (i in 0..<n) {
|
|
val c = 0
|
|
}
|
|
// Functions in the loop occupy O(1) space
|
|
for (i in 0..<n) {
|
|
function()
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Function ###
|
|
def function
|
|
# Perform some operations
|
|
0
|
|
end
|
|
|
|
### Constant time ###
|
|
def constant(n)
|
|
# Constants, variables, objects occupy O(1) space
|
|
a = 0
|
|
nums = [0] * 10000
|
|
node = ListNode.new
|
|
|
|
# Variables in the loop occupy O(1) space
|
|
(0...n).each { c = 0 }
|
|
# Functions in the loop occupy O(1) space
|
|
(0...n).each { function }
|
|
end
|
|
```
|
|
|
|
### 2. Linear Order $O(n)$ {data-toc-label="2. Linear Order"}
|
|
|
|
Linear order is common in arrays, linked lists, stacks, queues, etc., where the number of elements is proportional to $n$:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def linear(n: int):
|
|
"""Linear order"""
|
|
# A list of length n occupies O(n) space
|
|
nums = [0] * n
|
|
# A hash table of length n occupies O(n) space
|
|
hmap = dict[int, str]()
|
|
for i in range(n):
|
|
hmap[i] = str(i)
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Linear order */
|
|
void linear(int n) {
|
|
// Array of length n uses O(n) space
|
|
vector<int> nums(n);
|
|
// A list of length n occupies O(n) space
|
|
vector<ListNode> nodes;
|
|
for (int i = 0; i < n; i++) {
|
|
nodes.push_back(ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
unordered_map<int, string> map;
|
|
for (int i = 0; i < n; i++) {
|
|
map[i] = to_string(i);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Linear order */
|
|
void linear(int n) {
|
|
// Array of length n uses O(n) space
|
|
int[] nums = new int[n];
|
|
// A list of length n occupies O(n) space
|
|
List<ListNode> nodes = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) {
|
|
nodes.add(new ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
Map<Integer, String> map = new HashMap<>();
|
|
for (int i = 0; i < n; i++) {
|
|
map.put(i, String.valueOf(i));
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Linear order */
|
|
void Linear(int n) {
|
|
// Array of length n uses O(n) space
|
|
int[] nums = new int[n];
|
|
// A list of length n occupies O(n) space
|
|
List<ListNode> nodes = [];
|
|
for (int i = 0; i < n; i++) {
|
|
nodes.Add(new ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
Dictionary<int, string> map = [];
|
|
for (int i = 0; i < n; i++) {
|
|
map.Add(i, i.ToString());
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Linear order */
|
|
func spaceLinear(n int) {
|
|
// Array of length n uses O(n) space
|
|
_ = make([]int, n)
|
|
// A list of length n occupies O(n) space
|
|
var nodes []*node
|
|
for i := 0; i < n; i++ {
|
|
nodes = append(nodes, newNode(i))
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
m := make(map[int]string, n)
|
|
for i := 0; i < n; i++ {
|
|
m[i] = strconv.Itoa(i)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Linear order */
|
|
func linear(n: Int) {
|
|
// Array of length n uses O(n) space
|
|
let nums = Array(repeating: 0, count: n)
|
|
// A list of length n occupies O(n) space
|
|
let nodes = (0 ..< n).map { ListNode(x: $0) }
|
|
// A hash table of length n occupies O(n) space
|
|
let map = Dictionary(uniqueKeysWithValues: (0 ..< n).map { ($0, "\($0)") })
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Linear order */
|
|
function linear(n) {
|
|
// Array of length n uses O(n) space
|
|
const nums = new Array(n);
|
|
// A list of length n occupies O(n) space
|
|
const nodes = [];
|
|
for (let i = 0; i < n; i++) {
|
|
nodes.push(new ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
const map = new Map();
|
|
for (let i = 0; i < n; i++) {
|
|
map.set(i, i.toString());
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Linear order */
|
|
function linear(n: number): void {
|
|
// Array of length n uses O(n) space
|
|
const nums = new Array(n);
|
|
// A list of length n occupies O(n) space
|
|
const nodes: ListNode[] = [];
|
|
for (let i = 0; i < n; i++) {
|
|
nodes.push(new ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
const map = new Map();
|
|
for (let i = 0; i < n; i++) {
|
|
map.set(i, i.toString());
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Linear order */
|
|
void linear(int n) {
|
|
// Array of length n uses O(n) space
|
|
List<int> nums = List.filled(n, 0);
|
|
// A list of length n occupies O(n) space
|
|
List<ListNode> nodes = [];
|
|
for (var i = 0; i < n; i++) {
|
|
nodes.add(ListNode(i));
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
Map<int, String> map = HashMap();
|
|
for (var i = 0; i < n; i++) {
|
|
map.putIfAbsent(i, () => i.toString());
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Linear order */
|
|
#[allow(unused)]
|
|
fn linear(n: i32) {
|
|
// Array of length n uses O(n) space
|
|
let mut nums = vec![0; n as usize];
|
|
// A list of length n occupies O(n) space
|
|
let mut nodes = Vec::new();
|
|
for i in 0..n {
|
|
nodes.push(ListNode::new(i))
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
let mut map = HashMap::new();
|
|
for i in 0..n {
|
|
map.insert(i, i.to_string());
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Hash table */
|
|
typedef struct {
|
|
int key;
|
|
int val;
|
|
UT_hash_handle hh; // Implemented using uthash.h
|
|
} HashTable;
|
|
|
|
/* Linear order */
|
|
void linear(int n) {
|
|
// Array of length n uses O(n) space
|
|
int *nums = malloc(sizeof(int) * n);
|
|
free(nums);
|
|
|
|
// A list of length n occupies O(n) space
|
|
ListNode **nodes = malloc(sizeof(ListNode *) * n);
|
|
for (int i = 0; i < n; i++) {
|
|
nodes[i] = newListNode(i);
|
|
}
|
|
// Memory release
|
|
for (int i = 0; i < n; i++) {
|
|
free(nodes[i]);
|
|
}
|
|
free(nodes);
|
|
|
|
// A hash table of length n occupies O(n) space
|
|
HashTable *h = NULL;
|
|
for (int i = 0; i < n; i++) {
|
|
HashTable *tmp = malloc(sizeof(HashTable));
|
|
tmp->key = i;
|
|
tmp->val = i;
|
|
HASH_ADD_INT(h, key, tmp);
|
|
}
|
|
|
|
// Memory release
|
|
HashTable *curr, *tmp;
|
|
HASH_ITER(hh, h, curr, tmp) {
|
|
HASH_DEL(h, curr);
|
|
free(curr);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Linear order */
|
|
fun linear(n: Int) {
|
|
// Array of length n uses O(n) space
|
|
val nums = Array(n) { 0 }
|
|
// A list of length n occupies O(n) space
|
|
val nodes = mutableListOf<ListNode>()
|
|
for (i in 0..<n) {
|
|
nodes.add(ListNode(i))
|
|
}
|
|
// A hash table of length n occupies O(n) space
|
|
val map = mutableMapOf<Int, String>()
|
|
for (i in 0..<n) {
|
|
map[i] = i.toString()
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Linear time ###
|
|
def linear(n)
|
|
# A list of length n occupies O(n) space
|
|
nums = Array.new(n, 0)
|
|
|
|
# A hash table of length n occupies O(n) space
|
|
hmap = {}
|
|
for i in 0...n
|
|
hmap[i] = i.to_s
|
|
end
|
|
end
|
|
```
|
|
|
|
As shown in the following figure, the recursion depth of this function is $n$, meaning that there are $n$ unreturned `linear_recur()` functions existing simultaneously, using $O(n)$ stack frame space:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def linear_recur(n: int):
|
|
"""Linear order (recursive implementation)"""
|
|
print("Recursion n =", n)
|
|
if n == 1:
|
|
return
|
|
linear_recur(n - 1)
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Linear order (recursive implementation) */
|
|
void linearRecur(int n) {
|
|
cout << "Recursion n = " << n << endl;
|
|
if (n == 1)
|
|
return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Linear order (recursive implementation) */
|
|
void linearRecur(int n) {
|
|
System.out.println("Recursion n = " + n);
|
|
if (n == 1)
|
|
return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Linear order (recursive implementation) */
|
|
void LinearRecur(int n) {
|
|
Console.WriteLine("Recursion n = " + n);
|
|
if (n == 1) return;
|
|
LinearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Linear order (recursive implementation) */
|
|
func spaceLinearRecur(n int) {
|
|
fmt.Println("Recursion n =", n)
|
|
if n == 1 {
|
|
return
|
|
}
|
|
spaceLinearRecur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Linear order (recursive implementation) */
|
|
func linearRecur(n: Int) {
|
|
print("Recursion n = \(n)")
|
|
if n == 1 {
|
|
return
|
|
}
|
|
linearRecur(n: n - 1)
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Linear order (recursive implementation) */
|
|
function linearRecur(n) {
|
|
console.log(`Recursion n = ${n}`);
|
|
if (n === 1) return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Linear order (recursive implementation) */
|
|
function linearRecur(n: number): void {
|
|
console.log(`Recursion n = ${n}`);
|
|
if (n === 1) return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Linear order (recursive implementation) */
|
|
void linearRecur(int n) {
|
|
print('Recursion n = $n');
|
|
if (n == 1) return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Linear order (recursive implementation) */
|
|
fn linear_recur(n: i32) {
|
|
println!("Recursion n = {}", n);
|
|
if n == 1 {
|
|
return;
|
|
};
|
|
linear_recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Linear order (recursive implementation) */
|
|
void linearRecur(int n) {
|
|
printf("Recursion n = %d\r\n", n);
|
|
if (n == 1)
|
|
return;
|
|
linearRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Linear order (recursive implementation) */
|
|
fun linearRecur(n: Int) {
|
|
println("Recursion n = $n")
|
|
if (n == 1)
|
|
return
|
|
linearRecur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Linear space (recursive) ###
|
|
def linear_recur(n)
|
|
puts "Recursion n = #{n}"
|
|
return if n == 1
|
|
linear_recur(n - 1)
|
|
end
|
|
```
|
|
|
|
{ class="animation-figure" }
|
|
|
|
<p align="center"> Figure 2-17 Linear order space complexity generated by recursive function </p>
|
|
|
|
### 3. Quadratic Order $O(n^2)$ {data-toc-label="3. Quadratic Order"}
|
|
|
|
Quadratic order is common in matrices and graphs, where the number of elements is quadratically related to $n$:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def quadratic(n: int):
|
|
"""Quadratic order"""
|
|
# A 2D list occupies O(n^2) space
|
|
num_matrix = [[0] * n for _ in range(n)]
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Exponential order */
|
|
void quadratic(int n) {
|
|
// 2D list uses O(n^2) space
|
|
vector<vector<int>> numMatrix;
|
|
for (int i = 0; i < n; i++) {
|
|
vector<int> tmp;
|
|
for (int j = 0; j < n; j++) {
|
|
tmp.push_back(0);
|
|
}
|
|
numMatrix.push_back(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Exponential order */
|
|
void quadratic(int n) {
|
|
// Matrix uses O(n^2) space
|
|
int[][] numMatrix = new int[n][n];
|
|
// 2D list uses O(n^2) space
|
|
List<List<Integer>> numList = new ArrayList<>();
|
|
for (int i = 0; i < n; i++) {
|
|
List<Integer> tmp = new ArrayList<>();
|
|
for (int j = 0; j < n; j++) {
|
|
tmp.add(0);
|
|
}
|
|
numList.add(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Exponential order */
|
|
void Quadratic(int n) {
|
|
// Matrix uses O(n^2) space
|
|
int[,] numMatrix = new int[n, n];
|
|
// 2D list uses O(n^2) space
|
|
List<List<int>> numList = [];
|
|
for (int i = 0; i < n; i++) {
|
|
List<int> tmp = [];
|
|
for (int j = 0; j < n; j++) {
|
|
tmp.Add(0);
|
|
}
|
|
numList.Add(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Exponential order */
|
|
func spaceQuadratic(n int) {
|
|
// Matrix uses O(n^2) space
|
|
numMatrix := make([][]int, n)
|
|
for i := 0; i < n; i++ {
|
|
numMatrix[i] = make([]int, n)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Exponential order */
|
|
func quadratic(n: Int) {
|
|
// 2D list uses O(n^2) space
|
|
let numList = Array(repeating: Array(repeating: 0, count: n), count: n)
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Exponential order */
|
|
function quadratic(n) {
|
|
// Matrix uses O(n^2) space
|
|
const numMatrix = Array(n)
|
|
.fill(null)
|
|
.map(() => Array(n).fill(null));
|
|
// 2D list uses O(n^2) space
|
|
const numList = [];
|
|
for (let i = 0; i < n; i++) {
|
|
const tmp = [];
|
|
for (let j = 0; j < n; j++) {
|
|
tmp.push(0);
|
|
}
|
|
numList.push(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Exponential order */
|
|
function quadratic(n: number): void {
|
|
// Matrix uses O(n^2) space
|
|
const numMatrix = Array(n)
|
|
.fill(null)
|
|
.map(() => Array(n).fill(null));
|
|
// 2D list uses O(n^2) space
|
|
const numList = [];
|
|
for (let i = 0; i < n; i++) {
|
|
const tmp = [];
|
|
for (let j = 0; j < n; j++) {
|
|
tmp.push(0);
|
|
}
|
|
numList.push(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Exponential order */
|
|
void quadratic(int n) {
|
|
// Matrix uses O(n^2) space
|
|
List<List<int>> numMatrix = List.generate(n, (_) => List.filled(n, 0));
|
|
// 2D list uses O(n^2) space
|
|
List<List<int>> numList = [];
|
|
for (var i = 0; i < n; i++) {
|
|
List<int> tmp = [];
|
|
for (int j = 0; j < n; j++) {
|
|
tmp.add(0);
|
|
}
|
|
numList.add(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Exponential order */
|
|
#[allow(unused)]
|
|
fn quadratic(n: i32) {
|
|
// Matrix uses O(n^2) space
|
|
let num_matrix = vec![vec![0; n as usize]; n as usize];
|
|
// 2D list uses O(n^2) space
|
|
let mut num_list = Vec::new();
|
|
for i in 0..n {
|
|
let mut tmp = Vec::new();
|
|
for j in 0..n {
|
|
tmp.push(0);
|
|
}
|
|
num_list.push(tmp);
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Exponential order */
|
|
void quadratic(int n) {
|
|
// 2D list uses O(n^2) space
|
|
int **numMatrix = malloc(sizeof(int *) * n);
|
|
for (int i = 0; i < n; i++) {
|
|
int *tmp = malloc(sizeof(int) * n);
|
|
for (int j = 0; j < n; j++) {
|
|
tmp[j] = 0;
|
|
}
|
|
numMatrix[i] = tmp;
|
|
}
|
|
|
|
// Memory release
|
|
for (int i = 0; i < n; i++) {
|
|
free(numMatrix[i]);
|
|
}
|
|
free(numMatrix);
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Exponential order */
|
|
fun quadratic(n: Int) {
|
|
// Matrix uses O(n^2) space
|
|
val numMatrix = arrayOfNulls<Array<Int>?>(n)
|
|
// 2D list uses O(n^2) space
|
|
val numList = mutableListOf<MutableList<Int>>()
|
|
for (i in 0..<n) {
|
|
val tmp = mutableListOf<Int>()
|
|
for (j in 0..<n) {
|
|
tmp.add(0)
|
|
}
|
|
numList.add(tmp)
|
|
}
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Quadratic time ###
|
|
def quadratic(n)
|
|
# 2D list uses O(n^2) space
|
|
Array.new(n) { Array.new(n, 0) }
|
|
end
|
|
```
|
|
|
|
As shown in the following figure, the recursion depth of this function is $n$, and an array is initialized in each recursive function with lengths of $n$, $n-1$, $\dots$, $2$, $1$, with an average length of $n / 2$, thus occupying $O(n^2)$ space overall:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def quadratic_recur(n: int) -> int:
|
|
"""Quadratic order (recursive implementation)"""
|
|
if n <= 0:
|
|
return 0
|
|
# Array nums length is n, n-1, ..., 2, 1
|
|
nums = [0] * n
|
|
return quadratic_recur(n - 1)
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Quadratic order (recursive implementation) */
|
|
int quadraticRecur(int n) {
|
|
if (n <= 0)
|
|
return 0;
|
|
vector<int> nums(n);
|
|
cout << "In recursion n = " << n << ", nums length = " << nums.size() << endl;
|
|
return quadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Quadratic order (recursive implementation) */
|
|
int quadraticRecur(int n) {
|
|
if (n <= 0)
|
|
return 0;
|
|
// Array nums has length n, n-1, ..., 2, 1
|
|
int[] nums = new int[n];
|
|
System.out.println("In recursion n = " + n + ", nums length = " + nums.length);
|
|
return quadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Quadratic order (recursive implementation) */
|
|
int QuadraticRecur(int n) {
|
|
if (n <= 0) return 0;
|
|
int[] nums = new int[n];
|
|
Console.WriteLine("Recursion n = " + n + ", nums length = " + nums.Length);
|
|
return QuadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Quadratic order (recursive implementation) */
|
|
func spaceQuadraticRecur(n int) int {
|
|
if n <= 0 {
|
|
return 0
|
|
}
|
|
nums := make([]int, n)
|
|
fmt.Printf("In recursion n = %d, nums length = %d \n", n, len(nums))
|
|
return spaceQuadraticRecur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Quadratic order (recursive implementation) */
|
|
@discardableResult
|
|
func quadraticRecur(n: Int) -> Int {
|
|
if n <= 0 {
|
|
return 0
|
|
}
|
|
// Array nums has length n, n-1, ..., 2, 1
|
|
let nums = Array(repeating: 0, count: n)
|
|
print("In recursion n = \(n), nums length = \(nums.count)")
|
|
return quadraticRecur(n: n - 1)
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Quadratic order (recursive implementation) */
|
|
function quadraticRecur(n) {
|
|
if (n <= 0) return 0;
|
|
const nums = new Array(n);
|
|
console.log(`In recursion n = ${n}, nums length = ${nums.length}`);
|
|
return quadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Quadratic order (recursive implementation) */
|
|
function quadraticRecur(n: number): number {
|
|
if (n <= 0) return 0;
|
|
const nums = new Array(n);
|
|
console.log(`In recursion n = ${n}, nums length = ${nums.length}`);
|
|
return quadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Quadratic order (recursive implementation) */
|
|
int quadraticRecur(int n) {
|
|
if (n <= 0) return 0;
|
|
List<int> nums = List.filled(n, 0);
|
|
print('In recursion n = $n, nums length = ${nums.length}');
|
|
return quadraticRecur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Quadratic order (recursive implementation) */
|
|
fn quadratic_recur(n: i32) -> i32 {
|
|
if n <= 0 {
|
|
return 0;
|
|
};
|
|
// Array nums has length n, n-1, ..., 2, 1
|
|
let nums = vec![0; n as usize];
|
|
println!("In recursion n = {}, nums length = {}", n, nums.len());
|
|
return quadratic_recur(n - 1);
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Quadratic order (recursive implementation) */
|
|
int quadraticRecur(int n) {
|
|
if (n <= 0)
|
|
return 0;
|
|
int *nums = malloc(sizeof(int) * n);
|
|
printf("In recursion n = %d, nums length = %d\r\n", n, n);
|
|
int res = quadraticRecur(n - 1);
|
|
free(nums);
|
|
return res;
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Quadratic order (recursive implementation) */
|
|
tailrec fun quadraticRecur(n: Int): Int {
|
|
if (n <= 0)
|
|
return 0
|
|
// Array nums has length n, n-1, ..., 2, 1
|
|
val nums = Array(n) { 0 }
|
|
println("In recursion n = $n, nums length = ${nums.size}")
|
|
return quadraticRecur(n - 1)
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Quadratic space (recursive) ###
|
|
def quadratic_recur(n)
|
|
return 0 unless n > 0
|
|
|
|
# Array nums has length n, n-1, ..., 2, 1
|
|
nums = Array.new(n, 0)
|
|
quadratic_recur(n - 1)
|
|
end
|
|
```
|
|
|
|
{ class="animation-figure" }
|
|
|
|
<p align="center"> Figure 2-18 Quadratic order space complexity generated by recursive function </p>
|
|
|
|
### 4. Exponential Order $O(2^n)$ {data-toc-label="4. Exponential Order"}
|
|
|
|
Exponential order is common in binary trees. Observe the following figure: a "full binary tree" with $n$ levels has $2^n - 1$ nodes, occupying $O(2^n)$ space:
|
|
|
|
=== "Python"
|
|
|
|
```python title="space_complexity.py"
|
|
def build_tree(n: int) -> TreeNode | None:
|
|
"""Exponential order (build full binary tree)"""
|
|
if n == 0:
|
|
return None
|
|
root = TreeNode(0)
|
|
root.left = build_tree(n - 1)
|
|
root.right = build_tree(n - 1)
|
|
return root
|
|
```
|
|
|
|
=== "C++"
|
|
|
|
```cpp title="space_complexity.cpp"
|
|
/* Driver Code */
|
|
TreeNode *buildTree(int n) {
|
|
if (n == 0)
|
|
return nullptr;
|
|
TreeNode *root = new TreeNode(0);
|
|
root->left = buildTree(n - 1);
|
|
root->right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "Java"
|
|
|
|
```java title="space_complexity.java"
|
|
/* Driver Code */
|
|
TreeNode buildTree(int n) {
|
|
if (n == 0)
|
|
return null;
|
|
TreeNode root = new TreeNode(0);
|
|
root.left = buildTree(n - 1);
|
|
root.right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "C#"
|
|
|
|
```csharp title="space_complexity.cs"
|
|
/* Driver Code */
|
|
TreeNode? BuildTree(int n) {
|
|
if (n == 0) return null;
|
|
TreeNode root = new(0) {
|
|
left = BuildTree(n - 1),
|
|
right = BuildTree(n - 1)
|
|
};
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "Go"
|
|
|
|
```go title="space_complexity.go"
|
|
/* Driver Code */
|
|
func buildTree(n int) *TreeNode {
|
|
if n == 0 {
|
|
return nil
|
|
}
|
|
root := NewTreeNode(0)
|
|
root.Left = buildTree(n - 1)
|
|
root.Right = buildTree(n - 1)
|
|
return root
|
|
}
|
|
```
|
|
|
|
=== "Swift"
|
|
|
|
```swift title="space_complexity.swift"
|
|
/* Driver Code */
|
|
func buildTree(n: Int) -> TreeNode? {
|
|
if n == 0 {
|
|
return nil
|
|
}
|
|
let root = TreeNode(x: 0)
|
|
root.left = buildTree(n: n - 1)
|
|
root.right = buildTree(n: n - 1)
|
|
return root
|
|
}
|
|
```
|
|
|
|
=== "JS"
|
|
|
|
```javascript title="space_complexity.js"
|
|
/* Driver Code */
|
|
function buildTree(n) {
|
|
if (n === 0) return null;
|
|
const root = new TreeNode(0);
|
|
root.left = buildTree(n - 1);
|
|
root.right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "TS"
|
|
|
|
```typescript title="space_complexity.ts"
|
|
/* Driver Code */
|
|
function buildTree(n: number): TreeNode | null {
|
|
if (n === 0) return null;
|
|
const root = new TreeNode(0);
|
|
root.left = buildTree(n - 1);
|
|
root.right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "Dart"
|
|
|
|
```dart title="space_complexity.dart"
|
|
/* Driver Code */
|
|
TreeNode? buildTree(int n) {
|
|
if (n == 0) return null;
|
|
TreeNode root = TreeNode(0);
|
|
root.left = buildTree(n - 1);
|
|
root.right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "Rust"
|
|
|
|
```rust title="space_complexity.rs"
|
|
/* Driver Code */
|
|
fn build_tree(n: i32) -> Option<Rc<RefCell<TreeNode>>> {
|
|
if n == 0 {
|
|
return None;
|
|
};
|
|
let root = TreeNode::new(0);
|
|
root.borrow_mut().left = build_tree(n - 1);
|
|
root.borrow_mut().right = build_tree(n - 1);
|
|
return Some(root);
|
|
}
|
|
```
|
|
|
|
=== "C"
|
|
|
|
```c title="space_complexity.c"
|
|
/* Driver Code */
|
|
TreeNode *buildTree(int n) {
|
|
if (n == 0)
|
|
return NULL;
|
|
TreeNode *root = newTreeNode(0);
|
|
root->left = buildTree(n - 1);
|
|
root->right = buildTree(n - 1);
|
|
return root;
|
|
}
|
|
```
|
|
|
|
=== "Kotlin"
|
|
|
|
```kotlin title="space_complexity.kt"
|
|
/* Driver Code */
|
|
fun buildTree(n: Int): TreeNode? {
|
|
if (n == 0)
|
|
return null
|
|
val root = TreeNode(0)
|
|
root.left = buildTree(n - 1)
|
|
root.right = buildTree(n - 1)
|
|
return root
|
|
}
|
|
```
|
|
|
|
=== "Ruby"
|
|
|
|
```ruby title="space_complexity.rb"
|
|
### Exponential space (build full binary tree) ###
|
|
def build_tree(n)
|
|
return if n == 0
|
|
|
|
TreeNode.new.tap do |root|
|
|
root.left = build_tree(n - 1)
|
|
root.right = build_tree(n - 1)
|
|
end
|
|
end
|
|
```
|
|
|
|
{ class="animation-figure" }
|
|
|
|
<p align="center"> Figure 2-19 Exponential order space complexity generated by full binary tree </p>
|
|
|
|
### 5. Logarithmic Order $O(\log n)$ {data-toc-label="5. Logarithmic Order"}
|
|
|
|
Logarithmic order is common in divide-and-conquer algorithms. For example, merge sort: given an input array of length $n$, each recursion divides the array in half from the midpoint, forming a recursion tree of height $\log n$, using $O(\log n)$ stack frame space.
|
|
|
|
Another example is converting a number to a string. Given a positive integer $n$, it has $\lfloor \log_{10} n \rfloor + 1$ digits, i.e., the corresponding string length is $\lfloor \log_{10} n \rfloor + 1$, so the space complexity is $O(\log_{10} n + 1) = O(\log n)$.
|
|
|
|
## 2.4.4 Trading Time for Space
|
|
|
|
Ideally, we hope that both the time complexity and space complexity of an algorithm can reach optimal. However, in practice, optimizing both time complexity and space complexity simultaneously is usually very difficult.
|
|
|
|
**Reducing time complexity usually comes at the cost of increasing space complexity, and vice versa**. Sacrificing memory space to improve execution speed is called "trading space for time"; the reverse is called "trading time for space".
|
|
|
|
The choice of which approach depends on which aspect we value more. In most cases, time is more precious than space, so "trading space for time" is usually the more common strategy. Of course, when the data volume is very large, controlling space complexity is also very important.
|