JAVA基础-数据结构一(线性表、链表、栈、队列)

一、数组线性表(ADT)

线性表:又称动态数组,核心是动态数组,可以自行扩容,支持增删改查四种功能

java中有ArrayList也可以自行扩容,二者功能较为相似,且ArrayList也支持转换为数组。

ArrayList<String> list=new ArrayList<>();
int size=list.size();  
//转换为String类型数组
String[] array = (String[])list.toArray(new String[size]);
//转换为int类型数组
int[] arr = list.stream().mapToInt(k -> k).toArray();

 1.定义成员变量(泛型)

private E[] array;//定义一个泛型数组
private int size;//数组内元素的实际数量
public MyArray(int capacity)
{
     this.array=(E[]) new Object[capacity];
     this.size=0;//size代表数组里实际有效的数据数量
}

2. 添加元素

 添加指定的元素,线性表有可能元素已满,需要扩容

扩容后(或未扩容)再添加元素,并将元素数量+1

public void add(E element)
{//数组按照顺序添加元素
    //如果实际元素数量已达到数组长度,判断为线性表已满
    //线性表已满则扩容
     if(size>=array.length)
         resize();
     array[size]=element;
     size++;
}

3. 插入元素

输入指定元素和要插入的位置下标

需要进行两个判断:

1.需要判断插入的位置是否合法(别超出线性表已有的范围)

2.如果线性表现在已满,就扩容

 判断过后,实现插入:for循环解决,给指定位置赋值为输入元素即可

别忘了最后增加元素数量

 public void insert(E element,int index) throws IndexOutOfBoundsException {
        //插入元素必须按照顺序插入,并且插入次数达到数组长度时才能扩容
        if(index<0 || index>size)//判断数组是否越界
        {
            throw new IndexOutOfBoundsException("超出数组范围");
        }
        if(size>=array.length)//如果实际元素达到数组容量上限
        {//数组扩容
            resize();
        }
        //实现数组插入
        for (int i = size-1; i >=index; i--) {
            array[i+1]=array[i];
        }
        array[index]=element;//插入元素
        size++;
    }

4. 删除元素

输入要删除元素的位置下标

需要判断该位置是否超出线性表范围

判断不超出后,执行删除:一个for循环解决

记得让元素数量-1

public void delete(int index) throws IndexOutOfBoundsException 
{//删除指定位置的数组元素
        if(index<0||index>size)
        {
            throw new IndexOutOfBoundsException("数组越界,删除失败");
        }
        for(int i=index;i<size-1;i++)
        {
            array[i]=array[i+1];
        }
        size--;
    }

5. 线性表扩容

扩容

新建一个数组,数组范围为原数组的两倍

然后把旧数组复制到新数组里

把新数组命名为旧数组的名字(这样就可以继续使用旧数组的名字) 

而原旧数组已经被抛弃。

public void resize()
{//数组扩容
        E[] newArray=(E[]) new Object[array.length*2];
        //把旧数组的内容复制到新的数组中
        System.arraycopy(array,0,newArray,0,array.length);
        this.array=newArray;
}

6.输出

public void Print()
{
        for (int i = 0; i < size; i++) {
            System.out.print(array[i]+" ");
        }
}

7.主函数试验

public static void main(String[] args) {
        MyArray a=new MyArray(4);
        for(int i=0;i<5;i++)
            a.add(i);//0 1 2 3 4
        a.insert(9,2);//0 1 9 2 3 4
        a.delete(4);//0 1 9 2 4
        a.Print();
    }

8.完整代码

