Estructuras de datos Java y pilas y colas de algoritmos

        En la vida, a menudo nos encontramos con estas situaciones: 1. Cuando alguien distribuye libros en la escuela, si quiere sacar el libro de arriba para leer, puede sacarlo directamente, pero si quiere sacar el libro del medio Si mira el libro en esta posición, debe quitar el libro presionado para ver el libro. En este momento, solo se puede sacar primero la parte superior y luego se puede sacar la parte inferior.

 2. Cuando alguien está fuera de clase y va a la cafetería de la escuela a comer, cuando hay mucha gente, necesita hacer fila. Suponga que no hay corte de cola. Luego, si quiere comer, debe esperar a que las personas frente a él terminen de hacer fila, y luego puede comer cuando llegue. En este momento, el que hace cola va primero y el que hace cola va después.

Los dos casos anteriores corresponden a dos estructuras de datos en la estructura de datos: pila y cola. La característica principal del primero es el primero en entrar, el último en salir, y el caso más importante del segundo es el primero en entrar, el primero en salir. A continuación se describen principalmente las características y diferencias entre los dos.

1. Pila (pila)

1. Concepto

        Una pila es un tipo especial de lista lineal que solo permite la inserción y eliminación de elementos en un extremo fijo. Un extremo donde se realizan la inserción y eliminación de datos se denomina parte superior de la pila y el otro extremo se denomina parte inferior de la pila . Los elementos de datos en la pila siguen el principio LIFO (último en entrar, primero en salir).

Empujar pila : la operación de inserción de la pila se llama empujar/empujar/empujar, y los datos empujados están en la parte superior de la pila.

Pop : La eliminación de la pila se llama pop. Los datos de salida están en la parte superior de la pila.

 El principio subyacente de la implementación de la pila es una lista de secuencias o una lista enlazada. Aquí, usamos la lista de secuencias para implementar algunas operaciones en la pila, como empujar la pila, abrir la pila, verificar los elementos en la parte superior de la pila, y juzgar si la pila está vacía. Si usa la tabla de secuencia, solo necesita insertar y eliminar la cola. También es posible la eliminación del conector de cabeza, pero en este caso la complejidad de tiempo es alta, mientras que la eliminación del conector de cola y la cola solo requiere una complejidad de tiempo de O(1).

2. Implemente usted mismo algunas operaciones de la pila

1) Propiedades básicas

Aquí se supone que los elementos de tipo entero se almacenan, luego se define primero una matriz de tipo int. Al mismo tiempo, como se puede ver en la figura anterior, hay una parte superior de la pila, que es simplemente el tamaño efectivo de una matriz. Luego estamos definiendo una variable top de tipo int para almacenar el tamaño efectivo de la matriz. Aquí, asumimos que el tamaño de la matriz es 10.

class stack {
    private int[] array;
    private int top;
    //合适的构造方法,将数组初始化,刚开始top没有元素,是0;
    public stack() {
        this.array = new int[10];
    }
}

2) Empuje la pila (push)

Pasamos un valor val. Primero, necesitamos determinar si la mesa está llena. Si es así, necesitamos expandir la capacidad. Si no, después de poner el elemento, deja que top lo agregue una vez.

    //压栈操作
    public void push(int val) {
        if(this.array.length == this.top) {
            this.array = Arrays.copyOf(this.array, 2 * this.array.length);
        }
        this.array[top] = val;
        top++;
    }

3) ¿Está vacío (vacío)

Se puede juzgar si top es 0 o no.

    //是否为空
    public boolean empty() {
        return this.top == 0;
    }

4) pop la pila (pop)

Extraiga la pila, extraiga el elemento en la parte superior de la pila y, al mismo tiempo, use una variable para aceptarlo. Primero determine si está vacío, si está vacío, lance una excepción, de lo contrario, después de regresar al elemento superior de la pila, simplemente disminuya la parte superior en uno. 

    //出栈操作
    public int pop() {
        if(empty()) {
            throw new UnsupportedOperationException("栈为空!");
        }
        int ret = this.array[this.top - 1];//下标
        this.top--;//top减一
        return ret;
    }

5) Ver el elemento superior de la pila (mirar)

Similar a 4), solo necesita verlo, pero no necesita disminuir la parte superior en uno.

    //查看栈顶元素但不弹出
    public int peek() {
        if(empty()) {
            throw new UnsupportedOperationException("栈为空!");
        }
        int ret = this.array[this.top - 1];
        return ret;
    }

El resultado es el siguiente:

import java.util.Arrays;

class stack {
    //封装
    private int[] array;
    private int top;
    //合适的构造方法,将数组初始化,top默认是0;
    public stack() {
        this.array = new int[10];
    }
    //压栈操作
    public void push(int val) {
        if(this.array.length == this.top) {
            this.array = Arrays.copyOf(this.array, 2 * this.array.length);
        }
        this.array[top] = val;
        top++;
    }
    //出栈操作
    public int pop() {
        if(empty()) {
            throw new UnsupportedOperationException("栈为空!");
        }
        int ret = this.array[this.top - 1];
        this.top--;
        return ret;
    }
    //是否为空
    public boolean empty() {
        return this.top == 0;
    }
    //查看栈顶元素但不弹出
    public int peek() {
        if(empty()) {
            throw new UnsupportedOperationException("栈为空!");
        }
        int ret = this.array[this.top - 1];
        return ret;
    }
}

