我们知道置换分为三类:恒等置换、轮换、轮换组合。所以定义一个接口和三个实现类。
DisplaceExpression是接口,EmptyDisplaceExpression是恒等置换,用枚举做成了单例模式,CompositeDisplaceExpression是轮换组合,使用组合模式,CyclicDisplaceExpression是轮换。
接口核心方法是,表示应用于一个数组后,进行置换操作,返回一个新数组。因为置换是可以置换任何对象的,所以这里使用了Object[]。
Object[] apply(Object[] array);
因为计算机是赋值操作,所以对轮换位置的遍历要从后到前,并且需要特别处理首尾两个元素。而轮换的核心代码如下:
@Override
public Object[] apply(Object[] array) {
final Object[] objects = new Object[array.length];
System.arraycopy(array, 0, objects, 0, array.length);
/* 比如 M(1,2,3)作用于{1,2,3,4},算法为
* 1 移动到2 也就是 array[2] = array[1]
* 所以要从后往前
* temp = array[3]
* array[3]=array[2]
* array[2]=array[1]
* 然后array[1]=temp
* */
Object temp = array[cyclic[cyclic.length - 1]];
for (int i = cyclic.length - 1; i > 0; i--) {
objects[cyclic[i]] = array[cyclic[i - 1]];
}
objects[cyclic[0]] = temp;
return objects;
}
轮换组合的核心代码,就比较容易了。
@Override
public Object[] apply(Object[] array) {
// 循环去搞呗
Object[] result = array;
for (DisplaceExpression displaceExpression : expressions) {
result = displaceExpression.apply(result);
}
return result;
}
恒等置换的代码我就不写了,直接返回原数组。还有一个复杂的逻辑是轮换组合的化简方法。思路上,我是先找到每个位置置换后的位置,放入一个map中,然后根据这个map,重新生成置换表达式,Java代码如下:
public DisplaceExpression simplify() {
// 首先是先作用于一个数组
// 代数运算的化简
final TreeMap<Integer, Integer> positionMap = new TreeMap<>();
// 第一步是要获取所有的变量
final Set<Integer> positions = this.positions();
for (Integer position : positions) {
// 过滤掉自己映射到自己的特殊情况
final Integer next = this.next(position);
if (!Objects.equals(position, next)) {
positionMap.put(position, next);
}
}
List<DisplaceExpression> result = new ArrayList<>();
// 组成最简表达式
while (!positionMap.isEmpty()) {
List<Integer> cyclic = new ArrayList<>();
final Map.Entry<Integer, Integer> firstEntry = positionMap.firstEntry();
for (Integer k = firstEntry.getKey(), v = firstEntry.getValue();
!cyclic.contains(k);
k = v, v = positionMap.get(k)) {
cyclic.add(k);
}
cyclic.forEach(positionMap::remove);
if (!cyclic.isEmpty()) {
result.add(new CyclicDisplaceExpression(cyclic));
cyclic.clear();
}
}
if (result.isEmpty()) {
return EmptyDisplaceExpression.INSTANCE;
}
if (result.size() == 1) {
return result.get(0);
}
return new CompositeDisplaceExpression(result);
}
源码git地址: https://e.coding.net/buildt/math/displace.git