/** * 出队。 */ @Override public E dequeue(){ if (isEmpty()) { thrownew IllegalArgumentException("Cannot dequeue from an empty queue."); } E ret = data[front]; data[front] = null; front = (front + 1) % data.length; size--;
程序调用的系统栈。比如我们执行 A 函数,执行到第 2 行后其调用了 B 函数,那么 A 函数执行就暂停,开始调用 B 函数,此时就有一个栈来维护这个调用过程,类似 A2 就被 push 到栈里,记录 A 函数当前执行到第 2 行。类似的 B3 也可能被 push 到栈中去执行 C 函数,C 函数执行完了继续执行 B,那么栈就会执行一个 pop 操作。通过栈顶的记录,计算机就找到了继续执行哪个函数以及执行到哪里了。
编辑器中的括号匹配。
栈的实现
使用 Java 进行实现。我们将栈定义为一个接口。
1 2 3 4 5 6 7 8
publicinterfaceStack<E> {
intgetSize(); booleanisEmpty(); voidpush(E e); E pop(); E peek(); }
首先,三种语言的数组容量都是不可变的,这也是静态数组的特点,空间一旦开辟,就固定了;其次,对于元素的类型,Objective-C 是只要是对象即可,因此对元素类型的限制较小,而其他两种语言要求元素必须为指定的类型;最后,Swift 的数组使用值类型,而另外两种采用引用类型,这也使得 Swift 数组创建后,元素就无法做更改了。
/** * 在数组开头插入一个元素。 * 时间复杂度 O(n),因为需要向后挪动 n 个元素,数组中所有内容都要向后挪动。 * * @param e 插入的元素。 */ publicvoidaddFirst(E e){ add(0, e); }
/** * 获取某个元素。 * 时间复杂度 O(1)。 * * @param index 索引。 */ public E get(int index){ if (index < 0 || index >= size) { thrownew IllegalArgumentException("Get failed. Index is illegal."); }
return data[index]; }
/** * 获取数组最后一个元素。 */ public E getLast(){ return get(size - 1); }
/** * 获取数组第一个元素。 */ public E getFirst(){ return get(0); }
/** * 修改 index 索引位置的元素为 e。 * 时间复杂度 O(1)。这也是数组最大的优势,支持随机访问,知道索引的情况下改元素超快。 * * @param index 索引。 * @param e 新设置的元素。 */ publicvoidset(int index, E e){ if (index < 0 || index >= size) { thrownew IllegalArgumentException("Set failed. Index is illegal."); }
data[index] = e; }
/** * 查找数组中是否包含某个元素。 * 时间复杂度 O(n)。 */ publicbooleancontains(E e){ for (int i = 0; i < size; i++) { if (data[i].equals(e)) { returntrue; } } returnfalse; }
/** * 查找元素 e 所在的第一个索引,如果不存在该元素,则返回 -1。 * 时间复杂度 O(n)。 */ publicintfind(E e){ for (int i = 0; i < size; i++) { if (data[i].equals(e)) { return i; } } return -1; }
/** * 从数组中删除指定索引的元素,并将其返回。 * 时间复杂度 O(n) */ public E remove(int index){ if (index < 0 || index >= size) { thrownew IllegalArgumentException("Remove failed. Index is Illegal."); }
E ret = data[index];
for (int i = index + 1; i < size; i++) { data[i - 1] = data[i]; } size--; data[size] = null; // 可写可不写,写的话可以优化一点点内存。loitering objects != memory leak
/** * 删除第一个元素。 * 时间复杂度 O(n) * * @return 删除的元素。 */ public E removeFirst(){ return remove(0); }
/** * 删除最后一个元素。 * 时间复杂度 O(1) * * @return 删除的元素。 */ public E removeLast(){ return remove(size - 1); }
/** * 如果数组包含元素 e,则删除第一个 e。 * * @param e */ publicvoidremoveElement(E e){ int index = find(e); if (index != -1) { remove(index); } }
/** * 交换数组中指定两个索引的元素 */ publicvoidswap(int i, int j){ if (i < 0 || i >= size || j < 0 || j >= size) { thrownew IllegalArgumentException("Index is illegal."); }
使用 brew 安装 openjdk 后,需要关注(使用 brew info openjdk 查看):
1 2 3 4 5 6 7 8 9 10 11 12
For the system Java wrappers to find this JDK, symlink it with sudo ln -sfn /usr/local/opt/openjdk/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk.jdk
openjdk is keg-only, which means it was not symlinked into /usr/local, because macOS provides similar software and installing this software in parallel can cause all kinds of trouble.
If you need to have openjdk first in your PATH, run: echo 'export PATH="/usr/local/opt/openjdk/bin:$PATH"' >> ~/.zshrc
For compilers to find openjdk you may need to set: export CPPFLAGS="-I/usr/local/opt/openjdk/include"
同样,安装 openjdk@8 后,需要关注(使用 brew info openjdk@8 查看):
1 2 3 4 5 6 7 8 9 10 11
For the system Java wrappers to find this JDK, symlink it with sudo ln -sfn /usr/local/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk
openjdk@8 is keg-only, which means it was not symlinked into /usr/local, because this is an alternate version of another formula.
If you need to have openjdk@8 first in your PATH, run: echo 'export PATH="/usr/local/opt/openjdk@8/bin:$PATH"' >> ~/.zshrc
For compilers to find openjdk@8 you may need to set: export CPPFLAGS="-I/usr/local/opt/openjdk@8/include"