public class MyArray<E> {
    private E[] array;//定义一个泛型数组
    private int size;//数组内元素的实际数量
    public MyArray(int capacity)
    {
        this.array=(E[]) new Object[capacity];
        this.size=0;//size代表数组里实际有效的数据数量
    }
    public void add(E element)
    {//数组按照顺序添加元素
        if(size>=array.length)
            resize();
        array[size]=element;
        size++;
    }
    //数组插入元素
    public void insert(E element,int index) throws IndexOutOfBoundsException {
        //插入元素必须按照顺序插入,并且插入次数达到数组长度时才能扩容
        if(index<0 || index>size)//判断数组是否越界
        {
            throw new IndexOutOfBoundsException("超出数组范围");
        }
        if(size>=array.length)//如果实际元素达到数组容量上限
        {//数组扩容
            resize();
        }
        //实现数组插入
        for (int i = size-1; i >=index; i--) {
            array[i+1]=array[i];
        }
        array[index]=element;//插入元素
        size++;
    }
    public void delete(int index) throws IndexOutOfBoundsException {//删除指定位置的数组元素
        if(index<0||index>size)
        {
            throw new IndexOutOfBoundsException("数组越界,删除失败");
        }
        for(int i=index;i<size-1;i++)
        {
            array[i]=array[i+1];
        }
        size--;
    }
    public void resize()
    {//数组扩容
        E[] newArray=(E[]) new Object[array.length*2];
        //把旧数组的内容复制到新的数组中
        System.arraycopy(array,0,newArray,0,array.length);
        this.array=newArray;
    }
    public void Print()
    {
        for (int i = 0; i < size; i++) {
            System.out.print(array[i]+" ");
        }
    }

    public static void main(String[] args) {
        MyArray a=new MyArray(4);
        for(int i=0;i<5;i++)
            a.add(i);
        a.insert(9,2);
        a.delete(4);
        a.Print();
    }
}

二、链表

java自带的List列表结构
        void add(E element)在列表末尾添加元素
        E get(int index)获取指定索引位置的元素
        E set(int index,E element)替换指定索引位置的元素
        E remove(int index)移除指定索引位置的元素
        int size()返回表的大小

我们用自定义类重新实现List的单链表版本

包括:增删改查功能

优点:
线性表逻辑上相邻,物理上也相邻,可随机存取任意元素。
缺点:
线性表插入、删除操作需要移动大量元素
存储空间是预分配的,不灵活,空间浪费,表的存储空间难扩充 

 1.定义成员变量

java里面没有像C语言的结构体,但java有内部类

新建一个内部类Node表示链表内的单个节点,内部类中包括

        1.元素

        2.指向下一节点的指针

        3.构造函数给元素赋值

构造好节点类,再新建头结点和尾结点指针,并新建size表示链表的有效长度

    private static class Node<E>
    {//定义一个结点内部类
        E data;
        Node next;//指向下一结点的指针
        Node(E data)
        {
            this.data=data;
        }
    }
    private Node head;//头结点
    private Node last;//尾结点
    private int size;//链表实际长度

2. 查找节点

输入想要查找的节点下标,返回该下标位置的节点

新建一个指针,从头结点遍历到下标位置,返回指针指到下标位置的节点

    public Node get(int index)throws Exception
    {//获取指定下标位置的结点
        if(index<0 || index>=size)
            throw new IndexOutOfBoundsException("超出范围");
        Node temp=head;
        for (int i = 0; i < index; i++) {
            temp=temp.next;//指针后移
        }
        return temp;
    }

3. 插入节点

输入要插入的节点元素值,和要插入的位置下标

新建一个结点存储该结点元素值

先将要插入的节点指针指向插入位置的下一节点

然后再让插入位置的前一节点指向新结点

获取前一节点,可使用第二步定义的“查找节点”方法,输入位置-1下标

