数据结构--栈操作

栈的抽象数据类型
  栈是一种用于存储数据的简单数据结构,有点类似链表或者顺序表(统称线性表),栈与线性表的最大区别是数据的存取的操作,我们可以这样认为栈(Stack)是一种特殊的线性表,其插入和删除操作只允许在线性表的一端进行,一般而言,把允许操作的一端称为栈顶(Top),不可操作的一端称为栈底(Bottom),同时把插入元素的操作称为入栈(Push),删除元素的操作称为出栈(Pop)。若栈中没有任何元素,则称为空栈。
  栈只能从栈顶存取元素,同时先进入的元素反而是后出,而栈顶永远指向栈内最顶部的元素。到此可以给出栈的正式定义:栈(Stack)是一种有序特殊的线性表,只能在表的一端(称为栈顶,top,总是指向栈顶元素)执行插入和删除操作,最后插入的元素将第一个被删除,因此栈也称为后进先出(Last In First Out,LIFO)或先进后出(First In Last Out FILO)的线性表。栈的基本操作创建栈,判空,入栈,出栈,获取栈顶元素等,注意栈不支持对指定位置进行删除,插入,其接口Stack声明如下:

public interface Stack<T> {

   /**
    * 栈是否为空
    * @return
    */
   boolean isEmpty();

   /**
    * data元素入栈
    * @param data
    */
   void push(T data);

   /**
    * 返回栈顶元素,未出栈
    * @return
    */
   T peek();

   /**
    * 出栈,返回栈顶元素,同时从栈中移除该元素
    * @return
    */
   T pop();
}


#####  顺序栈的设计与实现:
		顺序栈的内部以顺序表为基础,实现对元素的存取操作,当然我们还可以采用内部数组实现顺序栈,在这里我们使用内部数据组来实现栈,至于以顺序表作为基础的栈实现,将以源码提供:
		

```java
package com.lzh.stack;

import java.io.Serializable;
import java.util.EmptyStackException;
import java.util.Stack;

public class StackTest<T> extends Stack<T> implements  Serializable {
     private static final long serialVersionUID=-5413303117698554397L;

     /*
      *栈顶指针,-1代表空栈
      */

     private int top=-1;

     /*
     容量大小默认为10
      */
     private int capacity=10;

     /*
     存放元素的数组
      */

     private T[] array;

     private int size;

     public StackTest(int capacity){
         array=(T[]) new Object[capacity];
     }

     public StackTest(){
         array=(T[])new Object[this.capacity];
     }

     /*
     获取栈顶元素值,不删除
      */

    @Override
    public synchronized T peek() {
        if (isEmpty()){
            new EmptyStackException();
        }
        return array[top];
    }

    /*
    添加元素,从栈顶(数组尾部)插入
    容量不足时,需要扩容
     */

    @Override
    public T push(T data) {
        //判断容量是否充足
        if (array.length == size){
            ensureCapacity(size*2 +1);
        }
        //从栈顶添加元素
        array[++top]=data;
        size++;
        return data;
    }

    /*
    从栈顶(顺序表尾部)删除
     */
    @Override
    public synchronized T pop() {
         if (isEmpty()){
             new EmptyStackException();
         }
         size--;
         return array[top--];
    }

    @Override
    public synchronized boolean isEmpty() {
        return this.top==-1;
    }

    @Override
    public  int size() {
        return size;
    }

    /*
    扩容的方法
     */
    @Override
    public  void ensureCapacity(int capacity) {
        if (capacity < size){
            return;
        }
        T[] old=array;
        array=(T[])new Object[capacity];
        //复制元素
        for (int i=0;i<size;i++){
            array[i]=old[i];
        }
    }

    public static void main(String[] args) {
        StackTest<String> s=new StackTest<String>();
        //压入栈
        s.push("A");
        s.push("B");
        s.push("C");

        System.out.println("size ->"+s.size);

        int l=s.size(); //size在减少,必须先记录

        for (int i=0;i<l;i++){
            //推出栈
            System.out.println("s.pop->"+s.pop());
            System.out.println("s.peek->"+s.peek());
        }
            //输出栈顶
        System.out.println("s.peek->"+s.peek());
    }
}

链式栈(Linked Stack),就是采用链式存储结构的栈,由于我们操作的是栈顶一端,因此这里采用单链表(不带头结点)作为基础,直接实现栈的添加,获取,删除等主要操作即可。

顺序栈与链式栈中各个操作的算法复杂度(时间和空间)对比,顺序栈复杂度如下:

操作 时间复杂度
SeqStack空间复杂度(用于N次push) O(n)
push()时间复杂度 O(1)
pop()时间复杂度 O(1)
peek()时间复杂度 O(1)
isEmpty()时间复杂度 O(1)
链式栈复杂度如下:

操作 时间复杂度
SeqStack空间复杂度创建(用于N次push) O(n)
push()时间复杂度 O(1)
pop()时间复杂度 O(1)
peek()时间复杂度 O(1)
isEmpty()时间复杂度 O(1)
由此可知栈的主要操作都可以在常数时间内完成,这主要是因为栈只对一端进行操作,而且操作的只是栈顶元素。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带着希望活下去

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值