This commit is contained in:
krahets
2023-07-26 10:57:40 +08:00
parent 6381f16506
commit f8f7086196
52 changed files with 4032 additions and 0 deletions

View File

@@ -318,6 +318,12 @@ comments: true
bool isEmpty = deque.isEmpty;W
```
=== "Rust"
```rust title="deque.rs"
```
## 5.3.2.   双向队列实现 *
双向队列的实现与队列类似,可以选择链表或数组作为底层数据结构。
@@ -1795,6 +1801,174 @@ comments: true
}
```
=== "Rust"
```rust title="linkedlist_deque.rs"
/* 双向链表节点 */
pub struct ListNode<T> {
pub val: T, // 节点值
pub next: Option<Rc<RefCell<ListNode<T>>>>, // 后继节点引用(指针)
pub prev: Option<Rc<RefCell<ListNode<T>>>>, // 前驱节点引用(指针)
}
impl<T> ListNode<T> {
pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {
Rc::new(RefCell::new(ListNode {
val,
next: None,
prev: None,
}))
}
}
/* 基于双向链表实现的双向队列 */
#[allow(dead_code)]
pub struct LinkedListDeque<T> {
front: Option<Rc<RefCell<ListNode<T>>>>, // 头节点 front
rear: Option<Rc<RefCell<ListNode<T>>>>, // 尾节点 rear
que_size: usize, // 双向队列的长度
}
impl<T: Copy> LinkedListDeque<T> {
pub fn new() -> Self {
Self {
front: None,
rear: None,
que_size: 0,
}
}
/* 获取双向队列的长度 */
pub fn size(&self) -> usize {
return self.que_size;
}
/* 判断双向队列是否为空 */
pub fn is_empty(&self) -> bool {
return self.size() == 0;
}
/* 入队操作 */
pub fn push(&mut self, num: T, is_front: bool) {
let node = ListNode::new(num);
// 队首入队操作
if is_front {
match self.front.take() {
// 若链表为空,则令 front, rear 都指向 node
None => {
self.rear = Some(node.clone());
self.front = Some(node);
}
// 将 node 添加至链表头部
Some(old_front) => {
old_front.borrow_mut().prev = Some(node.clone());
node.borrow_mut().next = Some(old_front);
self.front = Some(node); // 更新头节点
}
}
}
// 队尾入队操作
else {
match self.rear.take() {
// 若链表为空,则令 front, rear 都指向 node
None => {
self.front = Some(node.clone());
self.rear = Some(node);
}
// 将 node 添加至链表尾部
Some(old_rear) => {
old_rear.borrow_mut().next = Some(node.clone());
node.borrow_mut().prev = Some(old_rear);
self.rear = Some(node); // 更新尾节点
}
}
}
self.que_size += 1; // 更新队列长度
}
/* 队首入队 */
pub fn push_first(&mut self, num: T) {
self.push(num, true);
}
/* 队尾入队 */
pub fn push_last(&mut self, num: T) {
self.push(num, false);
}
/* 出队操作 */
pub fn pop(&mut self, is_front: bool) -> Option<T> {
// 若队列为空,直接返回 None
if self.is_empty() {
return None
};
// 队首出队操作
if is_front {
self.front.take().map(|old_front| {
match old_front.borrow_mut().next.take() {
Some(new_front) => {
new_front.borrow_mut().prev.take();
self.front = Some(new_front); // 更新头节点
}
None => {
self.rear.take();
}
}
self.que_size -= 1; // 更新队列长度
Rc::try_unwrap(old_front).ok().unwrap().into_inner().val
})
}
// 队尾出队操作
else {
self.rear.take().map(|old_rear| {
match old_rear.borrow_mut().prev.take() {
Some(new_rear) => {
new_rear.borrow_mut().next.take();
self.rear = Some(new_rear); // 更新尾节点
}
None => {
self.front.take();
}
}
self.que_size -= 1; // 更新队列长度
Rc::try_unwrap(old_rear).ok().unwrap().into_inner().val
})
}
}
/* 队首出队 */
pub fn pop_first(&mut self) -> Option<T> {
return self.pop(true);
}
/* 队尾出队 */
pub fn pop_last(&mut self) -> Option<T> {
return self.pop(false);
}
/* 访问队首元素 */
pub fn peek_first(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.front.as_ref()
}
/* 访问队尾元素 */
pub fn peek_last(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.rear.as_ref()
}
/* 返回数组用于打印 */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = self.to_array(node.borrow().next.as_ref());
nums.insert(0, node.borrow().val);
return nums;
}
return Vec::new();
}
}
```
### 基于数组的实现
与基于数组实现队列类似,我们也可以使用环形数组来实现双向队列。在队列的实现基础上,仅需增加“队首入队”和“队尾出队”的方法。
@@ -2914,6 +3088,120 @@ comments: true
}
```
=== "Rust"
```rust title="array_deque.rs"
/* 基于环形数组实现的双向队列 */
struct ArrayDeque {
nums: Vec<i32>, // 用于存储双向队列元素的数组
front: usize, // 队首指针,指向队首元素
que_size: usize, // 双向队列长度
}
impl ArrayDeque {
/* 构造方法 */
pub fn new(capacity: usize) -> Self {
Self {
nums: vec![0; capacity],
front: 0,
que_size: 0,
}
}
/* 获取双向队列的容量 */
pub fn capacity(&self) -> usize {
self.nums.len()
}
/* 获取双向队列的长度 */
pub fn size(&self) -> usize {
self.que_size
}
/* 判断双向队列是否为空 */
pub fn is_empty(&self) -> bool {
self.que_size == 0
}
/* 计算环形数组索引 */
fn index(&self, i: i32) -> usize {
// 通过取余操作实现数组首尾相连
// 当 i 越过数组尾部后,回到头部
// 当 i 越过数组头部后,回到尾部
return ((i + self.capacity() as i32) % self.capacity() as i32) as usize;
}
/* 队首入队 */
pub fn push_first(&mut self, num: i32) {
if self.que_size == self.capacity() {
println!("双向队列已满");
return
}
// 队首指针向左移动一位
// 通过取余操作,实现 front 越过数组头部后回到尾部
self.front = self.index(self.front as i32 - 1);
// 将 num 添加至队首
self.nums[self.front] = num;
self.que_size += 1;
}
/* 队尾入队 */
pub fn push_last(&mut self, num: i32) {
if self.que_size == self.capacity() {
println!("双向队列已满");
return
}
// 计算尾指针,指向队尾索引 + 1
let rear = self.index(self.front as i32 + self.que_size as i32);
// 将 num 添加至队尾
self.nums[rear] = num;
self.que_size += 1;
}
/* 队首出队 */
fn pop_first(&mut self) -> i32 {
let num = self.peek_first();
// 队首指针向后移动一位
self.front = self.index(self.front as i32 + 1);
self.que_size -= 1;
num
}
/* 队尾出队 */
fn pop_last(&mut self) -> i32 {
let num = self.peek_last();
self.que_size -= 1;
num
}
/* 访问队首元素 */
fn peek_first(&self) -> i32 {
if self.is_empty() { panic!("双向队列为空") };
self.nums[self.front]
}
/* 访问队尾元素 */
fn peek_last(&self) -> i32 {
if self.is_empty() { panic!("双向队列为空") };
// 计算尾元素索引
let last = self.index(self.front as i32 + self.que_size as i32 - 1);
self.nums[last]
}
/* 返回数组用于打印 */
fn to_array(&self) -> Vec<i32> {
// 仅转换有效长度范围内的列表元素
let mut res = vec![0; self.que_size];
let mut j = self.front;
for i in 0..self.que_size {
res[i] = self.nums[self.index(j as i32)];
j += 1;
}
res
}
}
```
## 5.3.3. &nbsp; 双向队列应用
双向队列兼具栈与队列的逻辑,**因此它可以实现这两者的所有应用场景,同时提供更高的自由度**。

View File

@@ -285,6 +285,12 @@ comments: true
bool isEmpty = queue.isEmpty;
```
=== "Rust"
```rust title="queue.rs"
```
## 5.2.2. &nbsp; 队列实现
为了实现队列,我们需要一种数据结构,可以在一端添加元素,并在另一端删除元素。因此,链表和数组都可以用来实现队列。
@@ -1090,6 +1096,88 @@ comments: true
}
```
=== "Rust"
```rust title="linkedlist_queue.rs"
/* 基于链表实现的队列 */
#[allow(dead_code)]
pub struct LinkedListQueue<T> {
front: Option<Rc<RefCell<ListNode<T>>>>, // 头节点 front
rear: Option<Rc<RefCell<ListNode<T>>>>, // 尾节点 rear
que_size: usize, // 队列的长度
}
impl<T: Copy> LinkedListQueue<T> {
pub fn new() -> Self {
Self {
front: None,
rear: None,
que_size: 0,
}
}
/* 获取队列的长度 */
pub fn size(&self) -> usize {
return self.que_size;
}
/* 判断队列是否为空 */
pub fn is_empty(&self) -> bool {
return self.size() == 0;
}
/* 入队 */
pub fn push(&mut self, num: T) {
// 尾节点后添加 num
let new_rear = ListNode::new(num);
match self.rear.take() {
// 如果队列不为空,则将该节点添加到尾节点后
Some(old_rear) => {
old_rear.borrow_mut().next = Some(new_rear.clone());
self.rear = Some(new_rear);
}
// 如果队列为空,则令头、尾节点都指向该节点
None => {
self.front = Some(new_rear.clone());
self.rear = Some(new_rear);
}
}
self.que_size += 1;
}
/* 出队 */
pub fn pop(&mut self) -> Option<T> {
self.front.take().map(|old_front| {
match old_front.borrow_mut().next.take() {
Some(new_front) => {
self.front = Some(new_front);
}
None => {
self.rear.take();
}
}
self.que_size -= 1;
Rc::try_unwrap(old_front).ok().unwrap().into_inner().val
})
}
/* 访问队首元素 */
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.front.as_ref()
}
/* 将链表转化为 Array 并返回 */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = self.to_array(node.borrow().next.as_ref());
nums.insert(0, node.borrow().val);
return nums;
}
return Vec::new();
}
}
```
### 基于数组的实现
由于数组删除首元素的时间复杂度为 $O(n)$ ,这会导致出队操作效率较低。然而,我们可以采用以下巧妙方法来避免这个问题。
@@ -1927,6 +2015,88 @@ comments: true
}
```
=== "Rust"
```rust title="array_queue.rs"
/* 基于环形数组实现的队列 */
struct ArrayQueue {
nums: Vec<i32>, // 用于存储队列元素的数组
front: i32, // 队首指针,指向队首元素
que_size: i32, // 队列长度
que_capacity: i32, // 队列容量
}
impl ArrayQueue {
/* 构造方法 */
fn new(capacity: i32) -> ArrayQueue {
ArrayQueue {
nums: vec![0; capacity as usize],
front: 0,
que_size: 0,
que_capacity: capacity,
}
}
/* 获取队列的容量 */
fn capacity(&self) -> i32 {
self.que_capacity
}
/* 获取队列的长度 */
fn size(&self) -> i32 {
self.que_size
}
/* 判断队列是否为空 */
fn is_empty(&self) -> bool {
self.que_size == 0
}
/* 入队 */
fn push(&mut self, num: i32) {
if self.que_size == self.capacity() {
println!("队列已满");
return;
}
// 计算尾指针,指向队尾索引 + 1
// 通过取余操作,实现 rear 越过数组尾部后回到头部
let rear = (self.front + self.que_size) % self.que_capacity;
// 将 num 添加至队尾
self.nums[rear as usize] = num;
self.que_size += 1;
}
/* 出队 */
fn pop(&mut self) -> i32 {
let num = self.peek();
// 队首指针向后移动一位,若越过尾部则返回到数组头部
self.front = (self.front + 1) % self.que_capacity;
self.que_size -= 1;
num
}
/* 访问队首元素 */
fn peek(&self) -> i32 {
if self.is_empty() {
panic!("index out of bounds");
}
self.nums[self.front as usize]
}
/* 返回数组 */
fn to_vector(&self) -> Vec<i32> {
let cap = self.que_capacity;
let mut j = self.front;
let mut arr = vec![0; self.que_size as usize];
for i in 0..self.que_size {
arr[i as usize] = self.nums[(j % cap) as usize];
j += 1;
}
arr
}
}
```
以上实现的队列仍然具有局限性,即其长度不可变。然而,这个问题不难解决,我们可以将数组替换为动态数组,从而引入扩容机制。有兴趣的同学可以尝试自行实现。
两种实现的对比结论与栈一致,在此不再赘述。

