STL sort算法技巧和基本排序算法实现
来源:互联网 发布:淘宝怎么上掌柜热卖 编辑:程序博客网 时间:2024/05/02 03:05
1.基本排序算法之一 冒泡排序 时间复杂度 o(n^2) 实现简单
//stable sort time (o(n^2))
template<class RandomAccessIterator >
void __bubble_sort_myself( RandomAccessIterator first , RandomAccessIterator last)
{
if(first == last) return ;
typedef typename iterator_traits<RandomAccessIterator>::difference_type distance;
distance len = last - first ;
distance i = 0 , j = 0 ;
for ( ; i < len ; i++ )
{
for(j = 0 ; j < len -i-1 ; j++)
{
if(*(first+j) > *(first+j+1))
iter_swap(first+j,first+j+1);
}
}
}
本算法小技巧,用len控制循环,比迭代器比较要稍快
2.基本排序算法之二 插入排序 时间复杂度 o(n^2) 实现简单
//插入排序 稳定 time (o(n^2))
template<class RandomAccessIterator >
void __insert_sort_myself( RandomAccessIterator first , RandomAccessIterator last)
{
if(first == last) return ;
typedef typename iterator_traits<RandomAccessIterator>::difference_type distance;
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
distance len = last - first ;
distance i , j ;
value_type temp ;
for ( i = 1 ; i < len ; i++)
{
temp = *(first + i) ;
if(temp < *first )//如果是第一个之前的数 直接copy
{
copy_backward(first ,first + i ,first + i + 1);
*first = temp;
}
else //因为temp必然在范围之内,所以循环比较 ,减去边界比较
{
__unguarded_linear_insert_sgi(first + i ,temp);
}
}
}
//插入排序的辅助函数 这里还可以优化 就是位置查找的方式可以选择二分查找方式
template<class RandomAccessIterator ,class T>
void __unguarded_linear_insert——sgi( RandomAccessIterator last , const T& temp)
{
RandomAccessIterator i = last;
--i;
while(*i > temp)
{
*last = *i;
last = i;
--i;
}
*last = temp;
}
ps:主要STL技巧就在这个辅助函数里面,前面判断了temp必然在范围之内,所以只需要比较交换就可以,不用去判断边界条件,算是一种优化吧
3.基本排序算法之三 快速排序 时间复杂度 o(nlogn) 最坏情况n^2
template<class T >//取中值函数
inline const T& __midian_myself(const T& a,const T& b,const T& c)
{
if( a > b)
if ( b > c)
return b;
else
return c > a ? a : c;
else if ( a > c)
return a;
else
return b > c ? c : b ;
}
template<class RandomAccessIterator , class T>//辅助函数,用于将元素分隔
RandomAccessIterator __unguarded_partition_myself( RandomAccessIterator first , RandomAccessIterator last , const T& t)
{
while ( true )
{
while ( *first < t ) ++first;
--last;
while ( *last > t ) --last;
if(!(first < last)) return first;
iter_swap( first , last) ;
++first ;
}
}
//快速排序 不稳定 time (o(n*logn)) 最坏情况o(n^2)
template<class RandomAccessIterator >
void __quick_sort_myself( RandomAccessIterator first , RandomAccessIterator last)
{
if(first == last) return;
RandomAccessIterator i = first + ( last -first ) / 2 ;
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type value = __midian_myself( *first ,*--last ,*i);//取3点中值
++last;
RandomAccessIterator j = __unguarded_partition_myself(first ,last , value);
//必要判别条件
if( j > first + 1 )
__quick_sort_myself(first , j);
if( last > j + 1 )
__quick_sort_myself(j , last);
}
ps:本算法花了蛮久时间,一直在纠结的是存在相同元素的情况,对于辅助函数的思考,就是分隔了以后不一定是大于的都在左边,小于的都在右边,有可能有等于的在两边,但是最终在多次递归之后,相同元素还是会聚合在一起!还有就是边界问题老出问题。见红色部分,必须判断。取中点的法式是用于避免最坏情况的发生。
4.基本排序算法之三 sgi_stl快速排序 时间复杂度 o(nlogn) 最坏情况约等于nlogn
//SGI STL sort 大部分情况用三点均值快速排序,分割恶化出现用Heap_sort也就是partial_sort,在小的子序列就用insert_sort
template<class RandomAccessIterator >
void __quick_sort_sgi( RandomAccessIterator first , RandomAccessIterator last)
{
if(first != last)
{
__introsort_loop_sgi(first , last ,value_type( first ), __lg((last-first) *2) );
__final_insertion_sort_sgi(first , last );
}
}
//取log的函数
template<class Size>
inline Size __lg(Size n)
{
Size k;
for( k = 0 ; n >1 ; n>>=1) ++k;
return k;
}
//一般情况快速排序,恶化用堆排序(o(nlogn))总体效率趋近nlogn
template<class RandomAccessIterator , class T, class Size>
void __introsort_loop_sgi(RandomAccessIterator first ,RandomAccessIterator last , T* , Size depth_limit)
{
while ( last - first > 16)
{
//分割恶化,就是说经过几次分割后仍有大部分元素在一起。
if(depth_limit == 0)
{
//等同于先make_heap();然后sort_heap();
partial_sort(first , last ,last);
return;
}
--depth_limit;
T value = __midian_myself(*first, *(first + (last- first)/2), *(last-1));
RandomAccessIterator cur = __unguarded_partition_sgi(first , last , value);
//递归调用 不断调整尾部位置就行了
__introsort_loop_sgi(cur , last , value_type(first), depth_limit);
last = cur;
}
}
template<class RandomAccessIterator >
void __final_insertion_sort_sgi( RandomAccessIterator first , RandomAccessIterator last)
{
//对前面的序列排序好之后,后面的都在范围内,所以采用不判定边界,只比较大小的函数__unguarded_linear_insert
if(last - first > 16)
{
__insert_sort_myself(first , first +16);
__unguarded_insertion_sort_sgi(first + 16 , last);
}
else
__insert_sort_myself(first , last);
}
//主要是为来不要判定边界条件作优化
template<class RandomAccessIterator >
inline void __unguarded_insertion_sort_sgi( RandomAccessIterator first , RandomAccessIterator last)
{
__unguarded_insertion_sort_aux(first , last , value_type(first));
}
template<class RandomAccessIterator ,class T>
void __unguarded_insertion_sort_aux( RandomAccessIterator first , RandomAccessIterator last , T*)
{
for(RandomAccessIterator i = first ; i!=last ; ++i)
__unguarded_linear_insert_sgi(i , T(*i));//利用不判定边界的方式
}
ps:本次试验的总结就是要注意函数名称递归函数名称不要写错,函数名最好区分于SGI函数名
5.基本排序算法之三归并排序 时间复杂度 o(nlogn) 最坏情况nlogn 采用迭代实现
//归并排序 不稳定 nlogn
template<class RandomAccessIterator >
void __merge_sort_myself( RandomAccessIterator first , RandomAccessIterator last)
{
if(first == last)return;
typedef typename iterator_traits<RandomAccessIterator>::difference_type distance;
distance len = last -first ;
for ( distance depth = 0 ; depth < __lg( len ) + 1 ; ++depth)
{
//从归并位置尾端开始,主要是防止出界运算!
distance pos = pow(2 , depth + 1);
for(pos ; pos < len; pos += pow(2,depth+1))
__insert_sort_myself ( first + pos - pow(2,depth+1) , first + pos );
//对后面几个在排序
__insert_sort_myself ( first + pos - pow(2,depth+1), last);
}
}
PS:归并排序的__insert_sort 可以用merge整合,归并排序主要是注意越界问题 但是如果用merge就要占用N个空间,消耗掉蛮多拷贝复制的资源。
5.基本排序算法之三堆排序 时间复杂度 o(nlogn) 最坏情况nlogn
其中算法复杂度主要有建立堆和调整堆的时间来决定。
算法通过不断的push来建立堆和不断的pop来输出序列
数据结构采用的是顺序存储,并且是Random迭代器
//建堆 遍历 注意传到push里面的尾节点位置不是last 而是last -1
template<class RandomAccessIterator >
void __make_heap_myself( RandomAccessIterator first , RandomAccessIterator last)
{
for (RandomAccessIterator i = first +1 ; i < last ; ++i)
__push_heap_myself(first , i);
}
//堆排序 直接利用出堆把大元素放在后续位置 即可 注意起始位置是last -1
template<class RandomAccessIterator >
void __sort_heap_myself( RandomAccessIterator first , RandomAccessIterator last)
{
for (RandomAccessIterator i = last-1 ; i > first ; --i)
__pop_heap_myself(first , i);
}
//把last位置的元素压入前面的堆 向上调整
template<class RandomAccessIterator>
void __push_heap_myself(RandomAccessIterator first,RandomAccessIterator last)
{
if ( first == last )
return ;
typedef typename iterator_traits<RandomAccessIterator>::difference_type distance;
typedef typename iterator_traits<RandomAccessIterator>::value_type T;
T temp = *last ;
distance des = last -first ;
distance parent = ( des-1 ) / 2;
while ( parent > 0)
{
if ( *(first + parent) >= temp )
{
*(first + des) = temp;
return;
}
else
{
*(first + des) = *(first + parent);
des = parent ;
parent = ( des -1 ) / 2;
}
}
//最后一个元素的比较
if(*first >= temp)
{
*(first +des) = temp;
}
else
{
*(first + des) = *first ;
*first = temp ;
}
}
//出堆函数,元素出堆到last上 先交换,在调整 第一个元素必然是最大的
template<class RandomAccessIterator>
void __pop_heap_myself(RandomAccessIterator first,RandomAccessIterator last)
{
iter_swap(first , last);
__adjust_heap_myself(first ,last,distance_type(first),value_type(first));
}
//用于pop的调整函数 向下调整
template<class RandomAccessIterator , class T ,class Distance>
void __adjust_heap_myself(RandomAccessIterator first,RandomAccessIterator last,Distance * ,T*)
{
T temp = *first;
Distance len = last - first ;
Distance des = 0 ;
while( true )
{
Distance left_pos = 2 * des + 1;
Distance right_pos = 2 * des + 2;
//有左右节点
if( right_pos < len)
{
//左边节点最大
if((*(first + left_pos) >= temp) && (*(first + left_pos)>= *(first + right_pos)) )
{
*(first + des) = *(first + left_pos );
des = left_pos;
}
//右边节点最大
else if((*(first + right_pos) >= temp) && (*(first + right_pos)>= *(first + left_pos)) )
{
*(first + des) = *(first + right_pos );
des = right_pos;
}
//元素本来最大
else //if(temp > *(first + 2*des +1) && temp > *(first + 2*des +2) )
{
*(first + des ) = temp;
return;
}
}
//只有左子节点
else if( right_pos == len)
{
if(temp > *(first + left_pos))
*(first + des) = temp;
else
{
*(first + des) = *(first + left_pos);
*(first + left_pos) = temp;
}
return;
}
//无左右节点
if(right_pos > len)
{
*(first + des) = temp ;
return;
}
}
}
ps:切记里面的大于等于 ,条件判断十分重要,如果没有等于,就会忽略一种情况,就是左右节点相同 比来比去就直接进入else了
目前为止,一些基本排序的实现已经列出了,排序比较总结
稳定排序 : 冒泡 , 插入 ,凡是o(n^2)的排序都是稳定的
快速,堆,归并则不稳定。
上面3个时间复杂度均值相同,但是快速排序会出现恶化分隔的情况,而归并排序需要辅助空间,以及成员的构造和赋值。
- STL sort算法技巧和基本排序算法实现
- STL - sort排序算法
- STL排序算法之sort()
- 九、STL算法-排序算法(sort)
- STL 排序算法之全排列sort和next_permutation
- STL sort排序算法详细介绍
- STL排序算法sort()相关用法
- STL中sort排序算法原理
- STL之排序算法SORT 详细介绍
- 整理:STL sort排序算法详细介绍
- 031day(STL排序算法sort)
- stl中list的sort算法实现
- stl中list的sort算法实现
- 基本排序算法实现
- 基本排序算法的分析和实现
- stl的排序 和 用算法实现的排序比较
- c++ STL 算法set_union和sort
- STL算法之sort和stable_sort
- 验证视图状态 MAC 失败
- jQuery调用WebService详解(POST)
- 【学习】各著名网站的使用语言情况
- 关于扩展STL算法时如何使用traits编程技法!!!
- fafafatttttttttt
- STL sort算法技巧和基本排序算法实现
- 工具集合及使用方法
- 关于win7_iis报500.19和500.21错误的解决方法
- 调色板的原理
- js实现树形菜单效果
- vistor模式
- C++读取文件所有内容+写一个新文件
- Erlang Tips:如何检查目标进程已经启动
- 消息中间件与WebsphereMQ入门