java中栈与队列基础知识、队列的不同实现方式

目录

一、栈

二、队列

队列的实现方式:

1.顺序队列

2.循环队列

3.链式队列

4.双端队列


一、栈

栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。

压栈:向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;

出栈:从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

后进先出!

public static void main(String[] args) {
       Stack<Integer> s = new Stack();
       s.push(1);
       s.push(2);
       s.push(3);
       s.push(4);
       System.out.println(s.size()); // 获取栈中有效元素个数---> 4
       System.out.println(s.peek()); // 获取栈顶元素---> 4
       s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
       System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
       if(s.empty()){
           System.out.println("栈空");
       }else{
           System.out.println(s.size());
       
二、队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

先进先出!

在Java中,Queue是个接口,底层是通过链表实现的。在实例化时必须实例化 LinkedList 的对象,因为 LinkedList 实现了 Queue 接口。

public static void main(String[] args) {
       Queue<Integer> q=new LinkedList<>();//linkedlist是双向链表
       q.offer(1);
       q.offer(2);
       q.offer(3);
       q.offer(4);
       q.offer(5);                  // 从队尾入队列
       System.out.println(q.size());
       System.out.println(q.peek());  // 获取队头元素
       q.poll();
       System.out.println(q.poll());  // 从队头出队列,并将删除的元素返回
       if(q.isEmpty()){
              System.out.println("队列空");    
       }else{
              System.out.println(q.size());    
       }
}

下面是一些java中队列的实现方式:

1.顺序队列

顺序队列是队列的一种,只是说队列的存在形式是队列中的元素是连续的,就像数组

顺序队列的实现方式

(1)队头不动,队尾动(很像数组)

在元素出队列时,队头不动,队尾动,每出一个元素,就把队列中剩余的元素往前搬移,从而队尾会跟着改变。

缺点:在出队列时,需要大量搬移元素,时间复杂度为O(N)。

(2)队头动,队尾不动

在元素出队列时,队头往后移动一个位置,队尾一直保持不动。

优点:在出队列时,只需把队头往后移动一个位置就好,所以时间复杂度为O(1)。

缺点:因为在元素在出队列时只是移动队头,并没有把元素在内存上删除,所以就会出现元素把整个内存耗尽,并且此内存中的存储都是不合法的元素,从而造成假溢出。

假溢出:看似内存中再存储不了元素了,但是此内存在理论上是可以使用的,内存被一些不合法的元素使用完了,从而造成一种溢出现象,但是此溢出是假溢出。

2.循环队列

循环队列是首尾相接的顺序存储队列,顾名思义循环队列就是队列的内存可以循环使用

在顺序队列中,出现了假溢出问题,那循环队列就是为了假溢出问题

循环队列的实现:

给定两个指针,分别标记队头和队尾,标记队头的指针是front,标记队尾的是rear。开始时,front是队头指针,rear是队尾指针,空队列时front和rear指向同一位置

class MyCircularQueue {
    int[] array;
    int front;//定义头结点
    int rear;//定义尾结点
    int count;//定义有效节点
    int N;//定义数组长度
    
	//定义数组
    public MyCircularQueue(int k) {
        array = new int[k];
        N = k;
    }
    //入队列
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }
        array[rear] = value;
        rear++;
        if(rear == N){
            rear = 0;
        }
        count++;
        return true;
    }
    //出队列
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front++;
        front %= N;
        count--;
        return true;
    }
    //返回队列头
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return array[front];
    }
    //返回队列尾
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        return array[(rear + N - 1)% N];
    }
    //检查是否满了
    public boolean isEmpty() {
        return 0 == count;
    }
    //检查是否为空
    public boolean isFull() {
        return count == array.length;
    }
}
3.链式队列

链式队列跟线性表的单链表一样,只是说只能从头出从尾进而已


/*
        * 链式队列
        * front:指向的是链表的头节点
        * rear:永远指向的是末尾节点
        * @param <T>
 */
class LinkQueue<T>{
    // 构造函数  offer  poll  peek   empty   size
    private Entry<T> front; // 队头
    private Entry<T> rear;
    private int count; // 记录链表节点的个数
 
    public LinkQueue(){
        front= new Entry<>(null, null);
    }
 
    public void offer(T val) {
        Entry<T> node = front;
        while(node.next != null){
            node = node.next;
        }
        node.next = new Entry<>(val, null);
        count++;
    }
 
    public T poll() {
        if(empty())
            return null;
        T val = front.next.data;
        front.next = front.next.next;
        count--;
        return val;
    }
 
    public T peek() {
        if(empty())
            return null;
        return front.next.data;
    }
 
    public boolean empty(){
        return front.next == null;
    }
 
    public int size(){
        return this.count;
    }
 
    static class Entry<T>{
        T data;
        Entry<T> next;
 
        public Entry(T data, Entry<T> next) {
            this.data = data;
            this.next = next;
        }
    }
}
 
 
public class LinkQueueTest {
    public static void main(String[] args) {
        LinkQueue<Integer> ls = new LinkQueue<>();
        ls.offer(1);
        ls.offer(2);
        ls.offer(3);
        ls.offer(4);
 
        System.out.println(ls.peek());
 
        System.out.println(ls.size());
 
        while(!ls.empty()){
            System.out.print(ls.poll() + " ");
        }
 
        System.out.println();
    }
}

4.双端队列

双端队列又名double ended queue,简称deque,双端队列没有队列和栈这样的限制级,它允许两端进行入队和出队操作,也就是说元素可以从队头出队和入队,也可以从队尾出队和入队

import java.util.List;
 
// 模拟实现队列---底层使用双向链表---在集合框架中Queue是一个接口---底层使用的是LinkedList
public class Queue<E> {
    // 双向链表节点
    public static class ListNode<E>{
        ListNode<E> next;
        ListNode<E> prev;
        E value;
 
        ListNode(E value){
            this.value = value;
        }
    }
 
    ListNode<E> first;   // 队头
    ListNode<E> last;    // 队尾
    int size = 0;
 
    // 入队列---向双向链表位置插入新节点
    public void offer(E e){
        ListNode<E> newNode = new ListNode<>(e);
        if(first == null){
            first = newNode;
            // last = newNode;
        }else{
            last.next = newNode;
            newNode.prev = last;
            // last = newNode;
        }
 
        last = newNode;
        size++;
    }
 
    // 出队列---将双向链表第一个节点删除掉
    public E poll(){
        // 1. 队列为空
        // 2. 队列中只有一个元素----链表中只有一个节点---直接删除
        // 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除
        E value = null;
        if(first == null){
            return null;
        }else if(first == last){
            last = null;
            first = null;
        }else{
            value = first.value;
            first = first.next;
            first.prev.next = null;
            first.prev = null;
        }
        --size;
        return value;
    }
 
    // 获取队头元素---获取链表中第一个节点的值域
    public E peek(){
        if(first == null){
            return null;
        }
 
        return first.value;
    }
 
    public int size() {
        return size;
    }
 
    public boolean isEmpty(){
        return first == null;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值