mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-01 17:53:18 +08:00
build
This commit is contained in:
@@ -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. 双向队列应用
|
||||
|
||||
双向队列兼具栈与队列的逻辑,**因此它可以实现这两者的所有应用场景,同时提供更高的自由度**。
|
||||
|
||||
@@ -285,6 +285,12 @@ comments: true
|
||||
bool isEmpty = queue.isEmpty;
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="queue.rs"
|
||||
|
||||
```
|
||||
|
||||
## 5.2.2. 队列实现
|
||||
|
||||
为了实现队列,我们需要一种数据结构,可以在一端添加元素,并在另一端删除元素。因此,链表和数组都可以用来实现队列。
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
以上实现的队列仍然具有局限性,即其长度不可变。然而,这个问题不难解决,我们可以将数组替换为动态数组,从而引入扩容机制。有兴趣的同学可以尝试自行实现。
|
||||
|
||||
两种实现的对比结论与栈一致,在此不再赘述。
|
||||
|
||||
@@ -283,6 +283,12 @@ comments: true
|
||||
bool isEmpty = stack.isEmpty;
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="stack.rs"
|
||||
|
||||
```
|
||||
|
||||
## 5.1.2. 栈的实现
|
||||
|
||||
为了深入了解栈的运行机制,我们来尝试自己实现一个栈类。
|
||||
@@ -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. 两种实现对比
|
||||
|
||||
### 支持操作
|
||||
|
||||
Reference in New Issue
Block a user