插入头结点、尾结点、中间某一节点的三种情况不同

    public void insert(E data,int index)throws Exception
    {
        if(index<0 || index>size)
            throw new IndexOutOfBoundsException("超出链表表长");
        Node insertNode=new Node(data);//定义待插入结点
        if(size==0)
        {//空链表
            head=insertNode;
            last=insertNode;
        }
        else if(index==0)
        {//插入到头结点前面
            insertNode.next=head;//把原头结点放在待插入元素的下一个位置上
            head=insertNode;//把待插入元素放置在头结点上
        }
        else if(index==size)
        {//插入到尾结点后面
            last.next=insertNode;//先把待插入结点放在尾结点的下一个位置
            last=insertNode;//再把待插入节点设置为尾结点,也就是指针后移了一位
        }
        else
        {//插入中间位置
            Node prevNode=get(index-1);//设置插入位置的前结点
            insertNode.next=prevNode.next;//先让待插入结点指向插入位置结点
            prevNode.next=insertNode;//再让前结点指向待插入结点
        }
        size++;
    }

4. 删除节点

 输入要删除节点的下标

如果为空表删不了

新建一个节点指针,指向将要被删除的节点(垃圾桶)

要删除谁,就把谁的值赋给垃圾桶指针,然后再让前一结点指向后一结点

删除头结点、尾结点、中间某一节点情况不同

    public void delete(int index)throws Exception
    {
        if(index<0 || index>=size)
        {
            throw new IndexOutOfBoundsException("删除失败,超出有效链表长度");
        }
        if(size==0)
        {//空链表
            System.out.println("链表中无有效结点,删除失败");
        }
        Node removeNode=new Node(null);
        if(index==0)
        {//删除head结点
            removeNode=head;//把旧的头结点设置为已删除结点
            head=head.next;//把头结点的下一个结点设置为新的头结点
        }
        else if(index==size-1)
        {//删除尾结点
            removeNode=last;//把旧的尾结点设置为已删除
            Node prevNode=get(size-2);//获取前结点
            prevNode.next=null;//让前结点指向空
            last=prevNode;//设置前结点为新的尾结点
        }
        else
        {//删除中间节点
            Node prevNode=get(index-1);//获取前结点
            Node nextNode=prevNode.next.next;//获取删除节点的下一节点
            removeNode = prevNode.next;
            prevNode.next=nextNode;//让前结点指向后节点
        }
        size--;
    }

5. 输出节点

    public void output()
    {
        Node temp=head;//设置一个结点指针指向头结点
        for (int i = 0; i < size; i++) {
            //遍历链表
            System.out.print(temp.data+" ");
            temp=temp.next;
        }
    }

 6.主函数检验

    public static void main(String[] args) throws Exception
    {
        MyList<Integer> LinkList=new MyList<>();
        LinkList.insert(3,0);//3
        LinkList.insert(8,1);//3->8
        LinkList.insert(3,2);//3->8->3
        LinkList.insert(8,3);//3->8->3->8
        LinkList.insert(9,1);//3->9->8->3->8
        LinkList.delete(0);//9->8->3->8
        LinkList.output();
    }

7.完整代码

/*
* java自带的List列表结构
* void add(E element)在列表末尾添加元素
* E get(int index)获取指定索引位置的元素
* E set(int index,E element)替换指定索引位置的元素
* E remove(int index)移除指定索引位置的元素
* int size()返回表的大小*/

