当前位置: 首页 > article >正文

基础数据结构——队列(链表实现,数组实现)

1.概述

计算机科学中,queue 是以顺序的方式维护的一组数据集合,在一端添加数据,从另一端移除数据。习惯来说,添加的一端称为,移除的一端称为,就如同生活中的排队买商品

接口信息如下

public interface Queue<E> {
    //向队列尾部添加值
    boolean offer(E value);

    //从队列头部获取值并移除
    E poll();

    //从队列头部获取值不移除
    E peek();

    //判断队列是否为空
    boolean isEmpty();

    //判断队列是否已满
    boolean isFull();
}

2.单向环形链表(带哨兵)实现队列

在这里插入图片描述

public class LinkedListQueue<E> implements Queue<E>, Iterable<E> {
    private Node<E> head = new Node<>(null, null);//定义头节点哨兵
    private Node<E> tail = head;//定义尾节点指针
    private int size;//队列长度
    private int capacity = 8;//容量

    public LinkedListQueue() {
        this.tail.next = head;
    }

    public LinkedListQueue(int capacity) {
        this.tail.next = head;
        this.capacity = capacity;
    }

    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        Node<E> add = new Node<>(value, head);
        tail.next = add;
        tail = add;
        size++;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = head.next;
        head.next = first.next;
        if (first == tail) {
            tail = head;
        }
        size--;
        return first.value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return head.next.value;
    }

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

    @Override
    public boolean isFull() {
        return capacity == size;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            Node<E> pointer = head.next;

            @Override
            public boolean hasNext() {
                return pointer != head;
            }

            @Override
            public E next() {
                E value = pointer.value;
                pointer = pointer.next;
                return value;
            }
        };
    }

    /**
     * 定义节点类
     */
    private static class Node<E> {
        private E value;
        private Node<E> next;

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }
}

3.环形数组实现队列

好处
  1. 对比普通数组,起点和终点更为自由,不用考虑数据移动
  2. “环”意味着不会存在【越界】问题
  3. 数组性能更佳
  4. 环形数组比较适合实现有界队列、RingBuffer 等

在这里插入图片描述下标计算

例如,数组长度是 5,当前位置是 3 ,向前走 2 步,此时下标为 ( 3 + 2 ) % 5 = 0 (3 + 2)\%5 = 0 (3+2)%5=0
在这里插入图片描述

( c u r + s t e p ) % l e n g t h (cur + step) \% length (cur+step)%length

  • cur 当前指针位置
  • step 前进步数
  • length 数组长度

注意:

  • 如果 step = 1,也就是一次走一步,可以在 >= length 时重置为 0 即可

判断空
在这里插入图片描述

判断满
在这里插入图片描述满之后的策略可以根据业务需求决定

  • 例如我们要实现的环形队列,满之后就拒绝入队
public class ArrayQueue<E> implements Queue<E>, Iterable<E> {
    private int head = 0;//起始指针
    private int tail = 0;//终点指针
    private E[] array;//数组数据

    @SuppressWarnings("all")
    public ArrayQueue(int capacity) {
        this.array = (E[]) new Object[capacity + 1];
    }

    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        //tail++;
        tail = (tail + 1) % array.length;
        return true;
    }

    @Override
    public E poll() {
        if(isEmpty()){
            return null;
        }
        E value = array[head];
        //head++;
        head = (head + 1) % array.length;
        return value;
    }

    @Override
    public E peek() {
        if(isEmpty()){
            return null;
        }
        return array[head];
    }

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

    @Override
    public boolean isFull() {
        //return tail + 1 == head;
        return (tail + 1) % array.length == head;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int index = head;

            @Override
            public boolean hasNext() {
                return index != tail;
            }

            @Override
            public E next() {
                E value = array[index];
                index = (index + 1) % array.length;
                return value;
            }
        };
    }
}

引入size变量

public class ArrayQueue2<E> implements Queue<E>, Iterable<E> {
    private int head = 0;//起始指针
    private int tail = 0;//终点指针
    private E[] array;//数组数据
    private int size = 0;//数组大小

