数据结构与算法之美-05 |栈

一、什么是栈?

栈是一种“操作受限”的线性表,只允许在一端插入和删除数据,后进者先出,先进者后出。
无论是数组或者是链表都可以实现栈的功能,栈只是一种特性的数据结构,可以理解为封装好的数组或者是封装好的链表。
当某个数据集合只涉及在一端插入和删除数据,并且满足后进先出、先进后出的特性,这时我们就应该首选“栈”这种数据结构。

二、实现栈

栈的主要操作是入栈和出栈,入栈和出栈,也就是在栈顶插入一个数据和从栈顶删除一个数据。
实际上,栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,我们叫作顺序栈,用链表实现的栈,我们叫作链式栈

一.顺序栈的实现(由数组封装)

这段代码是大佬自己写的,我参考一下,并写一个自己的顺序栈,链式栈的我自己写。

//大佬的代码
// 基于数组实现的顺序栈
public class ArrayStack {
   
     
  private String[] items;  // 数组
  private int count;       // 栈中元素个数
  private int n;           //栈的大小

  // 初始化数组,申请一个大小为n的数组空间
  public ArrayStack(int n) {
   
     
    this.items = new String[n];
    this.n = n;
    this.count = 0;
  }

  // 入栈操作
  public boolean push(String item) {
   
     
    // 数组空间不够了,直接返回false,入栈失败。
    if (count == n) return false;
    // 将item放到下标为count的位置,并且count加一
    items[count] = item;
    ++count;
    return true;
  }
  
  // 出栈操作
  public String pop() {
   
     
    // 栈为空,则直接返回null
    if (count == 0) return null;
    // 返回下标为count-1的数组元素,并且栈中元素个数count减一
    String tmp = items[count-1];
    --count;
    return tmp;
  }
}

//我自己的代码
package stackdemo;

public interface Stack<T> {
   
     

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

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

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

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

}

package stackdemo;

import java.io.Serializable;

public class ArrayStack<T> implements Stack<T>, Serializable {
   
     

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

    /**
     * 存放元素的数组
     */
    private T[] array;

    /**
     * 栈内元素个数
     */
    private int stackSize;
    /**
     * 带参构造
     */
    public ArrayStack(int defaultLength) {
   
     

        array = (T[]) new Object[defaultLength];
    }
    /**
     * 无参构造
     */
    public ArrayStack() {
   
     
        array = (T[]) new Object[defaultLength];
    }

    /**
     * 栈是否为空
     */
    @Override
    public boolean isEmpty() {
   
     
        if (stackSize == 0)
            return true;
        return false;
    }

    /**
     * 入栈
     */
    @Override
    public boolean push(T data) {
   
     
    //这里可以设置为自动扩容
        if (stackSize == defaultLength) {
   
     
            return false;
        }
        array[stackSize]=data;
        stackSize++;
        return true;

    }

    /**
     * 返回栈顶元素
     */
    @Override
    public T peek() {
   
     
        if (stackSize == 0) {
   
     
            return null;
        } else {
   
     
            T t = array[stackSize - 1];
            return t;
        }
    }

    /**
     * 出栈
     */
    @Override
    public T pop() {
   
     
        if (stackSize == 0) {
   
     
            return null;
        } else {
   
     
            T t = array[stackSize-1];
            array[stackSize - 1] = null;
            stackSize--;
            return t;
        }
    }
}

package stackdemo;

/**
 * 测试
 */
public class ArrayStackTest {
   
     
    public static void main(String[] args) {
   
     
        ArrayStack<String> arrayStack=new ArrayStack<String>();
        System.out.println(arrayStack.isEmpty());
        System.out.println(arrayStack.push("1234567"));
        System.out.println(arrayStack.isEmpty());
        System.out.println(arrayStack.peek());
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.isEmpty());
    }
}

执行结果
 

二.链式栈的实现(由链表封装)

package stackdemo;

import java.io.Serializable;
import java.util.LinkedList;

public class ListStack<T> implements Stack<T>, Serializable {
   
     
    private LinkedList<T> linkedList;
    private int listSize;

    public ListStack() {
   
     
        linkedList=new LinkedList<T>();
    }
    
    @Override
    public boolean isEmpty() {
   
     
        if (linkedList.isEmpty())
            return true;
        return false;
    }

    @Override
    public boolean push(T data) {
   
     
        //add加在尾部,push加在头部
        linkedList.add(data);
        listSize++;
        return true;
    }

    @Override
    public T peek() {
   
     
        if (linkedList.isEmpty())
            return null;
        return linkedList.get(listSize - 1);
    }

    @Override
    public T pop() {
   
     
        if (linkedList.isEmpty())
            return null;
        T t = linkedList.remove(listSize - 1);
        listSize--;
        return t;
    }
}
package stackdemo;

/**
 * 测试
 */
public class ArrayStackTest {
   
     
    public static void main(String[] args) {
   
     
//        ArrayStack<String> arrayStack=new ArrayStack<String>();
//        System.out.println(arrayStack.isEmpty());
//        System.out.println(arrayStack.push("1234567"));
//        System.out.println(arrayStack.isEmpty());
//        System.out.println(arrayStack.peek());
//        System.out.println(arrayStack.pop());
//        System.out.println(arrayStack.isEmpty());
        ListStack<String> listStack = new ListStack<String>();
        System.out.println(listStack.isEmpty());
        System.out.println(listStack.push("1234567"));
        System.out.println(listStack.isEmpty());
        System.out.println(listStack.peek());
        System.out.println(listStack.pop());
        System.out.println(listStack.isEmpty());

    }
}

执行结果:
 

三、栈的应用

四、数据结构堆栈和内存中的堆栈的区别

内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构。
内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区。
代码区:存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换。
静态数据区:存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系统自动分配和回收。
栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。
堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: