3.1_栈_顺序存储结构(数组形式)
【栈的定义】
栈(stack)是限定仅在表尾进行插入和删除操作的线性表。
栈又称为后进先出(Last In First Out)线性表,简称LIFO结构。
(PS:定义中的表尾是指 栈顶!)
【几个关键词 】
[ 栈顶(top) ]
允许插入和删除的一端称为 栈顶。
[ 栈底(bottom) ]
栈顶的另一端称为 栈底。
[ 空栈 ]
不含任何数据元素的栈。
【栈的插入操作——进栈(push)】
栈的插入操作,叫做进栈,也称为压栈、入栈。
【栈的删除操作——出栈(pop)】
栈的删除操作,叫做出栈,也称为弹栈。
【进栈出栈的变化形式】
如果3个整数1,2,3依次入栈,会有哪些出栈次序?
第一种:1-2-3进栈,即3-2-1出栈。
第二种:1进,1出,2斤,2出,3进,3出,进一个出一个,即1-2-3出栈。
第三种:1进,2进,2出,1出,3进,3出,即2-1-3出栈。
第四种:1进,1出,2进,3进,3出,2出,即1-3-2出栈。
第四种:1进,2进,2出,3进,3出,2出,即2-3-1出栈
【栈的抽象数据类型】
ADT 栈(stack)
Data
同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。
Operation
InitStack(*S) 初始化操作,建立一个空栈S
DestoryStack(*S) 若栈存在,则销毁它
ClearStack(*S) 将栈清空
StackEmpty(S) 若栈为空,返回true,否则返回false。
GetTop(S,*e) 若栈S存在且非空,用e返回S的栈顶元素。
Push(*S,e) 若栈S存在,插入新元素e到栈S中并成为栈顶元素。
Pop(*S,*e) 删除栈S中栈顶元素,并用e返回其值。
StackLength(S) 返回栈S的元素个数。
endADT
【自定义的栈MyStack.java】
package com.Higgin.Stack; import java.util.ArrayList; import java.util.Arrays; import java.util.EmptyStackException; public class MyStack { protected Object[] elementData; //栈中具体的对象数组 protected int elementCount; //栈顶指针 protected int capacityIncrement;//当栈满了,每次增长栈的容量 public MyStack(int initialCapacity,int capacityIncrement){ if(initialCapacity<0){ //如果初始化栈的容量小于0,抛出异常 throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } this.elementData=new Object[initialCapacity]; this.capacityIncrement=capacityIncrement; } public MyStack(int initialCapacity){ this(initialCapacity,0); //默认增长的容量为0 } public MyStack(){ this(10); //默认初始栈的容量为10 } /** * 返回栈中的已存的元素个数 */ public int size(){ return elementCount; } /** * 判断是否为空栈 */ public boolean empty(){ return size()==0; } /** * 进栈 */ public Object push(Object obj){ if((elementCount+1)>elementData.length){ //如果再添加一个对象,导致溢出,则扩容(若不想扩容直接抛出异常即可) grow(elementCount+1); //扩容 } elementData[elementCount++]=obj; return obj; } /** * 查看栈顶部的元素,但不从栈中移除它 */ public Object peek(){ int len=size(); if(len==0){ throw new EmptyStackException(); } return elementData[len-1]; } /** * 出栈 */ public Object pop(){ Object obj=peek(); //获取栈顶的对象,里面包含了判断栈是否为空的判断 elementCount--; elementData[elementCount]=null; return obj; } /** * 查找对象的位置 */ public int search(Object obj){ if(size()==0){ //如果是空栈,直接不找 throw new EmptyStackException(); } int i=lastIndexOf(obj); if(i>=0){ return size()-i; } return -1; } /** * 扩容 * (如果再存入数据时,容量不够,就进行扩容) */ public void grow(int minCapacity){ //扩容方法 int oldCapacity=elementData.length; //原来的容量 int newCapacity=oldCapacity+((capacityIncrement>0)?capacityIncrement:oldCapacity); //增长后的新容量:设置过就为 老容量+设置值 ,否则就直接翻倍 if(newCapacity<minCapacity){ //如果新增后的容量依然过小,直接把当前值指针的值传过来(这个应该是容量过大的时候) newCapacity=minCapacity; } if(newCapacity-Integer.MAX_VALUE>8){ if(minCapacity<0){ //说明都溢出了 throw new OutOfMemoryError(); //直接抛出错误 } newCapacity=(minCapacity>(Integer.MAX_VALUE-8)?Integer.MAX_VALUE:(Integer.MAX_VALUE-8)); } elementData=Arrays.copyOf(elementData, newCapacity); //扩容后的elementData } /** * 找出obj对象在 elementData[i]中最后的位置,对于栈而言,其实是离栈顶最近的位置 */ public int lastIndexOf(Object obj){ if(obj==null){ for(int i=elementCount-1;i>=0;i--){ if(elementData[i]==null){ return i; } } }else{ for(int i=elementCount-1;i>=0;i--){ if(obj.equals(elementData[i])){ return i; } } } return -1; } }
【测试】
package com.Higgin.Stack; import org.junit.Test; public class TestMyStack { @Test public void test1(){ MyStack ms=new MyStack(); System.out.println("是否为空==="+ms.empty()); //true ms.push(11); ms.push(22); ms.push(33); System.out.println("最近一次添加的是33==="+ms.peek()); //33 ms.push(44); ms.push(55); System.out.println("最近一次添加的是55==="+ms.peek()); //55 System.out.println("寻找22的位置==="+ms.search(22)); //4 System.out.println("寻找55的位置==="+ms.search(55)); //1 System.out.println("寻找99的位置(不存在)==="+ms.search(99)); //-1 ms.pop(); System.out.println("执行了一次pop,栈顶的元素==="+ms.peek()); //44 System.out.println("栈移除了之后的长度为===="+ms.size()); //4 } }
【运行结果】