This commit is contained in:
krahets
2023-04-09 04:34:58 +08:00
parent adcbab4d4c
commit 01d05cc1f0
26 changed files with 1501 additions and 1247 deletions

View File

@@ -295,11 +295,11 @@ comments: true
### 基于双向链表的实现
回忆上节内容,由于可以方便地删除链表头点(对应出队操作),以及在链表尾点后添加新点(对应入队操作),因此我们使用普通单向链表来实现队列。
回忆上节内容,由于可以方便地删除链表头点(对应出队操作),以及在链表尾点后添加新点(对应入队操作),因此我们使用普通单向链表来实现队列。
而双向队列的头部和尾部都可以执行入队与出队操作,换言之,双向队列的操作是“首尾对称”的,也需要实现另一个对称方向的操作。因此,双向队列需要使用「双向链表」来实现。
我们将双向链表的头点和尾点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除点。
我们将双向链表的头点和尾点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除点。
=== "LinkedListDeque"
![基于链表实现双向队列的入队出队操作](deque.assets/linkedlist_deque.png)
@@ -321,11 +321,11 @@ comments: true
=== "Java"
```java title="linkedlist_deque.java"
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
int val; // 点值
ListNode next; // 后继点引用(指针)
ListNode prev; // 前驱点引用(指针)
int val; // 点值
ListNode next; // 后继点引用(指针)
ListNode prev; // 前驱点引用(指针)
ListNode(int val) {
this.val = val;
prev = next = null;
@@ -334,7 +334,7 @@ comments: true
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private ListNode front, rear; // 头点 front ,尾点 rear
private ListNode front, rear; // 头点 front ,尾点 rear
private int queSize = 0; // 双向队列的长度
public LinkedListDeque() {
@@ -362,13 +362,13 @@ comments: true
// 将 node 添加至链表头部
front.prev = node;
node.next = front;
front = node; // 更新头
front = node; // 更新头
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
rear.next = node;
node.prev = rear;
rear = node; // 更新尾
rear = node; // 更新尾
}
queSize++; // 更新队列长度
}
@@ -391,24 +391,24 @@ comments: true
int val;
// 队首出队操作
if (isFront) {
val = front.val; // 暂存头点值
// 删除头
val = front.val; // 暂存头点值
// 删除头
ListNode fNext = front.next;
if (fNext != null) {
fNext.prev = null;
front.next = null;
}
front = fNext; // 更新头
front = fNext; // 更新头
// 队尾出队操作
} else {
val = rear.val; // 暂存尾点值
// 删除尾
val = rear.val; // 暂存尾点值
// 删除尾
ListNode rPrev = rear.prev;
if (rPrev != null) {
rPrev.next = null;
rear.prev = null;
}
rear = rPrev; // 更新尾
rear = rPrev; // 更新尾
}
queSize--; // 更新队列长度
return val;
@@ -450,18 +450,18 @@ comments: true
=== "C++"
```cpp title="linkedlist_deque.cpp"
/* 双向链表点 */
/* 双向链表点 */
struct DoublyListNode {
int val; // 点值
DoublyListNode *next; // 后继点指针
DoublyListNode *prev; // 前驱点指针
int val; // 点值
DoublyListNode *next; // 后继点指针
DoublyListNode *prev; // 前驱点指针
DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) {}
};
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private:
DoublyListNode *front, *rear; // 头点 front ,尾点 rear
DoublyListNode *front, *rear; // 头点 front ,尾点 rear
int queSize = 0; // 双向队列的长度
public:
@@ -470,7 +470,7 @@ comments: true
/* 析构方法 */
~LinkedListDeque() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
DoublyListNode *pre, *cur = front;
while (cur != nullptr) {
pre = cur;
@@ -500,13 +500,13 @@ comments: true
// 将 node 添加至链表头部
front->prev = node;
node->next = front;
front = node; // 更新头
front = node; // 更新头
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
rear->next = node;
node->prev = rear;
rear = node; // 更新尾
rear = node; // 更新尾
}
queSize++; // 更新队列长度
}
@@ -529,26 +529,26 @@ comments: true
int val;
// 队首出队操作
if (isFront) {
val = front->val; // 暂存头点值
// 删除头
val = front->val; // 暂存头点值
// 删除头
DoublyListNode *fNext = front->next;
if (fNext != nullptr) {
fNext->prev = nullptr;
front->next = nullptr;
delete front;
}
front = fNext; // 更新头
front = fNext; // 更新头
// 队尾出队操作
} else {
val = rear->val; // 暂存尾点值
// 删除尾
val = rear->val; // 暂存尾点值
// 删除尾
DoublyListNode *rPrev = rear->prev;
if (rPrev != nullptr) {
rPrev->next = nullptr;
rear->prev = nullptr;
delete rear;
}
rear = rPrev; // 更新尾
rear = rPrev; // 更新尾
}
queSize--; // 更新队列长度
return val;
@@ -591,19 +591,19 @@ comments: true
```python title="linkedlist_deque.py"
class ListNode:
""" 双向链表点 """
""" 双向链表点 """
def __init__(self, val: int) -> None:
""" 构造方法 """
self.val: int = val
self.next: ListNode | None = None # 后继点引用(指针)
self.prev: ListNode | None = None # 前驱点引用(指针)
self.next: ListNode | None = None # 后继点引用(指针)
self.prev: ListNode | None = None # 前驱点引用(指针)
class LinkedListDeque:
""" 基于双向链表实现的双向队列 """
def __init__(self) -> None:
""" 构造方法 """
self.front: ListNode | None = None # 头点 front
self.rear: ListNode | None = None # 尾点 rear
self.front: ListNode | None = None # 头点 front
self.rear: ListNode | None = None # 尾点 rear
self.__size: int = 0 # 双向队列的长度
def size(self) -> int:
@@ -625,13 +625,13 @@ comments: true
# 将 node 添加至链表头部
self.front.prev = node
node.next = self.front
self.front = node # 更新头
self.front = node # 更新头
# 队尾入队操作
else:
# 将 node 添加至链表尾部
self.rear.next = node
node.prev = self.rear
self.rear = node # 更新尾
self.rear = node # 更新尾
self.__size += 1 # 更新队列长度
def push_first(self, num: int) -> None:
@@ -649,22 +649,22 @@ comments: true
return None
# 队首出队操作
if is_front:
val: int = self.front.val # 暂存头点值
# 删除头
val: int = self.front.val # 暂存头点值
# 删除头
fnext: ListNode | None = self.front.next
if fnext != None:
fnext.prev = None
self.front.next = None
self.front = fnext # 更新头
self.front = fnext # 更新头
# 队尾出队操作
else:
val: int = self.rear.val # 暂存尾点值
# 删除尾
val: int = self.rear.val # 暂存尾点值
# 删除尾
rprev: ListNode | None = self.rear.prev
if rprev != None:
rprev.next = None
self.rear.prev = None
self.rear = rprev # 更新尾
self.rear = rprev # 更新尾
self.__size -= 1 # 更新队列长度
return val
@@ -777,11 +777,11 @@ comments: true
=== "JavaScript"
```javascript title="linkedlist_deque.js"
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
prev; // 前驱点引用 (指针)
next; // 后继点引用 (指针)
val; // 点值
prev; // 前驱点引用 (指针)
next; // 后继点引用 (指针)
val; // 点值
constructor(val) {
this.val = val;
@@ -792,8 +792,8 @@ comments: true
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
#front; // 头点 front
#rear; // 尾点 rear
#front; // 头点 front
#rear; // 尾点 rear
#queSize; // 双向队列的长度
constructor() {
@@ -813,7 +813,7 @@ comments: true
// 将 node 添加至链表尾部
this.#rear.next = node;
node.prev = this.#rear;
this.#rear = node; // 更新尾
this.#rear = node; // 更新尾
}
this.#queSize++;
}
@@ -829,7 +829,7 @@ comments: true
// 将 node 添加至链表头部
this.#front.prev = node;
node.next = this.#front;
this.#front = node; // 更新头
this.#front = node; // 更新头
}
this.#queSize++;
}
@@ -839,14 +839,14 @@ comments: true
if (this.#queSize === 0) {
return null;
}
const value = this.#rear.val; // 存储尾点值
// 删除尾
const value = this.#rear.val; // 存储尾点值
// 删除尾
let temp = this.#rear.prev;
if (temp !== null) {
temp.next = null;
this.#rear.prev = null;
}
this.#rear = temp; // 更新尾
this.#rear = temp; // 更新尾
this.#queSize--;
return value;
}
@@ -856,14 +856,14 @@ comments: true
if (this.#queSize === 0) {
return null;
}
const value = this.#front.val; // 存储尾点值
// 删除头
const value = this.#front.val; // 存储尾点值
// 删除头
let temp = this.#front.next;
if (temp !== null) {
temp.prev = null;
this.#front.next = null;
}
this.#front = temp; // 更新头
this.#front = temp; // 更新头
this.#queSize--;
return value;
}
@@ -904,11 +904,11 @@ comments: true
=== "TypeScript"
```typescript title="linkedlist_deque.ts"
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
prev: ListNode; // 前驱点引用 (指针)
next: ListNode; // 后继点引用 (指针)
val: number; // 点值
prev: ListNode; // 前驱点引用 (指针)
next: ListNode; // 后继点引用 (指针)
val: number; // 点值
constructor(val: number) {
this.val = val;
@@ -919,8 +919,8 @@ comments: true
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private front: ListNode; // 头点 front
private rear: ListNode; // 尾点 rear
private front: ListNode; // 头点 front
private rear: ListNode; // 尾点 rear
private queSize: number; // 双向队列的长度
constructor() {
@@ -940,7 +940,7 @@ comments: true
// 将 node 添加至链表尾部
this.rear.next = node;
node.prev = this.rear;
this.rear = node; // 更新尾
this.rear = node; // 更新尾
}
this.queSize++;
}
@@ -956,7 +956,7 @@ comments: true
// 将 node 添加至链表头部
this.front.prev = node;
node.next = this.front;
this.front = node; // 更新头
this.front = node; // 更新头
}
this.queSize++;
}
@@ -966,14 +966,14 @@ comments: true
if (this.queSize === 0) {
return null;
}
const value: number = this.rear.val; // 存储尾点值
// 删除尾
const value: number = this.rear.val; // 存储尾点值
// 删除尾
let temp: ListNode = this.rear.prev;
if (temp !== null) {
temp.next = null;
this.rear.prev = null;
}
this.rear = temp; // 更新尾
this.rear = temp; // 更新尾
this.queSize--;
return value;
}
@@ -983,14 +983,14 @@ comments: true
if (this.queSize === 0) {
return null;
}
const value: number = this.front.val; // 存储尾点值
// 删除头
const value: number = this.front.val; // 存储尾点值
// 删除头
let temp: ListNode = this.front.next;
if (temp !== null) {
temp.prev = null;
this.front.next = null;
}
this.front = temp; // 更新头
this.front = temp; // 更新头
this.queSize--;
return value;
}
@@ -1047,11 +1047,11 @@ comments: true
=== "Swift"
```swift title="linkedlist_deque.swift"
/* 双向链表点 */
/* 双向链表点 */
class ListNode {
var val: Int // 点值
var next: ListNode? // 后继点引用(指针)
var prev: ListNode? // 前驱点引用(指针)
var val: Int // 点值
var next: ListNode? // 后继点引用(指针)
var prev: ListNode? // 前驱点引用(指针)
init(val: Int) {
self.val = val
@@ -1060,8 +1060,8 @@ comments: true
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private var front: ListNode? // 头点 front
private var rear: ListNode? // 尾点 rear
private var front: ListNode? // 头点 front
private var rear: ListNode? // 尾点 rear
private var queSize: Int // 双向队列的长度
init() {
@@ -1091,14 +1091,14 @@ comments: true
// 将 node 添加至链表头部
front?.prev = node
node.next = front
front = node // 更新头
front = node // 更新头
}
// 队尾入队操作
else {
// 将 node 添加至链表尾部
rear?.next = node
node.prev = rear
rear = node // 更新尾
rear = node // 更新尾
}
queSize += 1 // 更新队列长度
}
@@ -1121,25 +1121,25 @@ comments: true
let val: Int
// 队首出队操作
if isFront {
val = front!.val // 暂存头点值
// 删除头
val = front!.val // 暂存头点值
// 删除头
let fNext = front?.next
if fNext != nil {
fNext?.prev = nil
front?.next = nil
}
front = fNext // 更新头
front = fNext // 更新头
}
// 队尾出队操作
else {
val = rear!.val // 暂存尾点值
// 删除尾
val = rear!.val // 暂存尾点值
// 删除尾
let rPrev = rear?.prev
if rPrev != nil {
rPrev?.next = nil
rear?.prev = nil
}
rear = rPrev // 更新尾
rear = rPrev // 更新尾
}
queSize -= 1 // 更新队列长度
return val
@@ -1181,14 +1181,14 @@ comments: true
=== "Zig"
```zig title="linkedlist_deque.zig"
// 双向链表
// 双向链表
fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
val: T = undefined, // 点值
next: ?*Self = null, // 后继点引用(指针)
prev: ?*Self = null, // 前驱点引用(指针)
val: T = undefined, // 点值
next: ?*Self = null, // 后继点引用(指针)
prev: ?*Self = null, // 前驱点引用(指针)
// Initialize a list node with specific value
pub fn init(self: *Self, x: i32) void {
@@ -1204,8 +1204,8 @@ comments: true
return struct {
const Self = @This();
front: ?*ListNode(T) = null, // 头点 front
rear: ?*ListNode(T) = null, // 尾点 rear
front: ?*ListNode(T) = null, // 头点 front
rear: ?*ListNode(T) = null, // 尾点 rear
que_size: usize = 0, // 双向队列的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -1250,13 +1250,13 @@ comments: true
// 将 node 添加至链表头部
self.front.?.prev = node;
node.next = self.front;
self.front = node; // 更新头
self.front = node; // 更新头
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
self.rear.?.next = node;
node.prev = self.rear;
self.rear = node; // 更新尾
self.rear = node; // 更新尾
}
self.que_size += 1; // 更新队列长度
}
@@ -1277,24 +1277,24 @@ comments: true
var val: T = undefined;
// 队首出队操作
if (is_front) {
val = self.front.?.val; // 暂存头点值
// 删除头
val = self.front.?.val; // 暂存头点值
// 删除头
var fNext = self.front.?.next;
if (fNext != null) {
fNext.?.prev = null;
self.front.?.next = null;
}
self.front = fNext; // 更新头
self.front = fNext; // 更新头
// 队尾出队操作
} else {
val = self.rear.?.val; // 暂存尾点值
// 删除尾
val = self.rear.?.val; // 暂存尾点值
// 删除尾
var rPrev = self.rear.?.prev;
if (rPrev != null) {
rPrev.?.next = null;
self.rear.?.prev = null;
}
self.rear = rPrev; // 更新尾
self.rear = rPrev; // 更新尾
}
self.que_size -= 1; // 更新队列长度
return val;

View File

@@ -264,7 +264,7 @@ comments: true
### 基于链表的实现
我们将链表的「头点」和「尾点」分别看作是队首和队尾,并规定队尾只可添加点,队首只可删除点。
我们将链表的「头点」和「尾点」分别看作是队首和队尾,并规定队尾只可添加点,队首只可删除点。
=== "LinkedListQueue"
![基于链表实现队列的入队出队操作](queue.assets/linkedlist_queue.png)
@@ -282,7 +282,7 @@ comments: true
```java title="linkedlist_queue.java"
/* 基于链表实现的队列 */
class LinkedListQueue {
private ListNode front, rear; // 头点 front ,尾点 rear
private ListNode front, rear; // 头点 front ,尾点 rear
private int queSize = 0;
public LinkedListQueue() {
@@ -302,13 +302,13 @@ comments: true
/* 入队 */
public void push(int num) {
// 尾点后添加 num
// 尾点后添加 num
ListNode node = new ListNode(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (front == null) {
front = node;
rear = node;
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
} else {
rear.next = node;
rear = node;
@@ -319,7 +319,7 @@ comments: true
/* 出队 */
public int pop() {
int num = peek();
// 删除头
// 删除头
front = front.next;
queSize--;
return num;
@@ -351,7 +351,7 @@ comments: true
/* 基于链表实现的队列 */
class LinkedListQueue {
private:
ListNode *front, *rear; // 头点 front ,尾点 rear
ListNode *front, *rear; // 头点 front ,尾点 rear
int queSize;
public:
@@ -362,7 +362,7 @@ comments: true
}
~LinkedListQueue() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
freeMemoryLinkedList(front);
}
@@ -378,14 +378,14 @@ comments: true
/* 入队 */
void push(int num) {
// 尾点后添加 num
// 尾点后添加 num
ListNode* node = new ListNode(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (front == nullptr) {
front = node;
rear = node;
}
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
else {
rear->next = node;
rear = node;
@@ -396,7 +396,7 @@ comments: true
/* 出队 */
void pop() {
int num = peek();
// 删除头
// 删除头
ListNode *tmp = front;
front = front->next;
// 释放内存
@@ -431,8 +431,8 @@ comments: true
""" 基于链表实现的队列 """
def __init__(self):
""" 构造方法 """
self.__front: ListNode | None = None # 头点 front
self.__rear: ListNode | None = None # 尾点 rear
self.__front: ListNode | None = None # 头点 front
self.__rear: ListNode | None = None # 尾点 rear
self.__size: int = 0
def size(self) -> int:
@@ -445,13 +445,13 @@ comments: true
def push(self, num: int) -> None:
""" 入队 """
# 尾点后添加 num
# 尾点后添加 num
node = ListNode(num)
# 如果队列为空,则令头、尾点都指向该
# 如果队列为空,则令头、尾点都指向该
if self.__front is None:
self.__front = node
self.__rear = node
# 如果队列不为空,则将该点添加到尾点后
# 如果队列不为空,则将该点添加到尾点后
else:
self.__rear.next = node
self.__rear = node
@@ -460,7 +460,7 @@ comments: true
def pop(self) -> int:
""" 出队 """
num = self.peek()
# 删除头
# 删除头
self.__front = self.__front.next
self.__size -= 1
return num
@@ -543,8 +543,8 @@ comments: true
```javascript title="linkedlist_queue.js"
/* 基于链表实现的队列 */
class LinkedListQueue {
#front; // 头点 #front
#rear; // 尾点 #rear
#front; // 头点 #front
#rear; // 尾点 #rear
#queSize = 0;
constructor() {
@@ -564,13 +564,13 @@ comments: true
/* 入队 */
push(num) {
// 尾点后添加 num
// 尾点后添加 num
const node = new ListNode(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (!this.#front) {
this.#front = node;
this.#rear = node;
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
} else {
this.#rear.next = node;
this.#rear = node;
@@ -581,7 +581,7 @@ comments: true
/* 出队 */
pop() {
const num = this.peek();
// 删除头
// 删除头
this.#front = this.#front.next;
this.#queSize--;
return num;
@@ -612,8 +612,8 @@ comments: true
```typescript title="linkedlist_queue.ts"
/* 基于链表实现的队列 */
class LinkedListQueue {
private front: ListNode | null; // 头点 front
private rear: ListNode | null; // 尾点 rear
private front: ListNode | null; // 头点 front
private rear: ListNode | null; // 尾点 rear
private queSize: number = 0;
constructor() {
@@ -633,13 +633,13 @@ comments: true
/* 入队 */
push(num: number): void {
// 尾点后添加 num
// 尾点后添加 num
const node = new ListNode(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (!this.front) {
this.front = node;
this.rear = node;
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
} else {
this.rear!.next = node;
this.rear = node;
@@ -651,7 +651,7 @@ comments: true
pop(): number {
const num = this.peek();
if (!this.front) throw new Error('队列为空');
// 删除头
// 删除头
this.front = this.front.next;
this.queSize--;
return num;
@@ -688,7 +688,7 @@ comments: true
/* 基于链表实现的队列 */
class LinkedListQueue
{
private ListNode? front, rear; // 头点 front ,尾点 rear
private ListNode? front, rear; // 头点 front ,尾点 rear
private int queSize = 0;
public LinkedListQueue()
@@ -712,14 +712,14 @@ comments: true
/* 入队 */
public void push(int num)
{
// 尾点后添加 num
// 尾点后添加 num
ListNode node = new ListNode(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (front == null)
{
front = node;
rear = node;
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
}
else if (rear != null)
{
@@ -733,7 +733,7 @@ comments: true
public int pop()
{
int num = peek();
// 删除头
// 删除头
front = front?.next;
queSize--;
return num;
@@ -770,8 +770,8 @@ comments: true
```swift title="linkedlist_queue.swift"
/* 基于链表实现的队列 */
class LinkedListQueue {
private var front: ListNode? // 头
private var rear: ListNode? // 尾
private var front: ListNode? // 头
private var rear: ListNode? // 尾
private var _size = 0
init() {}
@@ -788,14 +788,14 @@ comments: true
/* 入队 */
func push(num: Int) {
// 尾点后添加 num
// 尾点后添加 num
let node = ListNode(x: num)
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if front == nil {
front = node
rear = node
}
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
else {
rear?.next = node
rear = node
@@ -807,7 +807,7 @@ comments: true
@discardableResult
func pop() -> Int {
let num = peek()
// 删除头
// 删除头
front = front?.next
_size -= 1
return num
@@ -842,8 +842,8 @@ comments: true
return struct {
const Self = @This();
front: ?*inc.ListNode(T) = null, // 头点 front
rear: ?*inc.ListNode(T) = null, // 尾点 rear
front: ?*inc.ListNode(T) = null, // 头点 front
rear: ?*inc.ListNode(T) = null, // 尾点 rear
que_size: usize = 0, // 队列的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -883,14 +883,14 @@ comments: true
// 入队
pub fn push(self: *Self, num: T) !void {
// 尾点后添加 num
// 尾点后添加 num
var node = try self.mem_allocator.create(inc.ListNode(T));
node.init(num);
// 如果队列为空,则令头、尾点都指向该
// 如果队列为空,则令头、尾点都指向该
if (self.front == null) {
self.front = node;
self.rear = node;
// 如果队列不为空,则将该点添加到尾点后
// 如果队列不为空,则将该点添加到尾点后
} else {
self.rear.?.next = node;
self.rear = node;
@@ -901,7 +901,7 @@ comments: true
// 出队
pub fn pop(self: *Self) T {
var num = self.peek();
// 删除头
// 删除头
self.front = self.front.?.next;
self.que_size -= 1;
return num;

View File

@@ -264,9 +264,9 @@ comments: true
### 基于链表的实现
使用「链表」实现栈时,将链表的头点看作栈顶,将尾点看作栈底。
使用「链表」实现栈时,将链表的头点看作栈顶,将尾点看作栈底。
对于入栈操作,将元素插入到链表头部即可,这种点添加方式被称为“头插法”。而对于出栈操作,则将头点从链表中删除即可。
对于入栈操作,将元素插入到链表头部即可,这种点添加方式被称为“头插法”。而对于出栈操作,则将头点从链表中删除即可。
=== "LinkedListStack"
![基于链表实现栈的入栈出栈操作](stack.assets/linkedlist_stack.png)
@@ -284,7 +284,7 @@ comments: true
```java title="linkedlist_stack.java"
/* 基于链表实现的栈 */
class LinkedListStack {
private ListNode stackPeek; // 将头点作为栈顶
private ListNode stackPeek; // 将头点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack() {
@@ -343,7 +343,7 @@ comments: true
/* 基于链表实现的栈 */
class LinkedListStack {
private:
ListNode* stackTop; // 将头点作为栈顶
ListNode* stackTop; // 将头点作为栈顶
int stkSize; // 栈的长度
public:
@@ -353,7 +353,7 @@ comments: true
}
~LinkedListStack() {
// 遍历链表删除点,释放内存
// 遍历链表删除点,释放内存
freeMemoryLinkedList(stackTop);
}
@@ -515,7 +515,7 @@ comments: true
```javascript title="linkedlist_stack.js"
/* 基于链表实现的栈 */
class LinkedListStack {
#stackPeek; // 将头点作为栈顶
#stackPeek; // 将头点作为栈顶
#stkSize = 0; // 栈的长度
constructor() {
@@ -573,7 +573,7 @@ comments: true
```typescript title="linkedlist_stack.ts"
/* 基于链表实现的栈 */
class LinkedListStack {
private stackPeek: ListNode | null; // 将头点作为栈顶
private stackPeek: ListNode | null; // 将头点作为栈顶
private stkSize: number = 0; // 栈的长度
constructor() {
@@ -638,7 +638,7 @@ comments: true
/* 基于链表实现的栈 */
class LinkedListStack
{
private ListNode? stackPeek; // 将头点作为栈顶
private ListNode? stackPeek; // 将头点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack()
@@ -710,7 +710,7 @@ comments: true
```swift title="linkedlist_stack.swift"
/* 基于链表实现的栈 */
class LinkedListStack {
private var _peek: ListNode? // 将头点作为栈顶
private var _peek: ListNode? // 将头点作为栈顶
private var _size = 0 // 栈的长度
init() {}
@@ -771,7 +771,7 @@ comments: true
return struct {
const Self = @This();
stack_top: ?*inc.ListNode(T) = null, // 将头点作为栈顶
stack_top: ?*inc.ListNode(T) = null, // 将头点作为栈顶
stk_size: usize = 0, // 栈的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -1311,7 +1311,7 @@ comments: true
在数组(列表)实现中,入栈与出栈操作都是在预先分配好的连续内存中操作,具有很好的缓存本地性,效率很好。然而,如果入栈时超出数组容量,则会触发扩容机制,那么该次入栈操作的时间复杂度为 $O(n)$ 。
在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时变慢的问题。然而,入栈操作需要初始化点对象并修改指针,因而效率不如数组。进一步地思考,如果入栈元素不是 `int` 而是点对象,那么就可以省去初始化步骤,从而提升效率。
在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时变慢的问题。然而,入栈操作需要初始化点对象并修改指针,因而效率不如数组。进一步地思考,如果入栈元素不是 `int` 而是点对象,那么就可以省去初始化步骤,从而提升效率。
综上所述,当入栈与出栈操作的元素是基本数据类型(例如 `int` , `double` )时,则结论如下:
@@ -1322,7 +1322,7 @@ comments: true
在初始化列表时,系统会给列表分配“初始容量”,该容量可能超过我们的需求。并且扩容机制一般是按照特定倍率(比如 2 倍)进行扩容,扩容后的容量也可能超出我们的需求。因此,**数组实现栈会造成一定的空间浪费**。
当然,由于点需要额外存储指针,因此 **链表点比数组元素占用更大**
当然,由于点需要额外存储指针,因此 **链表点比数组元素占用更大**
综上,我们不能简单地确定哪种实现更加省内存,需要 case-by-case 地分析。

View File

@@ -6,6 +6,6 @@ comments: true
- 栈是一种遵循先入后出的数据结构,可以使用数组或链表实现。
- 在时间效率方面,栈的数组实现具有更好的平均效率,但扩容时会导致单次入栈操作的时间复杂度劣化至 $O(n)$ 。相对地,栈的链表实现具有更加稳定的效率表现。
- 在空间效率方面,栈的数组实现会造成一定空间浪费,然而链表点比数组元素占用内存更大。
- 在空间效率方面,栈的数组实现会造成一定空间浪费,然而链表点比数组元素占用内存更大。
- 队列是一种遵循先入先出的数据结构,可以使用数组或链表实现。对于两种实现的时间效率与空间效率对比,与上述栈的结论相同。
- 双向队列的两端都可以添加与删除元素。