/*数据结构就是用自定义类实现List结构:增删改查*/
public class MyList<E> 
{
    private static class Node<E>{//定义一个结点内部类
        E data;
        Node next;//指向下一结点的指针
        Node(E data)
        {
            this.data=data;
        }
    }
    private Node head;//头结点
    private Node last;//尾结点
    private int size;//链表实际长度
    //查找节点
    public Node get(int index)throws Exception
    {//获取指定下标位置的结点
        if(index<0 || index>=size)
            throw new IndexOutOfBoundsException("超出范围");
        Node temp=head;
        for (int i = 0; i < index; i++) {
            temp=temp.next;//指针后移
        }
        return temp;
    }
    //链表插入元素
    public void insert(E data,int index)throws Exception{
        if(index<0 || index>size)
            throw new IndexOutOfBoundsException("超出链表表长");
        Node insertNode=new Node(data);//定义待插入结点
        if(size==0)
        {//空链表
            head=insertNode;
            last=insertNode;
        }
        else if(index==0)
        {//头插
            insertNode.next=head;//把原头结点放在待插入元素的下一个位置上
            head=insertNode;//把待插入元素放置在头结点上
        }
        else if(index==size)
        {//尾差
            last.next=insertNode;//先把待插入结点放在尾结点的下一个位置
            last=insertNode;//再把待插入节点设置为尾结点,也就是指针后移了一位
        }
        else
        {//插入中间位置
            Node prevNode=get(index-1);//设置插入位置的前结点
            insertNode.next=prevNode.next;//先让待插入结点指向插入位置结点
            prevNode.next=insertNode;//再让前结点指向待插入结点
        }
        size++;
    }
    //链表删除元素
    public void delete(int index)throws Exception{
        if(index<0 || index>=size)
        {
            throw new IndexOutOfBoundsException("删除失败,超出有效链表长度");
        }
        if(size==0)
        {//空链表
            System.out.println("链表中无有效结点,删除失败");
        }
        Node removeNode=new Node(null);
        if(index==0)
        {//删除head结点
            removeNode=head;//把旧的头结点设置为已删除结点
            head=head.next;//把头结点的下一个结点设置为新的头结点
        }
        else if(index==size-1)
        {//删除尾结点
            removeNode=last;//把旧的尾结点设置为已删除
            Node prevNode=get(size-2);//获取前结点
            prevNode.next=null;//让前结点指向空
            last=prevNode;//设置前结点为新的尾结点
        }
        else
        {//删除中间节点
            Node prevNode=get(index-1);//获取前结点
            Node nextNode=prevNode.next.next;//获取删除节点的下一节点
            removeNode = prevNode.next;
            prevNode.next=nextNode;//让前结点指向后节点
        }
        size--;
    }
    //输出链表
    public void output()
    {
        Node temp=head;//设置一个结点指针指向头结点
        for (int i = 0; i < size; i++) {
            //遍历链表
            System.out.print(temp.data+" ");
            temp=temp.next;
        }
    }
    public static void main(String[] args) throws Exception {
        MyList<Integer> LinkList=new MyList<>();
        LinkList.insert(3,0);
        LinkList.insert(8,1);
        LinkList.insert(3,2);
        LinkList.insert(8,3);
        LinkList.insert(9,1);
        LinkList.delete(0);
        LinkList.output();
    }
}

三、栈

Java自带栈
Stack<E> stack=new Stack<>();
boolean stack.empty()                 测试此堆栈是否为空
E stack.pop()                         出栈
E stack.push(E item)                  入栈
E stack.peek()                        获取栈顶元素
int stack.search(Object o)            返回对象在堆栈里的位置下标

栈是后进先出的,经典例子如:弹夹压弹,羽毛球筒等

后面会附有实际运用的题目

栈的应用场景:

栈的输出顺序和输入顺序相反,所以栈通常用于对“历史”的回溯,也就是逆流而上追溯“历史”

例如实现递归的逻辑,就可以用栈来代替,因为栈可以回溯方法的调用链。 

栈还有一个著名的应用场景是面包屑导航,使用户在浏览页面时可以轻松地回
溯到上一级或更上一级页面。

1. 定义成员变量

栈由数组来实现,栈内实际元素的数量用size来记录

    private E[] arr;//将元素存到数组中
    private int size;//栈的实际长度(元素数量)

    public MyStack()
    {//调用无参构造方法 默认最大容量12
        this(12);
    }

    public MyStack(int MaxSize) {
        this.arr=(E[])new Object[MaxSize];
    }

 2.判断栈是否为空

    public boolean isEmpty()
    {//判断是否为空栈
        return this.size==0;
    }

3. 入栈

元素自栈顶入栈,栈顶为数组[size]

判断栈是否已满,已满就扩容

