11.17队列

目录

一.队列

1 概念

2.实现

1.底层原理

2.方法的实现

二.循环队列

1.底层实现

2.判断空还是满

3.循环队列的实现

四.队列和栈的转换

五.二维网格迁移

六.将数组分成相等的三部分


一.队列

1 概念

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

继承了两个接口

一个是Queue(队列)

另一个是Deque(双端队列)

实现的方法比较少 只是普通队列

就是双端队列

2.实现

1.底层原理

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

面试问题:

ArrayList和LinkList的区别是什么

从1.增删查改出发

2.内存的逻辑来说.

3.队列是没有下标的

(10条消息) ArrayList和LinkList的区别_只想撸铁的博客-CSDN博客

arraylist和linkedlist

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。 这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList. 因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

这里我们用到单向链表举例,源码是用的双向链表

如果用单向链表实现先进先出

那么就是队尾进,对头出的形式

那么

尾插法入队,头插法出队.这样时间复杂度都是O(1).

2.方法的实现

class Node{
    int val;
    Node next;
    public Node(int val){
        this.val=val;
    }
}
public class MyLinkedList {
    public Node head;
    public Node last;
    /**入队
     * w尾插法
     * val
     * val
     */
    public void offer(int val){
        Node node=new Node(val);
        if(this.head==null){
            this.head=node;
            this.last=node;
        }else{
            this.last.next=node;
            this.last=node;
        }
    }
    /**出队
     * 头节点
     *
     */
    public int poll(){
        if(this.head==null){
            throw new RuntimeException("队列为空");
        }
        int oldVal=this.head.val;
        this.head=this.head.next;
        return oldVal;
    }
    public boolean isEmpty(){
        return this.head==null;
    }
    public int peek(){
        if(isEmpty()){
            throw new RuntimeException("队列为空");
        }
        return this.head.val;
    }
}

二.循环队列

1.底层实现

数组

这里我们的实现就是用数组

用front定义对头

用real定义队尾

假设数组有十个元素

那么怎么构成循环呢

数组下标循环的小技巧

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

2.判断空还是满

但是我们有个疑问.

如果rear和front相遇了,到底是空的还是满的.

第一种情况

这两种情况都是相遇了

解决方法

1.用usedSize.用usedSize与数组长度比较.确定满或者空

2.用标志位.定义flag=false

入队列,没放一个元素,就置为true.

出队列.每出一个元素,就置为false.

第三种情况

每次存放元素之前,都先检查一下rear的下一个是不是front.如果是那就是满的

我们最后一个格子不放任何元素,用来作为判断是否满

3.循环队列的实现

数组下标循环的小技巧

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

class MyCircularQueue {
    int[] elem;
    int front;//对头下标
    int real;//队尾下标

    public MyCircularQueue(int k) {
        this.elem=new int[k+1];//队列长度是k那么就可以放k+1
        //因为我们这次设计的队列是会有一个空格子来判断是否满了
    }
    /**
     * 入队
     * @param value
     * @return
     */
    public boolean enQueue(int value) {
        if(isFull()) return false;

        elem[real]=value;
        real= (real+1)%elem.length;
        return true;

    }

    /**
     * 出队
     * @return
     */

    public boolean deQueue() {
        if(isEmpty()) return false;
       // elem[front]=elem[front+1];
        front=(front+1)% elem.length;
        return true;

    }

    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return elem[front];

    }

    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        int index=0;
        if(real==0){
            index=elem.length-1;
        }else{
            index=real-1;
        }
        return elem[index];

    }

    public boolean isEmpty() {

        return front==real;


    }

    public boolean isFull() {
        if((this.real+1)%elem.length==front){
            return true;//判断下一个是否是
        }
        return false;


    }
}

三.Java基础数据类型的默认值

1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。

2、单精度浮点型(float)的基本类型变量的默认值为0.0f。

3、双精度浮点型(double)的基本类型变量的默认值为0.0d。

4、字符型(char)的基本类型变量的默认为 “/u0000”。

5、布尔性的基本类型变量的默认值为 false。

6、引用类型的变量是默认值为 null。

7、数组引用类型的变量的默认值为 null。除关键数组变量的实例后,如果没有没有显示的为每个元素赋值,Java 就会把该数组的所有元素初始化为其相应类型的默认值。

四.队列和栈的转换

栈的特点是先进后出

而队列的特点是先进先出

如果我们用两个队列来实现的话

push可以正常用

但是在pop的时候要注意,因为对于队列来说pop的在栈里实现就是最后一个元素

