kotlin实现ArrayDeque
Deque双端队列,一直在使用,却从未了解过源码。
内部逻辑其实很简单
- 可扩容数组
- 循环队列,循环栈
- 扩容倍数1.5,size=size+(size shr 1)
- 只从两端存取元素
fun main() {
val deque = MyArrayDeque()
repeat(16) {
deque.addLast(it)
}
while (deque.isNotEmpty()) {
println(deque.removeLast())
}
}
class MyArrayDeque {
// 存元素,不能存null,初始容量为16,避免频繁扩容,一次扩容1.5倍
private var arr = arrayOfNulls<Int>(16)
// 头尾节点,tail一直为null
private var head: Int = 0
private var tail: Int = 0
// 实际容量
private var size: Int = 0
fun addFirst(value: Int) {
// 扩容
grow()
head = dec(head)
arr[head] = value
size++
}
fun addLast(value: Int) {
// 扩容
grow()
arr[tail] = value
tail = inc(tail)
size++
}
fun removeFirst(): Int {
if (isEmpty()) {
return -1
}
val res = arr[head]!!
head = inc(head)
size--
return res
}
fun removeLast(): Int {
if (isEmpty()) {
return -1
}
tail = dec(tail)
size--
return arr[tail]!!
}
// 加一
fun inc(i: Int) = if (i == arr.lastIndex) 0 else i + 1
// 减一
fun dec(i: Int) = if (i == 0) arr.lastIndex else i - 1
// 扩容,内部不一定扩容
private fun grow() {
// 至少还有一个容量
if (size < arr.size - 1) {
return
}
// 一次扩容1.5倍
val newArr = arrayOfNulls<Int>(arr.size + (arr.size shr 1))
// 从0开始
if (head < tail) {
for (i in head..<tail) {
newArr[i - head] = arr[i]
}
} else {
// 临时下标
var index = 0
// 现存头部
for (i in head..arr.lastIndex) {
newArr[index++] = arr[i]
}
// 尾部移动后面
for (i in 0..<tail) {
newArr[index++] = arr[i]
}
}
// 扩容后,head和tail重新计算
arr = newArr
head = 0
tail = size
}
fun size() = size
fun isEmpty() = size() == 0
fun isNotEmpty() = size() > 0
override fun toString(): String {
if (size == 0) {
return ""
}
val sb = StringBuilder()
if (head < tail) {
for (i in head..<tail) {
if (sb.isNotEmpty()) {
sb.append(", ")
}
sb.append(arr[i])
}
} else {
for (i in head..arr.lastIndex) {
if (sb.isNotEmpty()) {
sb.append(", ")
}
sb.append(arr[i])
}
for (i in 0..<tail) {
// 此时一定有至少一个元素,不用判断
sb.append(", ").append(arr[i])
}
}
return sb.toString()
}
}