public class Main {
    public static void main(String[] args) {
        stack stack = new stack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.peek());//3
        stack.pop();
        System.out.println(stack.peek());//2
        System.out.println(stack.empty());//false
    }
}

3. Algunas operaciones de la pila empaquetada oficialmente

Java ya ha encapsulado estas estructuras de datos y puede importar directamente el paquete apropiado para llamar. Si está interesado, puede ir al manual de ayuda de Java o ver el código fuente de estos métodos. Pila (Java Platform SE 8) (oracle.com) https://docs.oracle.com/javase/8/docs/api/java/util/Stack.html#push-E-

import java.util.Arrays;
import java.util.Stack;

public class Main {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();//要导入包
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.peek());//3
        stack.pop();
        System.out.println(stack.peek());//2
        System.out.println(stack.empty());//false
    }
}

2. Cola

(1), Cola (Cola)

1. Concepto

Queue: Una tabla lineal especial que solo permite operaciones de inserción de datos en un extremo y operaciones de eliminación de datos en el otro extremo.La cola tiene un First In First Out (primero en entrar, primero en salir). En la cola: El final de la operación de inserción se denomina cola (Tail/Rear). Dequeue: El extremo que realiza la operación de eliminación se denomina cabeza de la cola. (Cabeza/Frente)

2. Implemente algunas operaciones de la cola usted mismo

Las colas también se pueden implementar como matrices y listas vinculadas. Es mejor usar la estructura de la lista enlazada, porque si se usa la estructura de la matriz, la eficiencia será menor cuando los datos se eliminen de la cola en la cabecera de la matriz. Tiene un funcionamiento similar a la pila. Hacemos esto usando una lista enlazada simple. 

1) Propiedades básicas

Aquí se supone que se almacena un elemento de tipo entero, el nombre de la clase es Nodo, se define un valor de elemento de tipo int y se define un elemento de tipo referencia de tipo Nodo siguiente que almacena la dirección del siguiente elemento.

class Node {
    //私有权限,设置成公有的也行,更直接
    private int val;
    private Node next;
    
    public Node(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

2) Únete al equipo (oferta)

Pasamos un valor val, y establecemos dos punteros primero y último para almacenar las direcciones de la cabeza y la cola respectivamente. Primero, necesitamos determinar si este nodo se inserta por primera vez. Si es así, dejemos que el primero y el último apunten a este nodo al mismo tiempo. , si no, después de poner el elemento, deje que el último anterior apunte a la dirección del elemento insertado.

class queue {
    private Node first;
    private Node last;
    //入队
    public void offer(int val) {
        Node node = new Node(val);
        if(this.first == null) {
            this.first = node;
            this.last = node;
        } else {
            this.last.setNext(node);
            this.last = node;
        }
    }
}

3) ¿Está vacío (isEmpty)

Basta con juzgar si el primer puntero está vacío.

    //是否为空
    public boolean isEmpty() {
        return this.first == null;
    }

4) sacar de la cola (encuesta)

Primero determine si está vacío, en caso afirmativo, lance una excepción; de lo contrario, después de obtener el elemento, primero apunte directamente al siguiente elemento.

    //出队
    public int poll() {
        if(isEmpty()) {
            throw new UnsupportedOperationException("队为空!");
        } 
        int ret = this.first.getVal();
        this.first = this.first.getNext();
        return ret;
    }

5) Obtener el elemento principal pero no eliminarlo

Similar a 4), pero sin moverse primero.

    //得到队头元素但不删除
    public int peek() {
        if(isEmpty()) {
            throw new UnsupportedOperationException("队为空!");
        }
        int ret = this.first.getVal();
        return ret;
    }

El resultado es el siguiente:

class Node {
    //私有权限
    private int val;
    private Node next;

    public Node(int val) {
        this.val = val;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

class queue {
    private Node first;
    private Node last;
    //入队
    public void offer(int val) {
        Node node = new Node(val);
        if(this.first == null) {
            this.first = node;
            this.last = node;
        } else {
            this.last.setNext(node);
            this.last = node;
        }
    }
    //出队
    public int poll() {
        if(isEmpty()) {
            throw new UnsupportedOperationException("队为空!");
        }
        int ret = this.first.getVal();
        this.first = this.first.getNext();
        return ret;
    }
    //得到队头元素但不删除
    public int peek() {
        if(isEmpty()) {
            throw new UnsupportedOperationException("队为空!");
        }
        int ret = this.first.getVal();
        return ret;
    }
    //是否为空
    public boolean isEmpty() {
        return this.first == null;
    }
}

public class Main {
    public static void main(String[] args) {
        queue queue = new queue();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.peek());//1
        queue.poll();
        System.out.println(queue.peek());//2
        System.out.println(queue.isEmpty());//false
    }
}

3. Algunas operaciones de la cola empaquetada oficial

Cola (Java Platform SE 8) (oracle.com) https://docs.oracle.com/javase/8/docs/api/java/util/Queue.html

public class Main {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue.peek());//1
        queue.poll();
        System.out.println(queue.peek());//2
        System.out.println(queue.isEmpty());//false
    }
}

