• 算法,问题之解法也

  • 算法好坏的衡量标准:时间和空间,单位是对数、一次、二次、三次等

  • 算法中处理的数据,输入方式都是左闭又开,类型就迭代器, 如:[first, last)

  • STL中提供了很多算法,我们只研究感兴趣的几种

copy函数

  • 拷贝[first, last)到[result, reslut+(last - first))

  • 总体考虑:对象能够直接在内存级别拷贝,还是需要单独拷贝

  • 设计技巧:重载和特化

  • 如下图所示:

template<class InputIterator, class OutputIterator>
inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator reslut)
{
return __copy_dispatch<InputIterator, OutputIterator>()(first, last, result);
} // 特化
inline char* copy(const char* first, const char* last, char* result)
{
memmove(result, first, last - first);
return result + (last - first);
} // 特化
inline wchar_t* copy(const wchar_t* first, const wchar_t* last, wchar_t* result)
{
memmove(result, first, sizeof(wchar_t) * (last - first));
return result + (last - first);
}
template<class InputIterator, class OutputIterator>
struct __copy_dispatch
{
OutputIterator operator()(InputIterator first, InputIterator last, OutputIterator reslut)
{
return __copy(first, last, result, iterator_category(first));
}
} // 特化
template <class T>
struct __copy_dispatch<T*, T*>
{
T* operator()(T* first, T* last, T* result)
{
typedef typename __type_traits<T>::has_trival_assignment_operator t;
return __copy_t(first, last, result, t());
}
} // 特化
template <class T>
struct __copy_dispatch<const T*, T*>
{
T* operator()(const T* first, const T* last, T* result)
{
typedef typename __type_traits<T>::has_trival_assignment_operator t;
return __copy_t(first, last, result, t());
}
}
template<class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last, OutputIterator reslut, input_iterator_tag)
{
// 以判断迭代器是否相同为标准,速度慢
for(; first != last; ++result, ++first)
{
*result = *first;
}
return result;
} template<class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last, OutputIterator reslut, random_access_iterator_tag)
{
// 完全是为了复用
return __copy_d(first, last, result, distance_type(first));
} template<class InputIterator, class OutputIterator, class Distance>
inline OutputIterator __copy_d(InputIterator first, InputIterator last, OutputIterator reslut, Distance*)
{
// 以判断n值是否大于0为标准,速度快
for(Distance n = last - first; n > ; --n, ++result, ++first)
{
*result = *first;
}
return result;
}
templat <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __true_type)
{
// 直接复制内存
memmove(result, first, sizeof(T) * (last - first));
return result + (last - first);
} templat <class T>
inline T* __copy_t(const T* first, const T* last, T* result, __true_type)
{
// 每个数据单独复制
return __copy_d(first, last, result, (ptrdiff_t*));
}

copy_back函数

  • copy_back和copy的设计方式基本相同,问题的区别是拷贝的方向不同,copy是从first开始到last拷贝,copy_back是从last开始到first拷贝

  • copy_back的拷贝过程:*(result - 1) = *(last - 1), *(result - 2) = *(last - 2)...

find函数

  • 在[first, last)中找出第一个匹配的数据,返回指向该数据的Iterator

template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& value)
{
while(first != last && *first != *last) ++first;
return first;
}

sort函数

  • 插入排序

    • 优点:对于小型,基本有序的数据进行排序,效率最高

    • 缺点:对于大型数据,完全无序,效率非常低

  • 堆排序

    • 优点:对大型数据表现良好,所需的额外存储空间是和数据等同的大小

    • 缺点:对于小型数据不合适

    • 复杂度:平均O(NlogN),最坏O(N^2)

  • 快速排序

    • 优点:对于大型数据表现良好

    • 缺点:递归调用耗资源,不适用于小型数据

    • 复杂度:平均O(NlogN),最坏O(NlogN)

  • STL中的排序算法

    • 如果数据个数大于16,使用快速排序,如果快速排序递归的层次超过一定阈值,使用堆排序

    • 如果数据小于16,直接使用插入排序

    • 原因:

      • 小数据直接使用插入排序,效率高

      • 大型数据一开始就使用堆排序,复杂度是O(NlogN),一开始使用快速排序效率低于O(NlogN),如果一直使用快速排序,算法的复杂度会降低到最坏O(N^2),所以先快速排序再堆排序

  • 插入排序算法源码

template <class RandomAccessIterator>
void __insert_sort(RandomAccessIterator first, RandomAccessIterator last)
{
if(first == last)
{
return;
} for(RandomAccessIterator i = first + ; i != last,; i++)
{
__linear_insert(first, i, value_type(first));
}
} template <class RandomAccessIterator, class T>
inline void __linear_insert(RandomAccessIterator first, RandomAccessIterator last, T*)
{
T value = *last;
if(value < first)
{
// 需要插入的值比头部的值还小,直接整体拷贝
copy_back(first, last, last+);
*first = value;
}
else
{
// 从后向前,依次比较拷贝
__unguarded_linear_insert(last, value);
}
} template <class RandomAccessIterator, class T>
void __unguarded_linear_insert(RandomAccessIterator last, T value)
{
--next;
while(value < *next)
{
*last = *next;
last = next;
--next;
}
*last = value;
}
  • 快速排序算法源码
