PushQueue

推入队列,循环数组实现

当前为 2021-09-25 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/432936/973684/PushQueue.js

  1. /* exported PushQueue */
  2. /**
  3. * 推入队列,循环数组实现
  4. * @template T 数据类型
  5. * @version 0.1.0.20210923
  6. * @author Laster2800
  7. */
  8. class PushQueue {
  9. /** @type {number} 起始元素位置(指向起始元素后方) */
  10. index = 0
  11. /** @type {number} 队列长度 */
  12. size = 0
  13. /** @type {number} 最大长度 */
  14. maxSize = 0
  15. /** @type {number} 容量 */
  16. capacity = 0
  17. /** @type {T[]} 内部数据 */
  18. data = null
  19.  
  20. /**
  21. * @param {number} maxSize 队列的最大长度,达到此长度后继续推入数据,将舍弃末尾处的数据
  22. * @param {number} [capacity=maxSize] 容量,即循环数组的长度,不能小于 maxSize
  23. */
  24. constructor(maxSize, capacity) {
  25. this.maxSize = maxSize
  26. if (!capacity || capacity < maxSize) {
  27. capacity = maxSize
  28. }
  29. this.capacity = capacity
  30. this.data = new Array(capacity)
  31. }
  32.  
  33. /**
  34. * 设置推入队列的最大长度
  35. * @param {number} maxSize 队列的最大长度,不能大于 capacity
  36. */
  37. setMaxSize(maxSize) {
  38. if (maxSize > this.capacity) {
  39. maxSize = this.capacity
  40. }
  41. if (maxSize < this.size) {
  42. this.size = maxSize
  43. }
  44. this.maxSize = maxSize
  45. this.gc()
  46. }
  47.  
  48. /**
  49. * 重新设置推入队列的容量
  50. * @param {number} capacity 容量
  51. */
  52. setCapacity(capacity) {
  53. if (this.maxSize > capacity) {
  54. this.maxSize = capacity
  55. }
  56. if (this.size > capacity) {
  57. this.size = capacity
  58. }
  59. // no need to gc() here
  60. const data = this.toArray().reverse()
  61. this.capacity = capacity
  62. this.index = data.length
  63. data.length = capacity
  64. this.data = data
  65. }
  66.  
  67. /**
  68. * 向队列中推入数据,若队列已达到最大长度,则舍弃末尾处数据
  69. * @param {T} value 推入队列的数据
  70. */
  71. push(value) {
  72. this.data[this.index] = value
  73. this.index += 1
  74. if (this.index >= this.capacity) {
  75. this.index = 0
  76. }
  77. if (this.size < this.maxSize) {
  78. this.size += 1
  79. }
  80. if (this.maxSize < this.capacity && this.size === this.maxSize) { // maxSize 等于 capacity 时资源刚好完美利用,不必回收资源
  81. let release = this.index - this.size - 1
  82. if (release < 0) {
  83. release += this.capacity
  84. }
  85. this.data[release] = null
  86. }
  87. }
  88.  
  89. /**
  90. * 将队列末位处的数据弹出
  91. * @returns {T} 弹出的数据
  92. */
  93. pop() {
  94. if (this.size > 0) {
  95. let index = this.index - this.size
  96. if (index < 0) {
  97. index += this.capacity
  98. }
  99. this.size -= 1
  100. const result = this.data[index]
  101. this.data[index] = null
  102. return result
  103. }
  104. }
  105.  
  106. /**
  107. * 获取第 `n` 个元素(范围 `[0, size - 1]`)
  108. * @param {number} n 元素位置
  109. * @returns {T} 第 `n` 个元素
  110. */
  111. get(n) {
  112. if (this.size > 0 && n >= 0) {
  113. let index = this.index - n - 1
  114. if (index < 0) {
  115. index += this.capacity
  116. }
  117. return this.data[index]
  118. }
  119. }
  120.  
  121. /**
  122. * 设置第 `n` 个元素的值为 `value`(范围 `[0, size - 1]`,且第 `n` 个元素必须已存在)
  123. * @param {number} n 元素位置
  124. * @param {T} value 要设置的值
  125. * @returns {boolean} 是否设置成功
  126. */
  127. set(n, value) {
  128. if (n <= this.size - 1 && n >= 0) {
  129. let index = this.index - n - 1
  130. if (index < 0) {
  131. index += this.capacity
  132. }
  133. this.data[index] = value
  134. return true
  135. } else {
  136. return false
  137. }
  138. }
  139.  
  140. /**
  141. * 使用数组初始化推入队列
  142. * @param {Array<T>} array 初始化数组
  143. */
  144. fromArray(array) {
  145. if (this.maxSize < array.length) {
  146. this.data = array.slice(0, this.maxSize).reverse()
  147. } else {
  148. this.data = array.reverse()
  149. }
  150. this.index = this.data.length
  151. if (this.index >= this.capacity) {
  152. this.index = 0
  153. }
  154. this.size = this.data.length
  155. this.data.length = this.capacity
  156. }
  157.  
  158. /**
  159. * 将推入队列以数组的形式返回
  160. * @param {number} [maxLength=size] 读取的最大长度
  161. * @param {number} [offset=0] 起始点
  162. * @returns {Array<T>} 队列数据的数组形式
  163. */
  164. toArray(maxLength = this.size, offset = 0) {
  165. if (offset < 0) {
  166. offset = 0
  167. }
  168. if (offset + maxLength > this.size) {
  169. maxLength = this.size - offset
  170. }
  171. const ar = []
  172. let start = this.index - offset
  173. if (start < 0) {
  174. start += this.capacity
  175. }
  176. let end = start - maxLength
  177. for (let i = start - 1; i >= end && i >= 0; i--) {
  178. ar.push(this.data[i])
  179. }
  180. if (end < 0) {
  181. end += this.capacity
  182. for (let i = this.capacity - 1; i >= end; i--) {
  183. ar.push(this.data[i])
  184. }
  185. }
  186. return ar
  187. }
  188.  
  189. /**
  190. * 清理内部无效数据,释放内存
  191. */
  192. gc() {
  193. if (this.size > 0) {
  194. const start = this.index - 1
  195. let end = this.index - this.size
  196. if (end < 0) {
  197. end += this.capacity
  198. }
  199. if (start >= end) {
  200. for (let i = 0; i < end; i++) {
  201. this.data[i] = null
  202. }
  203. for (let i = start + 1; i < this.capacity; i++) {
  204. this.data[i] = null
  205. }
  206. } else {
  207. for (let i = start + 1; i < end; i++) {
  208. this.data[i] = null
  209. }
  210. }
  211. } else {
  212. this.data = new Array(this.capacity)
  213. }
  214. }
  215.  
  216. /**
  217. * 标准迭代器:`item`
  218. * @returns {IterableIterator<T>}
  219. */
  220. [Symbol.iterator]() {
  221. const iterator = this.entries()
  222. return {
  223. next: () => {
  224. const n = iterator.next()
  225. if (!n.done) {
  226. n.value = n.value[1]
  227. }
  228. return n
  229. },
  230. }
  231. }
  232.  
  233. /**
  234. * 迭代器:`[index, item]`
  235. * @returns {IterableIterator<[index: number, item: T]>}
  236. */
  237. entries() {
  238. let current = this.index - 1
  239. let end = this.index - this.size
  240. return {
  241. next: () => {
  242. if (current < 0 && end < 0) {
  243. current += this.capacity
  244. end += this.capacity
  245. }
  246. if (current >= end && current >= 0) {
  247. const n = { value: [current, this.data[current]], done: false }
  248. current -= 1
  249. return n
  250. } else {
  251. return { done: true }
  252. }
  253. },
  254.  
  255. [Symbol.iterator]() { return this },
  256. }
  257. }
  258. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址