数据结构之栈和队列

目录

1、栈(Stack)

1.1 概念

1.2 代码实现

2. 队列(Queue)

2.1 概念

2.2 代码实现

2.3 循环队列

2.3.1 思路解析  

2.3.2 代码实现

3. 双端队列 (Deque)

3.1 概念

3.2 代码实现


1、栈(Stack)

1.1 概念

栈栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。                                                                                                                                          入栈 push:栈的插入操作叫做进栈/压栈/入栈,入栈数据在栈顶。                                                出栈 pop:栈的删除操作叫做出栈。出栈数据在栈顶

数据结构之栈和队列_第1张图片

 数据结构之栈和队列_第2张图片

1.2 代码实现

1. 利用顺序表实现,即使用尾插 + 尾删的方式实现                                                                         2. 利用链表实现,则头尾皆可

相对来说,顺序表的实现上要更为简单一些,所以我们优先用顺序表实现栈。

package stack_queue.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

//基于数组的顺序表实现 栈
public class MyStack {
    //当前栈的数据个数
    private int size;
    //实际存储数据的动态数组 - ArrayList
    private List data = new ArrayList<>();

    /**
     * 将val入栈
     * @param val
     */
    public void push(E val){
        //默认尾插
        data.add(val);
        size++;
    }

    /**
     * 弹出栈顶元素
     * 返回栈顶的值
     * @return
     */
    public E pop(){
        if (isEmpty()){
            //栈为空
            throw new NoSuchElementException("stack is empty!cannot pop!");
        }
        //删除栈顶元素
        E val = data.remove(size - 1);
        size--;
        return val;
        //等同于 return data.remove(--size);
    }

    /**
     * 返回栈顶元素但不出栈
     * @return
     */
    public E peek(){
        if (isEmpty()){
            throw new NoSuchElementException("stack is empty!cannot peek");
        }
        return data.get(size-1);
    }

    /**
     * 判断当前栈是否为空
     * @return
     */
    private boolean isEmpty() {
        return size == 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(data.get(i));
            if (i!=size-1){
                //此时还未到栈顶,还没到数组末尾
                sb.append(",");
            }
        }
        sb.append("] top");
        return sb.toString();
    }
}

2. 队列(Queue)

2.1 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头 (Head/Front)

数据结构之栈和队列_第3张图片

 数据结构之栈和队列_第4张图片

2.2 代码实现

package stack_queue.queue.impl;

import java.util.NoSuchElementException;

/**
 * 基于链表实现的基础队列
 */
public class MyQueue implements Queue {
    //链表的每个节点
    private class Node{
        E val;
        Node next;
        public Node(E val){
            this.val = val;
        }
    }

    //当前队列中的元素个数
    private int size;
    //队首
    private Node head;
    //队尾
    private Node tail;

    //入队
    @Override
    public void offer(E val) {
        Node node = new Node(val);
        if (head == null){
            //此时链表为空
            head = tail = node;
        }else {
            tail.next = node;
            tail = node;
        }
        size++;
    }

    //出队
    @Override
    public E poll() {
        if (isEmpty()){
            throw new NoSuchElementException("queue is empty!cannot poll!");
        }
        E val = head.val;
        Node node = head;
        head = head.next;
        //将原来头节点脱钩
        node.next = null;
        size--;
        return val;
    }

    //返回队首元素
    @Override
    public E peek() {
        if (isEmpty()){
            throw new NoSuchElementException("queue is empty!cannot peek!");
        }
        return head.val;
    }
 
    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        //链表的遍历
        for (Node x =head; x != null;x = x.next){
            sb.append(x.val);
            if (x.next != null){
                //还没走到链表尾部
                sb.append(",");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}

2.3 循环队列

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。 环形队列通常使用数组实现。

数据结构之栈和队列_第5张图片

数组下标循环的小技巧

1. 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length

数据结构之栈和队列_第6张图片

 2. 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length

数据结构之栈和队列_第7张图片

2.3.1 思路解析  

数据结构之栈和队列_第8张图片

2.3.2 代码实现

package stack_queue.queue.impl;

import java.util.Arrays;
import java.util.NoSuchElementException;

//基于整形的循环队列
public class LoopQueue implements Queue {
    private Integer[] data;
    //指向当前循环队列的队首元素
    private int head;
    //指向当前循环队列的队尾元素的下一个位置
    private int tail;
    //当前队列中元素个数
    private int size;
    //n为希望保存的元素个数
    public LoopQueue(int n){
        //在循环队列中浪费一个空间不能存储元素,来判断是否已满
        data = new Integer[n + 1];
    }
    
    @Override
    public void offer(Integer val) {
        if (isFull()){
            throw new ArrayIndexOutOfBoundsException("queue is full!cannot offer new val");
        }
        data[tail] = val;
        tail = (tail + 1) % data.length;
        size++;
    }

    @Override
    public Integer poll() {
        if (isEmpty()){
            throw new NoSuchElementException("queue is empty!cannot poll");
        }
        Integer val = data[head];
        head = (head + 1) % data.length;
        size--;
        return val;
    }

    @Override
    public Integer peek() {
        if (isEmpty()){
            throw new NoSuchElementException("queue is empty!cannot peek");
        }
        return data[head];
    }

    @Override
    public boolean isEmpty() {
        return tail == head;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        //取得最后一个元素下标
        int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
        for (int i = head;i != tail;){
            sb.append(data[i]);
            if (i!=lastIndex){
                sb.append(", ");
            }
            i = (i + 1) % data.length;
        }
        sb.append("] tail");
        return sb.toString();
    }

    public boolean isFull(){
        return (tail + 1) % data.length == head;
    }
}

3. 双端队列 (Deque)

3.1 概念

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

3.2 代码实现

package stack_queue.queue;

import java.util.ArrayDeque;
import java.util.Deque;

//双端队列
public class DequeTest {
    public static void main(String[] args) {
        Deque deque = new ArrayDeque<>();
        deque.addLast(1);
        deque.addLast(3);
        deque.addLast(5);
        //尾插尾删或者头插头删就是栈
        while (!deque.isEmpty()){
            System.out.println(deque.pollLast());//5  3  1
        }

//        //头插尾删或者尾插头删就是队列
//        while (!deque.isEmpty()){
//            System.out.println(deque.pollFirst());//1  3  5
//        }

    }
}

本节完^_^

你可能感兴趣的:(笔记,数据结构,链表)