把元素加入到栈顶,记得有效长度+1

    public E push(E value){
        //入栈
        if(this.size == arr.length)
        {//栈满扩容
            E[] copyArr=(E[])new Object[arr.length*2];
            arr=copyArr;
        }
        this.arr[size]=value;
        this.size++;
        return value;
    }

4.获取栈顶元素

判断栈空

把栈顶元素返回

    public E get()
    {//获取栈顶元素
        if(isEmpty())
        {
            System.out.println("栈为空");
            return null;
        }
        return arr[size-1];
    }

 5.出栈

判断栈空

先把栈顶元素存起来,然后清除栈顶元素

再把栈的有效长度-1 

    public E pop()
    {//出栈
        if(isEmpty())
        {//栈空抛出异常
            throw new RuntimeException("栈中无元素");
        }
        E top=arr[size-1];//size始终比栈顶元素的下标多1
        arr[size]=null;
        size--;
        return top;
    }

6. 返回栈的长度

    public int getSize() {
        //返回数组大小
        return this.size;
    }

7. 打印栈

由于栈是只能通过一次出栈一个栈顶元素来遍历

而遍历结束,栈也就空了

因此要新建一个栈,把原栈输出的栈顶元素都存起来

等原栈遍历结束为空栈后,再把新建栈内存的元素再依次遍历入栈到原栈里

这样就保证了打印结束后,原栈内元素不变

    public void print()
    {
        MyStack<E> stack=new MyStack<>();//新建栈
        while(!isEmpty())//遍历到栈空(也可以改成输入要遍历的元素数量)
        {
            E elem=this.pop();//存储栈顶元素并出栈
            //栈顶元素为null说明是数组冗余的部分,非有效元素
            if(elem==null)
            {
                continue;
            }
            stack.push(elem);//把原栈栈顶元素入栈到新建栈
            System.out.print(elem+" ");
        }
        System.out.println();
        while(!stack.isEmpty())
        {//把新建栈的栈顶依次赋值给原栈
            E elem=stack.pop();
            this.push(elem);
        }
    }

 8.主函数检验

    public static void main(String[] args) {
        MyStack<Integer> stack=new MyStack<>();
        for (int i = 0; i < 11; i++) {
            stack.push(i);//入栈
        }
        stack.print();//10 9 8 7 6 5 4 3 2 1 0
        stack.pop();//10
        System.out.println(stack.get());//9
        System.out.println(stack.getSize());//10
    }

9.完整代码

/*
* Java自带栈
* Stack<E> stack=new Stack<>();
* boolean stack.empty() 测试此堆栈是否为空
* E stack.pop() 出栈
* E stack.push(E item)入栈
* E stack.peek() 获取栈顶元素
* int stack.search(Object o)返回对象在堆栈里的位置下标*/

/*
* java数据结构就是要实现java自带的堆栈的方法
* 了解堆栈实现的原理*/


public class MyStack<E> {
    private E[] arr;//将元素存到数组中
    private int size;//栈的实际长度(元素数量)

    public MyStack()
    {//调用无参构造方法 默认最大容量12
        this(12);
    }

    public MyStack(int MaxSize) {
        this.arr=(E[])new Object[MaxSize];
    }

    public boolean isEmpty()
    {//判断是否为空栈
        return this.size==0;
    }
    public E get()
    {//获取栈顶元素
        if(isEmpty())
        {
            System.out.println("栈为空");
            return null;
        }
        return arr[size-1];
    }
    public E push(E value){
        //入栈
        if(this.size == arr.length)
        {//栈满扩容
            E[] copyArr=(E[])new Object[arr.length*2];
            arr=copyArr;
        }
        this.arr[size]=value;
        this.size++;//栈的实际长度,始终比栈顶元素的下标多1
        return value;
    }
    public E pop()
    {//出栈
        if(isEmpty())
        {//栈空抛出异常
            throw new RuntimeException("栈中无元素");
        }
        E top=arr[size-1];
        arr[size]=null;
        size--;
        return top;
    }
    public int getSize() {
        //返回数组大小
        return this.size;
    }
    public void print()
    {
        MyStack<E> stack=new MyStack<>();
        while(!isEmpty())
        {
            E elem=this.pop();
            if(elem==null)
            {
                continue;
            }
            stack.push(elem);
            System.out.print(elem+" ");
        }
        System.out.println();
        while(!stack.isEmpty())
        {
            E elem=stack.pop();
            this.push(elem);
        }
    }
    public static void main(String[] args) {
        MyStack<Integer> stack=new MyStack<>();
        for (int i = 0; i < 11; i++) {
            stack.push(i);//入栈
        }
        stack.print();//10 9 8 7 6 5 4 3 2 1 0
        stack.pop();//10
        System.out.println(stack.get());//9
        System.out.println(stack.getSize());//10
    }
}

