常用数据结构(Java实现)


—————————————————————
gitee源码地址
—————————————————————

一、数组

/**
 * 自定义数据结构-数组
 * @author ZYQ
 * @Date 2021/2/15 16:19
 **/
public class Array<E> {

    /**
     * 用于存储元素的数组
     */
    private E[] data;
    /**
     * 当前存储的元素个数
     */
    private int size;

    /**
     * 每次扩大的倍数
     */
    private final static int EXPAND = 2;

    /**
     * 需要缩减的标志, 当元素个数小于等于 容量/NARROW_TAG时触发缩减
     */
    private final static int NARROW_TAG = 4;

    /**
     * 每次缩小的倍数
     */
    private final static int NARROW = 2;

    /**
     * 自定义数组的初始化容量
     * @param capacity 数组的初始容量
     */
    public Array(int capacity) {
        this.data = (E[])new Object[capacity];
    }

    /**
     * 数组的初始化容量默认为10
     */
    public Array() {
        this(10);
    }

    /**
     * 向数组的指定位置添加元素
     * @param index 插入元素的位置
     * @param e 添加的元素
     */
    public void add(int index, E e){
        // 判断下标是否合法
        if (index < 0 || index > this.size) {
            throw new IllegalArgumentException("添加元素失败, index必须不小于0且不大于size");
        }

        // 判断是否需要进行扩容
        if (this.size == this.data.length) {
            // 将容量扩大为原来的两倍
            this.resize(this.size * EXPAND);
        }

        // index后面的元素向后移动
        for (int i = this.size; i > index; i--) {
            this.data[i] = this.data[i-1];
        }

        this.data[index] = e;
        this.size ++;
    }

    /**
     * 向数组的第一个位置插入元素
     * @param e 添加的元素
     */
    public void addFirst(E e) {
        this.add(0, e);
    }

    /**
     * 向数组的最后添加元素
     * @param e 添加的元素
     */
    public void addLast(E e) {
        this.add(this.size, e);
    }

    /**
     * 移除数组中指定位置的元素
     * @param index 数组下标
     * @return 移除的元素
     */
    public E remove(int index) {
        // 判断下标是否合法
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("删除元素失败, index必须不小于0且小于size");
        }
        E ret = this.data[index];
        // index后面的元素往前移动
        for (int i = index; i < this.size - 1; i++){
            this.data[i] = this.data[i+1];
        }
        this.data[--this.size] = null;

        // 当存储元素的个数为总容量的四分之一时,将容量缩减为原来的一半
        if (this.size <= this.data.length/ NARROW_TAG && this.data.length/ NARROW > 0) {
            this.resize(this.data.length/ NARROW);
        }
        return ret;
    }

    /**
      * 删除第一个元素
      * @return 删除的元素
     */
    public E removeFirst() {
       return this.remove(0);
    }

    /**
     * 删除最后一个元素
     * @return 删除的元素
     */
    public E removeLast() {
        return this.remove(size - 1);
    }

    /**
     * 修改数组指定下标的元素
     * @param index 数组下标
     * @param e 修改后的元素
     * @return 返回修改前的元素
     */
    public E setData(int index, E e) {
        // 判断下标是否合法
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("修改元素失败, index必须不小于0且小于size");
        }
        E element = this.data[index];
        this.data[index] = e;
        return element;
    }

    /**
     * 获取指定下标的元素
     * @param index 数组下标
     * @return 返回元素
     */
    public E getData(int index) {
        return this.data[index];
    }

    /**
     * 在数组中查找指定元素,找到返回第一个的下标,否则返回负数
     * @param e 要查找的元素
     * @return 返回元素下标,否则返回负数
     */
    public int find(E e) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 重置数组的容量
     * @param newCapacity 数组的容量
     */
    private void resize(int newCapacity) {
        E[] arr = (E[]) new Object[newCapacity];
        if (size >= 0) {
            System.arraycopy(this.data, 0, arr, 0, size);
        }
        this.data = arr;
    }
