From 5eae7080353ddac6c56f10354d78b4ba5af1057a Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Wed, 1 Feb 2023 03:23:29 +0800 Subject: [PATCH] Fix array queue. --- codes/c/.gitignore | 8 + codes/c/chapter_stack_and_queue/array_queue.c | 46 +-- .../chapter_stack_and_queue/array_queue.cpp | 38 +- .../chapter_stack_and_queue/array_queue.cs | 33 +- .../go/chapter_stack_and_queue/array_queue.go | 61 ++-- .../go/chapter_stack_and_queue/queue_test.go | 8 + .../chapter_stack_and_queue/array_queue.java | 33 +- .../chapter_stack_and_queue/array_queue.js | 46 ++- codes/javascript/include/PrintUtil.js | 12 +- .../chapter_stack_and_queue/array_queue.py | 36 +- .../chapter_stack_and_queue/array_queue.swift | 33 +- .../chapter_stack_and_queue/array_queue.ts | 51 ++- codes/typescript/module/PrintUtil.ts | 20 +- .../chapter_stack_and_queue/array_queue.zig | 20 +- docs/chapter_stack_and_queue/queue.md | 345 ++++++++++-------- 15 files changed, 425 insertions(+), 365 deletions(-) create mode 100644 codes/c/.gitignore diff --git a/codes/c/.gitignore b/codes/c/.gitignore new file mode 100644 index 00000000..08b67f32 --- /dev/null +++ b/codes/c/.gitignore @@ -0,0 +1,8 @@ +# Ignore all +* +# Unignore all with extensions +!*.* +# Unignore all dirs +!*/ + +*.dSYM/ \ No newline at end of file diff --git a/codes/c/chapter_stack_and_queue/array_queue.c b/codes/c/chapter_stack_and_queue/array_queue.c index 7783e49b..74d45c84 100644 --- a/codes/c/chapter_stack_and_queue/array_queue.c +++ b/codes/c/chapter_stack_and_queue/array_queue.c @@ -8,10 +8,10 @@ /* 基于环形数组形成的队列 */ struct ArrayQueue { - int *nums; // 用于存储队列元素的数组 - int cap; // 队列容量 - int front; // 头指针,指向队首 - int rear; // 尾指针,指向队尾 + 1 + int *nums; // 用于存储队列元素的数组 + int front; // 队首指针,指向队首元素 + int queSize; // 尾指针,指向队尾 + 1 + int queCapacity; // 队列容量 }; typedef struct ArrayQueue ArrayQueue; @@ -20,33 +20,31 @@ typedef struct ArrayQueue ArrayQueue; ArrayQueue *newArrayQueue(int capacity) { ArrayQueue *queue = (ArrayQueue *) malloc(sizeof(ArrayQueue)); // 初始化数组 - queue->cap = capacity; - queue->nums = (int *) malloc(sizeof(int) * queue->cap); - queue->front = 0; - queue->rear = 0; + queue->queCapacity = capacity; + queue->nums = (int *) malloc(sizeof(int) * queue->queCapacity); + queue->front = queue->queSize = 0; return queue; } /* 析构函数 */ void delArrayQueue(ArrayQueue *queue) { free(queue->nums); - queue->cap = 0; + queue->queCapacity = 0; } /* 获取队列的容量 */ int capacity(ArrayQueue *queue) { - return queue->cap; + return queue->queCapacity; } /* 获取队列的长度 */ int size(ArrayQueue *queue) { - // 由于将数组看作环形队列,可能 rear < front,因此需要取余数 - return (capacity(queue) + queue->rear - queue->front) % capacity(queue); + return queue->queSize; } /* 判断队列是否为空 */ bool empty(ArrayQueue *queue) { - return queue->rear - queue->front == 0; + return queue->queSize == 0; } /* 访问队首元素 */ @@ -61,26 +59,30 @@ void offer(ArrayQueue *queue, int num) { printf("队列已满\r\n"); return; } - queue->nums[queue->rear] = num; - queue->rear = (queue->rear + 1) % capacity(queue); + // 计算队尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (queue->front + queue->queSize) % queue->queCapacity; + // 尾结点后添加 num + queue->nums[rear] = num; + queue->queSize++; } /* 出队 */ void poll(ArrayQueue *queue) { int num = peek(queue); - queue->front = (queue->front + 1) % capacity(queue); + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + queue->front = (queue->front + 1) % queue->queCapacity; + queue->queSize--; } /* 打印基于环形数组形成的队列 */ void printArrayQueue(ArrayQueue *queue) { - int siz = size(queue); - int cap = capacity(queue); - int arr[siz]; + int arr[queue->queSize]; // 拷贝 - for (int i = 0, j = queue->front; i < siz; i++, j++) { - arr[i] = queue->nums[j % cap]; + for (int i = 0, j = queue->front; i < queue->queSize; i++, j++) { + arr[i] = queue->nums[j % queue->queCapacity]; } - printArray(arr, siz); + printArray(arr, queue->queSize); } diff --git a/codes/cpp/chapter_stack_and_queue/array_queue.cpp b/codes/cpp/chapter_stack_and_queue/array_queue.cpp index 56b086e7..1090905e 100644 --- a/codes/cpp/chapter_stack_and_queue/array_queue.cpp +++ b/codes/cpp/chapter_stack_and_queue/array_queue.cpp @@ -9,16 +9,17 @@ /* 基于环形数组实现的队列 */ class ArrayQueue { private: - int *nums; // 用于存储队列元素的数组 - int cap; // 队列容量 - int front = 0; // 头指针,指向队首 - int rear = 0; // 尾指针,指向队尾 + 1 + int *nums; // 用于存储队列元素的数组 + int front; // 队首指针,指向队首元素 + int queSize; // 队列长度 + int queCapacity; // 队列容量 public: ArrayQueue(int capacity) { // 初始化数组 - cap = capacity; nums = new int[capacity]; + queCapacity = capacity; + front = queSize = 0; } ~ArrayQueue() { @@ -27,37 +28,39 @@ public: /* 获取队列的容量 */ int capacity() { - return cap; + return queCapacity; } /* 获取队列的长度 */ int size() { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity() + rear - front) % capacity(); + return queSize; } /* 判断队列是否为空 */ bool empty() { - return rear - front == 0; + return size() == 0; } /* 入队 */ void offer(int num) { - if (size() == capacity()) { + if (queSize == queCapacity) { cout << "队列已满" << endl; return; } + // 计算队尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % queCapacity; // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } /* 出队 */ void poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity(); + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + front = (front + 1) % queCapacity; + queSize--; } /* 访问队首元素 */ @@ -69,11 +72,10 @@ public: /* 将数组转化为 Vector 并返回 */ vector toVector() { - int siz = size(); - int cap = capacity(); + int cap = queCapacity; // 仅转换有效长度范围内的列表元素 - vector arr(siz); - for (int i = 0, j = front; i < siz; i++, j++) { + vector arr(queSize); + for (int i = 0, j = front; i < queSize; i++, j++) { arr[i] = nums[j % cap]; } return arr; diff --git a/codes/csharp/chapter_stack_and_queue/array_queue.cs b/codes/csharp/chapter_stack_and_queue/array_queue.cs index 81085a36..9491b0ef 100644 --- a/codes/csharp/chapter_stack_and_queue/array_queue.cs +++ b/codes/csharp/chapter_stack_and_queue/array_queue.cs @@ -12,14 +12,14 @@ namespace hello_algo.chapter_stack_and_queue /* 基于环形数组实现的队列 */ class ArrayQueue { - private int[] nums; // 用于存储队列元素的数组 - private int front = 0; // 头指针,指向队首 - private int rear = 0; // 尾指针,指向队尾 + 1 + private int[] nums; // 用于存储队列元素的数组 + private int front; // 队首指针,指向队首元素 + private int queSize; // 队列长度 public ArrayQueue(int capacity) { - // 初始化数组 nums = new int[capacity]; + front = queSize = 0; } /* 获取队列的容量 */ @@ -31,37 +31,38 @@ namespace hello_algo.chapter_stack_and_queue /* 获取队列的长度 */ public int size() { - int capacity = this.capacity(); - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity; + return queSize; } /* 判断队列是否为空 */ public bool isEmpty() { - return rear - front == 0; + return queSize == 0; } /* 入队 */ public void offer(int num) { - if (size() == capacity()) + if (queSize == capacity()) { Console.WriteLine("队列已满"); return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } /* 出队 */ public int poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 front = (front + 1) % capacity(); + queSize--; return num; } @@ -76,13 +77,11 @@ namespace hello_algo.chapter_stack_and_queue /* 返回数组 */ public int[] toArray() { - int size = this.size(); - int capacity = this.capacity(); // 仅转换有效长度范围内的列表元素 - int[] res = new int[size]; - for (int i = 0, j = front; i < size; i++, j++) + int[] res = new int[queSize]; + for (int i = 0, j = front; i < queSize; i++, j++) { - res[i] = nums[j % capacity]; + res[i] = nums[j % this.capacity()]; } return res; } diff --git a/codes/go/chapter_stack_and_queue/array_queue.go b/codes/go/chapter_stack_and_queue/array_queue.go index 7d0367df..95970bc7 100644 --- a/codes/go/chapter_stack_and_queue/array_queue.go +++ b/codes/go/chapter_stack_and_queue/array_queue.go @@ -6,54 +6,53 @@ package chapter_stack_and_queue /* 基于环形数组实现的队列 */ type arrayQueue struct { - data []int // 用于存储队列元素的数组 - capacity int // 队列容量(即最多容量的元素个数) - front int // 头指针,指向队首 - rear int // 尾指针,指向队尾 + 1 + nums []int // 用于存储队列元素的数组 + front int // 队首指针,指向队首元素 + queSize int // 队列长度 + queCapacity int // 队列容量(即最大容纳元素数量) } // newArrayQueue 基于环形数组实现的队列 -func newArrayQueue(capacity int) *arrayQueue { +func newArrayQueue(queCapacity int) *arrayQueue { return &arrayQueue{ - data: make([]int, capacity), - capacity: capacity, - front: 0, - rear: 0, + nums: make([]int, queCapacity), + queCapacity: queCapacity, + front: 0, + queSize: 0, } } // size 获取队列的长度 func (q *arrayQueue) size() int { - size := (q.capacity + q.rear - q.front) % q.capacity - return size + return q.queSize } // isEmpty 判断队列是否为空 func (q *arrayQueue) isEmpty() bool { - return q.rear-q.front == 0 + return q.queSize == 0 } // offer 入队 -func (q *arrayQueue) offer(v int) { - // 当 rear == capacity 表示队列已满 - if q.size() == q.capacity { +func (q *arrayQueue) offer(num int) { + // 当 rear == queCapacity 表示队列已满 + if q.queSize == q.queCapacity { return } - // 尾结点后添加 - q.data[q.rear] = v - // 尾指针向后移动一位,越过尾部后返回到数组头部 - q.rear = (q.rear + 1) % q.capacity + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + rear := (q.front + q.queSize) % q.queCapacity + // 尾结点后添加 num + q.nums[rear] = num + q.queSize++ } // poll 出队 func (q *arrayQueue) poll() any { - if q.isEmpty() { - return nil - } - v := q.data[q.front] - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - q.front = (q.front + 1) % q.capacity - return v + num := q.peek() + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + q.front = (q.front + 1) % q.queCapacity + q.queSize-- + return num } // peek 访问队首元素 @@ -61,11 +60,15 @@ func (q *arrayQueue) peek() any { if q.isEmpty() { return nil } - v := q.data[q.front] - return v + return q.nums[q.front] } // 获取 Slice 用于打印 func (q *arrayQueue) toSlice() []int { - return q.data[q.front:q.rear] + rear := (q.front + q.queSize) + if rear >= q.queCapacity { + rear %= q.queCapacity + return append(q.nums[q.front:], q.nums[:rear]...) + } + return q.nums[q.front:rear] } diff --git a/codes/go/chapter_stack_and_queue/queue_test.go b/codes/go/chapter_stack_and_queue/queue_test.go index b9ec79df..0104cea0 100644 --- a/codes/go/chapter_stack_and_queue/queue_test.go +++ b/codes/go/chapter_stack_and_queue/queue_test.go @@ -75,6 +75,14 @@ func TestArrayQueue(t *testing.T) { // 判断是否为空 isEmpty := queue.isEmpty() fmt.Println("队是否为空 =", isEmpty) + + /* 测试环形数组 */ + for i := 0; i < 10; i++ { + queue.offer(i) + queue.poll() + fmt.Print("第", i, "轮入队 + 出队后 queue =") + PrintSlice(queue.toSlice()) + } } func TestLinkedListQueue(t *testing.T) { diff --git a/codes/java/chapter_stack_and_queue/array_queue.java b/codes/java/chapter_stack_and_queue/array_queue.java index 5a1ab645..030fb06b 100644 --- a/codes/java/chapter_stack_and_queue/array_queue.java +++ b/codes/java/chapter_stack_and_queue/array_queue.java @@ -10,13 +10,13 @@ import java.util.*; /* 基于环形数组实现的队列 */ class ArrayQueue { - private int[] nums; // 用于存储队列元素的数组 - private int front = 0; // 头指针,指向队首 - private int rear = 0; // 尾指针,指向队尾 + 1 + private int[] nums; // 用于存储队列元素的数组 + private int front; // 队首指针,指向队首元素 + private int queSize; // 队列长度 public ArrayQueue(int capacity) { - // 初始化数组 nums = new int[capacity]; + front = queSize = 0; } /* 获取队列的容量 */ @@ -26,33 +26,34 @@ class ArrayQueue { /* 获取队列的长度 */ public int size() { - int capacity = capacity(); - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity; + return queSize; } /* 判断队列是否为空 */ public boolean isEmpty() { - return rear - front == 0; + return queSize == 0; } /* 入队 */ public void offer(int num) { - if (size() == capacity()) { + if (queSize == capacity()) { System.out.println("队列已满"); return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } /* 出队 */ public int poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 front = (front + 1) % capacity(); + queSize--; return num; } @@ -65,12 +66,10 @@ class ArrayQueue { /* 返回数组 */ public int[] toArray() { - int size = size(); - int capacity = capacity(); // 仅转换有效长度范围内的列表元素 - int[] res = new int[size]; - for (int i = 0, j = front; i < size; i++, j++) { - res[i] = nums[j % capacity]; + int[] res = new int[queSize]; + for (int i = 0, j = front; i < queSize; i++, j++) { + res[i] = nums[j % capacity()]; } return res; } diff --git a/codes/javascript/chapter_stack_and_queue/array_queue.js b/codes/javascript/chapter_stack_and_queue/array_queue.js index abe0766d..6dd278c6 100644 --- a/codes/javascript/chapter_stack_and_queue/array_queue.js +++ b/codes/javascript/chapter_stack_and_queue/array_queue.js @@ -4,48 +4,49 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ - /* 基于环形数组实现的队列 */ class ArrayQueue { - #queue; // 用于存储队列元素的数组 - #front = 0; // 头指针,指向队首 - #rear = 0; // 尾指针,指向队尾 + 1 + #nums; // 用于存储队列元素的数组 + #front = 0; // 队首指针,指向队首元素 + #queSize = 0; // 队列长度 constructor(capacity) { - this.#queue = new Array(capacity); + this.#nums = new Array(capacity); } /* 获取队列的容量 */ get capacity() { - return this.#queue.length; + return this.#nums.length; } /* 获取队列的长度 */ get size() { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (this.capacity + this.#rear - this.#front) % this.capacity; + return this.#queSize; } /* 判断队列是否为空 */ empty() { - return this.#rear - this.#front == 0; + return this.#queSize == 0; } /* 入队 */ offer(num) { if (this.size == this.capacity) throw new Error("队列已满"); + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + const rear = (this.#front + this.size) % this.capacity; // 尾结点后添加 num - this.#queue[this.#rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - this.#rear = (this.#rear + 1) % this.capacity; + this.#nums[rear] = num; + this.#queSize++; } /* 出队 */ poll() { const num = this.peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 this.#front = (this.#front + 1) % this.capacity; + this.#queSize--; return num; } @@ -53,17 +54,15 @@ class ArrayQueue { peek() { if (this.empty()) throw new Error("队列为空"); - return this.#queue[this.#front]; + return this.#nums[this.#front]; } /* 返回 Array */ toArray() { - const siz = this.size; - const cap = this.capacity; // 仅转换有效长度范围内的列表元素 - const arr = new Array(siz); - for (let i = 0, j = this.#front; i < siz; i++, j++) { - arr[i] = this.#queue[j % cap]; + const arr = new Array(this.size); + for (let i = 0, j = this.#front; i < this.size; i++, j++) { + arr[i] = this.#nums[j % this.capacity]; } return arr; } @@ -81,8 +80,7 @@ queue.offer(3); queue.offer(2); queue.offer(5); queue.offer(4); -console.log("队列 queue = "); -console.log(queue.toArray()); +console.log("队列 queue =", queue.toArray()); /* 访问队首元素 */ const peek = queue.peek(); @@ -90,8 +88,7 @@ console.log("队首元素 peek = " + peek); /* 元素出队 */ const poll = queue.poll(); -console.log("出队元素 poll = " + poll + ",出队后 queue = "); -console.log(queue.toArray()); +console.log("出队元素 poll = " + poll + ",出队后 queue =", queue.toArray()); /* 获取队列的长度 */ const size = queue.size; @@ -105,6 +102,5 @@ console.log("队列是否为空 = " + empty); for (let i = 0; i < 10; i++) { queue.offer(i); queue.poll(); - console.log("第 " + i + " 轮入队 + 出队后 queue = "); - console.log(queue.toArray()); + console.log("第 " + i + " 轮入队 + 出队后 queue =", queue.toArray()); } diff --git a/codes/javascript/include/PrintUtil.js b/codes/javascript/include/PrintUtil.js index 3590f333..a9d500af 100644 --- a/codes/javascript/include/PrintUtil.js +++ b/codes/javascript/include/PrintUtil.js @@ -4,11 +4,6 @@ * Author: IsChristina (christinaxia77@foxmail.com) */ -function Trunk(prev, str) { - this.prev = prev; - this.str = str; -} - /** * Print a linked list * @param head @@ -22,6 +17,11 @@ function printLinkedList(head) { console.log(list.join(" -> ")); } +function Trunk(prev, str) { + this.prev = prev; + this.str = str; +} + /** * The interface of the tree printer * This tree printer is borrowed from TECHIE DELIGHT @@ -83,6 +83,6 @@ function showTrunks(p) { } module.exports = { - printTree, printLinkedList, + printTree } diff --git a/codes/python/chapter_stack_and_queue/array_queue.py b/codes/python/chapter_stack_and_queue/array_queue.py index 947c0609..2420c67a 100644 --- a/codes/python/chapter_stack_and_queue/array_queue.py +++ b/codes/python/chapter_stack_and_queue/array_queue.py @@ -14,8 +14,8 @@ from include import * class ArrayQueue: def __init__(self, size): self.__nums = [0] * size # 用于存储队列元素的数组 - self.__front = 0 # 头指针,指向队首 - self.__rear = 0 # 尾指针,指向队尾 + 1 + self.__front = 0 # 队首指针,指向队首元素 + self.__size = 0 # 队列长度 """ 获取队列的容量 """ def capacity(self): @@ -23,35 +23,33 @@ class ArrayQueue: """ 获取队列的长度 """ def size(self): - # 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (self.capacity() + self.__rear - self.__front) % self.capacity() + return self.__size """ 判断队列是否为空 """ def is_empty(self): - return (self.__rear - self.__front) == 0 + return self.__size == 0 """ 入队 """ - def push(self, val): - if self.size() == self.capacity(): - print("队列已满") - return False + def push(self, num): + assert self.__size < self.capacity(), "队列已满" + # 计算尾指针,指向队尾索引 + 1 + # 通过取余操作,实现 rear 越过数组尾部后回到头部 + rear = (self.__front + self.__size) % self.capacity() # 尾结点后添加 num - self.__nums[self.__rear] = val - # 尾指针向后移动一位,越过尾部后返回到数组头部 - self.__rear = (self.__rear + 1) % self.capacity() + self.__nums[rear] = num + self.__size += 1 """ 出队 """ def poll(self): num = self.peek() - # 队头指针向后移动一位,若越过尾部则返回到数组头部 + # 队首指针向后移动一位,若越过尾部则返回到数组头部 self.__front = (self.__front + 1) % self.capacity() + self.__size -= 1 return num """ 访问队首元素 """ def peek(self): - if self.is_empty(): - print("队列为空") - return False + assert not self.is_empty(), "队列为空" return self.__nums[self.__front] """ 返回列表用于打印 """ @@ -93,3 +91,9 @@ if __name__ == "__main__": """ 判断队列是否为空 """ is_empty = queue.is_empty() print("队列是否为空 =", is_empty) + + """ 测试环形数组 """ + for i in range(10): + queue.push(i); + queue.poll(); + print("第", i, "轮入队 + 出队后 queue = ", queue.to_list()); diff --git a/codes/swift/chapter_stack_and_queue/array_queue.swift b/codes/swift/chapter_stack_and_queue/array_queue.swift index d76dbc9c..654be369 100644 --- a/codes/swift/chapter_stack_and_queue/array_queue.swift +++ b/codes/swift/chapter_stack_and_queue/array_queue.swift @@ -7,8 +7,8 @@ /* 基于环形数组实现的队列 */ class ArrayQueue { private var nums: [Int] // 用于存储队列元素的数组 - private var front = 0 // 头指针,指向队首 - private var rear = 0 // 尾指针,指向队尾 + 1 + private var front = 0 // 队首指针,指向队首元素 + private var queSize = 0 // 队列长度 init(capacity: Int) { // 初始化数组 @@ -22,14 +22,12 @@ class ArrayQueue { /* 获取队列的长度 */ func size() -> Int { - let capacity = capacity() - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity + queSize } /* 判断队列是否为空 */ func isEmpty() -> Bool { - rear - front == 0 + queSize == 0 } /* 入队 */ @@ -38,19 +36,22 @@ class ArrayQueue { print("队列已满") return } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num - nums[rear] = num - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity() + nums[rear] = num; + queSize++; } /* 出队 */ @discardableResult func poll() -> Int { let num = peek() - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity() - return num + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + front = (front + 1) % capacity(); + queSize--; + return num; } /* 访问队首元素 */ @@ -63,12 +64,10 @@ class ArrayQueue { /* 返回数组 */ func toArray() -> [Int] { - let size = size() - let capacity = capacity() // 仅转换有效长度范围内的列表元素 - var res = Array(repeating: 0, count: size) - for (i, j) in sequence(first: (0, front), next: { $0 < size - 1 ? ($0 + 1, $1 + 1) : nil }) { - res[i] = nums[j % capacity] + var res = Array(repeating: 0, count: queSize) + for (i, j) in sequence(first: (0, front), next: { $0 < queSize - 1 ? ($0 + 1, $1 + 1) : nil }) { + res[i] = nums[j % capacity()] } return res } diff --git a/codes/typescript/chapter_stack_and_queue/array_queue.ts b/codes/typescript/chapter_stack_and_queue/array_queue.ts index 1f67c648..ff489225 100644 --- a/codes/typescript/chapter_stack_and_queue/array_queue.ts +++ b/codes/typescript/chapter_stack_and_queue/array_queue.ts @@ -4,49 +4,50 @@ * Author: S-N-O-R-L-A-X (snorlax.xu@outlook.com) */ - /* 基于环形数组实现的队列 */ class ArrayQueue { - private queue: number[]; // 用于存储队列元素的数组 - private front: number = 0; // 头指针,指向队首 - private rear: number = 0; // 尾指针,指向队尾 + 1 - private CAPACITY: number = 1e5; + private nums: number[]; // 用于存储队列元素的数组 + private front: number; // 队首指针,指向队首元素 + private queSize: number; // 队列长度 - constructor(capacity?: number) { - this.queue = new Array(capacity ?? this.CAPACITY); + constructor(capacity: number) { + this.nums = new Array(capacity); + this.front = this.queSize = 0; } /* 获取队列的容量 */ get capacity(): number { - return this.queue.length; + return this.nums.length; } /* 获取队列的长度 */ get size(): number { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (this.capacity + this.rear - this.front) % this.capacity; + return this.queSize; } /* 判断队列是否为空 */ empty(): boolean { - return this.rear - this.front == 0; + return this.queSize == 0; } /* 入队 */ offer(num: number): void { if (this.size == this.capacity) throw new Error("队列已满"); + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + const rear = (this.front + this.queSize) % this.capacity; // 尾结点后添加 num - this.queue[this.rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - this.rear = (this.rear + 1) % this.capacity; + this.nums[rear] = num; + this.queSize++; } /* 出队 */ poll(): number { const num = this.peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 this.front = (this.front + 1) % this.capacity; + this.queSize--; return num; } @@ -54,17 +55,15 @@ class ArrayQueue { peek(): number { if (this.empty()) throw new Error("队列为空"); - return this.queue[this.front]; + return this.nums[this.front]; } /* 返回 Array */ toArray(): number[] { - const siz = this.size; - const cap = this.capacity; // 仅转换有效长度范围内的列表元素 - const arr = new Array(siz); - for (let i = 0, j = this.front; i < siz; i++, j++) { - arr[i] = this.queue[j % cap]; + const arr = new Array(this.size); + for (let i = 0, j = this.front; i < this.size; i++, j++) { + arr[i] = this.nums[j % this.capacity]; } return arr; } @@ -80,8 +79,7 @@ queue.offer(3); queue.offer(2); queue.offer(5); queue.offer(4); -console.log("队列 queue = "); -console.log(queue.toArray()); +console.log("队列 queue =", queue.toArray()); /* 访问队首元素 */ const peek = queue.peek(); @@ -89,8 +87,7 @@ console.log("队首元素 peek = " + peek); /* 元素出队 */ const poll = queue.poll(); -console.log("出队元素 poll = " + poll + ",出队后 queue = "); -console.log(queue.toArray()); +console.log("出队元素 poll = " + poll + ",出队后 queue =", queue.toArray()); /* 获取队列的长度 */ const size = queue.size; @@ -104,8 +101,8 @@ console.log("队列是否为空 = " + empty); for (let i = 0; i < 10; i++) { queue.offer(i); queue.poll(); - console.log("第 " + i + " 轮入队 + 出队后 queue = "); + console.log("第 " + i + " 轮入队 + 出队后 queue =", queue.toArray()); console.log(queue.toArray()); } -export { }; \ No newline at end of file +export { }; diff --git a/codes/typescript/module/PrintUtil.ts b/codes/typescript/module/PrintUtil.ts index 59f1af0e..882e12fc 100644 --- a/codes/typescript/module/PrintUtil.ts +++ b/codes/typescript/module/PrintUtil.ts @@ -7,16 +7,6 @@ import ListNode from './ListNode'; import { TreeNode } from './TreeNode'; -class Trunk { - prev: Trunk | null; - str: string; - - constructor(prev: Trunk | null, str: string) { - this.prev = prev; - this.str = str; - } -} - /** * Print a linked list * @param head @@ -30,6 +20,16 @@ function printLinkedList(head: ListNode | null): void { console.log(list.join(' -> ')); } +class Trunk { + prev: Trunk | null; + str: string; + + constructor(prev: Trunk | null, str: string) { + this.prev = prev; + this.str = str; + } +} + /** * The interface of the tree printer * This tree printer is borrowed from TECHIE DELIGHT diff --git a/codes/zig/chapter_stack_and_queue/array_queue.zig b/codes/zig/chapter_stack_and_queue/array_queue.zig index f57eb2a3..8bb2778c 100644 --- a/codes/zig/chapter_stack_and_queue/array_queue.zig +++ b/codes/zig/chapter_stack_and_queue/array_queue.zig @@ -12,8 +12,8 @@ pub fn ArrayQueue(comptime T: type) type { nums: []T = undefined, // 用于存储队列元素的数组 cap: usize = 0, // 队列容量 - front: usize = 0, // 头指针,指向队首 - rear: usize = 0, // 尾指针,指向队尾 + 1 + front: usize = 0, // 队首指针,指向队首元素 + queSize: usize = 0, // 尾指针,指向队尾 + 1 mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // 内存分配器 @@ -41,13 +41,12 @@ pub fn ArrayQueue(comptime T: type) type { // 获取队列的长度 pub fn size(self: *Self) usize { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (self.capacity() + self.rear - self.front) % self.capacity(); + return self.queSize; } // 判断队列是否为空 pub fn isEmpty(self: *Self) bool { - return self.rear == self.front; + return self.queSize == 0; } // 入队 @@ -56,17 +55,20 @@ pub fn ArrayQueue(comptime T: type) type { std.debug.print("队列已满\n", .{}); return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + var rear = (self.front + self.queSize) % self.capacity(); // 尾结点后添加 num - self.nums[self.rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - self.rear = (self.rear + 1) % self.capacity(); + self.nums[rear] = num; + self.queSize++; } // 出队 pub fn poll(self: *Self) T { var num = self.peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 self.front = (self.front + 1) % self.capacity(); + self.queSize--; return num; } diff --git a/docs/chapter_stack_and_queue/queue.md b/docs/chapter_stack_and_queue/queue.md index 34b6c012..ee0d052b 100644 --- a/docs/chapter_stack_and_queue/queue.md +++ b/docs/chapter_stack_and_queue/queue.md @@ -741,46 +741,53 @@ comments: true ```java title="array_queue.java" /* 基于环形数组实现的队列 */ class ArrayQueue { - private int[] nums; // 用于存储队列元素的数组 - private int front = 0; // 头指针,指向队首 - private int rear = 0; // 尾指针,指向队尾 + 1 - + private int[] nums; // 用于存储队列元素的数组 + private int front; // 队首指针,指向队首元素 + private int queSize; // 队列长度 + public ArrayQueue(int capacity) { - // 初始化数组 nums = new int[capacity]; + front = queSize = 0; } + /* 获取队列的容量 */ public int capacity() { return nums.length; } + /* 获取队列的长度 */ public int size() { - int capacity = capacity(); - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity; + return queSize; } + /* 判断队列是否为空 */ public boolean isEmpty() { - return rear - front == 0; + return queSize == 0; } + /* 入队 */ public void offer(int num) { - if (size() == capacity()) { + if (queSize == capacity()) { System.out.println("队列已满"); return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } + /* 出队 */ public int poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 front = (front + 1) % capacity(); + queSize--; return num; } + /* 访问队首元素 */ public int peek() { if (isEmpty()) @@ -796,50 +803,60 @@ comments: true /* 基于环形数组实现的队列 */ class ArrayQueue { private: - int *nums; // 用于存储队列元素的数组 - int cap; // 队列容量 - int front = 0; // 头指针,指向队首 - int rear = 0; // 尾指针,指向队尾 + 1 - + int *nums; // 用于存储队列元素的数组 + int front; // 队首指针,指向队首元素 + int queSize; // 队列长度 + int queCapacity; // 队列容量 + public: ArrayQueue(int capacity) { // 初始化数组 - cap = capacity; nums = new int[capacity]; + queCapacity = capacity; + front = queSize = 0; } + ~ArrayQueue() { delete[] nums; } + /* 获取队列的容量 */ int capacity() { - return cap; + return queCapacity; } + /* 获取队列的长度 */ int size() { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity() + rear - front) % capacity(); + return queSize; } + /* 判断队列是否为空 */ bool empty() { - return rear - front == 0; + return size() == 0; } + /* 入队 */ void offer(int num) { - if (size() == capacity()) { + if (queSize == queCapacity) { cout << "队列已满" << endl; return; } + // 计算队尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % queCapacity; // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } + /* 出队 */ void poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity(); + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + front = (front + 1) % queCapacity; + queSize--; } + /* 访问队首元素 */ int peek() { if (empty()) @@ -856,54 +873,43 @@ comments: true class ArrayQueue: def __init__(self, size): self.__nums = [0] * size # 用于存储队列元素的数组 - self.__front = 0 # 头指针,指向队首 - self.__rear = 0 # 尾指针,指向队尾 + 1 - + self.__front = 0 # 队首指针,指向队首元素 + self.__size = 0 # 队列长度 + """ 获取队列的容量 """ def capacity(self): return len(self.__nums) - + """ 获取队列的长度 """ def size(self): - # 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (self.capacity() + self.__rear - self.__front) % self.capacity() - + return self.__size + """ 判断队列是否为空 """ def is_empty(self): - return (self.__rear - self.__front) == 0 - + return self.__size == 0 + """ 入队 """ - def push(self, val): - if self.size() == self.capacity(): - print("队列已满") - return False + def push(self, num): + assert self.__size < self.capacity(), "队列已满" + # 计算尾指针,指向队尾索引 + 1 + # 通过取余操作,实现 rear 越过数组尾部后回到头部 + rear = (self.__front + self.__size) % self.capacity() # 尾结点后添加 num - self.__nums[self.__rear] = val - # 尾指针向后移动一位,越过尾部后返回到数组头部 - self.__rear = (self.__rear + 1) % self.capacity() - + self.__nums[rear] = num + self.__size += 1 + """ 出队 """ def poll(self): num = self.peek() - # 队头指针向后移动一位,若越过尾部则返回到数组头部 + # 队首指针向后移动一位,若越过尾部则返回到数组头部 self.__front = (self.__front + 1) % self.capacity() + self.__size -= 1 return num - + """ 访问队首元素 """ def peek(self): - if self.is_empty(): - print("队列为空") - return False + assert not self.is_empty(), "队列为空" return self.__nums[self.__front] - - """ 返回列表用于打印 """ - def to_list(self): - res = [0] * self.size() - j = self.__front - for i in range(self.size()): - res[i] = self.__nums[(j % self.capacity())] - j += 1 - return res ``` === "Go" @@ -911,63 +917,71 @@ comments: true ```go title="array_queue.go" /* 基于环形数组实现的队列 */ type arrayQueue struct { - data []int // 用于存储队列元素的数组 - capacity int // 队列容量(即最多容量的元素个数) - front int // 头指针,指向队首 - rear int // 尾指针,指向队尾 + 1 + nums []int // 用于存储队列元素的数组 + front int // 队首指针,指向队首元素 + queSize int // 队列长度 + queCapacity int // 队列容量(即最大容纳元素数量) } - + // newArrayQueue 基于环形数组实现的队列 - func newArrayQueue(capacity int) *arrayQueue { + func newArrayQueue(queCapacity int) *arrayQueue { return &arrayQueue{ - data: make([]int, capacity), - capacity: capacity, - front: 0, - rear: 0, + nums: make([]int, queCapacity), + queCapacity: queCapacity, + front: 0, + queSize: 0, } } - + // size 获取队列的长度 func (q *arrayQueue) size() int { - size := (q.capacity + q.rear - q.front) % q.capacity - return size + return q.queSize } - + // isEmpty 判断队列是否为空 func (q *arrayQueue) isEmpty() bool { - return q.rear-q.front == 0 + return q.queSize == 0 } - + // offer 入队 - func (q *arrayQueue) offer(v int) { - // 当 rear == capacity 表示队列已满 - if q.size() == q.capacity { + func (q *arrayQueue) offer(num int) { + // 当 rear == queCapacity 表示队列已满 + if q.queSize == q.queCapacity { return } - // 尾结点后添加 - q.data[q.rear] = v - // 尾指针向后移动一位,越过尾部后返回到数组头部 - q.rear = (q.rear + 1) % q.capacity + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + rear := (q.front + q.queSize) % q.queCapacity + // 尾结点后添加 num + q.nums[rear] = num + q.queSize++ } - + // poll 出队 func (q *arrayQueue) poll() any { - if q.isEmpty() { - return nil - } - v := q.data[q.front] - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - q.front = (q.front + 1) % q.capacity - return v + num := q.peek() + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + q.front = (q.front + 1) % q.queCapacity + q.queSize-- + return num } - + // peek 访问队首元素 func (q *arrayQueue) peek() any { if q.isEmpty() { return nil } - v := q.data[q.front] - return v + return q.nums[q.front] + } + + // 获取 Slice 用于打印 + func (q *arrayQueue) toSlice() []int { + rear := (q.front + q.queSize) + if rear >= q.queCapacity { + rear %= q.queCapacity + return append(q.nums[q.front:], q.nums[:rear]...) + } + return q.nums[q.front:rear] } ``` @@ -976,46 +990,55 @@ comments: true ```js title="array_queue.js" /* 基于环形数组实现的队列 */ class ArrayQueue { - #queue; // 用于存储队列元素的数组 - #front = 0; // 头指针,指向队首 - #rear = 0; // 尾指针,指向队尾 + 1 + #nums; // 用于存储队列元素的数组 + #front = 0; // 队首指针,指向队首元素 + #queSize = 0; // 队列长度 + constructor(capacity) { - this.#queue = new Array(capacity); + this.#nums = new Array(capacity); } + /* 获取队列的容量 */ get capacity() { - return this.#queue.length; + return this.#nums.length; } + /* 获取队列的长度 */ get size() { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (this.capacity + this.#rear - this.#front) % this.capacity; + return this.#queSize; } + /* 判断队列是否为空 */ empty() { - return this.#rear - this.#front == 0; + return this.#queSize == 0; } + /* 入队 */ offer(num) { if (this.size == this.capacity) throw new Error("队列已满"); + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + const rear = (this.#front + this.size) % this.capacity; // 尾结点后添加 num - this.#queue[this.#rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - this.#rear = (this.#rear + 1) % this.capacity; + this.#nums[rear] = num; + this.#queSize++; } + /* 出队 */ poll() { const num = this.peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 this.#front = (this.#front + 1) % this.capacity; + this.#queSize--; return num; } + /* 访问队首元素 */ peek() { if (this.empty()) throw new Error("队列为空"); - return this.#queue[this.#front]; + return this.#nums[this.#front]; } } ``` @@ -1025,47 +1048,56 @@ comments: true ```typescript title="array_queue.ts" /* 基于环形数组实现的队列 */ class ArrayQueue { - private queue: number[]; // 用于存储队列元素的数组 - private front: number = 0; // 头指针,指向队首 - private rear: number = 0; // 尾指针,指向队尾 + 1 - private CAPACITY: number = 1e5; - constructor(capacity?: number) { - this.queue = new Array(capacity ?? this.CAPACITY); + private nums: number[]; // 用于存储队列元素的数组 + private front: number; // 队首指针,指向队首元素 + private queSize: number; // 队列长度 + + constructor(capacity: number) { + this.nums = new Array(capacity); + this.front = this.queSize = 0; } + /* 获取队列的容量 */ get capacity(): number { - return this.queue.length; + return this.nums.length; } + /* 获取队列的长度 */ get size(): number { - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (this.capacity + this.rear - this.front) % this.capacity; + return this.queSize; } + /* 判断队列是否为空 */ empty(): boolean { - return this.rear - this.front == 0; + return this.queSize == 0; } + /* 入队 */ offer(num: number): void { if (this.size == this.capacity) throw new Error("队列已满"); + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + const rear = (this.front + this.queSize) % this.capacity; // 尾结点后添加 num - this.queue[this.rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - this.rear = (this.rear + 1) % this.capacity; + this.nums[rear] = num; + this.queSize++; } + /* 出队 */ poll(): number { const num = this.peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 this.front = (this.front + 1) % this.capacity; + this.queSize--; return num; } + /* 访问队首元素 */ peek(): number { if (this.empty()) throw new Error("队列为空"); - return this.queue[this.front]; + return this.nums[this.front]; } } ``` @@ -1082,52 +1114,60 @@ comments: true /* 基于环形数组实现的队列 */ class ArrayQueue { - private int[] nums; // 用于存储队列元素的数组 - private int front = 0; // 头指针,指向队首 - private int rear = 0; // 尾指针,指向队尾 + 1 + private int[] nums; // 用于存储队列元素的数组 + private int front; // 队首指针,指向队首元素 + private int queSize; // 队列长度 + public ArrayQueue(int capacity) { - // 初始化数组 nums = new int[capacity]; + front = queSize = 0; } + /* 获取队列的容量 */ public int capacity() { return nums.Length; } + /* 获取队列的长度 */ public int size() { - int capacity = this.capacity(); - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity; + return queSize; } + /* 判断队列是否为空 */ public bool isEmpty() { - return rear - front == 0; + return queSize == 0; } + /* 入队 */ public void offer(int num) { - if (size() == capacity()) + if (queSize == capacity()) { Console.WriteLine("队列已满"); return; } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num nums[rear] = num; - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity(); + queSize++; } + /* 出队 */ public int poll() { int num = peek(); - // 队头指针向后移动一位,若越过尾部则返回到数组头部 + // 队首指针向后移动一位,若越过尾部则返回到数组头部 front = (front + 1) % capacity(); + queSize--; return num; } + /* 访问队首元素 */ public int peek() { @@ -1144,52 +1184,53 @@ comments: true /* 基于环形数组实现的队列 */ class ArrayQueue { private var nums: [Int] // 用于存储队列元素的数组 - private var front = 0 // 头指针,指向队首 - private var rear = 0 // 尾指针,指向队尾 + 1 - + private var front = 0 // 队首指针,指向队首元素 + private var queSize = 0 // 队列长度 + init(capacity: Int) { // 初始化数组 nums = Array(repeating: 0, count: capacity) } - + /* 获取队列的容量 */ func capacity() -> Int { nums.count } - + /* 获取队列的长度 */ func size() -> Int { - let capacity = capacity() - // 由于将数组看作为环形,可能 rear < front ,因此需要取余数 - return (capacity + rear - front) % capacity + queSize } - + /* 判断队列是否为空 */ func isEmpty() -> Bool { - rear - front == 0 + queSize == 0 } - + /* 入队 */ func offer(num: Int) { if size() == capacity() { print("队列已满") return } + // 计算尾指针,指向队尾索引 + 1 + // 通过取余操作,实现 rear 越过数组尾部后回到头部 + int rear = (front + queSize) % capacity(); // 尾结点后添加 num - nums[rear] = num - // 尾指针向后移动一位,越过尾部后返回到数组头部 - rear = (rear + 1) % capacity() + nums[rear] = num; + queSize++; } - + /* 出队 */ @discardableResult func poll() -> Int { let num = peek() - // 队头指针向后移动一位,若越过尾部则返回到数组头部 - front = (front + 1) % capacity() - return num + // 队首指针向后移动一位,若越过尾部则返回到数组头部 + front = (front + 1) % capacity(); + queSize--; + return num; } - + /* 访问队首元素 */ func peek() -> Int { if isEmpty() {