//插入排序 将P位置的元素插到前P+1个元素中的正确位置,保证在P位置的时候前面的
//的元素是处于排序状态
//时间复杂度O(N*N)的时间界
template<class Comparable>
void insertionSort(vector<Comparable>& a)
{
int j;
for(size_t p = 1;p < a.size();p++)
{
Comparable temp = a[p];
for(j = p;j > 0 && temp < a[j-1];j--)
a[j] = a[j-1];
a[j] = temp;
}
}
插入排序是最容易理解的
//shell排序 保证h(k)排序性
//缩减增量排序
template<class Comparable>
void shellsort(vector<Comparable>& a)
{
for(int gap = a.size()/2;gap > 0;gap /= 2)//shell 增量
{
for(size_t i = gap;i < a.size();i++)
{
Comparable temp = a[i];
int j = i;
for(;j >= gap && temp < a[j-gap];j -= gap)
a[j] = a[j-gap];
a[j] = temp;
}
}
}
shell排序的理论证明非常困难,不过它的意思还是很简单的,实际上它是插入排序的进化版本,它最坏情况下的是运行时间是 亚N^2
如何理解这个排序算法,不防只看内部两层循环,是不是和插入排序很像?只是步长不同,shell排序是以增量的步长来插入的,它将位置i的元素插入到i,i-gap,i-2*gap...组成的序列中的正确位置当中。
//堆排序
//利用二叉堆的堆序性质
inline int leftchild(int i)
{
return i * 2 + 1;
}
template<class Comparable>
void percolatedown(vector<Comparable>& a,int i,int n) //数组,下滤的空穴位置,边界范围
{
int child;
Comparable temp;
for(temp = a[i];leftchild(i) < n;i = child)
{
child = leftchild(i);
if(child != n - 1 && a[child] < a[child + 1])
child++;
if(temp < a[child])
a[i] = a[child];
else
break;
}
a[i] = temp;
}
template<class Comparable>
void heapsort(vector<Comparable>& a)
{
for(int i = a.size()/2;i >= 0;i--)
percolatedown(a,i,a.size());
for(int j = a.size()-1;j > 0;j--)
{
swap(a[0],a[j]);
percolatedown(a,0,j);
}
}
堆排序是相对插入排序来说第二简单的算法,它的理论来源于二叉堆,二叉堆的插入时间为O(logN),那么总的时间是N*logN
//归并排序 采用分治策略
template<class Comparable>
void merge(vector<Comparable>& a,vector<Comparable>& tempArray,int leftpos,
int rightpos,int rightend) //归并函数,将两个排好序的数组合并
{
int leftend = rightpos - 1;
int temppos = leftpos;
int numelements = rightend - leftend + 1;
//
while(leftpos <= leftend && rightpos <= rightend)
if(a[leftpos] <= a[rightpos])
tempArray[temppos++] = a[leftpos++];
else
tempArray[temppos++] = a[rightpos++];
while(leftpos <= leftend)
tempArray[temppos++] = a[leftpos++];
while(rightpos <= rightend)
tempArray[temppos++] = a[rightpos++];
for(int i = 0;i < numelements;i++,rightend--)
a[rightend] = tempArray[rightend];
}
template<class Comparable>
void mergesort(vector<Comparable>& a,vector<Comparable>& tempArray,
int left,int right) //分治函数 运用递归思想进行分治
{
if(left < right)
{
int center = (left + right) / 2;
mergesort(a,tempArray,left,center);
mergesort(a,tempArray,center + 1,right);
merge(a,tempArray,left,center + 1,right);
}
}
template<class Comparable>
void mergesort(vector<Comparable>& a)
{
vector<Comparable> tempArray(a.size()); //临时数组 用于归并
mergesort(a,tempArray,0,a.size() - 1);
}
归并算法也是很容易理解的一个算法,是分治策略运用的经典例子。不断的划分子数组一直到不能划分为止,然后合并。它的时间复杂度下界为O(N*logN),缺点就是需要线性的附加内存,需要借助临时数组。