10.题目

1.有效的括号

题目介绍:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"
输出:true

示例 2:

输入:s = "()[]{}"
输出:true

示例 3:

输入:s = "(]"
输出:false

提示:

  • 1 <= s.length <= 104
  • s 仅由括号 '()[]{}' 组成
错误代码(非栈,思路错误) 

 

class Solution {
    public boolean isValid(String s) {
        int small=0;
        int middle=0;
        int big=0;
        int count=0;
        int count1=0;
        int count2=0;
        int count3=0;
        for(int i=0;i<s.length();i++)
        {
            if(small<0 || middle<0 || big<0 )    
                return false;
            
            System.out.println(small+" "+middle+" "+big);
            switch(s.charAt(i))
            {
                case '(':
                {
                    small++;
                    break;
                }
                case ')':
                {
                    small--;
                    break;
                }
                case '[':
                {
                    middle++;
                    if(small%2==1)//如果中括号出现在小括号里面
                        count++;
                    if(big%2==1)
                        count3++;
                    break;
                }
                case ']':
                {
                    middle--;
                    if(count%2==1 )
                    {
                        if( small%2==0)
                            return false;
                        count--;
                    }
                    if(count3%2==1)
                    {
                        if(big%2==0)
                            return false;
                        count3--;
                    }
                    break;
                }
                case '{':
                {
                    big++;
                    if(small%2==1)
                        count1++;
                    if(middle%2==1)
                        count2++;
                    break;
                }
                case '}':
                {
                    big--;

                    if(count1%2==1)
                    {
                        if(small%2==0)
                            return false;
                        count1--;
                    }
                    if(count2%2==1)
                    {
                        if( middle%2==0)
                            return false;
                        count2--;
                    }
                    break;
                }
                default:
                    break;
            }
        }
        if(small!=0 || middle!=0 || big!=0)  
            return false;
        return true;
    }

}

吐槽:这题做的我很痛苦,主要是思路也是错了,但不管怎么样,这个题还是很标准的要模拟栈来做题,既然都要用栈,就不如直接调用java的栈类,直接解决问题 

正确代码 
class Solution {
    public boolean isValid(String s) {
        int n=s.length();
        if(n%2==1) return false;
        Stack<Character> st=new Stack<>();
        char[] ch=s.toCharArray();
        for(int i=0;i<s.length();i++)
        {
            if(isOpen(ch[i]))
                st.push(ch[i]);
            else
                {
                    if(st.isEmpty())
                        return false;
                        char top=st.pop();
                        if(!isClose(top,ch[i]))
                            return false;
                }
        }
        return st.isEmpty();
    }
    static boolean isOpen(char c)
    {
        return c=='{' || c=='(' || c=='[';
    }
    static boolean isClose(char open,char close)
    {
        return  (open == '(' && close == ')') ||
               (open == '{' && close == '}') ||
               (open == '[' && close == ']');
    }
}

 

 

四、队列