// 取三值中点
template <class T>
inline const T& _median(const T& a, const T& b, const T& c)
{
if(a < b)
{
if(b < c)
{
return b;
}
else if(a < c)
{
return c;
}
else
{
return a;
}
}
else if(a < c)
{
return a;
}
else if(b < c)
{
return c;
}
else
{
return b;
}
}
template <class RandomAccessIterator, class T>
RandomAccessIterator __unguarded_partition(RandomAccessIterator first, RandomAccessIterator last, T pivot)
{
while(true)
{
while(*first < pivot)
{
++first;
} --last;
while(pivot < *last)
{
--last;
} if(!(first < last))
{
return first;
} iter_swap(first, last);
++first;
}
}
  • 堆排序算法源码

    • 见序列式容器中的堆章节

  • STL中的排序算法源码

template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last)
{
if(first != last)
{
// 快速排序和堆排序
__introsort_loop(first, last, value_type(first), __lg(last - first) * );
// 插入排序
__final_insertion_sort(first, last)
}
} // 找出2^k < n的最大k值
templat <class Size>
inline Size __lg(Size n)
{
Size k;
for(k = ; n > ; n >> )
{
++k;
}
return k;
} template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first, RandomAccessIterator last, T*, Size depth_limit)
{
while(last - first > )
{
if(depth_limit == )
{
partial_sort(first, last, last); // 堆排序
return;
} --depth_limit;
// 取中值
RandomAccessIterator cut = __unguarded_partition(first, last,
T(_median(
*first,
*(first + (last - first) / ),
*(last - )
)));
// 右半段递归sort
__introsort_loop(cut, last, value_type(first), depth_limit); // 左半段在while中递归sort
last = cut;
}
} template <class RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first, RandomAccessIterator last)
{
if(last - first > )
{
// 以下写法感觉有点冗余。先排序前16个数据,然后将后需要数据依次插入排序
__insertion_sort(first, first + );
__unguarded_insertion_sort(first + , last);
}
else
{
// 小于16,直接插入排序
__insert_sort(first, last);
}
} template <class RandomAccessIterator>
inline void __unguarded_insertion_sort(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(i, T(*i));
}
}

STL源码剖析:算法的更多相关文章

  1. STL源码剖析——算法#1 内存处理基本工具

    我们在学习序列式容器时,我们经常会遇到这三个函数:uninitialized_copy.uninitialized_fill.uninitialized_fill_n.在那时我们只是仅仅知道这些函数的 ...

  2. STL源码剖析(算法)

    STL中算法是基于迭代器来实现的. 有了容器中迭代器的实现(对operator*.operator++等的重载),STL中大部分算法实现就显得很简单了. 先看一例关于find算法的实现: templa ...

  3. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  4. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  5. (原创滴~)STL源码剖析读书总结1——GP和内存管理

    读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...

  6. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  7. STL"源码"剖析

    STL"源码"剖析-重点知识总结   STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...

  8. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  9. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...

  10. 《STL源码剖析》学习之traits编程

    侯捷老师在<STL源码剖析>中说到:了解traits编程技术,就像获得“芝麻开门”的口诀一样,从此得以一窥STL源码的奥秘.如此一说,其重要性就不言而喻了.      之前已经介绍过迭代器 ...

随机推荐

  1. 入门大数据---Sqoop简介与安装

    一.Sqoop 简介 Sqoop 是一个常用的数据迁移工具,主要用于在不同存储系统之间实现数据的导入与导出: 导入数据:从 MySQL,Oracle 等关系型数据库中导入数据到 HDFS.Hive.H ...

  2. NOIp ( on line ) 提高组 2020 总结

    T1 : 序列 题意: 一共有T组数据,每组数据有两个长度为n的序列a,b,m个操作,问a序列是否可以转换成b,是输出YES,否的话输出NO. m个操作分别为ti,xi,yi,若t为1,则x和y上的数 ...

  3. JVM源码分析之synchronized实现

    “365篇原创计划”第十二篇.   今天呢!灯塔君跟大家讲:   JVM源码分析之synchronized实现     java内部锁synchronized的出现,为多线程的并发执行提供了一个稳定的 ...

  4. vue安装及创建项目的几种方式

    原文地址:https://www.wjcms.net/archives/vue安装及创建项目的几种方式 VUE安装的方式 直接用 script标签 引入 对于制作原型或学习,你可以这样使用最新版本: ...

  5. 让网页变灰的实现_网站蒙灰CSS样式总汇

    每次全国哀悼日,各大网站首页都变成了灰色,添加以下全局CSS样式,可以实现此效果: 方法一 html { -webkit-filter: grayscale(100%);filter:progid:D ...

  6. 从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)

    在浏览器地址栏输入URL 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤 如果资源未缓存,发起新请求 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证. 检验 ...

  7. zabbix fping 监控网络质量

    1,zabbix server (proxy)安装fping wget http://www.fping.org/dist/fping-3.16.tar.gz tar zxvf fping-3.16. ...

  8. P3261 [JLOI2015]城池攻占 题解

    题目 小铭铭最近获得了一副新的桌游,游戏中需要用 \(m\) 个骑士攻占 \(n\) 个城池.这 \(n\) 个城池用 \(1\) 到 \(n\) 的整数表示.除 \(1\) 号城池外,城池 \(i\ ...

  9. SQLserver , MySQL的区别和各自的一些简单方法案列

    SQL Server数据库和MySQL数据库有什么区别呢?今天我们来分析一下这两种数据库的不同之处以及这两种数据库的一些简单用途:SQL Server数据库和MySQL数据库有什么区别: 对于程序开发 ...

  10. day13 作业

    目录 1.编写文件修改功能,调用函数时,传入三个参数(修改的文件路径,要修改的内容,修改后的内容)既可完成文件的修改 2.编写tail工具 3.编写登录功能 4.编写注册功能 选做题:编写ATM程序实 ...