View File

@@ -283,6 +283,12 @@ comments: true
bool isEmpty = stack.isEmpty;
```
=== "Rust"
```rust title="stack.rs"
```
## 5.1.2. &nbsp; 栈的实现
为了深入了解栈的运行机制,我们来尝试自己实现一个栈类。
@@ -989,6 +995,75 @@ comments: true
}
```
=== "Rust"
```rust title="linkedlist_stack.rs"
/* 基于链表实现的栈 */
#[allow(dead_code)]
pub struct LinkedListStack<T> {
stack_peek: Option<Rc<RefCell<ListNode<T>>>>, // 将头节点作为栈顶
stk_size: usize, // 栈的长度
}
impl<T: Copy> LinkedListStack<T> {
pub fn new() -> Self {
Self {
stack_peek: None,
stk_size: 0,
}
}
/* 获取栈的长度 */
pub fn size(&self) -> usize {
return self.stk_size;
}
/* 判断栈是否为空 */
pub fn is_empty(&self) -> bool {
return self.size() == 0;
}
/* 入栈 */
pub fn push(&mut self, num: T) {
let node = ListNode::new(num);
node.borrow_mut().next = self.stack_peek.take();
self.stack_peek = Some(node);
self.stk_size += 1;
}
/* 出栈 */
pub fn pop(&mut self) -> Option<T> {
self.stack_peek.take().map(|old_head| {
match old_head.borrow_mut().next.take() {
Some(new_head) => {
self.stack_peek = Some(new_head);
}
None => {
self.stack_peek = None;
}
}
self.stk_size -= 1;
Rc::try_unwrap(old_head).ok().unwrap().into_inner().val
})
}
/* 访问栈顶元素 */
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.stack_peek.as_ref()
}
/* 将 List 转化为 Array 并返回 */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = self.to_array(node.borrow().next.as_ref());
nums.push(node.borrow().val);
return nums;
}
return Vec::new();
}
}
```
### 基于数组的实现
在基于「数组」实现栈时,我们可以将数组的尾部作为栈顶。在这样的设计下,入栈与出栈操作就分别对应在数组尾部添加元素与删除元素,时间复杂度都为 $O(1)$ 。
@@ -1542,6 +1617,56 @@ comments: true
}
```
=== "Rust"
```rust title="array_stack.rs"
/* 基于数组实现的栈 */
struct ArrayStack<T> {
stack: Vec<T>,
}
impl<T> ArrayStack<T> {
/* 初始化栈 */
fn new() -> ArrayStack<T> {
ArrayStack::<T> { stack: Vec::<T>::new() }
}
/* 获取栈的长度 */
fn size(&self) -> usize {
self.stack.len()
}
/* 判断栈是否为空 */
fn is_empty(&self) -> bool {
self.size() == 0
}
/* 入栈 */
fn push(&mut self, num: T) {
self.stack.push(num);
}
/* 出栈 */
fn pop(&mut self) -> Option<T> {
match self.stack.pop() {
Some(num) => Some(num),
None => None,
}
}
/* 访问栈顶元素 */
fn peek(&self) -> Option<&T> {
if self.is_empty() { panic!("栈为空") };
self.stack.last()
}
/* 返回 &Vec */
fn to_array(&self) -> &Vec<T> {
&self.stack
}
}
```
## 5.1.3. &nbsp; 两种实现对比
### 支持操作