含生存期的矩形利用率问题求解

问题描述:

已知一宽为W高为H的目的矩形,时间序列为t0,t1,……,在时间tn时系统随机产生一宽为Wn(不超过W)高为Hn(不超过H)的小矩形,并且需将此小矩形放至目的矩形中,而且小矩形的生存期未知(即在同一时刻,产生一个小矩形时有可能同时需销毁若干个已存在小矩形)。寻找一算法使得在一段时间t内,目的矩形被重置的次数最少?

 

解决方案:

此问题类似于内存管理问题:随机出现的new(或malloc)和delete(或free)分别分配和释放内存,一段时间后,内存碎片的产生便会导致某一时刻new(或malloc)返回失败。这里的问题是,在产生的小矩形不能放至目的矩形时,便需要将目的矩形重置(即清空所有小矩形),求解结果为时间t内的重置次数尽可能少。

 

考虑到生存期问题,我们需要对目的矩形的可用空间进行分配和回收。当某个小矩形销毁时,我们将此空间重新加至可用空间中,并且尽可能拼接成更大的空间,以供下一个可能更大的小矩形使用(目的矩形左上角为原点(0,0)),采用伙伴系统算法。

 

先定义矩形分配的相关操作

 

// 定义矩形的小于操作符“<”,按从左至右,从上至下的顺序排列

inline bool operator<(RECT const& lhs, RECT const& rhs)

{

    return (lhs.top < rhs.top || (lhs.top == rhs.top && lhs.left < rhs.left));

}

 

// 如果使用的是STL,也可以特化模板类std::less

template<>

struct std::less<RECT>

{

    bool operator()(RECT const& lhs, RECT const& rhs) const

    {

        return (lhs.top < rhs.top || (lhs.top == rhs.top && lhs.left < rhs.left);

    }

}

 

// 使用vecotr保存可用空间的矩形,初始状态为只含有一个元素且为目的矩形

std::vecotr<RECT> rect_for_use;

rect_for_use.push_back(CRect(0, 0, W, H));

 

// 定义矩形的大于等于操作符“>=”

inline bool operator>=(RECT const& lhs, RECT const& rhs)

{

    return (lhs.right - lhs.left >= rhs.right - rhs.left && lhs.bottom - lhs.top >= rhs.bottom - rhs.top);

}

 

// 或者特化模板类std::greater_than

template<>

struct std::greater_than<RECT>

{

    bool operator()(RECT const& lhs, RECT const& rhs) const

    {

        return (lhs.right - lhs.left >= rhs.right - rhs.left && lhs.bottom - lhs.top >= rhs.bottom - rhs.top);

    }

}

 

// 从可用空间中查找一个能容下当前小矩形的空间

std::vector<RECT>::iterator it = std::find_if(rect_for_use.begin(), rect_for_use.end(), std::greater_than<RECT>());

 

// 如果未找到,重置目的矩形

if(it == rect_for_use.end())

{

    rect_for_use.erase(rect_for_use.begin(), rect_for_use.end());

    rect_for_use.push_back(CRect(0, 0, W, H));

}

 

再定义矩形回收的相关操作

 

// 查找需要插入的位置

std::vector<RECT>::iterator it = std::lower_bound(rect_for_use.begin(), rect_for_use.end(), rc, std::less<RECT>());

 

// 插入到可用空间中

it = std::insert(rect_for_use.begin(), rect_for_use.end(), it);

 

// 判断是否需要合并成更大的空间

while(1)
{
    if(it != rect_for_use.begin())
    {
        RECT& forward = *(it - 1);
        RECT& cur = *it;
        if(forward.top == cur.top && forward.bottom == cur.bottom && forward.right == cur.left)
        {

             forward.right = cur.right;

             it = rect_for_use.erase(it);
             continue;

         }
        else if(forward.left == cur.left && forward.right == cur.right && forward.bottom == cur.top)
        {

             forward.bottom = cur.bottom;

             it = rect_for_use.erase(it);
             continue;

         }
     }
     if(++it != rect_for_use.end())
          continue;
     break;
}

 

结论:

此算法原理很简单,实现也不复杂,在实践中随机情况下运行良好,并且效率较高。

 

附:实践中回收时合并操作并不一定只发生在相邻的两个矩形中,可能出现跳跃合并的情况,实现也是需要一个简单的查找而已。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章