/**
     * 交换两个元素的位置
     * @param i 元素1
     * @param j 元素2
     */
    public void swap(int i, int j) {
        // 判断下标是否合法
        if (i < 0 || i >= this.size || j < 0 || j >= this.size) {
            throw new IllegalArgumentException("交换元素失败, index必须不小于0且小于size");
        }
        E e = data[i];
        data[i] = data[j];
        data[j] = e;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("capacity = %d, size = %d\n", this.data.length, this.size));
        sb.append("[");
        for (int i = 0; i < this.size; i++) {
            sb.append(this.data[i]);
            if (i != this.size - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}

二、链表

/**
 * @author IT00ZYQ
 * @Date 2021/2/16 11:50
 **/
public class LinkedList<E> {

    private Node<E> head;

    private int size;


    public LinkedList() {
        this.head = new Node<>(null, null);
    }

    /**
     * 判断链表是否为空
     * @return true/false
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 获取元素个数
     * @return 元素个数
     */
    public int size() {
        return size;
    }

    /**
     * 向指定位置添加结点
     * @param e 要添加的元素
     */
    public void add(int index, E e) {

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("添加元素失败,index < 0 || index > size");
        }

        if (e == null) {
            throw new IllegalArgumentException("添加元素失败,添加的元素为NULL");
        }

        Node<E> temp = head;
        // 找到要插入位置的前一个结点
        for (int i=0; i<index; i++) {
            temp = temp.next;
        }
        // 插入结点
        temp.next = new Node<>(e, temp.next);
        size ++;
    }

    /**
     * 向链表头添加结点
     * @param e 添加的元素
     */
    public void addFirst(E e) {
        add(0, e);
    }

    /**
     * 向链表末端添加结点
     * @param e 添加的元素
     */
    public void addLast(E e) {
        add(size, e);
    }


    /**
     * 删除指定位置的结点
     * @param index 位置
     * @return 删除的元素
     */
    public E remove(int index) {

        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("删除元素失败,index < 0 || index > size");
        }

        Node<E> temp = head;
        // 找到要删除结点的前一个结点
        for (int i = 0; i < index; i++) {
            temp = temp.next;
        }
        // 获取要删除的结点
        Node<E> node = temp.next;
        // 删除结点的前一个结点的指针指向删除结点的下一个结点
        temp.next = node.next;
        // 删除结点的指针指向NULL, 便于gc回收
        node.next = null;

        size --;

        return node.e;
    }

    /**
     * 删除表头结点
     * @return
     */
    public E removeFirst() {
        return remove(0);
    }

    /**
     * 删除表尾结点
     * @return
     */
    public E removeLast() {
        return remove(size);
    }

    /**
     * 修改指定位置的结点
     * @param index 结点位置
     */
    public void set(int index, E e) {

        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("修改元素失败,index < 0 || index >= size");
        }

        Node<E> temp = head;
        // 找到要修改的结点
        for (int i=0; i<=index; i++) {
            temp = temp.next;
        }
        temp.e = e;
    }


    /**
     * 查看指定位置的元素
     * @param index 结点下标
     * @return 元素
     */
    public E get(int index) {

        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("查看元素失败,index < 0 || index >= size");
        }

        Node<E> temp = head;
        // 找到要修改的结点
        for (int i=0; i<=index; i++) {
            temp = temp.next;
        }
        return temp.e;
    }

    /**
     * 查看表头元素
     * @return 元素
     */
    public E getFirst() {
        return get(0);
    }

    /**
     * 查看表尾元素
     * @return 元素
     */
    public E getLast() {
        return get(size);
    }

    /**
     * 是否包含某个元素
     * @param e 元素
     * @return true/false
     */
    public boolean contain(E e) {
        Node<E> temp = this.head;
        while (temp.next != null) {
            if (temp.next.e.equals(e)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("LinkedList: size = %d\n", size));
        sb.append("head [ ");
        Node<E> temp = head;
        while (temp.next != null) {
            temp = temp.next;
            sb.append(temp.e);
            sb.append(" -> ");
        }
        sb.append("NULL ] tail");
        return sb.toString();
    }

    private static class Node<E> {
        E e;
        Node<E> next;

        public Node(E e, Node<E> next) {
            this.e = e;
            this.next = next;
        }

    }

}

三、栈

3.1 栈统一接口

/**
 * 栈接口
 * @author IT00ZYQ
 * @Date 2021/2/15 20:21
 **/
public interface Stack<E> {

    /**
     * 判断栈是否为空
     * @return true/false
     */
    boolean isEmpty();

    /**
     * 元素入栈
     * @param e 入栈的元素
     */
    void push(E e);

    /**
     * 弹出栈顶的元素
     * @return 栈顶的元素
     */
    E pop();

    /**
     * 查看栈顶的元素
     * @return 栈顶的元素
     */
    E peek();

    /**
     * 获取栈中元素的个数
     * @return 栈中元素的个数
     */
    int getSize();

}
3.2 基于数组实现栈
/**
 * 基于动态数组实现栈
 * @author IT00ZYQ
 * @Date 2021/2/15 18:41
 **/
public class ArrayStack<E> implements Stack<E>{

    /**
     * 栈
     */
    private Array<E> stack;

    public ArrayStack(int capacity) {
        stack = new Array<>(capacity);
    }

    public ArrayStack() {
        stack = new Array<>();
    }

    /**
     * 判断栈是否为空
     * @return true/false
     */
    @Override
    public boolean isEmpty() {
        return stack.isEmpty();
    }

    /**
     * 元素入栈
     * @param e 入栈的元素
     */
    @Override
    public void push(E e) {
        stack.addLast(e);
    }

    /**
     * 弹出栈顶的元素
     * @return 栈顶的元素
     */
    @Override
    public E pop() {
        return stack.removeLast();
    }

