[数据结构][算法][面向对象][Java]
https://github.com/z8g/common
文章目录
1 设计接口
1.1 容器接口Container
package ds;
import java.util.NoSuchElementException;
public interface Container{
int size();
default boolean isEmpty(){
return size() == 0;
}
default void notEmptyCheck() {
if (isEmpty()) {
throw new NoSuchElementException("size == 0");
}
}
}
1.2 背包接口Bag
package ds;
public interface Bag<T> extends Container {
void add(T data);
}
1.3 栈接口Stack
package ds;
public interface Stack<T>extends Container {
void push(T data);
T pop();
T peek();
}
1.4 队列接口Queue
package ds;
public interface Queue<T> extends Container {
T peek();
void enqueue(T data);
T dequeue();
}
1.5 Union-Find算法接口UF
package ds;
public interface UF {
int size();
int find(int p);
boolean connected(int p, int q);
void union(int p, int q);
default void validate(int p, int n) {
if (p < 0 || p >= n) {
throw new IllegalArgumentException("p>=0 && p<n");
}
}
}
2 实现接口
为数组和链表定义了公共的结点和迭代器实现。
2.1 结点类Node
package ds.util;
public class Node<T> {
public T data;
public Node<T> next;
}
2.2 数组迭代器ArrayIterator
package ds.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ArrayIterator<T> implements Iterator<T> {
private int i;
private final int size;
private final T[] array;
public ArrayIterator(T[] array, int size) {
this.array = array;
this.size = size;
}
@Override
public boolean hasNext() {
return i < size;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array[i++];
}
}
2.3 链表迭代器ListIterator
package ds.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ListIterator<T> implements Iterator<T> {
private Node<T> current;
public ListIterator(Node<T> first) {
current = first;
}
@Override
public boolean hasNext() {
return current != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T result = current.data;
current = current.next;
return result;
}
}
2.4 背包(Bag)的实现
背包(Bag)是一种不支持从中删除元素的集合数据类型。
2.4.1 能动态调整数组大小的Bag
package ds.impl;
import ds.Bag;
import java.util.Iterator;
import ds.util.ArrayIterator;
public class ArrayBag<T> implements Iterable<T>,Bag<T> {
private T[] array;
private int size;
public ArrayBag() {
array = (T[]) new Object[2];
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public void add(T data) {
if (size == array.length) {
resize(2 * array.length);
}
array[size++] = data;
}
private void resize(int capacity) {
assert capacity >= 0;
T[] tmp = (T[]) new Object[capacity];
System.arraycopy(array, 0, tmp, 0, size);
array = tmp;
}
@Override
public Iterator<T> iterator() {
return new ArrayIterator(array,size);
}
}
2.4.2 链式Bag的实现
package ds.impl;
import ds.util.Node;
import ds.Bag;
import java.util.Iterator;
import ds.util.ListIterator;
public class LinkedBag<T> implements Iterable<T>, Bag<T> {
private Node<T> first;
private int size;
public LinkedBag() {
first = null;
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public void add(T data) {
Node<T> old = first;
first = new Node<>();
first.data = data;
first.next = old;
size++;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (T data : this) {
s.append(data).append(' ');
}
return s.toString();
}
@Override
public Iterator<T> iterator() {
return new ListIterator(first);
}
}
2.5 栈(Stack)的实现
栈(Stack)是一种先进后出的数据类型。
2.5.1 能动态调整数组大小的Stack
package ds.impl;
import ds.Stack;
import java.util.Iterator;
import ds.util.ArrayIterator;
public class ArrayStack<T> implements Iterable<T>,Stack<T> {
private T[] array;
private int size;
public ArrayStack(){
array = (T[]) new Object[2];
size = 0;
}
@Override
public Iterator<T> iterator() {
return new ArrayIterator(array,size);
}
@Override
public int size() {
return size;
}
@Override
public void push(T data) {
if(size == array.length){
resize(2* array.length);
}
array[size++] = data;
}
private void resize(int capacity) {
assert capacity >= size;
T[] tmp = (T[]) new Object[capacity];
System.arraycopy(array, 0, tmp, 0, size);
array = tmp;
}
@Override
public T pop() {
notEmptyCheck();
T result = array[size-1];
array[size-1] = null;
size--;
if(size>0 && size == array.length/4){
resize(array.length/2);
}
return result;
}
@Override
public T peek() {
notEmptyCheck();
return array[size-1];
}
}
2.5.2 链式Stack的实现
package ds.impl;
import ds.util.Node;
import ds.Stack;
import java.util.Iterator;
import ds.util.ListIterator;
public class LinkedStack<T> implements Iterable<T>,Stack<T> {
private Node<T> first;
private int size;
public LinkedStack() {
first = null;
size = 0;
}
@Override
public int size() {
return size;
}
/**
* 向栈中推入一个新元素
*
* @param data 新元素
*/
@Override
public void push(T data) {
Node<T> oldFirst = first;
first = new Node<>();
first.data = data;
first.next = oldFirst;
size++;
}
/**
* 从栈中弹出栈首元素
*
* @return 栈首元素
*/
@Override
public T pop() {
notEmptyCheck();
T result = first.data;
first = first.next;
size--;
return result;
}
/**
* 查看栈首元素
* @return 栈首元素
*/
@Override
public T peek() {
notEmptyCheck();
return first.data;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (T data : this) {
s.append(data).append(' ');
}
return s.toString();
}
@Override
public Iterator<T> iterator() {
return new ListIterator(first);
}
}
2.6 队列(Queue)的实现
队列(Queue)是一种先进先出的数据类型。
2.6.1 能动态调整数组大小的Queue
package ds.impl;
import ds.Queue;
import java.util.Iterator;
public class ArrayQueue<T> implements Iterable<T>,Queue<T> {
private T[] array;
private int size;
private int first;
private int last;
public ArrayQueue() {
array = (T[]) new Object[2];
size = 0;
first = 0;
last = 0;
}
@Override
public int size() {
return size;
}
@Override
public void enqueue(T data) {
if (size == array.length) {
resize(2 * array.length);
}
array[last++] = data;
if (last == array.length) {
last = 0;
}
size++;
}
@Override
public T dequeue() {
notEmptyCheck();
T result = array[first];
array[first] = null;
size--;
first++;
if (first == array.length) {
first = 0;
}
if (size > 0 && size == array.length / 4) {
resize(array.length / 2);
}
return result;
}
@Override
public T peek(){
notEmptyCheck();
return array[first];
}
private void resize(int capacity) {
assert capacity >= size;
T[] tmp = (T[]) new Object[capacity];
for (int i = 0; i < size; i++) {
tmp[i] = array[(first + i) % array.length];
}
array = tmp;
first = 0;
last = size;
}
@Override
public Iterator<T> iterator() {
return new ds.util.ArrayIterator(array,size);
}
}
2.6.2 链式Queue的实现
package ds.impl;
import ds.util.Node;
import ds.Queue;
import java.util.Iterator;
import ds.util.ListIterator;
public class LinkedQueue<T> implements Iterable<T>, Queue<T> {
private Node<T> first;
private Node<T> last;
private int size;
public LinkedQueue() {
first = null;
last = null;
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public T peek() {
notEmptyCheck();
return first.data;
}
@Override
public void enqueue(T data) {
Node<T> oldLast = last;
last = new Node<>();
last.data = data;
last.next = null;
if (isEmpty()) {
first = last;
} else {
oldLast.next = last;
}
size++;
}
@Override
public T dequeue() {
notEmptyCheck();
T result = first.data;
first = first.next;
size--;
if (isEmpty()) {
last = null;
}
return result;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (T data : this) {
s.append(data).append(' ');
}
return s.toString();
}
@Override
public Iterator<T> iterator() {
return new ListIterator(first);
}
}
2.7 Union-Find算法的实现
并查集(Union-Find)是解决动态连通性问题的一类非常高效的数据结构。
2.7.1 DefaultUF
package ds.impl;
import ds.UF;
public class DefaultUF implements UF {
private int[] parent;
private byte[] rank;
private int size;
public DefaultUF(int n) {
if (n < 0) {
throw new IllegalArgumentException();
}
size = n;
parent = new int[n];
rank = new byte[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
rank[i] = 0;
}
}
@Override
public int find(int p) {
validate(p, parent.length);
while (p != parent[p]) {
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
@Override
public int size() {
return size;
}
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
@Override
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
return;
}
if (rank[rootP] < rank[rootQ]) {
parent[rootP] = rootQ;
} else if (rank[rootQ] > rank[rootP]) {
parent[rootQ] = rootP;
} else {
parent[rootQ] = rootP;
rank[rootP]++;
}
size--;
}
}
2.7.2 QuickFindUF
package ds.impl;
import ds.UF;
public class QuickFindUF implements UF {
private final int[] id;
private int size;
public QuickFindUF(int n) {
size = n;
id = new int[n];
for (int i = 0; i < n; i++) {
id[i] = i;
}
}
@Override
public int size() {
return size;
}
@Override
public int find(int p) {
validate(p, id.length);
return id[p];
}
@Override
public boolean connected(int p, int q) {
validate(p, id.length);
validate(q, id.length);
return id[p] == id[q];
}
@Override
public void union(int p, int q) {
validate(p, id.length);
validate(q, id.length);
int pID = id[p];
int qID = id[q];
if (pID == qID) {
return;
}
for (int i = 0; i < id.length; i++) {
if (id[i] == pID) {
id[i] = qID;
}
}
size--;
}
}
2.7.3 QuickUnionUF
package ds.impl;
import ds.UF;
public class QuickUnionUF implements UF {
private final int[] parent;
private int size;
public QuickUnionUF(int n) {
parent = new int[n];
size = n;
for (int i = 0; i < n; i++) {
parent[i] = i;
}
}
@Override
public int size() {
return size;
}
@Override
public int find(int p) {
validate(p, parent.length);
while (p != parent[p]) {
p = parent[p];
}
return p;
}
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
@Override
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
return;
}
parent[rootP] = rootQ;
size--;
}
}
2.7.4 WeightedQuickUnionUF
加权 quick-union算法,是目前所有实现中最优的算法
package ds.impl;
import ds.UF;
public class WeightedQuickUnionUF implements UF {
private final int[] parent;
private final int[] num;
private int size;
public WeightedQuickUnionUF(int n) {
size = n;
parent = new int[n];
num = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;
num[i] = 1;
}
}
@Override
public int size() {
return size;
}
@Override
public int find(int p) {
validate(p, parent.length);
while (p != parent[p]) {
p = parent[p];
}
return p;
}
@Override
public boolean connected(int p, int q) {
return find(p) == find(q);
}
@Override
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
return;
}
// make smaller root point to larger one
if (num[rootP] < num[rootQ]) {
parent[rootP] = rootQ;
num[rootQ] += num[rootP];
} else {
parent[rootQ] = rootP;
num[rootP] += num[rootQ];
}
size--;
}
}
2.8 测试
2.8.1 测试Stack
Dijkstra的双栈算数表达式求值算法
package test;
import java.util.Scanner;
import ds.impl.LinkedStack;
public class StackTest {
public static void main(String[] args) {
evaluate();
}
/**
* Dijkstra的双栈算数表达式求值算法
*/
public static void evaluate() {
String str = "( 1 + ( ( 2.3 + 3 ) / ( sqrt ( 16 ) * ( 5 % 9 ) ) ) )";
LinkedStack<String> opStack = new LinkedStack<>();
LinkedStack<Double> valStack = new LinkedStack<>();
Scanner scanner = new Scanner(str);
while (scanner.hasNext()) {
String s = scanner.next();
System.out.print(s + ' ');
switch (s) {
case "+":
case "-":
case "*":
case "/":
case "%":
case "sqrt":
opStack.push(s);
break;
case "(":
break;
case ")":
String op = opStack.pop();
double v = valStack.pop();
switch (op) {
case "+":
v = valStack.pop() + v;
break;
case "-":
v = valStack.pop() - v;
break;
case "*":
v = valStack.pop() * v;
break;
case "/":
v = valStack.pop() / v;
break;
case "%":
v = valStack.pop() % v;
break;
case "sqrt":
v = Math.sqrt(v);
break;
default:
break;
}
valStack.push(v);
break;
default:
valStack.push(Double.parseDouble(s));
break;
}
}
System.out.printf("= %f\n", valStack.pop());
}
}
2.8.2 测试Union-Find
package test;
import ds.UF;
import ds.impl.DefaultUF;
import ds.impl.QuickFindUF;
import ds.impl.QuickUnionUF;
public class UFTest {
public static void main(String[] args) {
UF uf;
int findResult;
uf = new QuickFindUF(10);
uf.union(4, 3);
uf.union(3, 8);
uf.union(6, 5);
uf.union(9, 4);
uf.union(2, 1);
uf.union(5, 0);
uf.union(7, 2);
uf.union(6, 1);
findResult = uf.find(3);
System.out.println(findResult);
System.out.println(uf.size());
System.out.println(uf.connected(4, 3));
System.out.println(uf.connected(9, 3));
uf = new DefaultUF(10);
uf.union(4, 3);
uf.union(3, 8);
uf.union(6, 5);
uf.union(9, 4);
uf.union(2, 1);
uf.union(5, 0);
uf.union(7, 2);
uf.union(6, 1);
findResult = uf.find(3);
System.out.println(findResult);
System.out.println(uf.size());
System.out.println(uf.connected(4, 3));
System.out.println(uf.connected(9, 3));
uf = new QuickUnionUF(10);
uf.union(4, 3);
uf.union(3, 8);
uf.union(6, 5);
uf.union(9, 4);
uf.union(2, 1);
uf.union(5, 0);
uf.union(7, 2);
uf.union(6, 1);
findResult = uf.find(3);
System.out.println(findResult);
System.out.println(uf.size());
System.out.println(uf.connected(4, 3));
System.out.println(uf.connected(9, 3));
}
}
3 排序算法
3.1 定义排序工具的类结构
需要实现排序器,以及通过静态方法调用。
package util;
import java.util.Arrays