mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-23 18:11:45 +08:00
First version.
This commit is contained in:
860
ru/docs/chapter_computational_complexity/space_complexity.md
Normal file
860
ru/docs/chapter_computational_complexity/space_complexity.md
Normal file
@@ -0,0 +1,860 @@
|
||||
# Пространственная сложность
|
||||
|
||||
<u>Пространственная сложность (space complexity)</u> используется для измерения роста объема памяти, занимаемого алгоритмом, по мере увеличения объема данных. Эта концепция очень похожа на временную сложность, только нужно заменить "время выполнения" на "занимаемый объем памяти".
|
||||
|
||||
## Пространство, связанное с алгоритмом
|
||||
|
||||
Память, используемая алгоритмом в процессе выполнения, в основном включает следующие типы.
|
||||
|
||||
- **Входное пространство**: используется для хранения входных данных алгоритма.
|
||||
- **Временное пространство**: используется для хранения переменных, объектов, контекста функций и других данных в процессе выполнения алгоритма.
|
||||
- **Выходное пространство**: используется для хранения выходных данных алгоритма.
|
||||
|
||||
В общем случае диапазон статистики пространственной сложности — это "временное пространство" плюс "выходное пространство".
|
||||
|
||||
Временное пространство можно дополнительно разделить на три части.
|
||||
|
||||
- **Временные данные**: используются для сохранения различных констант, переменных, объектов и т. д. в процессе выполнения алгоритма.
|
||||
- **Пространство стекового кадра**: используется для сохранения контекстных данных вызываемой функции. Система создает стековый кадр в верхней части стека при каждом вызове функции, и пространство стекового кадра освобождается после возврата функции.
|
||||
- **Пространство инструкций**: используется для сохранения скомпилированных инструкций программы, обычно игнорируется при фактической статистике.
|
||||
|
||||
При анализе пространственной сложности фрагмента программы **мы обычно учитываем три части: временные данные, пространство стекового кадра и выходные данные**, как показано на рисунке ниже.
|
||||
|
||||