    /**
     * 查看栈顶的元素
     * @return 栈顶的元素
     */
    @Override
    public E peek() {
        return stack.getLast();
    }

    /**
     * @return 栈中元素的个数
     */
    @Override
    public int getSize() {
        return stack.getSize();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("ArrayStack: capacity = %d, size = %d\n", stack.getCapacity(), stack.getSize()));
        sb.append("bottom [");
        for (int i = 0; i < stack.getSize(); i++) {
            sb.append(stack.getData(i));
            if (i != stack.getSize() - 1) {
                sb.append(", ");
            }
        }
        sb.append("] top");
        return sb.toString();
    }

}
3.3 基于链表实现栈
/**
 * 基于链表实现栈, 建表头作为栈顶,所有操作都是O(1)级别
 * @author IT00ZYQ
 * @Date 2021/2/16 14:17
 **/
public class LinkedListStack<E> implements Stack<E> {

    private LinkedList<E> stack;

    public LinkedListStack() {
        stack = new LinkedList<>();
    }

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

    @Override
    public void push(E e) {
        stack.addFirst(e);
    }

    @Override
    public E pop() {
        return stack.removeFirst();
    }

    @Override
    public E peek() {
        return stack.getFirst();
    }

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

四、队列

4.1 队列统一接口
/**
 * 队列接口
 * @author zyq
 */
public interface Queue<E> {

    /**
     * 判断队列是否为空
     * @return true/false
     */
    boolean isEmpty();

    /**
     * 元素入队
     * @param e 入队的元素
     */
    void enqueue(E e);

    /**
     * 元素出队
     * @return 出队的元素
     */
    E dequeue();

    /**
     * 查看队首的元素
     * @return 队首的元素
     */
    E getFront();

    /**
     * 获取队列中元素的个数
     * @return 队列中元素的个数
     */
    int getSize();

    /**
     * 获取队列的容量
     * @return 队列的容量
     */
    int getCapacity();

}
4.2 基于数组实现队列
/**
 * 基于动态数组实现队列
 * @author IT00ZYQ
 * @Date 2021/2/15 20:34
 **/
public class ArrayQueue<E> implements Queue<E> {

    private Array<E> arrayQueue;

    public ArrayQueue(int capacity) {
        arrayQueue = new Array<>(capacity);
    }

    public ArrayQueue() {
        arrayQueue = new Array<>();
    }

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

    @Override
    public void enqueue(E e) {
        arrayQueue.addLast(e);
    }

    @Override
    public E dequeue() {
        return arrayQueue.removeFirst();
    }

    @Override
    public E getFront() {
        return arrayQueue.getFirst();
    }

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

    @Override
    public int getCapacity() {
        return arrayQueue.getCapacity();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("ArrayQueue: capacity = %d, size = %d\n", arrayQueue.getCapacity(), arrayQueue.getSize()));
        sb.append("[");
        for (int i = 0; i < arrayQueue.getSize(); i++) {
            sb.append(arrayQueue.getData(i));
            if (i != arrayQueue.getSize() - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }
}
4.3 循环队列(解决队列出队效率问题)
/**
 * 循环队列的实现
 * @author IT00ZYQ
 * @Date 2021/2/15 20:39
 **/
public class LoopQueue<E> implements Queue<E> {

    /**
     * 存储元素的数组
     */
    private E[] data;

    /**
     * 队首下标,队尾下标,元素个数
     */
    private int front, tail, size;

    /**
     * 每次扩大的倍数
     */
    private final static int EXPAND = 2;

    /**
     * 需要缩减的标志, 当元素个数小于等于 容量/NARROW_TAG时触发缩减
     */
    private final static int NARROW_TAG = 4;

    /**
     * 每次缩小的倍数
     */
    private final static int NARROW = 2;

    public LoopQueue(int capacity) {
        this.data = (E[]) new Object[capacity + 1];
    }

    public LoopQueue() {
        this.data = (E[]) new Object[10 + 1];
    }


    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enqueue(E e) {
        // 判断队列是否已满
        if ((tail + 1) % data.length == front) {
            // 进行扩容
            resize(getCapacity() * EXPAND);
        }
        data[tail] = e;
        tail = (tail + 1) % data.length;
        size ++;
    }

    @Override
    public E dequeue() {
        if (isEmpty()) {
            throw new IllegalArgumentException("出队失败,队列为空");
        }

        E e = data[front];
        data[front] = null;
        size --;
        front = (front + 1) % data.length;

        // 判断是否需要进行缩容
        if (getCapacity() / NARROW_TAG >= size && getCapacity() / NARROW > 0) {
            // 容量缩减为原来的一半
            resize(getCapacity() / NARROW);
        }
        return e;
    }

    @Override
    public E getFront() {
        return data[front];
    }

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

    @Override
    public int getCapacity() {
        return this.data.length - 1;
    }