    @SuppressWarnings("all")
    public ArrayQueue2(int capacity) {
        this.array = (E[]) new Object[capacity];
    }

    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail] = value;
        tail = (tail + 1) % array.length;
        size++;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        E value = array[head];
        head = (head + 1) % array.length;
        size--;
        return value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head];
    }

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

    @Override
    public boolean isFull() {
        return array.length == size;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int pointer = head;
            int count = 0;

            @Override
            public boolean hasNext() {
                return size > count;
            }

            @Override
            public E next() {
                E value = array[pointer];
                pointer = (pointer + 1) % array.length;
                count++;
                return value;
            }
        };
    }
}

优化

public class ArrayQueue3<E> implements Queue<E>, Iterable<E> {
    /*
        求模运算:
        - 如果除数是 2 的 n 次方
        - 那么被除数的后 n 位即为余数 (模)
        - 求被除数的后 n 位方法: 与 2^n-1 按位与
     */
    private int head = 0;//起始指针
    private int tail = 0;//终点指针
    private final E[] array;//数组数据

    @SuppressWarnings("all")
    public ArrayQueue3(int capacity) {
        /**
         * capacity必须是 2的 n次方
         * 1.抛异常
         * 2.改成2的n次方
         *      1.找到比 capacity 大的最接近的 2 的 n 次方
         */
        /*if((capacity & capacity - 1) != 0){
            throw new IllegalArgumentException("capacity必须是2的幂");
        }*/
        /*
            2^4     = 16
            2^4.?   = 30
            2^5     = 32

              (int)log2(30) + 1
            2

            log2(x) = log10(x) / log10(2)

            1
            10      2^1
            100     2^2
            1000    2^3
         */
        capacity = 1 << (int) (Math.log10(capacity - 1) / Math.log10(2)) + 1;
        this.array = (E[]) new Object[capacity];
    }

    @Override
    public boolean offer(E value) {
        if (isFull()) {
            return false;
        }
        array[tail & array.length - 1] = value;
        tail++;
        return true;
    }

    @Override
    public E poll() {
        if (isEmpty()) {
            return null;
        }
        int idx = head & array.length - 1;
        E value = array[idx];
        array[idx] = null; // help GC
        head++;
        return value;
    }

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return array[head & array.length - 1];
    }

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

    @Override
    public boolean isFull() {
        return tail - head == array.length;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int index = head;

            @Override
            public boolean hasNext() {
                return index != tail;
            }

            @Override
            public E next() {
                E value = array[index & array.length - 1];
                index++;
                return value;
            }
        };
    }
}

http://www.kler.cn/news/365882.html

相关文章:

  • Visual studio 下载安装
  • 将获取的数据存储到Excel文件中
  • 麒麟v10 arm64 部署 kubesphere 3.4 修改记录
  • Oracle SQL Developer 同时打开多个table的设置
  • Python:背景知识及环境安装
  • filebeat收集日志直接输出到elasticsearch
  • 卷积神经网络评价指标
  • 关于 Linux 内核“合规要求”与俄罗斯制裁的一些澄清
  • 高效特征选择策略:提升Python机器学习模型性能的方法
  • 前端开发-HTML
  • 人工智能:未来生活与工作的变革者
  • uniapp 底部导航栏tabBar设置后不显示的问题——已解决
  • Django进一步掌握(10月22日)
  • Pyramidal Flow使用指南:快手、北大、北邮,开源可免费商用视频生成模型,快速上手教程
  • PostgreSQL使用clickhouse_fdw访问ClickHouse
  • PyCharm怎么添加解释器(怎么用已经具有torch环境)
  • Spring Boot技术栈在电影评论网站中的应用
  • CentOS 8修改Linux配置文件指定属性的值
  • 大麻股Tilray Brands分析:股价已获得强劲支撑,该买入还是卖出?
  • VSCode导入QSS文件
  • 多层感知机从零开始实现
  • PostgreSQL中查询每个账号的最新和最新前的数据
  • elementUI 时间控件控制时间选择
  • 扫雷游戏(C语言详解)
  • uni.showLoading 时禁止点击(防止表单重复提交) 小程序调取微信支付
  • 【NPM】工程化依赖包/库开发 之 常见开发结构/模式及特点