用数组和链表实现定容量栈和队列

一.什么是栈,什么是队列?

栈是后进先出(LIFO)即last in first out

我们若是想实现后进先出,由图可见,只能选择一个口操作数据

队列是先进先出(FIFO)即first in first out

我们若是想实现先进先出,由图可见,取出只与first相关,进入只与last相关

二.数组实现栈

数组与链表的区别见本人用Java实现简易链表的文章中,不清楚的小伙伴可以去看一下喔

1.通过构造方法初始化队列容量

由于数组在实例化确定了长度之后,长度是不可变的,所以需要有容量这个参数且要初始化容量


    public MyStack(int capacity) {
        datas=new Object[capacity];
    }
   //创建栈时,给定的定容量

2.成员变量

    Object datas[];//底层存储用的数组
    int size;//存储的数据个数

3.基本方法实现(put放入,take取出并删除)

  public void put(E e){
        datas[size] =e;
        size++;
    }

由于在删除数组中某个数据时,需要将后面的所有元素往前移动一个位置,所以我们在选择栈的操作口时,可以选择尾端,这样,就避免了移动大量数据

 public Object take(){
        Object last;
        if(size==0){
            throw new IndexOutOfBoundsException("栈中暂无数据,请先添加数据!!!");
        }
        else{
            last= datas[size-1];
            datas[size-1]=null;

        }
        size--;
        return last;
    }

三.链表实现栈

为什么要保证head这个节点的data一直为null?

head的data若不为null,用图示表示(图中head的data记为head)

下面图示两个栈的第一个节点都为右边的节点,只是第一个不可以之后,想利用存储上一个节点的方式破局,结果也是不行的

这两种方式均无法实现,其原因是一样的,它们的口分别是head和last,而像上面那样做,只会让新节点离口越来越远,也就是说无法让新节点与head或last联系起来,以至于无法取出刚存入的新节点

而解决方法就是让新节点一直都是在head之后的

取出新节点时,就可以直接与head联系起来,做到后进先出

head自己如果存有data值,无疑应该是第一个加入的,那就会变成先进先出了,所以设置一个这样特殊的head节点就可以很容易的实现先进先出啦

1.链表需要先创建一个节点类

public class MyNode<E> {
    Object data;
    MyNode<E> next;

    public MyNode(E data, MyNode<E> next) {
        this.data = data;
        this.next = next;
    }
}

2.成员变量

    MyNode<E> head;
    int size;

3.基本方法实现

 public void put(E e){
        //头节点不存储数据
        if(size==0){
            head= new MyNode<>(null,new MyNode<>(e,null));
        }
        else{
            //先获取之前的第一个节点
            MyNode<E> oldfirst=head.next;
            //创建一个新的节点
            // 新节点要指向之前的第一个节点
            MyNode<E> newnode=new MyNode<>(e,oldfirst);
            //头节点指向新节点
            head.next=newnode;
        }
        size++;
    }
 public Object take() {
        //如果栈为空,报错
        Object data;
        if (size == 0) {
            throw new IndexOutOfBoundsException("栈目前为空,请先加入数据!!");
        } else {
            //先记录一下要被取走的节点数据
            MyNode<E> oldfirst = head.next;
            data = oldfirst.data;
            head.next=oldfirst.next;
            size--;
        }
        return data;
    }

四.数组实现队列

  1. 构造方法定容量

 MyArrayQueue(int capacity){
     this.capacity=capacity;
     objects=new Object [this.capacity];
    }
  1. 成员变量

    int first=0;
    int last=0;
    //放入数据时与last有关
    //取出数据时与first有关
    int capacity;
    Object objects[];
  1. 方法实现

 public void put(E e ){
       //防止数据添加超出容量
        if(last==capacity){
            throw new IndexOutOfBoundsException("超出容量,无法添加!!!");
        }
        last++;
        objects[last-1]=e;
        System.out.println("放进去了一个数据");
    }
 public Object take(){
        //取之前判断队列是否为空
        if(first==last){
            throw new ArrayIndexOutOfBoundsException("当前数列为空,请先添加数据!!!");
        }
        Object f=objects[first];
        //得到这个数据之后,把这个数据删除掉
        //用数组的弊端?删除一个数据,需要将所有的数据往前移动?
        for(int i=1;i<last;i++){
            objects[i-1]=objects[i];
        }
        System.out.println("拿走了"+f);
        //同贪吃蛇类似,需要注意遍历的方向
        return f;
    }

五.链表实现队列

比起数组实现的队列,链表实现队列会更加容易

1.链表需要先创建一个节点类

public class MyNode<E> {
    Object data;
    MyNode<E> next;

    public MyNode(E data, MyNode<E> next) {
        this.data = data;
        this.next = next;
    }
}

2.成员变量

    MyNode<E> first;
    MyNode<E> last;
    int size;

3.方法实现

 public void put(E e){
       //实现addlast
       //头节点为空时,初始化头节点
       if(first==null) {
           first = new MyNode<>(e, null);
           last=first;
           size++;

       }
       else{
           last.next=new MyNode<>(e,null);
           last=last.next;
           size++;
       }

   }
 public Object take(){
       //当队列为空时
       if(size==0){
           throw new IndexOutOfBoundsException("没有数据可以被取出了!!");

       }
       //实现pollfirst
       Object data=first.data;
      MyNode<E> next =first.next;
      first.data=null;
      first.next=null;
      first=next;
      size--;
      return data;
   }

六.一些其他简单方法的实现

以下的方法实现以数组实现栈为例

栈中目前所存数据的个数

 public int sizeOf(){
        return size;
    }

栈是否为空

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

遍历栈中的数据

 public void travel(){
        System.out.print("{");
        for(int i=0;i<size-1;i++){
           Object data= datas[i];
           System.out.print(data+",");
        }
        Object data2=datas[size-1];
        System.out.print(data2);
        System.out.println("}");
    }

七.方法测试

测试方法的代码呈现

 public static void main(String[] args) {
        MyStack<String> stack=new MyStack<>(10);
        stack.put("李佳*");
        stack.put("赵怡*");
        stack.put("陈姝*");
        stack.travel();
        System.out.println("拿走了"+stack.take());
        System.out.println("拿走了"+stack.take());
        System.out.println("拿走了"+stack.take());
        System.out.println("栈中的数据个数为"+stack.sizeOf());
        System.out.println(stack.isEmpty());
    }

测试结果呈现

{李佳*,赵怡*,陈姝*}
拿走了陈姝*
拿走了赵怡*
拿走了李佳*
栈中的数据个数为0
true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值