    /**
     * 重置数组的容量
     * @param newCapacity 数组的容量
     */
    private void resize(int newCapacity) {
        E[] arr = (E[]) new Object[newCapacity + 1];
        for (int i=0; i< size; i++) {
            arr[i] = data[(front + i) % data.length];
        }
        front = 0;
        tail = size;
        this.data = arr;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("LoopQueue: capacity = %d, size = %d, front = %d, tail = %d\n", getCapacity(), getSize(), front, tail));
        sb.append("[");
        for (int i = 0; i < getSize(); i++) {
            sb.append(data[(front + i) % data.length]);
            if (i != getSize() - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }


    public static void main(String[] args) {
        Queue<Integer> queue = new LoopQueue<>();
        for (int i = 1; i <= 10; i++) {
            queue.enqueue(i);
            System.out.println("入队: " + queue);
            if (i%3 == 0) {
                queue.dequeue();
                System.out.println("出队: " + queue);
            }
        }

    }

}

五、树

5.1 二分搜索树
/**
 * 二分搜索树/二叉树
 * @author IT00ZYQ
 * @Date 2021/2/17 13:12
 **/
public class BinarySearchTree<E extends Comparable<E>> {

    private Node<E> root;
    private int size;

    /**
     * 判断二分搜索树是否为空
     * @return true/false
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 获取二分搜索树的结点数
     * @return 结点数
     */
    public int size() {
        return size;
    }

    /**
     * 向树中插入元素
     * @param e 元素
     */
    public void add(E e) {
        // 新添加的元素不能为NULL
        if (e == null) {
            throw new IllegalArgumentException("添加的元素为NULL");
        }
        root = add(root, e);
    }

    /**
     * 向以node为根节点的树中插入元素
     * @param node 根节点
     * @param e 元素
     * @return 新的二分搜素树的根节点
     */
    private Node<E> add(Node<E> node, E e) {
        // 根节点为NULL,新添加的结点作为根节点,直接返回
        if (node == null) {
            size ++;
            return new Node<>(e, null, null);
        }
        // 添加的元素小于当前结点的元素,更新左子树
        if (node.e.compareTo(e) > 0) {
            node.left = add(node.left, e);
        }
        // 添加的元素大于当前结点的元素,更新右子树
        if (node.e.compareTo(e) < 0) {
            node.right = add(node.right, e);
        }
        return node;
    }

    /**
     * 判断二分搜索树是否包含某个元素
     * @param e 元素
     * @return true/false
     */
    public boolean contain(E e) {
        return contain(root, e);
    }

    /**
     * 判断以Node为根节点的二分搜索树是否包含某个元素
     * @param node 根节点
     * @param e 查找的元素
     * @return true/false
     */
    private boolean contain(Node<E> node, E e) {
        // 当前结点为NULL,说明树中不包含该元素
        if (node == null) {
            return false;
        }
        // 找到元素
        if (node.e.compareTo(e) == 0) {
            return true;
        }
        // 目标元素小于当前元素,在其左子树中查找
        if (node.e.compareTo(e) > 0) {
            return contain(node.left, e);
        }
        // 目标元素大于当前元素,在其右子树中查找
        if (node.e.compareTo(e) < 0) {
            return contain(node.right, e);
        }
        return false;
    }

    /**
     * 层序遍历
     */
    public void levelOrder() {
        levelOrder(root);
    }

    /**
     * 层序遍历
     * @param node 根节点
     */
    private void levelOrder(Node<E> node) {
        // 检查二分查找树是否为空
        check(node);
        Queue<Node<E>> q = new LoopQueue<>();
        q.enqueue(node);
        while (!q.isEmpty()) {
            Node<E> dequeue = q.dequeue();
            System.out.print(dequeue.e + " ");
            if (dequeue.left != null) {
                q.enqueue(dequeue.left);
            }
            if (dequeue.right != null) {
                q.enqueue(dequeue.right);
            }
        }
    }

    /**
     * 对二分搜索树进行前序遍历
     */
    public void preOrder() {
        preOrder(root);
    }

    /**
     * 递归实现前序遍历
     * @param node 根节点
     */
    private void preOrder(Node<E> node) {
        // 检查树是否为空
        check(node);

        // 打印当前元素
        System.out.print(node.e + " ");
        // 遍历左子树
        if (node.left != null) {
            preOrder(node.left);
        }
        // 遍历右子树
        if (node.right != null) {
            preOrder(node.right);
        }
    }


    /**
     * 非递归实现前序遍历,使用堆栈
     */
    public void preOrderByStack() {
        // 检查树是否为空
        check(root);
        Stack<Node<E>> stack = new ArrayStack<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            Node<E> pop = stack.pop();
            System.out.print(pop.e + " ");
            // 由于堆栈是后进先出,左子树应该后进
            if (pop.right != null) {
                stack.push(pop.right);
            }
            if (pop.left != null) {
                stack.push(pop.left);
            }
        }
    }

