引入:
相比我们之前学习的数组,之前在一个数组中我们若是知道了一个数组中的某个数据的下标即可以立即的访问这个数据,
或者可以使用一个循环结构访问到每一项数据。
但是在本次学习的过程中,我们学习的这种数据结构,他的访问是受限制的,即在特定的时刻只有一个数据项可以被访问或者删除。
栈:
栈只允许访问一个数据项,即最后插入的数据项。只有移除这个数据项之后才能访问倒数第二个插入的数据项。后入先出
class StackX {
private int maxSize; // 栈数组的大小
private long[] stackArray;
private int top; // 栈顶
// 初始化栈信息 (构造器)
public StackX(int s) {
maxSize = s; // 初始化数组空间
stackArray = new long[maxSize]; // 创建数组
top = -1; // 初始化栈顶下标(表示当前没有数据)
}
/**
* 关于下面函数 ++top 的思考:
* 1. 因为顶的初始化值为-1, 若使用 top++ 的话,插入第一条数据的时候会报出空指针异常
* 2. 该数据结构的思想要求,栈顶的下标时刻指向最新插入的数据,若使用top++的话,执行完该句话以后,top就指向了下一个要插入数据的位置
*/
// 压入一条数据
public void push(long j) {
stackArray[++top] = j;
}
/**
* 结合上面的压入数据函数做一下思考:
* 1. 因为栈顶的指针时刻指向最新的数据所以在弹出的时候必须要使用 top 实时的值 不能发生变化
* 2. 在取了一条数据之后要求 top 自动指向前一条插入的数据,以方便下一次的取数据
* 3. 综上 在这里使用 top-- 是最合适的
*/
// 弹出一条数据
public long pop() {
return stackArray[top--];
}
// 查看栈顶元素
public long peek() {
return stackArray[top];
}
// 判断是否为空
public boolean isEmpty() {
return (top == -1);
}
// 判断是已经存满
public boolean isFull() {
return (top == maxSize-1);
}
}
public class Stack {
public static void main(String[] args) {
StackX theStack = new StackX(10);
theStack.push(20);
theStack.push(40);
theStack.push(60);
theStack.push(80);
while ( !theStack.isEmpty()) {
long value = theStack.pop();
System.out.print(value + " ");
}
System.out.println("");
}
}
····栈这种数据结构设计的很巧妙,在上面的代码中使用了数组的数据结构实现了栈:纵观全局使用了一个数组存储数据,操作一个 top 的数组下标来实现这种数据结构,个人觉得在用这种方式实现栈的核心思想有以下几点:
1. top 下标实时指向栈顶位置:这也是为什么 top 初值为 -1, 在压入的时候使用 ++top;在弹出的 时候使用 top–;
2. 他将一切操作数据的具体实现都用方法封装起来,就和上面引入中讲到的一样,在特定的情况下只有一条数据会被操作。
栈实例1 - 字符串反转:
输入一个字符串根据栈的性质:将该单词的字母依次压入栈中,然后在依次弹出,就会达到逆序的效果。
基于上面的代码:
class reverse {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入单词");
// 从控制台获取用户输入的单词
String word = sc.next();
int maxSize = word.length();
// 初始化栈信息
StackX2 theStack = new StackX2(maxSize);
// 将字符串分割为字符
char[] arr = word.toCharArray();
// 将分割好的字符依次压入栈中 (从第一个开始)
for (char c : arr) {
theStack.push(c);
}
// 再依次拿出
while ( !theStack.isEmpty() ) {
System.out.print(theStack.pop());
}
sc.close();
}
}
栈实例2 - 分隔符匹配:
输入一个带有分隔符的字符串 例如:a{b(c]d}e 判断他的左右分割符是否匹配:
需求解析:
先将字符串转换为字符数组;然后在将每个字符依次遍历出来,当判断到有左分隔符的时