数据结构基础02:栈
栈的应用
栈是一种线性结构,只能从一端添加元素(入栈),也只能从这一端取出元素(出栈),这一端称为栈顶
后进先出(Last In First Out)
编辑器:撤销操作
操作系统:系统调用栈
编译器:括号匹配
数组实现栈
栈和队列的底层有多种实现的方式,用数组实现是其中一种
常用方法为push()、pop()、peek()、getSize()、isEmpty()
public class Algorithm {
public static void main(String[] args) {
ArrayStack<Integer> stack = new ArrayStack<>(20);
for (int i = 0; i < 5; i++) {
stack.push(i);
System.out.println(stack);
}
System.out.println(stack.getSize());
System.out.println(stack.peek());
stack.pop();
System.out.println(stack);
System.out.println(stack.isEmpty());
}
}
/**
* 创建一个栈接口,就可以使用不同的数据结构来实现栈
*/
interface Stack<E> {
int getSize();
boolean isEmpty();
void push(E element);
E pop();
E peek();
}
/**
* 数组实现栈
*/
class ArrayStack<E> implements Stack<E>{
Array<E> array;
public ArrayStack(int capacity){
array = new Array<>(capacity);
}
public ArrayStack(){
array = new Array<>();
}
/**
* 重写栈接口的方法
*/
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
public void push(E element) {
array.addLast(element);
}
@Override
public E pop() {
return array.removeLast();
}
/**
* peek()方法只能查看栈顶元素,对数组来说是最后一个元素,其他元素无法查看
*/
@Override
public E peek() {
return array.getLast();
}
/**
* 重写toString()方法打印栈的信息,注意array.toString()方法打印的是数组的信息
*/
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("Stack: [");
for (int i = 0; i < array.getSize(); i++) {
str.append(array.get(i));
if (i != array.getSize() - 1){
str.append(", ");
}
}
str.append("] top");
return str.toString();
}
}
class Array<E> {
private E[] data;
private int size;
public Array(int capacity){
data = (E[]) new Object[capacity];
size = 0;
}
public Array(){
this(10);
}
public void add(int index, E element){
if (index < 0 || index > size){
throw new IllegalArgumentException("索引值非法");
}
if (size == data.length){
resize(2 * data.length);
}
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = element;
size++;
}
/**
* 栈只能在数组最后的位置增删元素
*/
public void addLast(E element){
add(size, element);
}
public E remove(int index){
if (index < 0 || index >= size) {
throw new IllegalArgumentException("索引值非法");
}
E target = data[index];
for (int i = index; i < size - 1; i++) {
data[i] = data[i + 1];
}
size--;
data[size] = null;
if (size == data.length / 4 && data.length / 2 != 0){
resize(data.length / 2);
}
return target;
}
public E removeLast(){
return remove(size - 1);
}
public int getSize(){
return size;
}
public E get(int index){
if (index < 0 || index >= size) {
throw new IllegalArgumentException("索引值非法");
}
return data[index];
}
public E getLast(){
return get(size - 1);
}
private void resize(int newCapacity){
E[] newData = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
public boolean isEmpty(){
return size == 0;
}
}
栈的复杂度分析
peek()、getSize()、isEmpty()方法的时间复杂度为O(1)
push()、pop()方法的均摊复杂度为O(1)