间接排序(indirectionSort):
直接应用基于谢尔排序、快速排序等这些算法的函数模板时,如果要排序的Comparable对象很大时,有时效率是很低的,问题在于,重新排列的Comparable对象时,进行了太多的复制工作,如果Comparable对象很大且难以复制,则代价将是很大的。解决的办法是:生成一个指向Comparable对象的指针数组,然后重新排列这些指针。一旦确定了元素应该在的位置,就可以直接将该元素放在相应的位置上,而不必过多的中间复制操作。这需要使用称为中间置换(in-situ permutation)的算法。【用C++实现的时候需要一些新的语法】
行为描述:
算法描述:
第一步:生成指针数组。令a为要排序的数组,p为指针数组。初始化后p[i]指向a[i];
第二步:使用p[i]所指的对象的值来确定p[i]的顺序并对p[i]排序[快速排序]。在数组a的对象完全不动,而数组p的指针重新排序。
第三步:移位实现p[i]回填到a[i]中;
C++特性:
1)vector<Comparable*>不运行
quickSort(p)重新排列指针时,quickSort模板算法为Comparable*,因此需要能够比较两个Comparable* 类型的“<”操作符。这种操作符对于指针变量是存在的,但对指针所指向的Comparable值却什么都不做。
2)智能指针类
包含指针动作的类有时候也称智能指针类(smart pointer classes)。这个类比普通指针高级一些,因为如果没有赋初始值时,将自动赋值为NULL。
3)重载operator<
将<用于所指的Comparable对象。
4)重载类型转换操作符
operator Comparable *()const将从一个Pointer<Comparable>转换为Comparable*类型,因此,p[i] = &a[i]隐式转换成立;
5)指针减法运算
nextj = p[j] - &a[0] 表示p[j]与起始地址的偏移距离;
间接排序的性质:
间接排序是由快速排序为解决内存不足而采取的改进算法,拥有快速排序的一般特性,其另一显著优势在于提高时间和空间利用率(减少复制操作次数)
间接排序实例:
//indirectionSort.cpp
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
template<class Comparable>
class Pointer{
public:
//Pointer constructor
Pointer(Comparable *p = NULL):pointee(p){
};
//operator< overwrite
bool operator<(const Pointer &p) const{
return (*pointee < *p.pointee);
};
//access the pointer value
operator Comparable * ( ) const{
return pointee;
};
private:
Comparable *pointee;
};
template<class Comparable>
void indirectionSort(vector<Comparable> &v);
//quickSort vector v
template<class Comparable>
void quickSort(vector<Comparable> &v);
//find median in vector v from index left, center, right
template<class Comparable>
const Comparable & median3(vector<Comparable> &v, int left, int right);
//quickSort the inner part
template<class Comparable>
void quickSort(vector<Comparable> &v, int left, int right);
//backup sort when vector size is smaller than 10
template<class Compareable>
void inserationSort(vector<Compareable> &v, int left, int right);
//main function
int main(){
int arr[] = {81, 94, 11, 96, 12, 35, 17, 95, 28, 58, 41, 75, 15};
int len = sizeof(arr) / sizeof(arr[0]);
vector<int> v;
for(int i = 0 ; i < len; i++){
v.push_back(arr[i]);
}
cout << "******* the original data ***********" << endl;
for(typename vector<int>::iterator itr = v.begin(); itr != v.end(); ++itr){
cout << *itr << " ";
}
cout << endl;
cout << "******* the sorted data ***********" << endl;
indirectionSort(v);
for(typename vector<int>::iterator itr = v.begin(); itr != v.end(); ++itr){
cout << *itr << " ";
}
cout << endl;
cout << " done ." << endl;
return 0;
}
template<class Comparable>
void indirectionSort(vector<Comparable> &v){
vector<Pointer<Comparable> > p(v.size());
int i, j, nextj;
//copy vector v into p
for(i = 0; i < v.size(); i++){
p[i] = &v[i]; //background construt temp variable
}
cout << endl;
//sort p
quickSort(p);
cout << " the sorted p is : ";
for(i = 0; i < v.size(); i++){
cout << *p[i] << " ";
}
cout << endl;
//restore p into v
for(i = 0; i < v.size(); i++){
if(p[i] != &v[i]){ //implicit convert Pointer<Comparable> p to Comparable* p
Comparable temp = v[i];
//find the proper index of v[i]
for(j = i; p[j] != &v[i]; j = nextj){
nextj = p[j] - &v[0]; //the distance betweent v[i] and v[0]
v[j] = *p[j];
p[j] = &v[j];
}
//insert v[i]
v[j] = temp;
//update p[j]/p[i]
p[j] = &v[j];
}
}
}
template<class Comparable>
void quickSort(vector<Comparable> &v){
quickSort(v, 0, v.size() - 1);
}
template<class Comparable>
const Comparable & median3(vector<Comparable> &v, int left, int right){
int center = (left + right) / 2;
//cout << v[left] << " , " << v[center] << " , " << v[right];
//sort the left, center and right in order
if(v[center] < v[left]){
swap(v[left], v[center]);
}
if(v[right] < v[left]){
swap(v[left], v[right]);
}
if(v[right] < v[center]){
swap(v[center], v[right]);
}
//cout << " : median is " << v[center] << endl;
swap(v[center], v[right -1]); //place the median to the last index
return v[right - 1];
}
template<class Comparable>
void quickSort(vector<Comparable> &v, int left, int right){
if(left + 10 <= right){ // using the quickSort when vector size is larger than 10
Comparable pivot = median3(v, left, right);
int i = left, j = right - 1;
for(;;){
while(v[++i] < pivot){}; //find the j's warning mark
while(pivot < v[--j]){}; //find the i's warning mark
if(i < j){
swap(v[i], v[j]); //swap the warning mark
}else{
break;
}
}
swap(v[i], v[right - 1]); //restore the pivot
quickSort(v, left, i - 1); //iterative quickSort the left part
quickSort(v, i + 1, right); //iterative quickSort the right part
}else{ //using the inserationSort when vector size is smaller than 10
inserationSort(v, left, right + 1);
}
}
template<class Compareable>
void inserationSort(vector<Compareable> &v, int left, int right){
if(left < right){
int j;
//traverse the vector form left to right
for(int p = left; p < right; p++){
Compareable temp = v[p];
//find the proper location
for(j = p; j > 0 && temp < v[j - 1]; j--){
v[j] = v[j - 1];
}
//insert into proper location
v[j] = temp;
}
}
}
practice makes perfect !