文章目录
—————————————————————
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();
}
}