所以我们需要把所有的都pop到另外一个空的队列,再pop出最后一个,也就是栈的第一个

这个题目的关键就是一定要保证至少有一个队列是空的

class MyStack {
    LinkedList<Integer> lisk1;
    LinkedList<Integer> lisk2;

    public MyStack() {
    lisk1=new LinkedList();
    lisk2=new LinkedList();
}

    public void push(int x) {
        if(!lisk1.isEmpty()){
            lisk1.offer(x);
        }else if(!lisk2.isEmpty()){
            lisk2.offer(x);
        }else{
            lisk1.offer(x);
        }

    }

    public int pop() {
        int val=0;
        if(!lisk1.isEmpty()){
            int size=lisk1.size();
            for(int i = 0;i<size-1;i++){
                val=lisk1.poll();
                lisk2.offer(val);
            }
            return lisk1.poll();
        }else{
            int size=lisk2.size();
            for(int i =0;i<size-1;i++){
                val=lisk2.poll();
                lisk1.offer(val);
            }
            return lisk2.poll();
        }

    }

    public int top() {
        int val=0;
        if(!lisk1.isEmpty()){
            int size=lisk1.size();
            for(int i = 0;i<size;i++){
                val=lisk1.poll();
                lisk2.offer(val);
            }
            return val;
        }else{
            int size=lisk2.size();
            for(int i =0;i<size;i++){
                val=lisk2.poll();
                lisk1.offer(val);
            }
            return val;
        }



    }

    public boolean empty() {
        return lisk1.isEmpty()&&lisk2.isEmpty();

    }
}

五.二维网格迁移

此题我们仔细研究,如果把整个二维数组平铺成一个一维数组

那就是每个元素向右移动一次,进行一个循环,这里就可以跟今天学的循环队列联系上了

我们可以把二维数组的每一个移动号的元素放在一维数组里,

从0开始模拟放元素,对于一维数组就是移动后的k位置,要对k进行取模,再k++

因为k位置超过长度后就又回到0.所以每次

都要取模,不能只取模一次'

这是这道题的精华

class Solution {
    public List<List<Integer>> shiftGrid(int[][] grid, int k) {
        //第一步,先平铺成一维数组,因为这个题的意思,就是向右移动多少位
        int len=grid.length * grid[0].length;//总长度
        int[] nums = new int[len];//行和列相乘
        int iMax = grid.length;//行的长度
        int jMax = grid[0].length;//列的长度
        for(int i = 0;i < iMax;i++) {//iMax总长度
            for(int j = 0;j < jMax;j++) {//第六行k %= nums.length,如果k等于nums.length就  
               k%=len;//就是0,k大于nums.length就是余数
             nums[k++] = grid[i][j];//相当于一个圆.要去掉圆的圈数就是移动的次数
             //然后开始从0模拟
            }//如果超过一维数组本身的长度,等于就是从0,大于就是取余.
            //太巧妙了.这个做法!
        }
       //因为题目要的是顺序表,就放到顺序表里.
       k=0;
       List<List<Integer>> lists=new ArrayList<>(grid.length);
        for(int i = 0;i < iMax;i++) {//iMax总长度
         List<Integer> tempList = new ArrayList<>(grid[0].length);//每次循环都建立一个新的表
            for(int j = 0;j < jMax;j++) {
              tempList.add(nums[k++]);
            }//二维网格就放好了
             lists.add(tempList);//把表放入表中
        }
               return lists;
   }

六.将数组分成相等的三部分

这道题一定要注意是跟剧索引来的.也就是连续的

我们的思路.就是先算出总大小,然后看能不能整除3,不能纠错了

然后遍历数组,看能不能分成三等分,其实遇到两组的时候就可以返回TRUE了

因为进入循环一定整除3/既然找到前两组,最后一组一定也是

如果还跳出了循环就说明是FALSE了

我今天还有另外一种情况

就是循环出来,如果是三组或者大于3但是整个等于0代表就是全是0那就是true

但是总有一个不对

class Solution {
    public boolean canThreePartsEqualSum(int[] arr) {
        int sum=0;
        for(int i:arr){
            sum+=i;
        }//这里算出了数组的总长度
        //这个题目要注意是连续的索引,不可以是跳过的,这样就很简单了
        if(sum%3!=0){
            return false;//说明不能整除3
        }
        int goal=sum/3;
        int i=0;
        sum=0;
        for(int j=0;j<arr.length;j++){
            sum+=arr[j];
              if(i==2){
                    return true;
                }
            if(sum==goal){
                i++;
                sum=0;
              
            }
        }
         return false;

    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值