包络(线)是在图形学中经常用到的一个概念,不严格的说法,是包含某个图形集的一个最小范围。对于多维空间,求解比较复杂,在二维空间中,对于普通的矩形较好处理,若不规则图形,则也比较复杂。下图给出一个二维矩形包络的情形,两个矩形的最小包含矩形。
____________________
| | |
+__________+ ____+
| | |
|_______________|____|
对于一维情形,就是普通的线段处理,比较简单。底下附上笔者用java编写的一个简单实现,供参考。可以考虑如何进行优化(算法改进,代码重构,指令优化等方向)。实际应用中,一些问题可以转化为求包络的问题。
package cn.itcast.client;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
// 线段描述对象[x1, x2]在数轴上的起止坐标
class Line implements Comparable {
int x1;
int x2;
public Line(int x1, int x2) {
this.x1 = x1;
this.x2 = x2;
}
// 用'------'的形式模拟图形化输出线段
public String toString() {
//if (true) return x1 + ", " + x2;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < x1; i++) {
sb.append(' ');
}
for (int i = x1; i < x2; i++) {
sb.append('-');
}
return sb.toString();
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int compareTo(Object arg0) {
Line l = (Line) arg0;
return x1 - l.x1;
/*
* if (x1 <= l.x1) return -1; else return 1;
*/
}
}
public class MaxLine {
public static void main(String[] args) {
// int[][] xy = {{1, 50}, {4, 60}};
// System.out.println(xy[0][1]);
MaxLine tst = new MaxLine();
// 生成测试数据
List lines = tst.generateLines();
tst.printLines(lines);
// 求解包络线并输出
List list = tst.envelope(lines);
System.out.println("output is:");
tst.printLines(list);
}
// 求包络线
public List envelope(List lines) {
int len = lines.size();
if (len == 1) return lines; // noop
List res = new ArrayList();
// 先对线段进行排序,按照x1升序排列
Line[] arrLine = (Line[]) lines.toArray(new Line[len]);
Arrays.sort(arrLine);
// 两两合并
for (int i = 0; i < len; i++) {
if (i == len - 1) {
res.add(arrLine[i]); // 加入最后一条线段到结果集中
break;
}
// 取出尝试合并的两条线段
Line l1 = arrLine[i];
Line l2 = arrLine[i + 1];
// 判断是否相交,即区间是否重叠
int x1 = Math.max(l1.getX1(), l2.getX1());
int x2 = Math.min(l1.getX2(), l2.getX2());
if (x1 <= x2) { // 线段相交,l1合并到l2
l2.setX1(Math.min(l1.getX1(), l2.getX1()));
l2.setX2(Math.max(l1.getX2(), l2.getX2()));
} else { // 线段不相交
res.add(l1);
}
}
return res;
}
public List generateLines() {
List lines = new ArrayList();
int maxLen = 20; // 最大线段长度
int lineCount = 15; // 生成线段个数
int start = 0; // 开始坐标x1
int end = 100; // 结束坐标x2
for (int i = 0; i < lineCount; i++) {
int x1 = (int) (Math.random() * (end - maxLen));
int x2 = x1 + (int) (Math.random() * maxLen);
lines.add(new Line(x1, x2));
}
return lines;
}
// 命令行形式模拟线段输出
public void printLines(List lines) {
for (Iterator iter = lines.iterator(); iter.hasNext();) {
Line l = (Line) iter.next();
System.out.println(l);
}
}
}