    /**
     * 对二分搜索树进行中序遍历
     */
    public void inOrder() {
        inOrder(root);
    }

    /**
     * 递归实现中序遍历
     * @param node 根节点
     */
    private void inOrder(Node<E> node) {
        // 检查树是否为空
        check(node);

        // 遍历左子树
        if (node.left != null) {
            inOrder(node.left);
        }
        // 打印当前元素
        System.out.print(node.e + " ");
        // 遍历右子树
        if (node.right != null) {
            inOrder(node.right);
        }
    }


    /**
     * 非递归实现中序遍历,使用堆栈
     * 1、令node = root;
     * 2、只要node不为NULL或堆栈不为空,则进行操作3
     * 3、若node不为NULL,则将node压入栈中,并将node.left赋值给node;
     *      否则,代表此时已达到该分支的最左结点,从栈中弹出结点,赋值给node,打印结点,
     *      并将node.right赋值给node
     * 4、当node为null且堆栈为空时,表示已遍历所有结点
     */
    public void inOrderByStack() {
        // 检查树是否为空
        check(root);
        Stack<Node<E>> stack = new ArrayStack<>();
        Node<E> node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node);
                node = node.left;
            }else {
                node = stack.pop();
                System.out.print(node.e + " ");
                node = node.right;
            }
        }
    }


    /**
     * 对二分搜索树进行后序遍历
     */
    public void postOrder() {
        postOrder(root);
    }
    /**
     * 递归实现后序遍历
     * @param node 根节点
     */
    private void postOrder(Node<E> node) {
        // 检查树是否为空
        check(node);

        // 遍历左子树
        if (node.left != null) {
            postOrder(node.left);
        }
        // 遍历右子树
        if (node.right != null) {
            postOrder(node.right);
        }
        // 打印当前元素
        System.out.print(node.e + " ");
    }

    /**
     * 非递归实现后序遍历
     */
    public void postOrderByStack() {
        // 检查树是否为空
        check(root);
        Stack<Node<E>> stack = new ArrayStack<>();
        Stack<Node<E>> s = new ArrayStack<>();
        stack.push(root);
        Node<E> node;
        while (!stack.isEmpty()) {
            node = stack.pop();
            s.push(node);
            if (node.left != null) {
                stack.push(node.left);
            }
            if (node.right != null) {
                stack.push(node.right);
            }
        }

        while (!s.isEmpty()) {
            System.out.print(s.pop().e + " ");
        }
    }

    /**
     * 递归方式获取二分搜索树的最小结点
     * @return 最小元素
     */
    public E minRecursive() {
        check(root);
        return minRecursive(root);
    }

    /**
     * 递归方式获取以node为根节点的二分搜索树的最小结点
     * @param node 根节点
     * @return 最小元素
     */
    private E minRecursive(Node<E> node) {
        if (node.left == null) {
            return node.e;
        }
        return minRecursive(node.left);
    }

    /**
     * 非递归方式获取二分搜索树的最小结点
     * @return 最小元素
     */
    public E min() {
        check(root);
        Node<E> n = root;
        while (n.left != null) {
            n = n.left;
        }
        return n.e;
    }


    /**
     * 递归方式获取二分搜索树的最大结点
     * @return 最大元素
     */
    public E maxRecursive() {
        check(root);
        return maxRecursive(root);
    }

    /**
     * 递归方式获取以node为根节点的二分搜索树的最大结点
     * @param node 根节点
     * @return 最大元素
     */
    private E maxRecursive(Node<E> node) {
        if (node.right == null) {
            return node.e;
        }
        return maxRecursive(node.right);
    }

    /**
     * 非递归方式获取二分搜索树的最大结点
     * @return 最大元素
     */
    public E max() {
        check(root);
        Node<E> n = root;
        while (n.right != null) {
            n = n.right;
        }
        return n.e;
    }

    /**
     * 删除二分搜索树中的最小结点
     * @return 最小元素
     */
    public E removeMin() {
        check(root);
        E e = minRecursive(root);
        root = removeMin(root);
        size --;
        return e;
    }

    /**
     * 删除以node为根节点的二分搜索树中的最小结点
     * @param node 根节点
     * @return 新的二分搜索树的根节点
     */
    private Node<E> removeMin(Node<E> node) {
        if (node.left == null) {
            return null;
        }
        // 将删除最小结点的左子树赋值给node结点并返回
        node.left = removeMin(node.left);
        return node;
    }

    /**
     * 删除二分搜索树中的最大结点
     * @return 最大元素
     */
    public E removeMax() {
        check(root);
        E e = maxRecursive(root);
        root = removeMax(root);
        size --;
        return e;
    }

    /**
     * 删除以node为根节点的二分搜索树中的最大结点
     * @param node 根节点
     * @return 新的二分搜索树的根节点
     */
    private Node<E> removeMax(Node<E> node) {
        if (node.right == null) {
            return null;
        }
        // 将删除最小结点的左子树赋值给node结点并返回
        node.right = removeMax(node.right);
        return node;
    }

    /**
     * 删除指定元素
     * @param e 删除的元素
     * @return 删除成功-true 删除失败-false
     */
    public boolean remove(E e) {
        // 获取删除指定结点前的结点数
        int beginSize = size;
        root = remove(root, e);
        // 删除结点前后size值相差1,删除成功
        if (beginSize -1 == size) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * 删除以node为根节点的二分搜索树中的元素e
     * @param node 根节点
     * @param e 要删除的元素
     * @return 返回新的根节点
     */
    private Node<E> remove(Node<E> node, E e) {
        // 当前结点为要删除的结点
        if (node.e.compareTo(e) == 0) {
            // 左右子树均为NULL
            if (node.left == null && node.right == null) {
                size --;
                return null;
            }
            // 左子树为NULL 直接用右子树取代原来的结点
            if (node.left == null) {
                node = node.right;
            }
            // 此时要删除的结点有左子树也有右子树
            // 获取左子树中的最大结点
            E lMax = maxRecursive(node.left);
            // 删除左子树中的最大结点
            node.left = removeMax(node.left);
            size --;
            // 将删除指定结点后的子树结点返回
            return new Node<>(lMax, node.left, node.right);
        }
        // 左子树不为NULL,并且要删除的元素小于当前结点的元素
        if (node.left != null && node.e.compareTo(e) > 0) {
            // 将删除指定结点后的左子树树赋值给当前结点的左子树
            node.left = remove(node.left, e);
        }
        // 右子树不为NULL,并且要删除的元素大于当前结点的元素
        if (node.right != null && node.e.compareTo(e) < 0) {
            // 将删除指定结点后的右子树树赋值给当前结点的右子树
            node.right = remove(node.right, e);
        }
        return node;
    }


    private static class Node<E> {
        E e;
        Node<E> left;
        Node<E> right;

        public Node(E e, Node<E> left, Node<E> right) {
            this.e = e;
            this.left = left;
            this.right = right;
        }
    }

    private void check(Node<E> node) {
        if (node == null) {
            throw new IllegalArgumentException("二分查找树为空");
        }
    }
}
5.2 线段树
/**
 * 线段树
 * @author IT00ZYQ
 * @Date 2021/2/20 19:56
 **/
