mirror of
https://github.com/krahets/hello-algo.git
synced 2026-11-11 08:20:38 +08:00
Retranslate the complete English edition from Simplified Chinese (#2010)
* Retranslate the complete English edition from Simplified Chinese * Polish three English explanations after reader-focused review
This commit is contained in:
@@ -1,32 +1,32 @@
|
||||
# Stack
|
||||
# Stacks
|
||||
|
||||
A <u>stack</u> is a linear data structure that follows the Last In, First Out (LIFO) principle.
|
||||
A <u>stack</u> is a linear data structure that follows a last-in, first-out rule.
|
||||
|
||||
We can compare a stack to a pile of plates on a table. If we specify that only one plate can be moved at a time, then to get the bottom plate, we must first remove the plates above it one by one. If we replace the plates with various types of elements (such as integers, characters, objects, etc.), we get the stack data structure.
|
||||
Think of a stack of plates on a table. If we can move only one plate at a time, reaching the bottom plate requires removing all the plates above it first. Replace the plates with elements such as integers, characters, or objects, and we have a stack.
|
||||
|
||||
As shown in the figure below, we call the top of the stacked elements the "top" and the bottom the "bottom." The operation of adding an element to the top is called "push," and the operation of removing the top element is called "pop."
|
||||
As shown below, the upper end is the “top” of the stack and the lower end is the “bottom.” Adding an element to the top is called “pushing,” and removing the top element is called “popping.”
|
||||
|
||||

|
||||

|
||||
|
||||
## Common Stack Operations
|
||||
## Common stack operations
|
||||
|
||||
The common operations on a stack are shown in the table below. The specific method names depend on the programming language used. Here, we use the common naming convention of `push()`, `pop()`, and `peek()`.
|
||||
The table below lists common operations. Actual method names depend on the programming language; here we use the familiar names `push()`, `pop()`, and `peek()`.
|
||||
|
||||
<p align="center"> Table <id> Efficiency of Stack Operations </p>
|
||||
<p align="center"> Table <id> Efficiency of stack operations </p>
|
||||
|
||||
| Method | Description | Time Complexity |
|
||||
| -------- | ---------------------------------------------- | --------------- |
|
||||
| `push()` | Push element onto stack (add to top) | $O(1)$ |
|
||||
| `pop()` | Pop top element from stack | $O(1)$ |
|
||||
| `peek()` | Access top element | $O(1)$ |
|
||||
| Method | Description | Time complexity |
|
||||
| -------- | ---------------------- | ---------- |
|
||||
| `push()` | Push an element onto the top | $O(1)$ |
|
||||
| `pop()` | Remove the top element | $O(1)$ |
|
||||
| `peek()` | Access the top element | $O(1)$ |
|
||||
|
||||
Typically, we can directly use the built-in stack class provided by the programming language. However, some languages may not provide a dedicated stack class. In such cases, we can use the language's "array" or "linked list" as a stack and simply avoid using operations unrelated to stack behavior.
|
||||
We can usually use a language's built-in stack class. If no dedicated class is provided, use an array or linked list as a stack and avoid operations unrelated to stack behavior.
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python title="stack.py"
|
||||
# Initialize stack
|
||||
# Python does not have a built-in stack class, can use list as a stack
|
||||
# Initialize a stack
|
||||
# Python has no built-in stack class; use a list as a stack
|
||||
stack: list[int] = []
|
||||
|
||||
# Push elements
|
||||
@@ -36,23 +36,23 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.append(5)
|
||||
stack.append(4)
|
||||
|
||||
# Access top element
|
||||
# Access the top element
|
||||
peek: int = stack[-1]
|
||||
|
||||
# Pop element
|
||||
# Pop an element
|
||||
pop: int = stack.pop()
|
||||
|
||||
# Get stack length
|
||||
# Get the stack size
|
||||
size: int = len(stack)
|
||||
|
||||
# Check if empty
|
||||
# Check whether the stack is empty
|
||||
is_empty: bool = len(stack) == 0
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
|
||||
```cpp title="stack.cpp"
|
||||
/* Initialize stack */
|
||||
/* Initialize a stack */
|
||||
stack<int> stack;
|
||||
|
||||
/* Push elements */
|
||||
@@ -62,23 +62,23 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
int top = stack.top();
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
stack.pop(); // No return value
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
int size = stack.size();
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
bool empty = stack.empty();
|
||||
```
|
||||
|
||||
=== "Java"
|
||||
|
||||
```java title="stack.java"
|
||||
/* Initialize stack */
|
||||
/* Initialize a stack */
|
||||
Stack<Integer> stack = new Stack<>();
|
||||
|
||||
/* Push elements */
|
||||
@@ -88,23 +88,23 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
int peek = stack.peek();
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
int pop = stack.pop();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
int size = stack.size();
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
boolean isEmpty = stack.isEmpty();
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="stack.cs"
|
||||
/* Initialize stack */
|
||||
/* Initialize a stack */
|
||||
Stack<int> stack = new();
|
||||
|
||||
/* Push elements */
|
||||
@@ -114,24 +114,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.Push(5);
|
||||
stack.Push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
int peek = stack.Peek();
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
int pop = stack.Pop();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
int size = stack.Count;
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
bool isEmpty = stack.Count == 0;
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
|
||||
```go title="stack_test.go"
|
||||
/* Initialize stack */
|
||||
// In Go, it is recommended to use Slice as a stack
|
||||
/* Initialize a stack */
|
||||
// In Go, a slice is recommended for use as a stack
|
||||
var stack []int
|
||||
|
||||
/* Push elements */
|
||||
@@ -141,25 +141,25 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack = append(stack, 5)
|
||||
stack = append(stack, 4)
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
peek := stack[len(stack)-1]
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
pop := stack[len(stack)-1]
|
||||
stack = stack[:len(stack)-1]
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
size := len(stack)
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
isEmpty := len(stack) == 0
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="stack.swift"
|
||||
/* Initialize stack */
|
||||
// Swift does not have a built-in stack class, can use Array as a stack
|
||||
/* Initialize a stack */
|
||||
// Swift has no built-in stack class; use an Array as a stack
|
||||
var stack: [Int] = []
|
||||
|
||||
/* Push elements */
|
||||
@@ -169,24 +169,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.append(5)
|
||||
stack.append(4)
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
let peek = stack.last!
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
let pop = stack.removeLast()
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
let size = stack.count
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
let isEmpty = stack.isEmpty
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="stack.js"
|
||||
/* Initialize stack */
|
||||
// JavaScript does not have a built-in stack class, can use Array as a stack
|
||||
/* Initialize a stack */
|
||||
// JavaScript has no built-in stack class; use an Array as a stack
|
||||
const stack = [];
|
||||
|
||||
/* Push elements */
|
||||
@@ -196,24 +196,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
const peek = stack[stack.length-1];
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
const pop = stack.pop();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
const size = stack.length;
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
const is_empty = stack.length === 0;
|
||||
```
|
||||
|
||||
=== "TS"
|
||||
|
||||
```typescript title="stack.ts"
|
||||
/* Initialize stack */
|
||||
// TypeScript does not have a built-in stack class, can use Array as a stack
|
||||
/* Initialize a stack */
|
||||
// TypeScript has no built-in stack class; use an Array as a stack
|
||||
const stack: number[] = [];
|
||||
|
||||
/* Push elements */
|
||||
@@ -223,24 +223,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
const peek = stack[stack.length - 1];
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
const pop = stack.pop();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
const size = stack.length;
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
const is_empty = stack.length === 0;
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="stack.dart"
|
||||
/* Initialize stack */
|
||||
// Dart does not have a built-in stack class, can use List as a stack
|
||||
/* Initialize a stack */
|
||||
// Dart has no built-in stack class; use a List as a stack
|
||||
List<int> stack = [];
|
||||
|
||||
/* Push elements */
|
||||
@@ -250,24 +250,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.add(5);
|
||||
stack.add(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
int peek = stack.last;
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
int pop = stack.removeLast();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
int size = stack.length;
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
bool isEmpty = stack.isEmpty;
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="stack.rs"
|
||||
/* Initialize stack */
|
||||
// Use Vec as a stack
|
||||
/* Initialize a stack */
|
||||
// Use a Vec as a stack
|
||||
let mut stack: Vec<i32> = Vec::new();
|
||||
|
||||
/* Push elements */
|
||||
@@ -277,29 +277,29 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
let top = stack.last().unwrap();
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
let pop = stack.pop().unwrap();
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
let size = stack.len();
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
let is_empty = stack.is_empty();
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="stack.c"
|
||||
// C does not provide a built-in stack
|
||||
// C provides no built-in stack
|
||||
```
|
||||
|
||||
=== "Kotlin"
|
||||
|
||||
```kotlin title="stack.kt"
|
||||
/* Initialize stack */
|
||||
/* Initialize a stack */
|
||||
val stack = Stack<Int>()
|
||||
|
||||
/* Push elements */
|
||||
@@ -309,24 +309,24 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack.push(5)
|
||||
stack.push(4)
|
||||
|
||||
/* Access top element */
|
||||
/* Access the top element */
|
||||
val peek = stack.peek()
|
||||
|
||||
/* Pop element */
|
||||
/* Pop an element */
|
||||
val pop = stack.pop()
|
||||
|
||||
/* Get stack length */
|
||||
/* Get the stack size */
|
||||
val size = stack.size
|
||||
|
||||
/* Check if empty */
|
||||
/* Check whether the stack is empty */
|
||||
val isEmpty = stack.isEmpty()
|
||||
```
|
||||
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="stack.rb"
|
||||
# Initialize stack
|
||||
# Ruby does not have a built-in stack class, can use Array as a stack
|
||||
# Initialize a stack
|
||||
# Ruby has no built-in stack class; use an Array as a stack
|
||||
stack = []
|
||||
|
||||
# Push elements
|
||||
@@ -336,37 +336,37 @@ Typically, we can directly use the built-in stack class provided by the programm
|
||||
stack << 5
|
||||
stack << 4
|
||||
|
||||
# Access top element
|
||||
# Access the top element
|
||||
peek = stack.last
|
||||
|
||||
# Pop element
|
||||
# Pop an element
|
||||
pop = stack.pop
|
||||
|
||||
# Get stack length
|
||||
# Get the stack size
|
||||
size = stack.length
|
||||
|
||||
# Check if empty
|
||||
# Check whether the stack is empty
|
||||
is_empty = stack.empty?
|
||||
```
|
||||
|
||||
??? pythontutor "Code Visualization"
|
||||
??? pythontutor "Visualize execution"
|
||||
|
||||
https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%A0%88%0A%20%20%20%20%23%20Python%20%E6%B2%A1%E6%9C%89%E5%86%85%E7%BD%AE%E7%9A%84%E6%A0%88%E7%B1%BB%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%8A%8A%20list%20%E5%BD%93%E4%BD%9C%E6%A0%88%E6%9D%A5%E4%BD%BF%E7%94%A8%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%85%A5%E6%A0%88%0A%20%20%20%20stack.append%281%29%0A%20%20%20%20stack.append%283%29%0A%20%20%20%20stack.append%282%29%0A%20%20%20%20stack.append%285%29%0A%20%20%20%20stack.append%284%29%0A%20%20%20%20print%28%22%E6%A0%88%20stack%20%3D%22,%20stack%29%0A%0A%20%20%20%20%23%20%E8%AE%BF%E9%97%AE%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%0A%20%20%20%20peek%20%3D%20stack%5B-1%5D%0A%20%20%20%20print%28%22%E6%A0%88%E9%A1%B6%E5%85%83%E7%B4%A0%20peek%20%3D%22,%20peek%29%0A%0A%20%20%20%20%23%20%E5%85%83%E7%B4%A0%E5%87%BA%E6%A0%88%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%85%83%E7%B4%A0%20pop%20%3D%22,%20pop%29%0A%20%20%20%20print%28%22%E5%87%BA%E6%A0%88%E5%90%8E%20stack%20%3D%22,%20stack%29%0A%0A%20%20%20%20%23%20%E8%8E%B7%E5%8F%96%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%0A%20%20%20%20size%20%3D%20len%28stack%29%0A%20%20%20%20print%28%22%E6%A0%88%E7%9A%84%E9%95%BF%E5%BA%A6%20size%20%3D%22,%20size%29%0A%0A%20%20%20%20%23%20%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%20%20%20%20is_empty%20%3D%20len%28stack%29%20%3D%3D%200%0A%20%20%20%20print%28%22%E6%A0%88%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%20%3D%22,%20is_empty%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false
|
||||
https://pythontutor.com/render.html#code=%22%22%22Driver%20Code%22%22%22%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20%23%20Initialize%20a%20stack%0A%20%20%20%20%23%20Python%20has%20no%20built-in%20stack%20class%3B%20use%20a%20list%20as%20a%20stack%0A%20%20%20%20stack%20%3D%20%5B%5D%0A%0A%20%20%20%20%23%20Push%20elements%0A%20%20%20%20stack.append%281%29%0A%20%20%20%20stack.append%283%29%0A%20%20%20%20stack.append%282%29%0A%20%20%20%20stack.append%285%29%0A%20%20%20%20stack.append%284%29%0A%20%20%20%20print%28%22Stack%3A%20stack%20%3D%22%2C%20stack%29%0A%0A%20%20%20%20%23%20Access%20the%20top%20element%0A%20%20%20%20peek%20%3D%20stack%5B-1%5D%0A%20%20%20%20print%28%22Top%20element%3A%20peek%20%3D%22%2C%20peek%29%0A%0A%20%20%20%20%23%20Pop%20an%20element%0A%20%20%20%20pop%20%3D%20stack.pop%28%29%0A%20%20%20%20print%28%22Popped%20element%3A%20pop%20%3D%22%2C%20pop%29%0A%20%20%20%20print%28%22After%20popping%3A%20stack%20%3D%22%2C%20stack%29%0A%0A%20%20%20%20%23%20Get%20the%20stack%20size%0A%20%20%20%20size%20%3D%20len%28stack%29%0A%20%20%20%20print%28%22Stack%20size%3A%20size%20%3D%22%2C%20size%29%0A%0A%20%20%20%20%23%20Check%20whether%20the%20stack%20is%20empty%0A%20%20%20%20is_empty%20%3D%20len%28stack%29%20%3D%3D%200%0A%20%20%20%20print%28%22Is%20the%20stack%20empty%20%3D%22%2C%20is_empty%29&cumulative=false&curInstr=2&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false
|
||||
|
||||
## Stack Implementation
|
||||
## Implementing a stack
|
||||
|
||||
To gain a deeper understanding of how a stack operates, let's try implementing a stack class ourselves.
|
||||
To understand how a stack works more deeply, let us implement a stack class ourselves.
|
||||
|
||||
A stack follows the LIFO principle, so we can only add or remove elements at the top. However, both arrays and linked lists allow adding and removing elements at any position. **Therefore, a stack can be viewed as a restricted array or linked list**. In other words, we can "shield" some irrelevant operations of arrays or linked lists so that their external logic conforms to the characteristics of a stack.
|
||||
A stack follows last-in, first-out order, so elements can be added or removed only at the top. Arrays and linked lists allow insertion and deletion at arbitrary positions, **so a stack can be viewed as a restricted array or linked list**. By hiding irrelevant operations, we make its public behavior conform to the stack's rules.
|
||||
|
||||
### Linked List Implementation
|
||||
### Implementation with a linked list
|
||||
|
||||
When implementing a stack using a linked list, we can treat the head node of the linked list as the top of the stack and the tail node as the base.
|
||||
When implementing a stack with a linked list, treat the head as the top and the tail as the bottom.
|
||||
|
||||
As shown in the figure below, for the push operation, we simply insert an element at the head of the linked list. This node insertion method is called the "head insertion method." For the pop operation, we just need to remove the head node from the linked list.
|
||||
As shown below, pushing simply inserts a node at the head, an operation called “head insertion.” Popping removes the head node.
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -374,18 +374,18 @@ As shown in the figure below, for the push operation, we simply insert an elemen
|
||||
=== "<3>"
|
||||

|
||||
|
||||
Below is sample code for implementing a stack based on a linked list:
|
||||
Here is an implementation using a linked list:
|
||||
|
||||
```src
|
||||
[file]{linkedlist_stack}-[class]{linked_list_stack}-[func]{}
|
||||
```
|
||||
|
||||
### Array Implementation
|
||||
### Implementation with an array
|
||||
|
||||
When implementing a stack using an array, we can treat the end of the array as the top of the stack. As shown in the figure below, push and pop operations correspond to adding and removing elements at the end of the array, both with a time complexity of $O(1)$.
|
||||
For an array-based stack, use the end of the array as the top. As shown below, pushing and popping correspond to adding and removing the last element, both taking $O(1)$ time.
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -393,38 +393,38 @@ When implementing a stack using an array, we can treat the end of the array as t
|
||||
=== "<3>"
|
||||

|
||||
|
||||
Since elements pushed onto the stack may increase continuously, we can use a dynamic array, which eliminates the need to handle array expansion ourselves. Here is the sample code:
|
||||
Since elements may keep arriving, use a dynamic array so that resizing is handled for us. An implementation follows:
|
||||
|
||||
```src
|
||||
[file]{array_stack}-[class]{array_stack}-[func]{}
|
||||
```
|
||||
|
||||
## Comparison of the Two Implementations
|
||||
## Comparing the implementations
|
||||
|
||||
**Supported Operations**
|
||||
**Supported operations**
|
||||
|
||||
Both implementations support all operations defined by the stack. The array implementation additionally supports random access, but this goes beyond the stack definition and is generally not used.
|
||||
Both implementations support all stack operations. An array also allows random access, but that is outside the stack abstraction and is generally not used.
|
||||
|
||||
**Time Efficiency**
|
||||
**Time efficiency**
|
||||
|
||||
In the array-based implementation, both push and pop operations occur in pre-allocated contiguous memory, which has good cache locality and is therefore more efficient. However, if pushing exceeds the array capacity, it triggers an expansion mechanism, causing the time complexity of that particular push operation to become $O(n)$.
|
||||
In an array-based stack, pushes and pops operate in preallocated contiguous memory, giving good cache locality and high efficiency. However, a push that exceeds the array's capacity triggers expansion, making that particular push an $O(n)$ operation.
|
||||
|
||||
In the linked list-based implementation, list expansion is very flexible, and there is no issue of reduced efficiency due to array expansion. However, the push operation requires initializing a node object and modifying pointers, so it is relatively less efficient. Nevertheless, if the pushed elements are already node objects, the initialization step can be omitted, thereby improving efficiency.
|
||||
A linked list grows flexibly and avoids the slowdown associated with array expansion. However, pushing requires creating a node object and updating pointers, so it is relatively slower. If the element is already a node object, the creation step can be skipped to improve efficiency.
|
||||
|
||||
In summary, when the elements pushed and popped are basic data types such as `int` or `double`, we can draw the following conclusions:
|
||||
For elements of primitive types such as `int` or `double`, we can therefore draw the following conclusions.
|
||||
|
||||
- The array-based stack implementation has reduced efficiency when expansion is triggered, but since expansion is an infrequent operation, the average efficiency is higher.
|
||||
- The linked list-based stack implementation can provide more stable efficiency performance.
|
||||
- An array-based stack slows down when expansion is triggered, but expansion is infrequent, so average efficiency is higher.
|
||||
- A linked-list stack provides more consistent performance.
|
||||
|
||||
**Space Efficiency**
|
||||
**Space efficiency**
|
||||
|
||||
When initializing a list, the system allocates an "initial capacity" that may exceed the actual need. Additionally, the expansion mechanism typically expands at a specific ratio (e.g., 2x), and the capacity after expansion may also exceed actual needs. Therefore, **the array-based stack implementation may cause some space wastage**.
|
||||
When a dynamic array is initialized, its initial capacity may exceed actual needs. Expansion typically multiplies the capacity by a fixed factor, such as 2, which may again leave excess space. **An array-based stack can therefore waste some space**.
|
||||
|
||||
However, since linked list nodes need to store additional pointers, **the space occupied by linked list nodes is relatively large**.
|
||||
However, linked-list nodes also store pointers, **so each node occupies relatively more space**.
|
||||
|
||||
In summary, we cannot simply determine which implementation is more memory-efficient and need to analyze the specific situation.
|
||||
We cannot say universally which implementation uses less memory; the answer depends on the situation.
|
||||
|
||||
## Typical Applications of Stack
|
||||
## Typical applications
|
||||
|
||||
- **Back and forward in browsers, undo and redo in software**. Every time we open a new webpage, the browser pushes the previous page onto the stack, allowing us to return to the previous page via the back operation. The back operation is essentially performing a pop. To support both back and forward, two stacks are needed to work together.
|
||||
- **Program memory management**. Each time a function is called, the system adds a stack frame to the top of the stack to record the function's context information. During recursion, the downward recursive phase continuously performs push operations, while the upward backtracking phase continuously performs pop operations.
|
||||
- **Browser back and forward navigation, and software undo and redo**. When a new web page is opened, the browser pushes the previous page onto a stack. Going back pops that page. Supporting both back and forward requires two stacks working together.
|
||||
- **Program memory management**. Each function call adds a stack frame containing the function's context. During recursion, frames are pushed as calls descend and popped as they return.
|
||||
|
||||
Reference in New Issue
Block a user