矩形近似算法

时间:2012-02-10 23:49:36

标签: c++ algorithm approximation

我有一个小于32个绝对矩形大小的枚举,我需要给出尺寸并找到我的枚举中的最佳近似值。

有没有比我用大量嵌套ifelse制定的意大利面条代码更好(即更具可读性和可维护性)的方式?

目前我刚刚:

enum imgOptsScale {
    //Some relative scales
    w005h005 = 0x8,
    w010h010 = 0x9,
    w020h020 = 0xA,
    w040h040 = 0xB,
    w070h070 = 0xC,
    w100h100 = 0xD,
    w150h150 = 0xE,
    w200h200 = 0xF,
    w320h320 = 0x10,
    w450h450 = 0x11,
    w200h010 = 0x12,
    w200h020 = 0x13,
    w200h070 = 0x14,
    w010h200 = 0x15,
    w020h200 = 0x16,
    w070h200 = 0x17
};
imgOptsScale getClosestSizeTo(int width, int height);

我想在得到进一步编码之前我会寻求帮助。我应该强调偏离过于复杂的库,尽管我对算法更感兴趣而不是容器,这应该在资源受限的系统上运行。

3 个答案:

答案 0 :(得分:2)

是...将您的32种不同尺寸放在预先构建的二进制搜索树中,然后递归搜索树中的“最佳”尺寸。基本上,如果当前节点的矩形的左子预先构建的矩形小于输入矩形,并且当前节点的矩形大于输入矩形,则会停止搜索。然后,您将返回与两者之间的输入矩形“最接近”的预定义矩形。

递归搜索创建的干净代码的一个很好的补充是它在搜索时间内也是对数而不是线性。

顺便说一句,您需要随机化将初始预定义矩形值插入二叉搜索树的顺序,否则您最终会得到一个看起来像链表的退化树,而您将无法获得对数搜索时间,因为树的高度将是节点的数量,而不是对数节点的对数。

因此,例如,如果您按照矩形区域对树进行排序(假设没有两个具有相同区域的矩形),那么您可以执行以下操作:

//for brevity, find the rectangle that is the 
//greatest rectangle smaller than the input
const rec_bstree* find_best_fit(const rec_bstree* node, const rec& input_rec)
{
    if (node == NULL)
        return NULL;

    rec_bstree*  return_node;

    if (input_rec.area < node->area)
        return_node = find_best_fit(node->left_child, input_rec);
    else if (input_rec.area > node->area)
        return_node = find_best_fit(node->right_child, input_rec);

    if (return_node == NULL)
        return node;
}
顺便说一句,如果树太复杂,你也可以简单地做一个数组或std::vector个矩形实例,使用std::sort使用某种类型的标准对它们进行排序,然后进行二进制搜索在阵列上。

答案 1 :(得分:2)

我想我会用几个结构阵列来处理这个结构,一个用于水平测量,一个用于垂直测量。

通读数组以查找下一个更大的大小,并返回相应的键。从两个键构建最终的框测量。 (由于32只允许5位,这可能不是很理想 - 你可能想要水平2.5位和垂直2.5位,但我这里简单的方法需要6位 - 水平3位,垂直3位你可以从其中一个列表中删除一半的元素(也可以调整<< 3),如果你对其中一个维度具有较少自由度的情况很好。如果你想要更好地表示这两个维度,这可能需要足够的重新工作,这种方法可能不合适。)

未经测试的伪代码:

struct dimen {
    int x;
    int key;
}

struct dimen horizontal[] = { { .x = 10, .key = 0 },
                              { .x = 20, .key = 1 },
                              { .x = 50, .key = 2 },
                              { .x = 90, .key = 3 },
                              { .x = 120, .key = 4 },
                              { .x = 200, .key = 5 },
                              { .x = 300, .key = 6 },
                              { .x = 10000, .key = 7 }};

struct dimen vertical[] = { { .x = 10, .key = 0 },
                           { .x = 20, .key = 1 },
                           { .x = 50, .key = 2 },
                           { .x = 90, .key = 3 },
                           { .x = 120, .key = 4 },
                           { .x = 200, .key = 5 },
                           { .x = 300, .key = 6 },
                           { .x = 10000, .key = 7 }};

/* returns 0-63 as written */
int getClosestSizeTo(int width, int height) {
    int horizontal_key = find_just_larger(horizontal, width);
    int vertical_key = find_just_larger(vertical, height);
    return (horizontal_kee << 3) & vertical_key;
}

int find_just_larger(struct dimen* d, size) {
    int ret = d.key;
    while(d.x < size) {
        d++;
        ret = d.key;
    }
    return ret;
}

答案 2 :(得分:1)

这是我提出的解决方案,

enum imgOptsScale {
    notScaled = 0x0,
    //7 relative scales upto = 0x7
    w010h010, w010h025, w010h060, w010h120, w010h200, w010h310, w010h450,
    w025h010, w025h025, w025h060, w025h120, w025h200, w025h310, w025h450,
    w060h010, w060h025, w060h060, w060h120, w060h200, w060h310, w060h450,
    w120h010, w120h025, w120h060, w120h120, w120h200, w120h310, w120h450,
    w200h010, w200h025, w200h060, w200h120, w200h200, w200h310, w200h450,
    w310h010, w310h025, w310h060, w310h120, w310h200, w310h310, w310h450,
    w450h010, w450h025, w450h060, w450h120, w450h200, w450h310, w450h450,
    w730h010, w730h025, w730h060, w730h120, w730h200, w730h310, w730h450
};
//Only call if width and height are actually specified. else 0=>10px 
imgOptsScale getClosestSizeTo(int width, int height) {
    static const int possSizes[] = {10, 25, 60, 120, 200, 310, 450, 730};
    static const int sizesHalfways[] = {17, 42, 90, 160, 255, 380, 590};
    int widthI = 6;
    while (sizesHalfways[widthI - 1] > width && --widthI>0);
    int heightI = 6;
    while (sizesHalfways[heightI - 1] > height && --heightI>0);
    return (imgOptsScale)(8 + 7 * widthI + heightI);
}