(2), cola doble (Deque)

        Una deque es una cola que permite operaciones de encolado y desencolado en ambos extremos. Los elementos se pueden sacar y poner en cola desde el principio de la cola, y también se pueden sacar y poner en cola desde el final de la cola. Veamos directamente la encapsulación de Java de estas operaciones. Si estás interesado, puedes leer su código fuente.


Deque (Plataforma Java SE 8) (oracle.com) https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html

(3) cola circular

En la práctica, encontrará un tipo de cola llamada cola circular. Lo ilustramos con colas estáticas.

A veces, estamos mostrando los elementos al principio de la cola y luego necesitamos agregar nuevos elementos, que se pueden agregar directamente al final de la cola. Si una matriz está llena, lo primero que viene a la mente es la expansión. Pero cuando volvimos a mirar, encontramos que la posición que apareció al frente estaba vacía.

 Esto ahorra mucho espacio. A continuación, usamos una matriz para implementar una cola circular nosotros mismos.

1) Propiedades básicas

Como se puede ver en la figura anterior, una cola circular debe contener al menos una matriz (elemento), una cabeza de cola (frontal) y una cola de cola (posterior). Lo envolvemos en la clase MyCircularQueue. Proporcione un constructor adecuado (MyCircularQueue).En este constructor, defina el tamaño de la matriz, el subíndice de la cabeza de la cola y el subíndice de la cola de la cola.

class MyCircularQueue {   
    private int[] elem;//数组
    private int front;//头下标
    private int rear;//尾下标

    public MyCircularQueue(int k) {
       
        this.elem = new int[k];
        this.rear = 0;
        this.front = 0;
    }
}

2) Ingrese a la cola (enterQueue)

En cada paso de la operación de ingreso a la cola, es necesario juzgar si la cola está llena (isFull). Si está llena, se informa un error. De lo contrario, el elemento se coloca en el espacio del subíndice de cola, y en al mismo tiempo, el subíndice de la cola se incrementa en 1. Pero no se puede agregar directamente aquí De la situación anterior, podemos saber que puso 8 en el subíndice de 0, donde trasero es originalmente el subíndice 7, que obviamente está fuera de los límites en +1. Se requieren cambios menores. cambiarlo a:

this.rear = (this.rear + 1) % this.elem.length; (la longitud de la matriz)

    public boolean enterQueue(int val) {
        if(isFull()) {
            return false;
        }
        this.elem[this.rear] = val;
        this.rear = (this.rear + 1) % this.elem.length;
        return true;
    }
    public boolean isFull() {

        return (this.rear + 1) % this.elem.length == this.front;
    }

3) Fuera de la cola (deleteQueue)

Determine si está vacío, si no, deje que el encabezado subíndice +1.

    public boolean deleteQueue() {
        if(isEmpty()) {
            return false;
        }
        this.front = (this.front + 1) % this.elem.length;
        return true;
    }
    public boolean isEmpty() {
        //相遇了,就是空的队列,不理解可以去画图
        return this.front == this.rear;
    }

4) Obtenga el elemento principal (Frente)

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

5) Obtener el elemento trasero (Trasero)

Cabe señalar que si la parte trasera alcanza la capacidad máxima, en +1, llegará al subíndice 0, que debe tenerse en cuenta.

    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        //当rear到0下标的时候
        int index = (this.rear == 0) ? this.elem.length - 1 : this.rear - 1;
        return this.elem[index];
    }

El código completo es el siguiente:

class MyCircularQueue {

    private int[] elem;//数组
    private int front;//头下标
    private int rear;//尾下标

    public MyCircularQueue(int k) {
        
        this.elem = new int[k];
        this.rear = 0;
        this.front = 0;
    }

    public boolean enterQueue(int val) {
        if(isFull()) {
            return false;
        }
        this.elem[this.rear] = val;
        this.rear = (this.rear + 1) % this.elem.length;
        return true;
    }

    public boolean deleteQueue() {
        if(isEmpty()) {
            return false;
        }
        this.front = (this.front + 1) % this.elem.length;
        return true;
    }

    //得到队头的元素
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return this.elem[this.front];
    }

    //得到队尾的元素
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        //当rear到0下标的时候
        int index = (this.rear == 0) ? this.elem.length - 1 : this.rear - 1;
        return this.elem[index];
    }

    public boolean isEmpty() {
        //相遇了,就是空的队列
        return this.front == this.rear;
    }

    public boolean isFull() {

        return (this.rear + 1) % this.elem.length == this.front;
    }
}

Supongo que te gusta

Origin blog.csdn.net/Naion/article/details/122428859
Recomendado
Clasificación