算法与数据结构—线性表-栈和队列

123 阅读4分钟

栈的定义
  • 栈是一种线性表的特殊表现形式,栈是按照后进后出的原则处理数据;类型结构分为顺序存储结构和链式存储结构;
  • 顺序存储结构的特点——存储线性表的数据元素的方式是一段地址连续的存储单元;
  • 链式存储结构的特点——存储线性表的数据元素的方式是一段地址不连续、任意的存储单元;
  • 存储结构的对比:


栈的基本操作

栈的基本操作只有两个:

  • 入栈(Push):即将数据保存到栈顶。进行该操作前,先修改栈顶指针,使其向上移一个元素位置,然后将数据保存到栈顶指针所指的位置 ;
  • 出栈(Pop):即将栈顶的数据弹出,然后修改栈顶指针,使其指向栈中的下一个元素 

栈的主要操作:

  • 判断栈的状态  boolean empty();
  • 返回栈中元素的数量  int size();
  • 入栈操作 void push(E item);
  • 出栈操作 E pop();
  • 获取栈顶元素 E peek();

栈的实现

栈的实现方式有两种,一种是基于数组实现,一种是基于链表实现;

public interface Stack<E>  {

    //判断栈是否为空
    public boolean empty();

    //返回栈中元素数量
    public int size();

    //压栈
    public void push(E item);

    //弹栈
    public E pop();

    //查看栈顶元素(不弹栈)
    public E peek();
}

1:基于数组实现

import java.util.Arrays;
import java.util.EmptyStackException;

public class ArrayStack<E> implements Stack<E> {

    private final static int DEFAULT_CAPACITY = 10;

    private E[] data;

    private int size;

    private int top; //栈顶索引

    public ArrayStack(int capacity) {
        this.data = (E[]) new Object[capacity];
        this.size = 0;
        this.top = -1;
    }

    public ArrayStack(){
        this(DEFAULT_CAPACITY);
    }


    @Override
    public boolean empty() {
        return size == 0;
    }

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

    @Override
    public void push(E item) {
        if(data.length == size) {
            grow(data.length*2);
        }
        data[++top] = item;
        size++;
    }

    private void grow(int capacity) {
        if(capacity <= DEFAULT_CAPACITY){
            return;
        }
        data = Arrays.copyOf(data, capacity);
    }

    @Override
    public E pop() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        if(size < data.length/2) {
            grow(data.length/2);
        }
        size--;
        return data[top--];
    }

    @Override
    public E peek() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        return data[top];
    }

    public static void main(String [] args){
        Stack<Integer> stack = new ArrayStack();
        for(int i=0; i<100; i++){
            stack.push(i+1);
        }
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());

        int size = stack.size();
        for(int i=0; i<size; i++){
            System.out.println("The element is: " + stack.pop());
        }
    }
}

2:基于链表实现

import java.util.Arrays;
import java.util.EmptyStackException;

public class LinkedStack<E> implements Stack<E> {
    private static class  Node<E>{
        public E data;
        public Node<E> next;
        public Node(E val, Node<E> next) {
            this.data = val;
            this.next = next;
        }
    }

    private Node<E> top;

    private int size;

    public  LinkedStack(){
        this.top = null;
        this.size = 0;
    }

    @Override
    public boolean empty() {
        return size == 0;
    }

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

    @Override
    public void push(E item) {
        top = new Node(item, top);
        size++;
    }

    @Override
    public E pop() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        E result = top.data;
        top = top.next;
        size--;
        return result;
    }

    @Override
    public E peek() {
        if(size == 0) {
            throw new EmptyStackException();
        }
        return top.data;
    }

    public static void main(String [] args){
        Stack<Integer> stack = new LinkedStack();
        for(int i=0; i<100; i++){
            stack.push(i+1);
        }
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());

        int size = stack.size();
        for(int i=0; i<size; i++){
            System.out.println("The element is: " + stack.pop());
        }
    }
}
栈的应用