JAVA自带Queue队列接口
LinkedList(双向链表)、ArrayList均可实现Queue
boolean add(E element):         将指定的元素添加到队列的末尾,如果成功则返回true,                                      如果队列已满则抛出异常。
boolean offer(E element)        同上,如果队列已满返回false;
E remove()                      移除并返回队列头部元素,如果队列为空抛出异常
E poll()                        同上,如果队列为空返回null
E element()                     获取队列头部的元素,但不移除,队列为空抛出异常
E peek()                        同上,队列为空返回null
int size()                      返回队列中元素个数
boolean isEmpty()               判断队列是否为空
clear()                         清空
contains(Object o)              是否包含某元素

使用自定义类实现队列,满足先进先出的原则,实现循环队列 

队列的应用:

队列的输出顺序和输入顺序相同,所以队列通常用于对“历史”的回放,也就 是按照“历史”顺序,把“历史”重演一遍。

例如在多线程中,争夺公平锁的等待队列,就是按照访问顺序来决定线程在队 列中的次序的。

再如网络爬虫实现网站抓取时,也是把待抓取的网站URL存入队列中,再按照存 入队列的顺序来依次抓取和解析的。 

1.定义成员变量

队列元素由数组实现,定义一个头部指针和一个尾部指针

队列长度由new MyQueue(int MaxSize)决定

需要注意,由于循环队列的定义,出于判断队空还是队满的区分,只要队不空,头指针和尾指针永远至少隔一个位置

也就是说,队列里的实际元素数量永远比队列长度少1

    private E[] arr;
    private int front;//头部指针
    private int rear;//尾部指针
    public MyQueue(int MaxSize)
    {
        arr=(E[])new Object[MaxSize];
    }

2. 判断队列是否为空

初始位置,头指针和尾指针都没动 

    public boolean isEmpty()
    {
        return rear==front;//头指针等于尾指针,队列无元素
    }

3. 入队

先判断队列是否已满,判断已满的方法是,(尾指针+1)%队列长度==头指针

如果未满,就为尾指针赋值,需注意,队列为循环队列,尾指针的位置取决于头指针的位置

因此尾指针的位置需要%长度,表示在一个循环里

添加元素后,尾指针+1

    public boolean offer(E element) throws Exception {
        //判断队列是否已满,已满返回false
        if((rear+1)%arr.length==front)
        {
            System.out.println("队列已满");
            return false;
        }
        arr[rear%arr.length]=element;
        rear=(rear+1)%arr.length;//队尾指针后移一位
        return true;
    }

4. 出队

判断队空

存储队首的元素后,清除队首元素后把头指针后移一位,就能达到出队的效果 

    public E poll() throws Exception {
        //如果队列为空,返回null
        if(isEmpty())
        {
            System.out.println("队列为空");
            return null;
        }
        E element=arr[front];//存储需要出队的元素
        arr[front]=null;
        front=(front+1)%arr.length;//队头指针后移一位
        return element;
    }

5. 获取队首元素

    public E getElement()
    {
        //判断是否为空,为空返回null
        if(isEmpty())
            return null;
        return arr[front];
    }

6. 获取队列长度

    public int size()
    {
        return (rear+arr.length-front)% arr.length;
    }

7. 清空队列

    public boolean clear()
    {
        E[] newArr=(E[]) new Object[arr.length];
        arr=newArr;
        front=rear=0;//必须让指针回归零的位置
        return true;
    }

8. 队列是否包含某元素

    public boolean contains(E element)
    {
        if(isEmpty())
            return false;
        for (E e : arr) {
            if(e==element)
                return true;
        }
        return false;
    }

9. 输出队列

    public void print()
    {
        for (int i = front; i != rear; i=(i+1)%arr.length) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

10.主函数检验

public static void main(String[] args) throws Exception {
        MyQueue<Integer> myque=new MyQueue<>(5);
        myque.offer(1);//入队rear0->1
        myque.offer(2);//rear1->2
        myque.offer(3);//rear2->3
        myque.offer(4);//rear3->4
        myque.poll();//1出队 front0->1
        myque.poll();//2出队 front1->2
        myque.offer(5);//5入队 rear4->5->0
        myque.print();//3 4 5 rear==0 front==2
        System.out.println(myque.getElement());//3
        System.out.println(myque.contains(4));//true
        System.out.println(myque.contains(1));//false
        myque.offer(3);//入队 rear0->1+1==front队列已满
        myque.offer(8);//
        myque.offer(9);
        myque.print();//3 4 5 3队列实际可存储元素为arr.length-1个也就是4个
        System.out.println(myque.clear());//清空
        myque.offer(888);
        myque.print();//888
    }

11.完整代码

import java.util.Scanner;
/*
* JAVA自带Queue队列接口
* LinkedList(双向链表)、ArrayList均可实现Queue
* boolean add(E element): 将指定的元素添加到队列的末尾,如果成功则返回true,如果队列已满则抛出异常。
* boolean offer(E element)同上,如果队列已满返回false;
* E remove() 移除并返回队列头部元素,如果队列为空抛出异常
* E poll() 同上,如果队列为空返回null
* E element()获取队列头部的元素,但不移除,队列为空抛出异常
* E peek() 同上,队列为空返回null
* int size()返回队列中元素个数
* boolean isEmpty() 判断队列是否为空
* clear()清空
* contains(Object o)是否包含某元素
   */
public class MyQueue<E> 
{
    private E[] arr;
    private int front;//头部指针
    private int rear;//尾部指针
    public MyQueue(int MaxSize)
    {
        arr=(E[])new Object[MaxSize];
    }
    //判断是否为空
    public boolean isEmpty()
    {
        return rear==front;//头指针等于尾指针,队列无元素
    }
    //入队
    public boolean offer(E element) throws Exception {
        //判断队列是否已满,已满返回false
        if((rear+1)%arr.length==front)
        {
            System.out.println("队列已满");
            return false;
        }
        arr[rear%arr.length]=element;
        rear=(rear+1)%arr.length;//队尾指针后移一位
        return true;
    }
    //出队
    public E poll() throws Exception {
        //如果队列为空,返回null
        if(isEmpty())
        {
            System.out.println("队列为空");
            return null;
        }
        E element=arr[front];//存储需要出队的元素
        arr[front]=null;
        front=(front+1)%arr.length;//队头指针后移一位
        return element;
    }
    //获取队首元素
    public E getElement()
    {
        //判断是否为空,为空返回null
        if(isEmpty())
            return null;
        return arr[front];
    }
    //返回队列中的元素个数
    public int size()
    {
        return (rear+arr.length-front)% arr.length;
    }
    //清空
    public boolean clear()
    {
        E[] newArr=(E[]) new Object[arr.length];
        arr=newArr;
        front=rear=0;//必须让指针回归零的位置
        return true;
    }
    //是否包含某元素
    public boolean contains(E element)
    {
        if(isEmpty())
            return false;
        for (E e : arr) {
            if(e==element)
                return true;
        }
        return false;
    }
    //输出队列
    public void print()
    {
        for (int i = front; i != rear; i=(i+1)%arr.length) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) throws Exception {
        MyQueue<Integer> myque=new MyQueue<>(5);
        myque.offer(1);//入队rear0->1
        myque.offer(2);//rear1->2
        myque.offer(3);//rear2->3
        myque.offer(4);//rear3->4
        myque.poll();//1出队 front0->1
        myque.poll();//2出队 front1->2
        myque.offer(5);//5入队 rear4->5->0
        myque.print();//3 4 5 rear==0 front==2
        System.out.println(myque.getElement());//3
        System.out.println(myque.contains(4));//true
        System.out.println(myque.contains(1));//false
        myque.offer(3);//入队 rear0->1+1==front队列已满
        myque.offer(8);//
        myque.offer(9);
        myque.print();//3 4 5 3队列实际可存储元素为arr.length-1个也就是4个
        System.out.println(myque.clear());//清空
        myque.offer(888);
        myque.print();//888
    }
}

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值