public class SegmentTree<E> {

    /**
     * 存放原数据
     */
    private E[] data;

    /**
     * 将原数据构造成线段树线段树
     */
    private E[] tree;

    private Merger<E> merger;

    public SegmentTree(E[] data, Merger<E> merger) {
        this.data = (E[])new Object[data.length];
        this.data = data;
        this.merger = merger;
        this.tree = (E[])new Object[4 * data.length];
        if (data.length != 0) {
            buildTree(0, 0, data.length - 1);
        }
    }

    /**
     * 构建以index为根,l,r为data数组左右边界的线段树
     * @param index 线段树中的数组下标
     * @param l 左边界
     * @param r 右边界
     */
    private void buildTree(int index, int l, int r) {
        if (l == r) {
            tree[index] = data[l];
            return;
        }

        // 分割点
        int mid = l + (r - l) / 2;
        // 计算左孩子下标
        int left = leftChild(index);
        // 计算右孩子下标
        int right = rightChild(index);
        // 递归创建左子树
        buildTree(left, l, mid);
        // 递归创建右子树
        buildTree(right, mid + 1, r);

        // 当前结点赋值
        tree[index] = merger.merger(tree[left], tree[right]);
    }


    /**
     * 获取指定区间的值
     * @param l 左边界
     * @param r 右边界
     * @return 元素值
     */
    public E query(int l, int r) {
        if (l < 0 || l >= data.length || r < 0 || r >= data.length) {
            throw new IllegalArgumentException("索引越界");
        }
        return query(0, 0, data.length - 1, l, r);
    }

    /**
     * 递归查询指定区间的值
     * @param index 开始下标
     * @param l 当前查询数组左边界
     * @param r 当前查询数组右边界
     * @param ql 目标左边界
     * @param qr 目标右边界
     * @return 区间的值
     */
    private E query(int index, int l, int r, int ql, int qr) {
        if (l == ql && r == qr) {
            return tree[index];
        }

        int mid = l + (r - l)/2;
        int left = leftChild(index);
        int right = rightChild(index);

        // 查询目标全部在左子树
        if (qr <= mid) {
            return query(left, l, mid, ql, qr);
        }
        // 查询目标全部在右子树
        if (ql > mid) {
            return query(right, mid + 1, r, ql, qr);
        }

        // 查询目标分布与左右两子树
        E leftResult = query(left, l, mid, ql, mid);
        E rightResult = query(right, mid + 1, r, mid + 1, qr);
        return merger.merger(leftResult, rightResult);
    }

