Data Structures: Stacks and Queues

1. Stack (stack)

1. The concept of stack:

A stack is a special linear list that only allows insertion and deletion of elements at one end. The end where data insertion and deletion operations are performed is called the top of the stack , and the other end is called the bottom of the stack . The data elements in the stack follow the principle of LIFO (Last In First Out).

 2. Implementation of the stack

The implementation of the stack can generally be implemented using an array or a linked list. Relatively speaking, the structure of the array is better. Because the cost of tail-inserting data in an array is relatively small.

 With the continuous push into the stack, the data in the stack is also increasing, and the operations of pushing into and popping out of the stack are all performed on the top of the stack.

 //入栈
    void  push(T ele);
    //出栈
    T pop();
    //查看顶部元素
    T peek();
    //栈是否为空
    boolean isEmpty();
    //栈中的元素
    int size();
 private selfArray<T> data;

    public Arrstack() {
        this.data = new selfArray<>();
    }

    public Arrstack(int capacity) {
        this.data = new selfArray<>(capacity);
    }

    @Override
    public void push(T ele) {
        data.addlast(ele);
    }

    @Override
    public T pop() {
        return data.removeTail();
    }

    @Override
    public T peek() {
        return data.getindex(size() - 1);
    }

    @Override
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override
    public int size() {
        return data.getSize();
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder("栈顶[");
        T[] arr = data.getDate();
        for (int i = data.getSize()-1; i >= 0; i--) {
            stringBuilder.append(arr[i]);
        }
        stringBuilder.append("]栈底");
        return stringBuilder.toString();
    }

1. Push into the stack (implementation method of the underlying array):

 //向中间添加元素
    public void addmid(T val,int index)  {
        //对入参进行判断
        if(index<0||index>size){
            throw new IllegalArgumentException("数组越界异常");
        }
        //判断此容器有没有满
        if(this.size==this.capacity){
            int newcapa = this.capacity*2;
            reserve(newcapa);
        }
        //将指定的位置之后的元素向后移
        for (int i = this.size-1; i >=index ; i--) {
            this.data[i + 1] = this.data[i];
        }
        //将元素插入到指定位置
        this.data[index]=val;
        //更新size的值
        this.size+=1;
    }

2. Pop out:

//删除任意位置的元素
    public  T  remove(int index){
        if(index<0||index>=this.size){
            throw new IllegalArgumentException("数组索引越界");
        }
        T  a = this.data[index];
        for (int i = index; i <size-1 ; i++) {
            this.data[i]=this.data[i+1];
        }
        this.size-=1;
        if(this.size<=this.capacity/4&&this.size>1){
            int newcapa = this.capacity/2;
            reserve(newcapa);
        }
        return a;
    }

3. Get the element at the top of the stack

//获取指定位置的元素
    public  T getindex(int index){
        if(index<0||index>=size){
            throw new IllegalArgumentException("数组越界异常");
        }
        return this.data[index];
    }

Two. Queue

1. Concept

The queue is a linear data structure; the queue only allows deletion operations at the front end of the table, and insertion operations at the back end of the table. Like the stack, the queue is a linear table with limited operations; the end of the insertion operation It is called the tail of the team, and the end that performs the delete operation is called the head of the team.

2. Code implementation 

1. Array-based implementation

  //入队
    void offer(T ele);

    //出队
    T poll();

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

    //队中实际的元素
    int size();

    //查看对首的元素
    T peek();
CycleArray<T> data;

    public ArrQueue() {
        this.data=new  CycleArray<>();
    }

    public ArrQueue(int capacity){
        this.data=new  CycleArray<>(capacity);
    }

    @Override
    public void offer(T ele) {
        data.addtail(ele);
    }

    @Override
    public T poll() {
        return data.removeHead();
    }

    @Override
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override
    public int size() {
        return data.getSize();
    }

    @Override
    public T peek() {
        Optional<T> optional = data.getFront();
        if(optional.isPresent()){
            return optional.get();
        }
        return null;
    }

2. Circular Queue

When deleting elements in the array, the elements will move forward. In order to solve the problem of moving forward, you can use front to record the position of the head of the queue, and use tail to record the position of the end of the queue. This is a circular queue.   It can be implemented by using an array or by using a loop linked list implementation.
Key point: Circular queue, whether it is implemented by an array or a linked list, needs to open an extra space, which means that if a circular queue that stores k data, it needs to open k+1 space, otherwise it will not be possible to judge empty and full

 (1) Array code implementation

 

  //数据容器
    private T[] data;
    //数组大小
    private int capacity;
    //数组实际存入的元素数量
    private int size;
    //声明两个索引  队首
     int front=0;
     //队尾
     int tail=0;

    public CycleArray() {
        this(10);
    }

    public CycleArray(int capacity) {
        this.capacity = capacity+1;
        this.data = (T[]) new Object[this.capacity];
        this.size = 0;
    }

    //判断数组是否为空
    public boolean isEmpty() {
        return this.front==this.tail;
    }

    //获取数组的大小
    public int getCapacity() {
        return this.capacity;
    }

    //获取实际元素的个数
    public int getSize() {
        return this.size;
    }

    //向尾部添加元素
    public void addtail(T val){
        //当队列已满,需要进行扩容
        if((this.tail+1)%this.capacity==this.front){
            //新容积
            int Newcapa = (this.capacity-1)*2;
            reserve(Newcapa);
        }
        //将val插入队列的尾部
        this.data[this.tail]=val;
        //tail向后移
        this.tail=(this.tail+1)%capacity;
        //更新size的值
        this.size+=1;
    }
    public  T[] getDate(){
       return this.data;
    }
    //扩容
    public void reserve(int Newcapa) {
        T[]newdata = (T[])new Object[Newcapa+1];
       int cur = this.front;
       int index=0;
       while (cur!=this.tail){
           newdata[index++]=this.data[cur];
           cur=(cur+1)%this.capacity;
       }
        //更新新数组的属性
        this.capacity=Newcapa+1;
        this.data=newdata;
        this.front=0;
        this.tail=this.size;
    }
    //删除头部的元素
    public T removeHead(){
       //判断队列是否为空
        if(this.front==this.tail){
            return null;
        }
        T val = this.data[this.front];
        this.front=(this.front+1)%capacity;
        this.size--;

        //判断是否缩容
        if(this.size<=this.capacity/4&&this.capacity/2>1){
            reserve(this.capacity/2);
        }
        return val;
    }

    public Optional<T>  getFront(){
        if(isEmpty()){
            return Optional.empty();
        }
        return Optional.of(this.data[this.front]);
    }

    //重写tostring
    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        int cur = this.front;
        while (cur!=this.tail){
            stringBuilder.append(this.data[cur]);
            if((cur+1)%this.capacity!=this.tail){
                stringBuilder.append(",");
            }
            cur=(cur+1)%this.capacity;

        }
        stringBuilder.append(":"+this.front+"<--->"+this.tail);
        return stringBuilder.toString();
    }

Guess you like

Origin blog.csdn.net/weixin_71243923/article/details/127672597