利用栈求算术表达式的值,中缀表达式转后缀表达式求解算法表达式?求后缀表达式的值?

队列

队列的定义

队列是一种特殊的线性表,特点是先进先出;其结构也分为链式存储结构和顺序存储结构;


  • 只允许在表的前端进行删除操作,而在表的后端进行插入操作;

  • 进行插入操作的端称为队尾;

  • 进行删除操作的端称为队头; 

存储结构对比

即,顺序存储结构(循环队列)和链式存储结构(链队列)对比


队列的实现

队列的实现方式有两种,一种是基于数组实现,一种是基于链表实现;

public interface Queue<E> {

    //返回队列元素数量
    public int size();

    //队列是否为空
    public boolean empty();

    //入队
    public void enqueue(E e);

    //出队
    public E dequeue();

    //查看队首元素
    public E peek();
}

1:基于数组实现

import java.util.Arrays;

public class ArrayQueue<E> implements Queue<E> {

    private static final int DEFAULT_CAPACITY = 10;

    private E[] data;

    private int size;

    private int head;

    private int tail;

    public  ArrayQueue(int capacity) {
        this.data = (E[]) new Object[capacity];
        this.size = 0;
        this.head = -1;
        this.tail = -1;
    }

    public ArrayQueue() {
        this(DEFAULT_CAPACITY);
    }

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

    @Override
    public boolean empty() {
        return size == 0;
    }

    @Override
    public void enqueue(E e) {
        if(data.length == size) {
            grow(data.length*2);
        }
        tail = (tail + 1) % data.length;
        data[tail] = e;
        if(size == 0){
            head = tail;
        }
        size++;
    }

    private void grow(int capacity) {
        if(capacity <= DEFAULT_CAPACITY) {
            return;
        }
        E[] oldData = data;
        data = (E[]) new Object[capacity];
        for(int i=0; i<size; i++) {
            data[i] = oldData[(head+i)%oldData.length];
        }
        head = 0;
        tail = size - 1;
    }

    @Override
    public E dequeue() {
        if(size == 0) {
            throw new RuntimeException("队列为空...");
        }
        E result = data[head];
        head = (head + 1) % data.length;
        size--;
        if(size < data.length/2) {
            grow(data.length/2);
        }
        return result;
    }

    @Override
    public E peek() {
        if(size == 0) {
            throw new RuntimeException("队列为空...");
        }
        return data[head];
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new ArrayQueue<>();
        for(int i=0; i<100; i++) {
            queue.enqueue(i+1);
        }
        int size = queue.size();

        for(int i=0; i<size; i++){
            System.out.println("The element is: " + queue.dequeue());
        }
    }
}

2:基于链表实现

public class LinkedQueue<E> implements Queue<E> {

    private static class Node<E> {
        private E data;
        private Node<E> next;
        public Node(E val, Node<E> next) {
            this.data = val;
            this.next = next;
        }
    }

    private Node<E> head;
    private Node<E> tail;

    private int size;

    public LinkedQueue() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }

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

    @Override
    public boolean empty() {
        return size == 0;
    }

    @Override
    public void enqueue(E e) {
        Node<E> prev = tail;
        tail = new Node(e, null);
        if(size == 0) {
            head = tail;
        }else{
            prev.next = tail;
        }
        size++;
    }

    @Override
    public E dequeue() {
        if(size == 0) {
            throw new RuntimeException("队列为空...");
        }
        E result = head.data;
        head = head.next;
        size--;
        if(size == 0) {
            tail = null;
        }
        return result;
    }

    @Override
    public E peek() {
        if(size == 0) {
            throw new RuntimeException("队列为空...");
        }
        return head.data;
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedQueue<>();
        for(int i=0; i<100; i++) {
            queue.enqueue(i+1);
        }
        int size = queue.size();
        for(int i=0; i<size; i++){
            System.out.println("The element is: " + queue.dequeue());
        }
    }
}