一、概述:
栈(stack):栈是一种线性的结构,这种数据结构仅限在线程表的一段进行插入和删除操作。其中线性表插入的和删除的一段称为栈顶(top),不循序插入和删除的一段称为栈底(bottom)。所以栈数据结构是遵循“后入先出”,也就是“LIFO”。
二、栈的特征
(1)栈也是一种线性的机构。
(2)相比较数组,占对应的操作是数组的子集。
(3)只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶。
(4)栈是一种后进先出的数据结构。称为:Liast In First Out(LIFO)
三、栈的应用:
(1)无处不在的Undo操作(撤销)。
(2)程序调用的系统栈。

(3)括号匹配-编译器

通过java.util.Stack来实现一个括号匹配器:
public class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for(int i=0; i< s.length();i++){
char c = s.charAt(i);
if(c == '(' || c == '[' || c == '{')
stack.push(c);
else{
if(stack.isEmpty())
return false;
char topChar = stack.pop();
if(c == ')' && topChar != '(')
return false;
if(c == ']' && topChar != '[')
return false;
if(c == '}' && topChar != '{')
return false;
}
}
return stack.isEmpty();
}
public static void main(String[] args) {
System.out.println((new Solution()).isValid("()[]{}"));
System.out.println((new Solution()).isValid("()[]{]}"));
}
}
java.util.Stack这个栈数据结构得底层是通过java.util.Vector实现的,Stack继承了Vector,而Vector和ArrayList一样实现了List接口,Vector和ArrayList是实现原理上是非常相似的,它们都是通过数组实现的,不过与ArrayList不同的是,Vector支持线程的同步,即某一个时刻只有一个线程能够操作Vector,避免了多线程同时引起的不一致性,它的同步是通过synchronized实现的,同步需要很高的花费,访问它要比访问ArrayList要慢;Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。
四、栈的实现:
(一) 通过自定义ArrayList封装一个栈数据结构:
1、定义Stack接口:
public interface Stack<E> {
//查看栈元素的数量
int getSize();
//查看栈元素是否为空;
boolean isEmpty();
//压栈
void push(E e);
//弹出
E pop();
//查看栈顶元素
E peek();
}
2、创建自定义ArrayList
public class CustomArray<E> {
//private int[] data;
private E[] data;
private int size;
//构造函数,出入数组的容量capocity构造CustomArray
public CustomArray(int capacity){
//data = new int[capacity];
/**
* java语言中不支持泛型语法,因为泛型是java在1.5之后引入的,这是一个历史
* 遗留问题。所以我们在声明泛型类数组的时候,要有用一个折中的方案现用Object
* 声明一个数组,再强转为泛型类型(E[])
* */
data = (E[])new Object[capacity];
size = 0;
}
public CustomArray(){
this(10);
}
// 获取数组中的元素个数
public int getSize(){
return size;
}
// 获取数组的容量
public int getCapacity(){
return data.length;
}
//返回数组是否为空
public boolean isEmpty(){
return size == 0;
}
// 想所有的元素后添加一个新的元素
public void addLast(E e){
if(size == data.length){
//throw new IllegalArgumentException("AddLast failed.CustomArray is full.");
resize(2 * data.length);
}
data[size] = e;
size ++;
}
public void addLastPuls(E e){
add(size,e);
}
public void addFirst(E e){
add(0,e);
}
// 在第index个位置插入一个新的元素e
public void add(int index,E e){
if(size == data.length)
//throw new IllegalArgumentException("Add failed.Array is full.");
resize(2 * data.length);
if(index < 0 || index > size){
throw new IllegalArgumentException("Add failed.Require index >= 0 and index <= size");
}
for(int i = size - 1;i >= index; i--){
data[i+1] = data[i];
}
data[index] = e;
size ++;
}
// 获取index索引位置的元素
public E get(int index){
if(index<0 || index>=size)
throw new IllegalArgumentException("Get failed.Index is illegal.");
return data[index];
}
// 修改index索引位置的元素为e
public void set(int index, E e){
if(index<0 || index>=size)
throw new IllegalArgumentException("Get failed.Index is illegal.");
data[index] = e;
}
// 查看数组中是否有元素e
public boolean contains(E e) {
for (int i = 0; i < size; i++){
if (data[i].equals(e))
return true;
}
return false;
}
// 查询数组中元素e所在的索引,如果不存在元素e,则返回-1
public int find(E e){
for (int i = 0; i < size; i++){
if (data[i].equals(e))
return i;
}
return -1;
}
public E remove(int index){
if(index<0 || index>=size)
throw new 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 object
if(size == data.length/4 && data.length / 2 != 0)
resize(data.length / 2);
return ret;
}
// 从数组中删除第一个元素,返回参数的元素
public E removeFirst(){
return remove(0);
}
// 从数组中删除最后一个袁术,返回删除的元素
public E removeLast(){
return remove(size - 1);
}
public void removeElement(E e){
int index = find(e);
if(index != -1){
remove(index);
}
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append(String.format("Array:size = %d , capadity = %d\n",size,data.length));
res.append('[');
for(int i = 0;i < size; i++){
res.append(data[i]);
if(i != size - 1){
res.append(", ");
}
}
res.append(']');
return res.toString();
}
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 E getLast(){
return get(size-1);
}
public E getFirst(){
return get(0);
}
}
3、自定义Stack实现类:
public class ArrayStack<E> implements Stack<E> {
CustomArray<E> array;
public ArrayStack(int capacity){
array = new CustomArray<>(capacity);
}
public ArrayStack(){
array = new CustomArray<>();
}
@Override
public int getSize(){
return array.getSize();
}
@Override
public boolean isEmpty(){
return array.isEmpty();
}
public int getCapacity(){
return array.getCapacity();
}
@Override
public void push(E e){
array.addLast(e);
}
@Override
public E pop(){
return array.removeLast();
}
@Override
public E peek(){
return array.getLast();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Stack:");
res.append('[');
for(int i = 0; i<array.getSize(); i++){
res.append(array.get(i));
if(i != array.getSize() - 1){
res.append(", ");
}
}
res.append("] top");
return res.toString();
}
}
4、自定义测试类
public class StackTest {
public static void main(String [] args){
ArrayStack<Integer> stack = new ArrayStack<>();
for(int i=0; i<5; i++){
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
(二) 通过自定义LinkedList封装一个栈数据结构:
1、定义Stack接口:
public interface Stack<E> {
//查看栈元素的数量
int getSize();
//查看栈元素是否为空;
boolean isEmpty();
//压栈
void push(E e);
//弹出
E pop();
//查看栈顶元素
E peek();
}
2、实现一个自定义的LinkedList类:
public class CustomLinkedList<E> {
/**
* 将节点的设置成私有的内部类,也就是只有在链表这个数据结构内
* 可以被访问到。在链表这个结构外用户是无法访问到这个节点类(Node.class)的。
* 针对外部的用户屏蔽底层的实现细节;
* */
private class Node{
public E e;
public Node next;
public Node(E e, Node next){
this.e = e;
this.next = next;
}
public Node(E e){
this(e,null);
}
public Node(){
this(null,null);
}
@Override
public String toString(){
return e.toString();
}
}
//private Node head;
private Node dummyHead;
int size;
public CustomLinkedList(){
//head = null;
//设置唯一的虚拟头节点
dummyHead = new Node(null,null);
size = 0;
}
// 获取链表中的元素个数;
public int getSize(){
return size;
}
// 返回链表是否为空
public boolean isEmpty(){
return size == 0;
}
// 在链表头添加新的元素e
public void addFirst(E e){
/*
Node node = new Node(e);
node.next = head;
head = node;
*/
//head = new Node(e,head);
add(0,e);//设置虚拟节点版本
//size ++;
}
/**
* 在链表的index(0-based)位置添加新的元素e
* 在链表中不是一个常用操作
* */
public void add(int index,E e){
if(index < 0 || index > size)
throw new IllegalArgumentException("Add failed. Illegal index.");
/*
if(index == 0)
addFirst(e);
else{
Node prev = head;
for(int i = 0; i < index -1; i++)
prev = prev.next;
// Node node = new Node(e);
// node.next = prev.next;
// prev.next = node;
prev.next = new Node(e,prev.next);
size ++;
}
*/
//设置虚拟节点头
Node prev = dummyHead;
for(int i = 0; i < index; i++)
prev = prev.next;
prev.next = new Node(e,prev.next);
size ++;
}
// 在链表末尾添加新的元素e
public void addList(E e){
add(size,e);
}
//获得链表的第index(0-based)个位置的元素
//在链表中不是一个常用的操作
public E get(int index){
if(index < 0 || index >= size){
throw new IllegalArgumentException("Get Failed.Illegal index.");
}
Node cur = dummyHead.next;
for(int i=0; i<index;i++)
cur = cur.next;
return cur.e;
}
//获取链表的第一个元素
public E getFirst(){
return get(0);
}
// 获得链表的最后一个元素
public E getLast(){
return get(size-1);
}
//修改链表的第index(0-based)哥位置的元素为e
//在链表中不是一个常用的操作
public void set(int index,E e){
if(index < 0 || index >= size){
throw new IllegalArgumentException("Update Failed.Illegal index.");
}
Node cur = dummyHead.next;
for(int i=0; i<index; i++)
cur = cur.next;
cur.e = e;
}
//查找链表中是否有元素e
public boolean contains(E e){
Node cur = dummyHead.next;
while(cur != null){
if(cur.e.equals(e)){
return true;
}
cur = cur.next;
}
return false;
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
/*
Node cur = dummyHead.next;
while(cur != null){
res.append(cur + "->");
cur = cur.next;
}*/
for(Node cur =dummyHead.next; cur != null; cur =cur.next){
res.append(cur + "->");
}
res.append("NULL");
return res.toString();
}
//从链表中删除index(0-based)位置的元素,返回参数的元素
//在链表中不是一个常用的操作
public E remove(int index){
if(index<0 || index >= size)
throw new IllegalArgumentException("Remove failed.Index is illegal");
Node prev = dummyHead;
for(int i=0;i<index;i++)
prev = prev.next;
Node retNode = prev.next;
prev.next = retNode.next;
size --;
return retNode.e;
}
// 从链表中删除第一个元素,返回删除的元素
public E removeFirst(){
return remove(0);
}
// 从链表中删除最后一个元素,返回删除的元素
public E removeLast(){
return remove(size-1);
}
}
3、自定义Stack实现类:
public class LinkedListStack<E> implements Stack<E> {
private CustomLinkedList<E> list;
public LinkedListStack(){
list = new CustomLinkedList<>();
}
@Override
public int getSize(){
return list.getSize();
}
@Override
public boolean isEmpty(){
return list.isEmpty();
}
@Override
public void push(E e){
list.addFirst(e);
}
@Override
public E pop(){
return list.removeFirst();
}
@Override
public E peek(){
return list.getFirst();
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append("Stack:top");
res.append(list);
return res.toString();
}
}
4、自定义测试类:
public class StackTest {
public static void main(String [] args){
LinkedListStack<Integer> stack = new LinkedListStack<>();
for(int i=0; i<5; i++){
stack.push(i);
System.out.println(stack);
}
stack.pop();
System.out.println(stack);
}
}
本文介绍了栈(Stack)的基本概念、特征,如后进先出(LIFO)的性质,以及栈在撤销操作、程序调用和括号匹配等场景中的应用。还探讨了如何通过Java的`java.util.Stack`以及自定义`ArrayList`和`LinkedList`实现栈数据结构。
551

被折叠的 条评论
为什么被折叠?



