From e7187b1639a4ef1980b5642b30333b09719cadf3 Mon Sep 17 00:00:00 2001 From: krahets Date: Thu, 2 Mar 2023 03:11:15 +0800 Subject: [PATCH] build --- chapter_stack_and_queue/deque.md | 249 ++++++++++++++++++++++++++++++- index.md | 8 +- 2 files changed, 245 insertions(+), 12 deletions(-) diff --git a/chapter_stack_and_queue/deque.md b/chapter_stack_and_queue/deque.md index 66c7a0310..dc746411b 100644 --- a/chapter_stack_and_queue/deque.md +++ b/chapter_stack_and_queue/deque.md @@ -337,7 +337,7 @@ comments: true /* 基于双向链表实现的双向队列 */ class LinkedListDeque { private ListNode front, rear; // 头结点 front ,尾结点 rear - private int size = 0; // 双向队列的长度 + private int queSize = 0; // 双向队列的长度 public LinkedListDeque() { front = rear = null; @@ -345,7 +345,7 @@ comments: true /* 获取双向队列的长度 */ public int size() { - return size; + return queSize; } /* 判断双向队列是否为空 */ @@ -372,7 +372,7 @@ comments: true node.prev = rear; rear = node; // 更新尾结点 } - size++; // 更新队列长度 + queSize++; // 更新队列长度 } /* 队首入队 */ @@ -412,7 +412,7 @@ comments: true } rear = rPrev; // 更新尾结点 } - size--; // 更新队列长度 + queSize--; // 更新队列长度 return val; } @@ -452,9 +452,139 @@ comments: true === "C++" ```cpp title="linkedlist_deque.cpp" - [class]{ListNode}-[func]{} + /* 双向链表结点 */ + struct DoubleListNode { + int val; // 结点值 + DoubleListNode *next; // 后继结点指针 + DoubleListNode *prev; // 前驱结点指针 + DoubleListNode(int val) : val(val), prev(nullptr), next(nullptr) {} + }; - [class]{LinkedListDeque}-[func]{} + /* 基于双向链表实现的双向队列 */ + class LinkedListDeque { + private: + DoubleListNode *front, *rear; // 头结点 front ,尾结点 rear + int queSize = 0; // 双向队列的长度 + + public: + /* 构造方法 */ + LinkedListDeque() : front(nullptr), rear(nullptr) {} + + /* 析构方法 */ + ~LinkedListDeque() { + // 释放内存 + DoubleListNode *pre, *cur = front; + while (cur != nullptr) { + pre = cur; + cur = cur->next; + delete pre; + } + } + + /* 获取双向队列的长度 */ + int size() { + return queSize; + } + + /* 判断双向队列是否为空 */ + bool isEmpty() { + return size() == 0; + } + + /* 入队操作 */ + void push(int num, bool isFront) { + DoubleListNode *node = new DoubleListNode(num); + // 若链表为空,则令 front, rear 都指向 node + if (isEmpty()) + front = rear = node; + // 队首入队操作 + else if (isFront) { + // 将 node 添加至链表头部 + front->prev = node; + node->next = front; + front = node; // 更新头结点 + // 队尾入队操作 + } else { + // 将 node 添加至链表尾部 + rear->next = node; + node->prev = rear; + rear = node; // 更新尾结点 + } + queSize++; // 更新队列长度 + } + + /* 队首入队 */ + void pushFirst(int num) { + push(num, true); + } + + /* 队尾入队 */ + void pushLast(int num) { + push(num, false); + } + + /* 出队操作 */ + int poll(bool isFront) { + // 若队列为空,直接返回 -1 + if (isEmpty()) + return -1; + int val; + // 队首出队操作 + if (isFront) { + val = front->val; // 暂存头结点值 + // 删除头结点 + DoubleListNode *fNext = front->next; + if (fNext != nullptr) { + fNext->prev = nullptr; + front->next = nullptr; + } + front = fNext; // 更新头结点 + // 队尾出队操作 + } else { + val = rear->val; // 暂存尾结点值 + // 删除尾结点 + DoubleListNode *rPrev = rear->prev; + if (rPrev != nullptr) { + rPrev->next = nullptr; + rear->prev = nullptr; + } + rear = rPrev; // 更新尾结点 + } + queSize--; // 更新队列长度 + return val; + } + + /* 队首出队 */ + int pollFirst() { + return poll(true); + } + + /* 队尾出队 */ + int pollLast() { + return poll(false); + } + + /* 访问队首元素 */ + int peekFirst() { + return isEmpty() ? -1 : front->val; + } + + /* 访问队尾元素 */ + int peekLast() { + return isEmpty() ? -1 : rear->val; + } + + /* 返回数组用于打印 */ + vector toVector() { + DoubleListNode *node = front; + vector res(size()); + for (int i = 0; i < res.size(); i++) { + res[i] = node->val; + node = node->next; + } + return res; + } + }; ``` === "Python" @@ -1352,7 +1482,112 @@ comments: true === "C++" ```cpp title="array_deque.cpp" - [class]{ArrayDeque}-[func]{} + /* 基于环形数组实现的双向队列 */ + class ArrayDeque { + private: + vector nums; // 用于存储双向队列元素的数组 + int front; // 队首指针,指向队首元素 + int queSize; // 双向队列长度 + + public: + /* 构造方法 */ + ArrayDeque(int capacity) { + nums.resize(capacity); + front = queSize = 0; + } + + /* 获取双向队列的容量 */ + int capacity() { + return nums.size(); + } + + /* 获取双向队列的长度 */ + int size() { + return queSize; + } + + /* 判断双向队列是否为空 */ + bool isEmpty() { + return queSize == 0; + } + + /* 计算环形数组索引 */ + int index(int i) { + // 通过取余操作实现数组首尾相连 + // 当 i 越过数组尾部后,回到头部 + // 当 i 越过数组头部后,回到尾部 + return (i + capacity()) % capacity(); + } + + /* 队首入队 */ + void pushFirst(int num) { + if (queSize == capacity()) { + cout << "双向队列已满" << endl; + return; + } + // 队首指针向左移动一位 + // 通过取余操作,实现 front 越过数组头部后回到尾部 + front = index(front - 1); + // 将 num 添加至队首 + nums[front] = num; + queSize++; + } + + /* 队尾入队 */ + void pushLast(int num) { + if (queSize == capacity()) { + cout << "双向队列已满" << endl; + return; + } + // 计算尾指针,指向队尾索引 + 1 + int rear = index(front + queSize); + // 将 num 添加至队尾 + nums[rear] = num; + queSize++; + } + + /* 队首出队 */ + int pollFirst() { + int num = peekFirst(); + // 队首指针向后移动一位 + front = index(front + 1); + queSize--; + return num; + } + + /* 队尾出队 */ + int pollLast() { + int num = peekLast(); + queSize--; + return num; + } + + /* 访问队首元素 */ + int peekFirst() { + if (isEmpty()) + throw out_of_range("双向队列为空"); + return nums[front]; + } + + /* 访问队尾元素 */ + int peekLast() { + if (isEmpty()) + throw out_of_range("双向队列为空"); + // 计算尾元素索引 + int last = index(front + queSize - 1); + return nums[last]; + } + + /* 返回数组用于打印 */ + vector toVector() { + // 仅转换有效长度范围内的列表元素 + vector res(queSize); + for (int i = 0, j = front; i < queSize; i++, j++) { + res[i] = nums[index(j)]; + } + return res; + } + }; ``` === "Python" diff --git a/index.md b/index.md index 1a8900ba1..cbaa025e5 100644 --- a/index.md +++ b/index.md @@ -58,13 +58,11 @@ hide:

-近两年来,我在力扣上分享了一些题解和算法文章,回复了许多读者的评论问题,遇到最多的一类问题则是“如何入门学习算法”。我逐渐也对这个问题好奇了起来。 +两年前,我在力扣上分享了《剑指 Offer》系列题解,受到了很多小伙伴的喜爱与支持。在此期间,我也回复了许多读者的评论问题,遇到最多的问题是“如何入门学习算法”。我渐渐也对这个问题好奇了起来。 -两眼一抹黑地刷题应该是最受欢迎的方式。刷题就如同玩“扫雷”游戏一样,基础好的同学可以顺利地将地雷逐个排掉,而基础不足的同学很可能被炸的满头是包,并在受挫中渐渐退缩。通读教材书籍也是常用方法,但对于面向求职的同学来说,毕业季、投递简历、应付笔面试已经占用大部分精力,厚重的书本也因此成为巨大的挑战。 +两眼一抹黑地刷题应该是最受欢迎的方式,简单粗暴且有效。然而,刷题就如同玩“扫雷”游戏,自学能力强的同学能够顺利地将地雷逐个排掉,而基础不足的同学很可能被炸的满头是包,并在受挫中步步退缩。通读教材书籍也是常用方法,但对于面向求职的同学来说,毕业季、投递简历、应付笔面试已经占用大部分精力,厚重的书本也因此成为巨大的挑战。 -如果你也有上述烦恼,那么很幸运这本书找到了你。本书是我对于该问题给出的答案,虽然不一定正确,但至少代表一次积极的尝试。这本书虽然不足以让你直接拿到 Offer ,但会引导你探索数据结构与算法的“知识地图”,带你了解不同“地雷”的形状大小和分布位置,让你掌握各种“排雷方法”。有了这些本领,相信你可以更加得心应手地开展算法学习,逐步搭建起完整的知识体系。 - -本书提供可一键运行的源代码,已被翻译至十余种编程语言,托管在 [github.com/krahets/hello-algo](https://github.com/krahets/hello-algo) 仓库。发行版 PDF 的更新周期较长,想看最新内容的小伙伴可以前往 [www.hello-algo.com](https://www.hello-algo.com/) 网页版。 +如果你也有上述烦恼,那么很幸运这本书找到了你。本书是我对于该问题给出的答案,虽然不一定正确,但至少代表一次积极的尝试。这本书虽然不足以让你直接拿到 Offer ,但会引导你探索数据结构与算法的“知识地图”,带你了解不同“地雷”的形状大小和分布位置,让你掌握各种“排雷方法”。有了这些本领,相信你可以更加得心应手地刷题与阅读文献,逐步搭建起完整的知识体系。

作者简介