我们在之前学习了各种排序的算法,那么我们的排序类(Sort)和数组类(Array)之间的关系如下。

排序之代理类(三十三)_第1张图片

        那么我们需要将排序类和数组类之间关联起来,怎么进行关联呢?我们需要在排序类中新增几个成员函数,具体函数原型如下

排序之代理类(三十三)_第2张图片

        具体代码如下,我们在 Array.h 中添加如下代码

T* array() const
{
    return m_array;
}

        上面函数用来获取 array 的头地址。Sort.h 代码如下

template 
static void Select(Array& array, bool min2max = true)
{
    Select(array.array(), array.length(), min2max);
}

template 
static void Insert(Array& array, bool min2max = true)
{
    Insert(array.array(), array.length(), min2max);
}

template 
static void Bubble(Array& array, bool min2max = true)
{
    Bubble(array.array(), array.length(), min2max);
}

template 
static void Shell(Array& array, bool min2max = true)
{
    Shell(array.array(), array.length(), min2max);
}

template 
static void Merge(Array& array, bool min2max = true)
{
    Merge(array.array(), array.length(), min2max);
}

template 
static void Quick(Array& array, bool min2max = true)
{
    Quick(array.array(), array.length(), min2max);
}

        我们在 main.cpp 中添加如下测试代码

#include 
#include "Sort.h"
#include "StaticArray.h"

using namespace std;
using namespace DTLib;

int main()
{
    StaticArray sa;

    for(int i=0; i<5; i++)
    {
        sa[i] = i;
    }

    Sort::Bubble(sa, false);

    for(int i=0; i<5; i++)
    {
        cout << sa[i] << endl;
    }
    
    return 0;
}

        排序结果如下

排序之代理类(三十三)_第3张图片

        我们看到已经正确进行排序。那么在排序的工程应用中,有个经典的问题:那就是当待排数据元素为体积庞大的对象时,我们应如何提高排序的效率呢?我们以下来的示例代码作为分析

#include 
#include 
#include "Sort.h"

using namespace std;
using namespace DTLib;

struct Test : public Object
{
    int id;
    int data1[1000];
    double data2[500];

    bool operator < (const Test& obj)
    {
        return id < obj.id;
    }

    bool operator >= (const Test& obj)
    {
        return id >= obj.id;
    }

    bool operator > (const Test& obj)
    {
        return id > obj.id;
    }

    bool operator <= (const Test& obj)
    {
        return id <= obj.id;
    }
};

Test t[1000];

int main()
{
    clock_t begin = 0;
    clock_t end = 0;

    for(int i=0; i<1000; i++)
    {
        t[i].id = i;
    }

    begin = clock();

    Sort::Bubble(t, 1000, false);

    end = clock();

    cout << "Time : " << (end - begin) << endl;

    return 0;
}

        我们来看看花费的时间,结果如下

图片.png

        我们看到花费时间很长。那么我们来分析下。在排序过程中,要不可避免的进行交换操作;然而交换操作的本质是数据元素间的相互复制,如当数据元素体积较大时,交换操作耗时巨大。我们来看看经典的做法:代理模式。

        1、为待排数据元素设置代理对象;

        2、对代理对象所组成的序列进行排序;

        3、需要访问有序数据元素时,通过访问代理序列完成。

        也就是说,我们通过操作代理对象进而来操作原来的数据对象。如下:

排序之代理类(三十三)_第4张图片

        代理效果如下图所示

排序之代理类(三十三)_第5张图片

        我们看到用小对象数据来代替大对象数据,具体代码如下

#include 
#include 
#include "Sort.h"

using namespace std;
using namespace DTLib;

struct Test : public Object
{
    int id;
    int data1[1000];
    double data2[500];

    bool operator < (const Test& obj)
    {
        return id < obj.id;
    }

    bool operator >= (const Test& obj)
    {
        return id >= obj.id;
    }

    bool operator > (const Test& obj)
    {
        return id > obj.id;
    }

    bool operator <= (const Test& obj)
    {
        return id <= obj.id;
    }
};

class TestProxy : public Object
{
protected:
    Test* m_pTest;
public:
    int id()
    {
        return m_pTest->id;
    }

    int* data1()
    {
        return m_pTest->data1;
    }

    double* data2()
    {
        return m_pTest->data2;
    }

    Test& test() const
    {
        return *m_pTest;
    }

    bool operator < (const TestProxy& obj)
    {
        return test() < obj.test();
    }

    bool operator >= (const TestProxy& obj)
    {
        return test() >= obj.test();
    }

    bool operator > (const TestProxy& obj)
    {
        return test() > obj.test();
    }

    bool operator <= (const TestProxy& obj)
    {
        return test() <= obj.test();
    }

    Test& operator = (Test& test)
    {
        m_pTest = &test;

        return test;
    }
};

Test t[1000];
TestProxy pt[1000];

int main()
{
    clock_t begin = 0;
    clock_t end = 0;

    for(int i=0; i<1000; i++)
    {
        t[i].id = i;
        pt[i] = t[i];
    }

    begin = clock();

    Sort::Bubble(pt, 1000, false);

    end = clock();

    cout << "Time : " << (end - begin) << endl;

    return 0;
}

        结果如下

图片.png

        我们看到效率提高了50倍左右,这就是经典的代理类模式。我们通过对代理类的学习,总结如下:1、当排序体积是很庞大的对象时,使用代理模式间接完成;2、代理模式的使用有效避开大对象交换时的耗时操作;3、代理模式解决方案是空间换时间思想的体现。