排序——排序的工程应用示例

1,排序类(Sort)与数组类(Array)的关系:

 

       1,Sort 除了可以排序 C 中的原生数组类外,还要应该可以排序 Array 里面的数组类;

       2,本文第一小部分改写 Array 使之满足;

       3,新增的成员函数: 

 

2,增加数组类在排序中应用的成员函数(仅 *.cpp 文件):

 1    /* 以下六个重载的排序是为了对 Array 对象排序;第一个参数代表外部的数组对象,Array 是父类,则 array 既可以代表静态数组对象,也可以代表动态数组对象,第二个参数意义不变*/
 2     template < typename T>//排序类的成员函数必然是用静态的成员函数通过模板实现的
 3     static void Select(Array<T>& array, bool min2max = true)
 4     {
 5         Select(array.array(), array.length(), min2max); // 将数组类中封装的原生数组的首地址和原生数组的长度拿出来
 6    }
 7 
 8     template < typename T>  // 排序类就能够成功的作用于数组类对象,将数组类对象所代表的那些元素序列进行排序
 9     static void Insert(Array<T>& array, bool min2max = true)
10     {
11         Insert(array.array(), array.length(), min2max);
12    }
13 
14     template < typename T>
15     static void Bubble(Array<T>& array, bool min2max = true)
16     {
17         Bubble(array.array(), array.length(), min2max);
18    }
19 
20     template < typename T>
21     static void Shell(Array<T>& array, bool min2max = true)
22     {
23         Shell(array.array(), array.length(), min2max);
24     }
25 
26     template < typename T>
27     static void Merge(Array<T>& array, bool min2max = true)
28     {
29         Merge(array.array(), array.length(), min2max);
30    }
31 
32     template < typename T>
33     static void Quick(Array<T>& array, bool min2max = true)
34     {
35         Quick(array.array(), array.length(), min2max);
36     }

             

3,当待排序数据元素为体积庞大的对象时,如何提高排序效率?

      

       1,这时更加高效的算法带来额的时间改善是微不足道的;

              1,排序过程中不可避免的需要进行交换操作;

                     1,比较和交换;

              2,交换操作的本质为数据元素间的相互复制;

              3,当数据元素体积较大时,交换操作耗时巨大;

                     1,比较操作的耗时,一般根据两三个关键字作比较来确定,所以耗时很少;            

       2,解决方案:代理模式:

 

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

                     1,生活中代理办签证,有时候要自己出现;

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

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

       3,代理模式示意图:

 

              1,在代码里面创建一个代理对象数组,初始化的时候,让代理对象一对一的代理原始数据元素;

              2,然后使用具体的排序函数对代理对象组成的数组进行排序;

       4,代理模式创建:

              1,创建代理类,通过代理对象来操作被代理对象;

                     1,成员指针指向被代理对象;

                     2,重载相等操作符用于被代理对象到代理对象的一一映射;

                     3,成员函数指向被代理对象成员变量来通过代理访问被代理对象共有成员;

                     4,成员函数得到被代理对象;

                     5,定义代理类之间的比较操作(被代理对象的比较);

              2,构建被代理对象时,赋值一一映射到代理;

              3,对代理对象进行排序;

  5,代理模式代码实现及其测试示例:

  1 #include <iostream>
  2 #include <ctime>
  3 #include "Sort.h"
  4 
  5 using namespace std;
  6 using namespace DTLib;
  7 
  8 struct Test : public Object
  9 {
 10     int id;
 11     int data1[1000];
 12    double data2[500];
 13 
 14     bool operator < (const Test& obj)
 15     {
 16         return id < obj.id;
 17    }
 18 
 19     bool operator >= (const Test& obj)
 20     {
 21         return id >= obj.id;
 22    }
 23 
 24     bool operator > (const Test& obj)
 25     {
 26         return id > obj.id;
 27    }
 28 
 29     bool operator <= (const Test& obj)
 30     {
 31         return id <= obj.id;
 32     }
 33 };
 34 
 35 // 实现代理类,有了代理类,才可以有代理对象,如果项目对时间要求不高的话,没必要使用,因为使代码变得复杂了空间换时间的理念
 36 class TestProxy : public Object
 37 {
 38 protected:
 39    Test* m_pTest;  // 指向被代理的对象
 40 
 41 public:
 42     // 代理对象必须像原始的被代理对象一样的可以干同样的事情,原始对象能干的功能,代理对象也要能实现
 43     int id()
 44     {
 45         return m_pTest->id;
 46    }
 47 
 48     int* data1()
 49     {
 50         return m_pTest->data1;
 51    }
 52 
 53     double* data2()
 54     {
 55         return m_pTest->data2;
 56    }
 57 
 58     // 必要的时候能够请出委托者,办护照
 59     Test& test() const
 60     {
 61         return *m_pTest;
 62    }
 63 
 64     // 代理类之间的比较就是原始对象之间的比较
 65     bool operator < (const TestProxy& obj)
 66     {
 67         return test() < obj.test();
 68    }
 69 
 70     bool operator >= (const TestProxy& obj)
 71     {
 72         return test() >=obj.test();
 73    }
 74 
 75     bool operator > (const TestProxy& obj)
 76     {
 77         return test() > obj.test();
 78    }
 79 
 80     bool operator <= (const TestProxy& obj)
 81     {
 82         return test() <= obj.test();
 83    }
 84 
 85     // 重载这个赋值操作符,让其和被代理对象一一映射,不用构造函数
 86     Test& operator = (Test& test)
 87     {
 88         m_pTest = &test;
 89         return test;
 90     }
 91 };
 92 
 93    Test t[1000];
 94    TestProxy pt[1000];
 95 
 96 int main()
 97 {
 98     clock_t begin = 0;
 99    clock_t end = 0;
100 
101     for(int i=0; i<1000; i++)
102     {
103         t[i].id = i;
104         pt[i] = t[i];  // 一一映射,pt 里面的元素代理的 t 里面的对象
105    }
106 
107     begin = clock();
108     Sort::Bubble(pt, 1000, false );
109    end = clock();
110 
111    cout << "Time: " << (end - begin) << endl;
112 
113     for(int i=0; i<1000; i++)
114     {
115         cout << t[i].id << " " << pt[i].id() << endl;
116    }
117 
118     return 0;
119 }

       6,如果项目对于时间或者效率没有太高要求(50 倍),没必要使用这个方案,因为这里会使代码变得复杂了;

4,小结:

       1,DTLib 中的排序类和数组类之间存在关联关系;

       2,排序类能够对数组类对象进行排序;

       3,当排序体积庞大的对象时,使用代理模式间接完成;

              1,操作代理对象等价于操作于原始对象;

       4,代理模式的使用有效避开大对象交换时的耗时操作;

       5,代理模式解决方案是空间换时间思想的体现;

              1,也增加了代码复杂性;

猜你喜欢

转载自www.cnblogs.com/dishengAndziyu/p/10924002.html