你好,我是goldsunC
让我们一起进步吧!
堆栈简介
堆栈(Stack,又称栈)
是一组相同数据类型的组合,所有的操作均在堆栈顶端进行,具有“后进先出”
(Last In First Out,LIFO)的特性。堆栈结构在计算机中的应用非常广泛。
堆栈只能在一端进行输入输出,就像一个无盖的桶一样。堆栈具有一个固定的栈底和一个浮动的栈顶,栈顶可以理解为一个永远指向栈中最上面元素的指针,每当有数据输入或者输出时,它会随之的上浮或者下落。
向栈中输入数据的操作被称为“压栈”
,数据被压入后,栈顶的指针上浮一格,从栈中输出数据的操作被称为“弹栈”
,如果数据弹出后栈顶的指针指向了栈底,那么这个堆栈就是空的。
堆栈是一种抽象性数据结构,其主要特性如下:
- 只能从栈的顶端访问数据。
- 数据的访问符合
“后进先出”
的原则。
后进先出就可以理解为你向桶中放置物品,放置的时候一个物品压着一个物品,当取物品的时候只能从最上边取。
堆栈的基本操作一般有以下几种:
方法 | 作用 |
---|---|
PUSH | 向堆栈顶端压入数据 |
POP | 取出堆栈顶端的数据 |
EMPTY | 判断堆栈是否是空堆栈 |
FULL | 判断堆栈是否已满 |
其实堆栈主要的特点特性就这么多,但其数据结构在很多地方有很大用处,下面再介绍一下实现堆栈的几种方法。
Stack
在Java中,Stack类
是用来实现堆栈的工具类,它是Vector
的子类,具有Vector
的所有方法,使用Stack的话我们就不用关注堆栈实现的细节了,Stack类能实现的操作方法如下:
方法 | 作用 |
---|---|
public Stack() | 是栈类唯一的构造函数,用它来创建一个堆栈。 |
public Object push(Object item) | 将指定的对象压入栈中。 |
public Object pop() | 将堆栈最上面的元素从栈中取出,并返回这个对象。 |
public boolean empty() | 若堆栈中没有元素,则返回true,否则返回false。 |
需要注意的是,压入堆栈和弹出堆栈的数据都是“对象”,而不能是基本数据类型,即可以是Integer(1),而不能是1。
使用举例:
public class StackTest {
static int[] num = {new Integer(1),
new Integer(2),
new Integer(3)};
public static void main(String[] args) {
Stack stk = new Stack();
for (int i=0;i<num.length;i++)
stk.push(num[i]);
System.out.println("stk="+stk);
System.out.println("依次取出元素:");
while (!stk.empty())
System.out.println(stk.pop());
}
}
OUT:
stk=[1, 2, 3]
依次取出元素:
3
2
1
堆栈的数组实现
除了使用Java中的Stack类外,堆栈本身也可以使用静态数组或者动态链表来实现,只要满足堆栈的两个基本原则即可。以数组来制作和实现堆栈的优点是算法简单,但是往往需要考虑使用最大可能性的数组空间,会很可能造成内存空间的浪费,而链表实现堆栈的优点是可以动态改变表的长度,不过算法较为复杂一点。
用数组实现堆栈,首先定义一个类:
class stack{
private int[] stack;//栈数组
private int top;//顶部指针
public stack(int stackSize){//构造方法
stack = new int[stackSize];
top = -1;//起始指针位置为-1
}
//判断堆栈是否为空
public boolean empty() {
if (top == -1)
return true;
else return false;
}
//类方法:压入数据
public void push(int data) {
if (top>=stack.length) {
System.out.println("堆栈已经满了,无法再加入新元素");
}else {
stack[++top] = data;//压入数据
}
}
//弹出数据
public int pop() {
if (this.empty()) {
System.out.println("堆栈中已经没有数据,弹出-1");
return -1;
}
else return stack[top--];
}
}
上面例子中类的字段
包括栈存放数据所需要的数组和栈顶指针
。
另外还包括构造方法和三个实例方法:
stack(int stackSize)
:构造方法,将两个字段初始化。empty()
:判断当前栈数组是否为空,返回布尔值。push(int data)
:向栈中压入数据,无返回值。pop()
:从栈中取出数据,并返回该数据值。
定义好这个栈数组类后就可以进行实例化使用了,示例如下:
public class StackByArray {
public static void main(String[] args) throws IOException {
int value;//要压入的数据
stack stk = new stack(10);
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入10个数据:");
for (int i=0;i<10;i++) {
value = Integer.parseInt(buf.readLine());
stk.push(value);
}
System.out.println("------------------");
while (!stk.empty())
System.out.println("堆栈弹出的元素为:"+stk.pop());
}
}
//依次输入1,2,3...10。
//输出结果:
------------------
堆栈弹出的元素为:10
堆栈弹出的元素为:9
堆栈弹出的元素为:8
堆栈弹出的元素为:7
堆栈弹出的元素为:6
堆栈弹出的元素为:5
堆栈弹出的元素为:4
堆栈弹出的元素为:3
堆栈弹出的元素为:2
堆栈弹出的元素为:1
栈的链表实现
用数组实现堆栈虽然算法简单,但是堆栈本身长度是随时变动的,就不可避免的浪费内存空间,而使用链表来制作堆栈可以随时改变表的长度。
用链表实现堆栈,首先需要定义两个类:
class Node{
int data;
Node next;
public Node(int data){
this.data = data;
this.next = null;
}
}
class stackLink{
public Node front;//栈底
public Node rear; //栈顶
//类方法:判断当前栈是否为空
public boolean isEmpty(){
return front == null;
}
//类方法:加入数据
public void push(int data){
Node newNode = new Node(data);
if (this.isEmpty()){
front = newNode;
rear = newNode;
}else {
rear.next = newNode;
rear = newNode;
}
}
//类方法:删除数据
public void pop() {
Node newNode;
if (this.isEmpty()) {
System.out.println("堆栈是空的,无法删除数据!");
return;
}
newNode = front;
if (newNode==rear) {
front = null;
rear = null;
System.out.println("已将最后一个元素删除,目前为空堆栈!");
}else {
while (newNode.next!=rear)
newNode = newNode.next;
newNode.next = rear.next;
rear = newNode;
}
}
//类方法:打印堆栈数据
public void print() {
Node current = front;
while (current!=null) {
System.out.println("["+current.data+"]");
current = current.next;
}
System.out.println();
}
}
两个类分别是Node
和stackLink
,前者是堆栈中各个数据的链表节点,后者就是堆栈,节点类中包含一个整型数据
和一个指向下一节点的指针
,栈中包含栈顶和栈底两个指针节点以及判断栈是否为空
、压栈
、弹栈
、打印数据
四个方法。
主类如下:
public class StackByLink {
public static void main(String[] args) throws IOException{
stackLink stk = new stackLink();
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int select;
while (true) {
System.out.println("按0结束,按1向堆栈中加入数据,按2在堆栈中弹出数据:");
select = Integer.parseInt(bf.readLine());
if (select == 0)
break;
else if (select == 1) {
System.out.println("请输入想要加入的数据:");
select = Integer.parseInt(bf.readLine());
stk.push(select);
System.out.println("数据加入后堆栈内容:");
stk.print();
}else if (select == 2) {
stk.pop();
System.out.println("数据弹出后堆栈内容:");
stk.print();
}else {
System.out.println("输入有误!");
}
}
}
}
运行程序后,程序进入循环,按0推出程序,按1可以向堆栈中加入数据,按2从堆栈中弹出数据,每次压栈和弹栈后打印栈中现有的数据,大家可以运行程序看看效果。
本文简单介绍了堆栈的一些内容,比较简单但是很有用,由堆栈衍生的问题很多很多,日后再更新一些问题及解决方法。