mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-03 10:40:15 +08:00
build
This commit is contained in:
@@ -295,11 +295,11 @@ comments: true
|
||||
|
||||
### 基于双向链表的实现
|
||||
|
||||
回忆上节内容,由于可以方便地删除链表头结点(对应出队操作),以及在链表尾结点后添加新结点(对应入队操作),因此我们使用普通单向链表来实现队列。
|
||||
回忆上节内容,由于可以方便地删除链表头节点(对应出队操作),以及在链表尾节点后添加新节点(对应入队操作),因此我们使用普通单向链表来实现队列。
|
||||
|
||||
而双向队列的头部和尾部都可以执行入队与出队操作,换言之,双向队列的操作是“首尾对称”的,也需要实现另一个对称方向的操作。因此,双向队列需要使用「双向链表」来实现。
|
||||
|
||||
我们将双向链表的头结点和尾结点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除结点。
|
||||
我们将双向链表的头节点和尾节点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除节点。
|
||||
|
||||
=== "LinkedListDeque"
|
||||

|
||||
@@ -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;
|
||||
|
||||
@@ -264,7 +264,7 @@ comments: true
|
||||
|
||||
### 基于链表的实现
|
||||
|
||||
我们将链表的「头结点」和「尾结点」分别看作是队首和队尾,并规定队尾只可添加结点,队首只可删除结点。
|
||||
我们将链表的「头节点」和「尾节点」分别看作是队首和队尾,并规定队尾只可添加节点,队首只可删除节点。
|
||||
|
||||
=== "LinkedListQueue"
|
||||

|
||||
@@ -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;
|
||||
|
||||
@@ -264,9 +264,9 @@ comments: true
|
||||
|
||||
### 基于链表的实现
|
||||
|
||||
使用「链表」实现栈时,将链表的头结点看作栈顶,将尾结点看作栈底。
|
||||
使用「链表」实现栈时,将链表的头节点看作栈顶,将尾节点看作栈底。
|
||||
|
||||
对于入栈操作,将元素插入到链表头部即可,这种结点添加方式被称为“头插法”。而对于出栈操作,则将头结点从链表中删除即可。
|
||||
对于入栈操作,将元素插入到链表头部即可,这种节点添加方式被称为“头插法”。而对于出栈操作,则将头节点从链表中删除即可。
|
||||
|
||||
=== "LinkedListStack"
|
||||

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