|
||||
|
||||
Соответствующий код выглядит следующим образом:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python title=""
|
||||
class Node:
|
||||
"""Класс"""
|
||||
def __init__(self, x: int):
|
||||
self.val: int = x # значение узла
|
||||
self.next: Node | None = None # ссылка на следующий узел
|
||||
|
||||
def function() -> int:
|
||||
"""Функция"""
|
||||
# выполнение некоторых операций...
|
||||
return 0
|
||||
|
||||
def algorithm(n) -> int: # входные данные
|
||||
A = 0 # временные данные (константа, обычно обозначается заглавной буквой)
|
||||
b = 0 # временные данные (переменная)
|
||||
node = Node(0) # временные данные (объект)
|
||||
c = function() # пространство стекового кадра (вызов функции)
|
||||
return A + b + c # выходные данные
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp title=""
|
||||
/* Структура */
|
||||
struct Node {
|
||||
int val;
|
||||
Node *next;
|
||||
Node(int x) : val(x), next(nullptr) {}
|
||||
};
|
||||
|
||||
/* Функция */
|
||||
int func() {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int algorithm(int n) { // входные данные
|
||||
const int a = 0; // временные данные (константа)
|
||||
int b = 0; // временные данные (переменная)
|
||||
Node* node = new Node(0); // временные данные (объект)
|
||||
int c = func(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java title=""
|
||||
/* Класс */
|
||||
class Node {
|
||||
int val;
|
||||
Node next;
|
||||
Node(int x) { val = x; }
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
int function() {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int algorithm(int n) { // входные данные
|
||||
final int a = 0; // временные данные (константа)
|
||||
int b = 0; // временные данные (переменная)
|
||||
Node node = new Node(0); // временные данные (объект)
|
||||
int c = function(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title=""
|
||||
/* Класс */
|
||||
class Node(int x) {
|
||||
int val = x;
|
||||
Node next;
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
int Function() {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Algorithm(int n) { // входные данные
|
||||
const int a = 0; // временные данные (константа)
|
||||
int b = 0; // временные данные (переменная)
|
||||
Node node = new(0); // временные данные (объект)
|
||||
int c = Function(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
|
||||
```go title=""
|
||||
/* Структура */
|
||||
type node struct {
|
||||
val int
|
||||
next *node
|
||||
}
|
||||
|
||||
/* Создание структуры node */
|
||||
func newNode(val int) *node {
|
||||
return &node{val: val}
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
func function() int {
|
||||
// выполнение некоторых операций...
|
||||
return 0
|
||||
}
|
||||
|
||||
func algorithm(n int) int { // входные данные
|
||||
const a = 0 // временные данные (константа)
|
||||
b := 0 // временные данные (переменная)
|
||||
newNode(0) // временные данные (объект)
|
||||
c := function() // пространство стекового кадра (вызов функции)
|
||||
return a + b + c // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title=""
|
||||
/* Класс */
|
||||
class Node {
|
||||
var val: Int
|
||||
var next: Node?
|
||||
|
||||
init(x: Int) {
|
||||
val = x
|
||||
}
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
func function() -> Int {
|
||||
// выполнение некоторых операций...
|
||||
return 0
|
||||
}
|
||||
|
||||
func algorithm(n: Int) -> Int { // входные данные
|
||||
let a = 0 // временные данные (константа)
|
||||
var b = 0 // временные данные (переменная)
|
||||
let node = Node(x: 0) // временные данные (объект)
|
||||
let c = function() // пространство стекового кадра (вызов функции)
|
||||
return a + b + c // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title=""
|
||||
/* Класс */
|
||||
class Node {
|
||||
val;
|
||||
next;
|
||||
constructor(val) {
|
||||
this.val = val === undefined ? 0 : val; // значение узла
|
||||
this.next = null; // ссылка на следующий узел
|
||||
}
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
function constFunc() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
|
||||
function algorithm(n) { // входные данные
|
||||
const a = 0; // временные данные (константа)
|
||||
let b = 0; // временные данные (переменная)
|
||||
const node = new Node(0); // временные данные (объект)
|
||||
const c = constFunc(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "TS"
|
||||
|
||||
```typescript title=""
|
||||
/* Класс */
|
||||
class Node {
|
||||
val: number;
|
||||
next: Node | null;
|
||||
constructor(val?: number) {
|
||||
this.val = val === undefined ? 0 : val; // значение узла
|
||||
this.next = null; // ссылка на следующий узел
|
||||
}
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
function constFunc(): number {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
|
||||
function algorithm(n: number): number { // входные данные
|
||||
const a = 0; // временные данные (константа)
|
||||
let b = 0; // временные данные (переменная)
|
||||
const node = new Node(0); // временные данные (объект)
|
||||
const c = constFunc(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title=""
|
||||
/* Класс */
|
||||
class Node {
|
||||
int val;
|
||||
Node next;
|
||||
Node(this.val, [this.next]);
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
int function() {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int algorithm(int n) { // входные данные
|
||||
const int a = 0; // временные данные (константа)
|
||||
int b = 0; // временные данные (переменная)
|
||||
Node node = Node(0); // временные данные (объект)
|
||||
int c = function(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
/* Структура */
|
||||
struct Node {
|
||||
val: i32,
|
||||
next: Option<Rc<RefCell<Node>>>,
|
||||
}
|
||||
|
||||
/* Создание структуры Node */
|
||||
impl Node {
|
||||
fn new(val: i32) -> Self {
|
||||
Self { val: val, next: None }
|
||||
}
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
fn function() -> i32 {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn algorithm(n: i32) -> i32 { // входные данные
|
||||
const a: i32 = 0; // временные данные (константа)
|
||||
let mut b = 0; // временные данные (переменная)
|
||||
let node = Node::new(0); // временные данные (объект)
|
||||
let c = function(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title=""
|
||||
/* Функция */
|
||||
int func() {
|
||||
// выполнение некоторых операций...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int algorithm(int n) { // входные данные
|
||||
const int a = 0; // временные данные (константа)
|
||||
int b = 0; // временные данные (переменная)
|
||||
int c = func(); // пространство стекового кадра (вызов функции)
|
||||
return a + b + c; // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title=""
|
||||
/* Класс */
|
||||
class Node(var _val: Int) {
|
||||
var next: Node? = null
|
||||
}
|
||||
|
||||
/* Функция */
|
||||
fun function(): Int {
|
||||
// выполнение некоторых операций...
|
||||
return 0
|
||||
}
|
||||
|
||||
fun algorithm(n: Int): Int { // входные данные
|
||||
val a = 0 // временные данные (константа)
|
||||
var b = 0 // временные данные (переменная)
|
||||
val node = Node(0) // временные данные (объект)
|
||||
val c = function() // пространство стекового кадра (вызов функции)
|
||||
return a + b + c // выходные данные
|
||||
}
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
### Класс ###
|
||||
class Node
|
||||
attr_accessor :val # значение узла
|
||||
attr_accessor :next # ссылка на следующий узел
|
||||
|
||||
def initialize(x)
|
||||
@val = x
|
||||
end
|
||||
end
|
||||
|
||||
### Функция ###
|
||||
def function
|
||||
# выполнение некоторых операций...
|
||||
0
|
||||
end
|
||||
|
||||
### Алгоритм ###
|
||||
def algorithm(n) # входные данные
|
||||
a = 0 # временные данные (константа)
|
||||
b = 0 # временные данные (переменная)
|
||||
node = Node.new(0) # временные данные (объект)
|
||||
c = function # пространство стекового кадра (вызов функции)
|
||||
a + b + c # выходные данные
|
||||
end
|
||||
```
|
||||
|
||||
## Метод расчета
|
||||
|
||||
Метод расчета пространственной сложности в целом аналогичен временной сложности, только нужно изменить объект статистики с "количества операций" на "размер используемого пространства".
|
||||
|
||||
В отличие от временной сложности, **мы обычно обращаем внимание только на наихудшую пространственную сложность**. Это связано с тем, что память является жестким требованием, и мы должны обеспечить достаточный резерв памяти для всех входных данных.
|
||||
|
||||
Рассмотрим следующий код, "наихудший" в наихудшей пространственной сложности имеет два значения.
|
||||
|
||||
1. **На основе наихудших входных данных**: когда $n < 10$, пространственная сложность равна $O(1)$; но когда $n > 10$, инициализированный массив `nums` занимает $O(n)$ пространства, поэтому наихудшая пространственная сложность равна $O(n)$.
|
||||
2. **На основе пикового значения памяти во время выполнения алгоритма**: например, до выполнения последней строки программа занимает $O(1)$ пространства; при инициализации массива `nums` программа занимает $O(n)$ пространства, поэтому наихудшая пространственная сложность равна $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
|
||||
```
|
||||
|
||||
**В рекурсивных функциях необходимо учитывать пространство стекового кадра**. Рассмотрим следующий код:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python title=""
|
||||
def function() -> int:
|
||||
# выполнение некоторых операций
|
||||
return 0
|
||||
|
||||
def loop(n: int):
|
||||
"""Пространственная сложность цикла O(1)"""
|
||||
for _ in range(n):
|
||||
function()
|
||||
|
||||
def recur(n: int):
|
||||
"""Пространственная сложность рекурсии O(n)"""
|
||||
if n == 1:
|
||||
return
|
||||
return recur(n - 1)
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp title=""
|
||||
int func() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
void loop(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
void recur(int n) {
|
||||
if (n == 1) return;
|
||||
recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java title=""
|
||||
int function() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
void loop(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
function();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
void recur(int n) {
|
||||
if (n == 1) return;
|
||||
recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title=""
|
||||
int Function() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
void Loop(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
Function();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
int Recur(int n) {
|
||||
if (n == 1) return 1;
|
||||
return Recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
|
||||
```go title=""
|
||||
func function() int {
|
||||
// выполнение некоторых операций
|
||||
return 0
|
||||
}
|
||||
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
func loop(n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
function()
|
||||
}
|
||||
}
|
||||
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
func recur(n int) {
|
||||
if n == 1 {
|
||||
return
|
||||
}
|
||||
recur(n - 1)
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title=""
|
||||
@discardableResult
|
||||
func function() -> Int {
|
||||
// выполнение некоторых операций
|
||||
return 0
|
||||
}
|
||||
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
func loop(n: Int) {
|
||||
for _ in 0 ..< n {
|
||||
function()
|
||||
}
|
||||
}
|
||||
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
func recur(n: Int) {
|
||||
if n == 1 {
|
||||
return
|
||||
}
|
||||
recur(n: n - 1)
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title=""
|
||||
function constFunc() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
function loop(n) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
constFunc();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
function recur(n) {
|
||||
if (n === 1) return;
|
||||
return recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "TS"
|
||||
|
||||
```typescript title=""
|
||||
function constFunc(): number {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
function loop(n: number): void {
|
||||
for (let i = 0; i < n; i++) {
|
||||
constFunc();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
function recur(n: number): void {
|
||||
if (n === 1) return;
|
||||
return recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title=""
|
||||
int function() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
void loop(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
function();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
void recur(int n) {
|
||||
if (n == 1) return;
|
||||
recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title=""
|
||||
fn function() -> i32 {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
fn loop(n: i32) {
|
||||
for i in 0..n {
|
||||
function();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
fn recur(n: i32) {
|
||||
if n == 1 {
|
||||
return;
|
||||
}
|
||||
recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title=""
|
||||
int func() {
|
||||
// выполнение некоторых операций
|
||||
return 0;
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
void loop(int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
void recur(int n) {
|
||||
if (n == 1) return;
|
||||
recur(n - 1);
|
||||
}
|
||||
```
|
||||
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title=""
|
||||
fun function(): Int {
|
||||
// выполнение некоторых операций
|
||||
return 0
|
||||
}
|
||||
/* Пространственная сложность цикла O(1) */
|
||||
fun loop(n: Int) {
|
||||
for (i in 0..<n) {
|
||||
function()
|
||||
}
|
||||
}
|
||||
/* Пространственная сложность рекурсии O(n) */
|
||||
fun recur(n: Int) {
|
||||
if (n == 1) return
|
||||
return recur(n - 1)
|
||||
}
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title=""
|
||||
def function
|
||||
# выполнение некоторых операций
|
||||
0
|
||||
end
|
||||
|
||||
### Пространственная сложность цикла O(1) ###
|
||||
def loop(n)
|
||||
(0...n).each { function }
|
||||
end
|
||||
|
||||
### Пространственная сложность рекурсии O(n) ###
|
||||
def recur(n)
|
||||
return if n == 1
|
||||
recur(n - 1)
|
||||
end
|
||||
```
|
||||
|
||||
Функции `loop()` и `recur()` имеют временную сложность $O(n)$, но пространственная сложность различается.
|
||||
|
||||
- Функция `loop()` вызывает `function()` $n$ раз в цикле, на каждой итерации `function()` возвращается и освобождает пространство стекового кадра, поэтому пространственная сложность остается $O(1)$.
|
||||
- Рекурсивная функция `recur()` в процессе выполнения будет иметь одновременно $n$ невозвращенных вызовов `recur()`, занимая $O(n)$ пространства стекового кадра.
|
||||
|
||||
## Распространенные типы
|
||||
|
||||
При размере входных данных $n$ на рисунке ниже показаны распространенные типы пространственной сложности (от низкой к высокой).
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline
|
||||
\text{константный порядок} < \text{логарифмический порядок} < \text{линейный порядок} < \text{квадратичный порядок} < \text{экспоненциальный порядок}
|
||||
\end{aligned}
|
||||
$$
|
||||
|
||||

|
||||
|
||||
### Константный порядок $O(1)$
|
||||
|
||||
Константный порядок часто встречается в константах, переменных, объектах, количество которых не зависит от размера входных данных $n$.
|
||||
|
||||
Следует отметить, что память, занимаемая при инициализации переменных или вызове функций в цикле, освобождается при переходе к следующей итерации, поэтому не накапливается, и пространственная сложность остается $O(1)$:
|
||||
|
||||
```src
|
||||
[file]{space_complexity}-[class]{}-[func]{constant}
|
||||
```
|
||||
|
||||
### Линейный порядок $O(n)$
|
||||
|
||||
Линейный порядок часто встречается в массивах, связанных списках, стеках, очередях и т. д., где количество элементов пропорционально $n$:
|
||||
|
||||
```src
|
||||
[file]{space_complexity}-[class]{}-[func]{linear}
|
||||
```
|
||||
|
||||
Как показано на рисунке ниже, глубина рекурсии этой функции равна $n$, т. е. одновременно существует $n$ невозвращенных функций `linear_recur()`, использующих $O(n)$ пространства стекового кадра:
|
||||
|
||||
```src
|
||||
[file]{space_complexity}-[class]{}-[func]{linear_recur}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Квадратичный порядок $O(n^2)$
|
||||
|
||||
Квадратичный порядок часто встречается в матрицах и графах, где количество элементов имеет квадратичную зависимость от $n$:
|
||||
|
||||
```src
|
||||
[file]{space_complexity}-[class]{}-[func]{quadratic}
|
||||
```
|
||||
|
||||
Как показано на рисунке ниже, глубина рекурсии этой функции равна $n$, и в каждой рекурсивной функции инициализируется массив длиной $n$, $n-1$, $\dots$, $2$, $1$ соответственно, средняя длина составляет $n / 2$, поэтому общее занимаемое пространство составляет $O(n^2)$:
|
||||
|
||||
```src
|
||||
[file]{space_complexity}-[class]{}-[func]{quadratic_recur}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Экспоненциальный порядок $O(2^n)$
|
||||
|
||||
Экспоненциальный порядок часто встречается в двоичных деревьях. Как показано на рисунке ниже, "полное двоичное дерево" с $n$ уровнями име
|
||||
Reference in New Issue
Block a user