3.0 栈和队列

3.1 栈

学习总结
        栈(Stack)是一种操作受限的线性表,其插入和删除操作只允许在线性表的一端进行。允许进行操作的一端称为栈顶( top),不允许操作的一端则称为栈底( bottom)。栈的插入操作通常称为入栈(push),栈的删除操作则称为出栈(pop)。如果栈中无数据元素,则称为空栈
        栈就像一个向上开口的箱子,刚开始放入的物体会放置在底部(栈底),继续放置物体时一层一层摞上去,当从箱子里取东西时,最上面(栈顶)的会被最先拿走。因此,栈顶元素是最后入栈、最先出栈,栈底元素则是最先入栈、最后出栈,即栈具有后进先出(LIFO,LastIn First Out)的特征。栈结构如图3-1所示。

        【注意】栈限定的是元素插入和删除操作的位置,元素插入和删除操作进行的时间并未限定。也就是说,出栈可以随时进行,只要出栈的是栈顶元素即可。例如,有3个元素a、b、c按顺序先后入栈并且每个元素只入一次栈,则出栈的次序可以有abc、acb、bac、bca.cba共5种。


 3.1.1 栈的抽象数据类型


        虽然栈的操作受限降低了其灵活性,但也更有效和更容易实现。栈的基本操作主要有创建栈、入栈、出栈、取栈顶元素、判断栈是否为空等。
        栈抽象数据类型的Java接口声明如下:

//栈抽象数据类型,T表示数据元素的数据类型
public interface Stack<T> {
    public void push(T t);        //在栈的顶端插入元素T
    public T pop();                //栈顶元素出栈,返回值为出栈的栈顶元素
    public T peek();                //取栈顶元素,但栈顶元素不出栈
    public boolean isEmpty();        //判断栈是否为空
}

        Java类库中的java.util.Stack类就是栈结构的典型代表。

3.1.2顺序栈


        栈作为一种特殊的线性表,同样可以采用顺序存储结构和链式存储结构。采用顺序存储结构的栈称为顺序栈(Sequential Stack)。
1.顺序栈的存储结构
        顺序栈用一维数组来存储元素,约定数组下标为0的一端表示栈底,则另一端是栈顶,用变量top表示栈顶元素在数组中的位置,通常也把top称为栈顶指针。当栈中有一个元素时,top值为0,因此一般用top=-1表示栈空;设数组的长度为length,当top=length-1时,表示栈满。入栈时,top 加1,指向新的栈顶位置,新元素放置到栈顶;出栈时,先取出栈顶元素,然后 top减1。顺序栈操作示意图如图3-2所示,这里数组的长度为4。

2.顺序栈的基本操作
        定义顺序栈类SeqStack 实现顺序栈接口 Stack,除了实现接口中相应操作方法外,定义泛型数组stack用于存储数据元素,定义变量 length表示栈的初始容量,定义整型变量top表示栈顶指针,指向栈顶元素位置。类 SeqStack 的代码描述如下;

 

//顺序栈类
public class SeqStack<T>implements Stack<T>{

    private T]stack = null;            //声明一维数组,表示顺序栈
    private int length;                //表示顺序栈的容量
    private int top;                    //栈顶指针


    //栈初始化
    public SeqStack(){

        stack=(T[])new 0bject [16];    //构造一维的泛型数组,默认大小为16
        length=16;top = -1;            //栈初始化,栈中没有元素
    
    }
    public SeqStack (int size) {

        stack =(T[])new Object [size];        //构造一维的泛型数组,大小由参数决定

        length=size;top = -1;        //栈初始化,栈中没有元素
    
    }

    //实现栈接口的相关方法//元素入栈
    @override
    public void push(T t){     //判断栈是否已满,如果已满,则抛出异常;如果未满,则元素入栈

       if(top == length -1){
            throw new RuntimeException("栈已经满,元素不能再进栈");
        } else{
            stack[++top]-t;        //栈顶指针先加1,再将元素放入栈顶位置
        }
    }
    //元素出栈
    @override
    public T pop(){        //判断栈是否为空,若为空,则抛出异常;若不空,则元素出栈

        if (this.isEmptyO)){
            throw new RuntimeException("栈为空,没有元素出栈");
        }else {
            return stack[top--];//先将栈顶元素值获取返回,并将栈顶指针减1

    //获取栈顶元素coverride
    public T peek {

        //判断栈是否为空,若为空,则抛出异常;若不空,则返回栈顶元素

        if(this.isEmpty(){
            throw new RuntimeException(”栈为空");
        }else{
                return stack[top]; //直接将栈顶元素值返回
                }
    }

     //判断栈是否为空
    @override
    public boolean isEmpty(){

    //ltop为-1,代表栈中没有元素,为空栈
        return top==-l;
    }
}

3.1.3 链式栈


        栈的另外一种实现方式是采用链表,采用链式存储结构的栈称为链式栈简称为链栈(Linked Stack)

        1.链式栈的存储结构
        链栈一般用单链表实现,由于栈的插入、删除操作只能在一端进行,而对于单链表来说,本身是有头指针的,在头部插入、删除结点要比尾部相对容易,因此将不带头结点的单链表头部作为栈顶,单链表的头指针即为栈顶指针top。

​​​​​​​

        2.链式栈的基本操作
        跟单链表一样,链栈的结点包含数据域和指向下一个结点的指针域。构成链栈的基本结点可以描述如下:

​​​​​​​

public class LinkedNode<T> {
    private T data;
    private LinkedNode next;//构造方法
    public LinkedNode( {
    }
    public LinkedNode (T data){
    this.data =data;
    this.next = null;
    public LinkedNode(T data, LinkedNode<T> next) {
    this.data =data;
    this.next = next;
    )
    //省略相应属性的setter和getter方法
}

 

//链栈类
public class Linkedstack<T> implements stack<T>{
    private LinkedNode<T> top; //代表栈顶指针
    //栈初始化
    public Linkedstack(){
    top=null;
    //将栈顶指针top置空,构造一个空链栈
    }
    //元素入栈override
    public void push(T t){
    //将新结点指向栈顶,再移动栈顶指针指向新结点,新结点成为栈顶元素
    LinkedNode<T> node=new LinkedNode<T>(t);/*使用传递的进栈
    数值,先构造新结点*/
    node . setNext(top);//设置新结点指向栈顶指针top-node;
    //设置栈顶指针指向新结点
    }
    //元素出栈override
    publicT pop( {
    /*判断链栈是否为空,若为空,抛出异常;若不为空,则取栈顶元素的值并
    返回,修改栈顶指针指向下一个结点*/
    if (this.isEmpty(O) {
    throw new RuntimeException(”栈为空,没有元素可出栈");
    }
    TtopData=top.getData(; //获取栈顶元素的值
    //修改栈顶指针,指向下一个结点
    top=top.getNext();
    return topData;
    //获取栈顶元素
    public T peek() {
    /*判断链栈是否为空,若为空,抛出异常;若不为空,则取栈顶元素的值并
    返回*/
    if(this.isEmptyO){
    throw new RuntimeException("栈为空,没有元素可出柱");
    return top.getData();
    //返回栈顶元素的值
    )
    //判断栈是否为空@override
    public boolean isEmpty() {
    if(top==nul1) return true;
    else return false;
    }
}
    

        

 3.2 队列


        队列和栈一样,也是操作受限的线性表。队列(Queue)是插入和删除操作在线性表的两端进行,一端允许插入操作,而另一端只允许删除操作,允许插入的一端称为队尾(Rear),允许删除的另一端则称为队头(Front)。队列的插入操作通常称为入队或进队,删除操作通常称为出队。如果队列中没有元素,则称为空队列。
        由于队列的插入操作在队尾,删除操作在队头,因此最先入队也会最先出队,最后进队的最后出队,即队列
        具有先进先出(FIFO, First In First Out)的特征。队列的结
        构如图所示。

3.2.1队列抽象数据类型

        队列作为一种特殊的线性表,插入和删除操作在两端进行,一般会使用队指针(front)和队尾指针(rear)表示队列操作的两端。队列的基本操作主要有建队列、入队、出队、取队头元素、判断队列是否为空等。
设计队列的抽象数据类型接口 Queue,其中的操作的数据元素用泛型描述代码如下:

//队列抽象数据类型,其中T表示队列中数据的类型
public interface Queue<T>{
    public void enqueue(T t); //元素入队,在队尾插入元素Tpublic T dequeue();
    //元素出队,队头元素出队
    public T peek();
    //取队头元素值,但队头元素不出队
    public boolean isEmpty(); //判断队列是否为空
}

3.2.2 顺序队列


        队列作为特殊的线性表,和栈一样有顺序存储和链式存储两种结构。队列的顺序存储称为顺序队列(Sequential Queue).
1.顺序队列
与顺序表类似,顺序队列用一个一维数组存放元素数据,用两个变量front和rear,分别表示队头和队尾的位置。定义顺序队列类 SeqQueue 实现队列接口Queue,其中成员变量描述如下:

 

public class SeqQueue<T>implements Queue<T>{
    private T[]queue-null;//声明一维数组,存储队列元素
    private int length;     //数组的大小,表示队列的最大容量
   
    private int front;          //表示队头位置
    
    private int rear;           //表示队尾位置
    
    //实现队列接口的相关方法
}

3.2.3 链式队列


        在循环队列中,若队列已满,再有元素入队,就会出现“真溢出”现象,这时队列可用链式结构存储。队列的链式存储称为链式队列,简称链队。
1.链式队列的存储结构
链式队列其实就是单链表,只是操作限制了队尾插入元素,队头删除元素。通常使用带头结点的单链表实现,以使空队列和非空队列操作一致,便于实现。在链队中,需要设置队头(front)和队尾(rear)两个指针,分别指向链队的头结点和尾结点,如图3-15所示。当队头和队尾指针都指向头结点时,表示是一个空队列。

​​​​​​​

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值