	/**
     * 更新指定下标的值
     * @param index 数组下标
     * @param e 新元素
     */
    public void update(int index, E e) {
        if (index < 0 || index >= data.length) {
            throw new IllegalArgumentException("下标越界");
        }
        update(0, 0, data.length - 1, index, e);
    }

    /**
     * 递归更新以index为根的线段树
     * @param index 线段树的根
     * @param l index位置左边界
     * @param r index位置右边界
     * @param tag 目标下标
     * @param e 新的元素
     */
    private void update(int index, int l, int r, int tag, E e) {
        // 找到需要更新的位置
        if (l == r) {
            tree[index] = e;
            return;
        }

        int mid = l + (r - l)/2;
        int left = leftChild(index);
        int right = rightChild(index);

        // 要更新的目标在左子树
        if (tag <= mid) {
            update(left, l, mid, tag, e);
        }
        // 要更新的目标在右子树
        if (tag > mid) {
            update(right, mid + 1, r, tag, e);
        }

        tree[index] = merger.merger(tree[left], tree[right]);
    }
    
    /**
     * 左孩子结点的下标
     * @param index 元素下标
     * @return 左孩子节点的下标
     */
    private int leftChild(int index) {
        return 2 * index + 1;
    }

    /**
     * 获取右孩子结点下标
     * @param index 父节点下标
     * @return 右孩子结点下标
     */
    private int rightChild(int index) {
        return 2 * index + 2;
    }
}

/**
 * 线段是计算方法接口
 * @param <E>
 * @author zyq
 */
public interface Merger<E> {

    /**
     * 计算方法
     * @param e1 元素1
     * @param e2 元素2
     * @return 结果
     */
    E merger(E e1, E e2);

}
5.3 前缀树Trie
import java.util.Map;
import java.util.TreeMap;

/**
 * 前缀树
 * @author IT00ZYQ
 * @Date 2021/2/22 12:29
 **/
public class Trie {
    private Node root;
    /**
     * 单词数
     */
    private int size;

    public Trie() {
        this.root = new Node(new TreeMap<>());
        this.size = 0;
    }

    /**
     * 单词数统计
     * @return size
     */
    public int size() {
        return size;
    }

    /**
     * 判断是否为空树
     * @return true/false
     */
    public Boolean isEmpty() {
        return size == 0;
    }

    /**
     * 向前缀树中添加单词
     * @param word 添加的单词
     */
    public void add(String word) {
        Node cur = root;
        // 遍历单词的字符,将单词拆分为一个一个字符
        for (int i = 0; i < word.length(); i++) {
            Character c = word.charAt(i);
            Node node = cur.map.get(c);
            if (node == null) {
                // 前缀树中未存储该字符,添加结点
                cur.map.put(c, new Node(new TreeMap<>()));
            }
            cur = cur.map.get(c);
        }
        // 将该位置的单词结束标志置为true
        cur.wordEnd = true;
        size ++;
    }

    /**
     * 递归方式向前缀树中添加单词
     * @param word 添加的单词
     */
    public void insert(String word) {
        insert(root, word, 0);
        size ++;
    }

    /**
     * 递归方式添加单词
     * @param node 根节点
     * @param word 单词
     * @param index 索引
     */
    private void insert(Node node, String word, int index) {
        if (index >= word.length()) {
            return;
        }
        Character c = word.charAt(index);
        if (node.map.get(c) == null) {
            node.map.put(c, new Node(new TreeMap<>()));
        }
        insert(node.map.get(c), word, index + 1);
        if (index == word.length() - 1) {
            node.map.get(c).wordEnd = true;
        }
    }


    /**
     * 查询前缀树中是否包含指定的单词
     * @param word 查询的单词
     * @return true/false
     */
    public Boolean contains(String word) {
        Node cur = root;
        for (int i = 0; i < word.length(); i++) {
            Character c = word.charAt(i);
            if (cur.map.get(c) == null) {
                return false;
            }
            cur = cur.map.get(c);
        }
        return cur.wordEnd;
    }

    /**
     * 递归方式判断前缀树中是否包含指定的单词
     * @param word 单词
     * @return true/false
     */
    public Boolean have(String word) {
        return have(root, word, 0);
    }

    /**
     * 递归方式判断以node为根的前缀树中是否包含指定的单词
     * @param node 根节点
     * @param word 单词
     * @param index 索引
     * @return true/false
     */
    private Boolean have(Node node, String word, int index) {
        Character c = word.charAt(index);
        Node n = node.map.get(c);
        if (index == word.length() - 1) {
            return n != null && n.wordEnd;
        }
        if (n == null) {
            return false;
        }
        return have(n, word, index + 1);
    }

    /**
     * 查询前缀树中是否包含某个前缀
     * @param pre 查询的前缀
     * @return true/false
     */
    public Boolean containsPre(String pre) {
        Node cur = root;
        for (int i = 0; i < pre.length(); i++) {
            Character c = pre.charAt(i);
            if (cur.map.get(c) == null) {
                return false;
            }
            cur = cur.map.get(c);
        }
        return true;
    }

    /**
     * 递归查询前缀树中是否包含某个前缀
     * @param pre 查询的前缀
     * @return true/false
     */
    public Boolean havePre(String pre) {
        return havePre(root, pre, 0);
    }
    /**
     * 递归方式判断以node为根的前缀树中是否包含指定的前缀
     * @param node 根节点
     * @param pre 前缀
     * @param index 索引
     * @return true/false
     */
    private Boolean havePre(Node node, String pre, int index) {
        Character c = pre.charAt(index);
        Node n = node.map.get(c);
        if (index == pre.length() - 1) {
            return n != null;
        }
        if (n == null) {
            return false;
        }
        return havePre(n, pre, index + 1);
    }

    private static class Node {
        Map<Character, Node> map;
        Boolean wordEnd;
        public Node(Map<Character, Node> map, Boolean wordEnd) {
            this.map = map;
            this.wordEnd = wordEnd;
        }

        public Node(Map<Character, Node> map) {
            this(map, false);
        }
    }
}

六、堆

/**
 * 最大堆
 * @author IT00ZYQ
 * @Date 2021/2/20 15:41
 **/
public class Heap<E extends Comparable<E>> {

    private Array<E> heap;

    public Heap(int capacity) {
        this.heap = new Array<>(capacity);
    }

    public Heap () {
        this.heap = new Array<>();
    }

    public Heap(E[] arr) {
        // 传入一个数组,进行Heapify
        heap = new Array<>(arr);
        // 只需对每个非叶子结点进行siftDown操作即可
        // 最后一个结点的父节点即为最后一个非叶子结点
        for (int i = getParent(heap.getSize() - 1); i >= 0; i--) {
            siftDown(i);
        }
    }

    public boolean isEmpty() {
        return heap.isEmpty();
    }

    public int size() {
        return heap.getSize();
    }


    /**
     * 添加元素
     * @param e 添加的元素
     */
    public void add(E e) {
        heap.addLast(e);
        siftUp(heap.getSize() - 1);
    }

    /**
     * 取出元素
     * @return 取出的元素
     */
    public E extractMax() {
        if (heap.isEmpty()) {
            throw new IllegalArgumentException("堆为空,无法进行操作");
        }
        E top = top();
        E e = heap.removeLast();
        heap.setData(0, e);
        siftDown(0);
        return top;
    }

    /**
     * 获取堆顶的元素
     * @return 堆顶元素
     */
    public E top() {
        return heap.getFirst();
    }

    /**
     * 上浮操作,使堆符合最大堆的限制
     * @param i 开始上浮操作的下标
     */
    private void siftUp(int i) {
        while (i > 0 && heap.getData(i).compareTo(heap.getData(getParent(i))) > 0) {
            heap.swap(i, getParent(i));
            i = getParent(i);
        }
    }

    /**
     * 下潜操作,使堆符合最大堆的限制
     * @param i 开始下潜操作的下标
     */
    private void siftDown(int i) {
        while (getLeftChild(i) < heap.getSize()) {
            // 获取左孩子结点的下标
            int leftChild = getLeftChild(i);
            // 获取右孩子结点的下标
            int rightChild = getRightChild(i);
            if (rightChild < heap.getSize()) {
                if (heap.getData(i).compareTo(heap.getData(leftChild)) > 0 &&
                        heap.getData(i).compareTo(heap.getData(rightChild)) > 0) {
                    break;
                }
                // 有右孩子结点
                E left = heap.getData(leftChild);
                E right = heap.getData(rightChild);
                if (left.compareTo(right) > 0) {
                    // 左孩子结点元素较大
                    heap.swap(i, leftChild);
                    i = leftChild;
                }else {
                    // 右孩子结点元素较大
                    heap.swap(i, rightChild);
                    i = rightChild;
                }
            }else {
                if (heap.getData(i).compareTo(heap.getData(leftChild)) > 0) {
                    break;
                }
                // 无右孩子结点
                heap.swap(i, leftChild);
                i = leftChild;
            }
        }
    }

    /**
     * 获取指定结点的父结点的下标
     * @param i 结点下标
     * @return 父结点的下标
     */
    private int getParent(int i) {
        return (i - 1) / 2;
    }

    /**
     * 获取指定结点的左孩子结点的下标
     * @param i 结点下标
     * @return 左孩子结点的下标
     */
    private int getLeftChild(int i) {
        return 2 * i + 1;
    }

    /**
     * 获取指定结点的右孩子结点的下标
     * @param i 结点下标
     * @return 右孩子结点的下标
     */
    private int getRightChild(int i) {
        return 2 * i + 2;
    }

    @Override
    public String toString(){
        return heap.toString();
    }

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

it00zyq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值