数据结构与算法(1)——栈

:一种先进后出的逻辑数据结构,具体实现方式有两种,链表和数组。

实现

热身:定容栈

API设计(java语言描述)

public classFixedCapacityStackOfStrings
FixedCapacityStackOfStrings(int cap)创建一个容量为cap的空栈
voidpush(String item)添加一个字符串
Stringpop()删除最后一个添加的字符串
booleanisEmpty()栈是否为空
intsize()栈中的字符串数量

实现

class FixedCapacityStackOfStrings(cap: Int = 30, var size: Int = 0) {
    private val str = arrayOfNulls<String>(max(cap, 30))
    fun isEmpty(): Boolean = size == 0
    fun push(item: String) {
        str[size++] = item
    }

    fun pop(): String = str[--size] ?: throw IllegalAccessException("栈内没有元素")
}

测试

fun test01() {
    val stack = FixedCapacityStack<String>(15)
    stack.push("4")
    stack.push("5")
    stack.push("6")
    println("定容字符串栈现在的大小是${stack.size}") // 3
    println("定容字符串栈是否为空:${stack.isEmpty()}") // false
    repeat(3) { println("背包弹出元素:${stack.pop()}") } // 3 2 1
    println("定容字符串栈是否为空:${stack.isEmpty()}") // true
}

备注:kotlin的StringArray不是基础数组,用它来写数据结构与算法没有意义,这里用Array

特点:使用数组实现,简单易操作,而且能做到后进先出的特性

缺点:必须在初始化时限定大小,并且无法扩容。

未采用泛型编程,所以仅限于字符串操作

融合泛型,实现自定义元素

class FixedCapacityStack<Item>(cap: Int = 30, var size: Int = 0) {
    @Suppress("UNCHECKED_CAST")
    private val arrays = arrayOfNulls<Any>(max(cap, 30)) as Array<Item?>
    fun isEmpty(): Boolean = size == 0
    fun push(item: Item) {
        arrays[size++] = item
    }
    fun pop(): Item = arrays[--size] ?: throw IllegalAccessException("栈内没有元素")
}
fun test02() {
    val stack = FixedCapacityStackOfStrings(15)
    stack.push("1")
    stack.push("2")
    stack.push("3")
    println("定容字符串栈现在的大小是${stack.size}") // 3
    println("定容字符串栈是否为空:${stack.isEmpty()}") // false
    repeat(3) { println("背包弹出元素:${stack.pop()}") } // 3 2 1
    println("定容字符串栈是否为空:${stack.isEmpty()}") // true
}
  • 这里要拓展一个点,kotlin的压制异常类型转换用的是 @Suppress(“UNCHECKED_CAST”),和java的**@SuppressWarnings(“unchecked”)**不同

调整数组大小(改造为下压栈)

class ResizingArrayStack<Item>(cap: Int = 30, var size: Int = 0) {
    @Suppress("UNCHECKED_CAST")
    private var arrays = arrayOfNulls<Any>(max(cap, 10)) as Array<Item?>
    fun isEmpty(): Boolean = size == 0
    fun push(item: Item) {
        // 长度达到上限就扩容
        if (size == arrays.size) resize(2 * arrays.size)
        arrays[size++] = item
    }

    fun pop(): Item? = run {
        val item = arrays[--size]
        arrays[size] = null // 避免对象游离
        if (size > 0 && size == arrays.size / 4) resize(arrays.size / 4)
        item
    }

    // 扩容/缩容函数
    private fun resize(max: Int) {
        @Suppress("UNCHECKED_CAST")
        val temp = arrayOfNulls<Any>(max) as Array<Item?>
        for (index in 0 until size) {
            temp[index] = arrays[index]
        }
//        println("内存变为${max}")
        arrays = temp
    }
}

测试

fun test03() {
    val stack = ResizingArrayStack<Int>(10)
    for (i in 0..40) {
        stack.push(i)
    }
    for (i in 0..40) {
        stack.pop()
    }
}

日常使用:

// 栈(数组实现)
fun main() {
    val stack = Stack<Int>()
    stack.push(1)
    stack.push(2)
    stack.pop().run(::println)
    println("==========")
    stack.reversed().forEach(::println)
}

typealias Stack<E> = ArrayDeque<E>
fun <E> Stack<E>.push(e: E) = this.add(e)
fun <E> Stack<E>.pop() = this.removeLast()
// 注意:遍历的时候需要stack.reversed()

// typealias Stack<E> = LinkedList<E>

事实上,现代数据结构的ArrayDeque和LinkedList就有压栈和出栈的能力,区别在于LinkedList遍历也是倒序的,而ArrayQueue遍历是正序的,所以,个人习惯用LinkedList

// 同为日常使用
fun main() {
    val stack = Stack<Int>()
    stack.push(1)
    stack.push(2)
    stack.push(3)
    stack.pop().run(::println)
    println("==========")
    stack.forEach(::println)
}

typealias Stack<E> = LinkedList<E>

栈(链表实现)

补充概念:链表

链表是一种递归的数据结构,它或者为空(null),或者指向一个结点(node)的引用,该结点含有一个泛型的元素和一个指向另一条链表的引用。

private class Node {
    Item item;
    Node next;
}

一个node里有两个实例变量,一个存储元素,一个指向下一个Node对象

实现

class Stack2<Item> /*: Iterable<Item>*/ {
    private var first: Node? = Node()
    var size = 0
    private inner class Node(
        var item: Item? = null,
        var next: Node? = null
    )

    fun push(item: Item) {
//        val oldFirst = first
//        first = Node(item, oldFirst)
//        first?.item = item
//        first?.next = oldFirst
        first = Node(item, first)
        size++
    }

    fun pop(): Item {
        val item = first?.item
        first = first?.next
        size--
        return item ?: throw IllegalAccessException("栈内没有元素")
    }
//    override fun iterator(): Iterator<Item> = Iter()
}

fun main() {
    val stack = Stack2<Int>()
    stack.push(1)
    stack.push(2)
    repeat(2) { println(stack.pop()) }
}

暂时未实现迭代器遍历

日常使用

fun main() {
    val stack = Stack<Int>()
    repeat(4, stack::push)
    stack.pop().run(::println)
    println("==========")
    stack.forEach(::println)
}

typealias Stack<E> = LinkedList<E>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值