队列基本知识

1. 什么是队列 (Queue)

队列 (queue) 是一种采用先进先出 (first in first out) 策略的抽象数据结构。最常用的就是在宽度优先搜索 (BFS) 中,记录待扩展的节点。

队列内部存储元素的方式一般有两种,数组(array) 和链表(linked list) 。两者的主要区别就是:

  • 数组对随机访问有较好性能
  • 链表对插入和删除元素有较好性能

1.1 用链表实现队列

1) 链表是由多个节点构成的,一个节点由两部分组成:数据域指针域

在队列中,我们只需要用两个指针head和tail分别指向链表的头部和尾部即可实现队列的基本功能

public class MyQueue {
    // @param item: An integer
    // @return: nothing 
    ListNode head, tail;
    public MyQueue(){
        head = tail = null;
    }

    public void enqueue(int item) {
        if(head == null){
            tail = new ListNode(item);
            head = tail;
        }else{
            tail.next = new ListNode(item);
            tail = tail.next;
        }
    }
    // @return: An integer
    public int dequeue() {
        if(head != null){
            int res = head.val;
            head = head.next;
            return res;
        }
        return -1;
    }
}

class ListNode{
    int val;
    ListNode next;
    public ListNode(int val){
        this.val = val;
        next = null;
    }
}

注:

  • 一个".java"源文件中可以有多个类,但只能有一个public类,并且public类名必须与文件名相一致。
  • this表示对当前对象的引用。表示用类的成员变量,而非函数参数,注意在成员变量和函数参数同名时进行区分。

1.2 用数组实现循环队列 

1)为了克服“假溢出“现象,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

思路:在循环队列中,通过成员变量数组来表示一组地址连续的存储单元,再定义两个整型变量head和tail分别指示队首和队尾的位置,循环效果则用“模运算”实现。

将tail对 (数组长度)MAXSIZE取模,每当tail达到末尾时,使其回到队首。如果这样我们发现一个问题,队列为空和队列已满的条件都是 tail % MAXSIZE = head

为了避免这种无法判断的情况,我们规定当循环队列剩一个空位置时,就认为队列已满。这样队列已满的条件就成了 (tail+1) % MAXSIZE = head

public class MyQueue {
    /*
     * @param item: An integer
     * @return: nothing
     */
    int maxsize = 100000;
    int[] arr;
    int head, tail;
    public MyQueue(){
        head = tail = 0;
        arr = new int[maxsize];
    }

    public void enqueue(int item) {
        if((tail+1) % maxsize == head){
            return;
        }
        arr[tail++] = item;
        tail %= maxsize;
    }

    /*
     * @return: An integer
     */
    public int dequeue() {
        if(head == tail){
            return -1;
        }
        int val = arr[head++];
        head %= maxsize;
        return val;
    }

2. Java常用的几个interface

1)Set可以知道某物是否存在于集合中,不会存储重复元素。Set的实现类在面试中常用的是:

  • HashSet:无重复数据,可以有空数据,数据无序
  • TreeSet:无重复数据,不能有空数据,数据有序
Set<String> set = new HashSet<>();
for(int i=0;i<6;i++){
    set.add(i + "");
}
Iterator<String> iter = set.iterator();
while(iter.hasNext()){
    system.out.print(iter.next() + " ");
} 

2) Map用于存储具有映射关系的数据。Map中存了两组数据 (key和value),它们都可以是任何引用类型的数据,key不能重复,我们可以通过key取到对应的value。Map的实现类在面试中常用的是:

  • HashMap:key无重复,value允许重复;允许key和value为空;数据无序
  • TreeMap:key无重复,value允许重复;key不允许有null,value允许有null;有序

3) List是一个元素有序、可以重复、可以为null的集合。List的实现类在面试中常用的是:

  • ArrayList:基于动态数组实现
  • LinkedList:基于链表实现

4) Queue支持FIFO,即队首删除、队尾添加,其实现类有:

  • PriorityQueue:基于堆(heap)实现;非FIFO (最先出队列的是优先级最高的元素)
  • Queue:基于链表实现;FIFO
Queue<String> queue = new LinkedList<String>();
queue.offer("a");
queue.poll();    // 显示a
queue.peek();    // 显示null
  1. add(E), offer(E)在尾部添加:它们都建议实现类禁止添加null元素,否则会报空指针NullPointerException,LinkedList没有这样的要求;add方法在添加失败 (队列已满)时,会报一些运行时错误,offer方法在添加失败时会返回false。
  2. remove(), poll()删除并返回头部:队列为空时,remove方法会报NoSuchElementException,poll方法返回null。
  3. element(), peek()获取头部但不删除:队列为空时,element方法抛出异常,peek方法只会返回null。

3. Interface & 抽象类

1)interface语法规则

interface只包含方法的定义常量,而没有方法的实现和变量

interface中的所有成员变量都默认是由public static final修饰的。

interface中的所有方法都默认是由public abstract修饰的。

实现interface的类中,必须提供interface中所有方法的具体实现内容。

多个不同的类可以实现同一个interface,一个类可以实现多个不同的interface。

interface可以继承另一个interface,使用extends关键字。

@override是一种注释,标明该方法是继承自父类或interface的实现

2)java多态

父类引用变量可以指向子类对象,前提是必须有子父类关系或类实现interface关系。

interface类型变量只能调用在子类对象中实现的自身定义的方法

3)抽象类

抽象类不能实例化

抽象类和抽象方法必须用关键字abstract修饰

抽象方法只能存在于抽象类中,但抽象类不一定有抽象方法

若抽象类的子类是具体类,则该子类必须重写抽象类中的所有抽象方法

//Animal类
public abstract class Animal {
 
    public void sleep() {
        System.out.println("sleep");
    }
    public abstract void eat(); 
}

4)抽象类与接口的比较

单继承,多实现

interface中的方法都必须是public的,对外部开放;而abstract class的方法可以设置为protected

4. 拓展

1)泛型

2)取模运算(即取余数):a%b

3)protected修饰符的访问权限:

  • 基类的protected成员是包内可见的,并对子类可见。
  • 若子类与基类不在同一包中,那么在子类中,可以访问其从基类继承而来的protected方法,而不能访问基类的实例的protected方法。

4)控制台输入输出

Scanner scan = new Scanner(System.in);
while(scan.hasNextLine()){
    String str = scan.nextLine();
}
scan.close();

使用特定分隔符:先调用scan.useDelimiter(),然后scan.next()或scan.nextInt()返回被分隔符分割的字符。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值