您的位置:首页 > 其它

常见排序算法(归并排序-曾经的笔记)

2011-03-31 02:47 387 查看
四、归并排序
思想:将两个或两个以上的有序表组合成一个新的有序表。
两路归并的迭代算法:
1个元素的表总是有序的。所以对n个元素的待排序列,每个元素可看成1个有序子表。对子表两两合并生成 个子表,所得子表除最后一个子表长度可能为1外,其余子表长度均为2。再进行两两合并,直到生成n个元素按关键码有序的表。
【效率分析】
需要一个与表等长的辅助元素数组空间,所以空间复杂度为O(n)。
对n个元素的表,将这n个元素看作叶结点,若将两两归并生成的子表看作它们的父结点,则归并过程对应由叶向根生成一棵二叉树的过程。所以归并趟数约等于二叉树的高度-1,即log2n,每趟归并需移动记录n次,故时间复杂度为O(nlog2n)。

template <class _It, class _ItMem, typename _Cmp>
inline void Merge2(_It first, _It mid, _It last, _ItMem mem, _Cmp& cmp)
{ // 合并排序算法中的实现合并的子程序
_It tmp_mid = mid;
while( (first<tmp_mid) && (mid<last))
{
if( cmp(*first, *mid) )
{
*mem++ = *first++;
}
else
{
*mem++ = *mid++;
}
}
while (first<tmp_mid)
{
*mem++ = *first++;
}
while (mid<last)
{
*mem++ = *mid++;
}
}

template <class _Ty, class _It, typename _Cmp>
void MergeSort2(_It first, _It last, _Ty& tmp, _Cmp& cmp) throw()
{	//对 [first, last) 进行合并排序  非递归版本
_Ty* pBackup = new _Ty[last - first];
int length = last - first;

bool bToMem = true;
for(int len=1; len<length; len*=2)
{
if (bToMem)
{
for(int mid=len; mid+len<=length; mid+=2*len)
{
Merge2(first+mid-len, first+mid, first+mid+len, pBackup+mid-len, cmp);
}
if(mid-len<length)
{
Merge2(first+mid-len, first+(mid<length ? mid:length), first+length,
pBackup+mid-len, cmp);
}
}
else
{
for(int mid=len; mid+len<=length; mid+=2*len)
{
Merge2(pBackup+mid-len, pBackup+mid, pBackup+mid+len, first+mid-len, cmp);
}
if(mid-len<length)
{
Merge2(pBackup+mid-len, pBackup+(mid<length ? mid:length), pBackup+length,
first+mid-len, cmp);
}
}
bToMem = !bToMem;
}

if ( !bToMem )
{
for (int i=0; i<length; i++)
{
*(first+i) = *(pBackup+i);
}
}
}

下面是两路归并的递归算法:(元素复制过多了,有时间再修改)
template <class _Ty, class _It, typename _Cmp>
inline void Merge(_It first, _It mid, _It last, _Ty* const mem, _Cmp& cmp)
{ // 合并排序算法中的实现合并的子程序
int iLLength = mid - first;
int iRLength = last - mid;
_Ty* const L = mem;
_Ty* const R = mem + iLLength;
for(int i=0; i<iLLength; i++)
{
L[i] = *(first+i);
}
for(int j=0; j<iRLength; j++)
{
R[j] = *(mid+j);
}

i = j = 0;

for(_It k=first; k<last; k++)
{
if((i<iLLength) && (j<iRLength) && ( cmp(L[i], R[j])) || (j == iRLength))
{
*k = L[i];
i++;
}
else if(j<iRLength)
{
*k = R[j];
j++;
}
}
}

template <class _Ty, class _It, typename _Cmp>
inline void _MergeSort(_It first, _It last, _Ty* const mem, _Cmp& cmp)
{//对 [first, last) 进行合并排序 不申请内存
if(first < last-1)
{
_It mid = first + (last-first)/2;
_MergeSort(first, mid, mem, cmp);
_MergeSort(mid, last, mem, cmp);
Merge(first, mid, last, mem, cmp);
}
}

template <class _Ty, class _It, typename _Cmp>
void MergeSort(_It first, _It last, _Ty& tmp, _Cmp& cmp) throw()
{//对 [first, last) 进行合并排序
if(first < last-1)
{
_It mid = first + (last-first)/2;
_Ty* mem = new _Ty[last - first];
_MergeSort(first, mid, mem, cmp);
_MergeSort(mid, last, mem, cmp);
Merge(first, mid, last, mem, cmp);
delete mem;
}
}

五、非比较排序
1.计数排序
思想:对每一个输入元素x,确定出小于x的元素个素。有了这一信息,就可以把x直接放到它在最终输出数组中的位置上。计数排序假设n个输入元素中的每一个都是介于0到k之间的整数,此处k为某个整数。当k=O(n)时,计数排序的运行时间为⊙(n)。计数排序可用作基数排序的子过程。
2.基数排序
基数排序是一种借助于多关键码排序的思想,是将单关键码按基数分成“多关键码”进行排序的方法。
3.桶排序
思想:把区间[0,1)划分成n个相同大小的子区间(或称桶),然后,将n个输入数分布到各个桶中去,因为输入数均匀分布在[0,1)上,所以,一般不会有很多数落在一个桶中的情况出现。最后,需对各个桶中的数进行排序,按序输出即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: