栈
栈:栈(英语:stack)又称为堆栈或堆叠,属于线性数据结构,其满足后进先出原则,进行数据的存储。
特点,只在一端进行插入,删除操作,其表现为:从栈顶放入(入栈),栈顶取出(出栈)
后进先出 Last In First Out LIFO 类似羽毛球筒
经典应用:
1. 文本撤销
2. 程序调用系统栈
执行方法时,调用子方法,入栈,执行完,出栈; 可找到上一次中断的位置)
3. 递归
…
一般操作系统中,入栈的操作使得栈顶的地址减小,出栈的操作使得栈顶的地址增大。
栈在程序的运行中有着举足轻重的作用。最重要的是栈保存了一个函数调用时所需要的维护信息,这常常称之为堆栈帧或者活动记录。堆栈帧一般包含如下几方面的信息:
1.函数的返回地址和参数
2.临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。
栈的实现
根据栈的后进先出特性,以及查看Stack.java 源码时,发现只需要实现如下接口:
class Stack<E> extends Vector<E>
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
在Vector 中,具体实现使用的是数组
isEmpty - 栈是否为空
push - 入栈
pop - 出栈
peek - 查看栈顶元素
search - 搜索某元素
数组
在实现时,多加了2个方法,一个用于数组的动态大小变化,一个是栈内容打印。
/**
* @author stormxz
*
* @param <E> 泛型
*/
public class ArrStack<E> {
//定义默认数据长度
private int DATA_LENGTH = 10;
//int 数据类型的数据
private E[] data;
//描述数据中的实际个数
private int size;
/**
* 初始化无参构造函数,此时为默认长度
*/
public ArrStack() {
data = (E[]) new Object[DATA_LENGTH];
}
/**
* @return 判断数组是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* @param value 添加的值
*
* 在末尾添加数据
*/
public void push(E value) {
if (size == data.length) {
upDateArrayLength(2 * data.length);
}
data[size] = value;
size++;
}
/**
* @param length 新数组的长度
*
* 更新数组容量 长度大小 复杂度O(n)
*/
public void upDateArrayLength(int length) {
E[] newData = (E[]) new Object[length];
for (int i = 0; i < size; i++) {
newData[i] = data[i];
}
data = newData;
}
/**
* 删除栈顶元素,并返回
*/
public E pop() {
if (size <= 0) {
throw new IllegalArgumentException("栈已空");
}
E value = data[size - 1];
data[size - 1] = null;
size--;
if (size == data.length / 2 && data.length > 1) {
upDateArrayLength(data.length / 2);
}
return value;
}
/**
* @param index 查看栈顶元素
*
* 查看栈顶元素,并返回数据
*/
public E peek() {
if (size <= 0) {
throw new IllegalArgumentException("栈已空");
}
return data[size - 1];
}
/**
* @param value 查找的值
* @return 对应值的索引
*
* 查找值的位置
*/
public int search(E value) {
for (int i = 0; i < size; i++) {
if (data[i] == value) {
return i;
}
}
return -1;
}
/** (non-Javadoc)
* @see java.lang.Object#toString()
*
* 打印输出
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
sb.append(data[i]);
if (i != size -1) {
sb.append(", ");
} else {
sb.append("]");
}
}
System.out.println("Array size = " + size + "
length = " + data.length);
return sb.toString();
}
}
链表
使用链表的好处是,长度没有定死,与数组相比减少了数据copy的过程
链表实现栈功能
栈的小应用
括号匹配
将字符串逆序输出
public void useStack() {
Stack mStack = new Stack();
String str = "hello, world";
char[] c = str.toCharArray();
for (char mStr : c) {
mStack.push(mStr);
}
while(!mStack.isEmpty()) {
System.out.print(mStack.pop());
}
}
运行结果:
dlrow ,olleh
总结
- 从栈的实现可以看出,在进行入栈和出栈的时间复杂度都为O(1),也就是说栈操作所耗的时间不依赖栈中数据项的个数,因此操作时间很短。
- 搜索操作时间复杂度为O(n)。
- 栈后进先出的特性,能够解决一些常见问题。
~看到新问题会继续补充