全网最全栈和队列介绍

本文详细介绍了数据结构中的栈和队列的基本概念、特性以及它们的实现方式,包括基于数组和链表的实现。此外,还探讨了循环队列的条件和操作,并提供了具体的代码实现。最后,提到了双端队列Deque这一能够从两端进行操作的数据结构。这些基础知识对于理解高级数据结构和算法设计至关重要。
摘要由CSDN通过智能技术生成

目录

1.栈(Stack)

2.队列(Queue)

循环队列:

 双端队列Deque(是一个接口,它的一个重要子类LinkedList)


1.栈(Stack)

定义:   一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO Last In First Out )的原则。
压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
出栈:栈的删除操作叫做出栈。 出数据在栈顶
核心操作:
            pop():移除栈顶元素
            peek():查看栈顶元素但不删除
            push():向栈中添加元素
栈的底层实现由两种:
            基于数组的实现-顺序栈
            基于链表的实现-链式栈
一般来说,顺序栈的实现较为简单。
实现代码如下:
package stack_queue.stack;

import java.util.NoSuchElementException;

public class Stack<E> {
    private E[] elementData;
    //当前栈中元素个数
    private int size;
    public Stack(){
        elementData = (E[]) new Object[10];
        size = 0;

    }
    public Stack(int initCap){
        elementData = (E[]) new Object[initCap];
    }
    //入栈操作
    public void push(E value){
        elementData[size ++] = value;
    }
    //出栈操作,返回原先的栈顶元素
    public E pop(){
        if (getSize() == 0){
            //当前栈为空
            throw new NoSuchElementException("栈为空");
        }
        E oldValue = elementData[size-1];
        size--;
        elementData[size] = null;
        return oldValue;

    }
    //查看栈顶元素但不出栈
    public E peek(){
        if (getSize() == 0){
            throw new NoSuchElementException("栈为空");
        }
        return elementData[size-1];

    }
    public int getSize(){
        return size;
    }
    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < size; i++) {
            sb.append(elementData[i]);
            if (i != size - 1){
                sb.append(",");
            }

        }
        sb.append("] top");
        return sb.toString();
    }

}
package stack_queue.stack;

public class StackTest {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(3);
        stack.push(5);
        //[1,3,5]top
        System.out.println(stack);
        //5
        System.out.println(stack.peek());
        stack.pop();
        //[1,3]top
        System.out.println(stack);
    }
}

2.队列(Queue)

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

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低(即每次出队后都需要进行数组元素的搬移操作,非常耗时)。
基于链表的实现:
代码如下:
package stack_queue.queue;

public class QueueTest {
    public static void main(String[] args) {
        Queue queue = new LinkedQueue();
        queue.offer(1);
        queue.offer(3);
        queue.offer(5);
        //front[1,3,5] tail
        System.out.println(queue);
        queue.poll();
        System.out.println(queue);

    }
}
package stack_queue.queue;

import java.util.NoSuchElementException;

//给予链表的队列
//队首进队尾出
public class LinkedQueue implements Queue {
    private Node head;
    private Node tail;
    private int size;
    private class Node{
        private int data;
        private Node next;

        public Node(int data){
            this.data = data;
        }
    }

    /**
     * 入队操作
     * @param value
     */
    @Override
    public void offer(int value) {
        Node node = new Node(value);
        if(head == null){
            head = tail = node;
        }else {
            tail.next = node;
            tail = node;
        }
        size++;
    }

    @Override
    public int poll() {
        if (size == 0){
            throw new NoSuchElementException("队列为空!");
        }
        int oldValue = head.data;
        Node tmpHead = head;
        head = head.next;
        tmpHead.next = null;
        size--;
        return oldValue;
    }

    @Override
    public int peek() {
        if (size == 0){
            throw new NoSuchElementException("队列为空!");
        }
        return head.data;
    }
    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        Node node = head;
        while (node != null){
            sb.append(node.data);
            if (node.next != null){
                sb.append(",");
            }
            node = node.next;
        }
        sb.append("] tail");
        return sb.toString();
        
    }
}

循环队列:

条件:①front指向循环队列的第一个元素索引

          ②tail永远指向循环队列的最后一个元素的下一个位置arr[tail] = x;

          ③当front == tail时循环队列为空

          ④当tail + 1 == front时,循环队列为满(设定在循环队列中浪费一个空间,这个空间不能存储元素,这是判断满和空的区别)

          ⑤每次front和tail添加或者删除元素后向后移动,(front + 1) % data.length; (tail + 1) % data.length

注意:驱魔的核心是当走到数组末尾时,据需从头开始入队和出队。

 循环队列代码的实现:

package stack_queue.queue;

public class LoopQueue implements Queue{
    private int[] data;
    //有效元素个数
    private int size;
    //指向队首元素下标
    private int front;
    //指向队尾元素的下一个位置下标
    private int tail;

    public LoopQueue(int k){
        data = new int[k + 1];
    }
    @Override
    public void offer(int value) {
        //判断队列是否已满
        if (isFull()){
            //队列已满
            System.err.println("queue is full!");
            return;
        }
        data[tail] = value;
        tail = (tail + 1) % data.length;
        size++;
    }

    @Override
    public int poll() {
        //判断队列是否为空
        if (isEmpty()){
            System.err.println("queue is empty!");
            return -1;
        }
        int value = data[front];
        front = (front + 1) % data.length;
        size--;
        return value;
    }

    @Override
    public int peek() {
        if (isEmpty()){
            System.err.println("queue is empty!");
            return -1;
        }

            return data[front];
    }
    public int getTail(){
        if (isEmpty()) {
            System.err.println("queue is empty!");
            return -1;
        }
        //最后一个元素的下标
        int index = tail == 0 ? data.length - 1 : tail - 1;
        return data[index];
    }
    public boolean isFull(){
        if ((tail + 1) % data.length == front)
            return true;
        return false;
    }
    public boolean isEmpty(){
        return tail == front;
    }
    public int getSize() {
        return size;
    }
    //遍历循环队列
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("front [");
        //取得最后一个元素的索引
        int lastIndex = tail == 0 ? data.length - 1: tail - 1;
        //遍历循环队列
        for (int i = front; i != tail;) {
            sb.append(data[i]);
            if (i != lastIndex){
                sb.append(",");
            }
            i = (i + 1) % data.length;
        }
        sb.append("] tail");
        return sb.toString();
    }
}
package stack_queue.queue;
import stack_queue.queue.LinkedQueue;
public class QueueTest {
    public static void main(String[] args) {
        LoopQueue loopQueue = new LoopQueue(3);
        loopQueue.offer(1);
        loopQueue.offer(3);
        loopQueue.offer(5);
        //front[1,3,5]tail
        System.out.println(loopQueue);
        loopQueue.poll();
        //[3,5]
        System.out.println(loopQueue);
        loopQueue.offer(7);
        System.out.println(loopQueue);
    }
}

 双端队列Deque(是一个接口,它的一个重要子类LinkedList)

        普通队列只能从一端插入另一端删除。而双端队列两端可以同时进行插入和删除。

注意:栈和队列经常作为高阶数据结构的辅助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值