【算法】插入排序 insertion_sort
2014-04-22 17:20
405 查看
准备写个《STL 源码剖析》的读书笔记,开个专栏,名为《STL 的实现》,将源码整理一遍。很喜欢侯捷先生写在封底的八个字:天下大事,必作于细!他在书中写到:“我开玩笑地对朋友说,这本书出版,给大学课程中的「数据结构」和「算法」两门授课老师出了个难题。几乎所有可能的作业题目(复杂度证明题除外),本书都有了详尽的解答。然而,如果学生能够从庞大的SGI STL源码中干净抽出某一部份,加上自己的包装,做为呈堂作业,也足以证明你有资格获得学分和高分。事实上,追踪一流作品并于其中吸取养份,远比自己关起门来写个三流作品,价值高得多—我的确认为99.99%的程序员所写的程序,在SGI
STL面前都是三流水平。”有的人说只需把 STL 的那些接口弄清楚就行了,没有必要看它是如何实现的,我觉得你要是不看的话真的太可惜了,而侯先生则认为“从技术研究与本质提升的角度看,深究细节可以让你彻底掌握一切;不论是为了重温数据结构和算法,或是想要扮演轮子角色,或是想要进一步扩张别人的轮子,都可因此获得深厚扎实的基础。”
本专栏分为【容器】、【算法】、【迭代器】、【分配器】、【适配器】、【仿函数】等几个部分。第一篇讲解 STL 内置的一个算法:插入排序,它将用于 std::sort 中。普通的插入排序算法如下:
其中内循环的终止条件中有一关系表达式 p != first 用于判断是否越界,而在 STL 的实现中为了减小这一开销,在下面的 linear_insert 函数的开始就检测尾是否小于头,若不成立,就表明要插入的元素一定不会排在最前面,所以在后面的移动元素过程中就不用作越界检查了,它的作用类似于“哨兵”。STL 中插入排序的实现如下:
可以看到,实现中将这个算法多次抽象,这是因为有的函数譬如 unguarded_insertion_sort 将用于其他算法,便于代码重用。STL 的源码编写是很有讲究的,比如上面的 value < *first 这个表达式,可不能写成 *first > value,因为迭代器所指的对象未必定义了大于这个操作,标准中规定要排序,客户端必须保证小于号的定义(或是传入仿函数作为比较标准),所以源码中就只用小于来判断。
STL面前都是三流水平。”有的人说只需把 STL 的那些接口弄清楚就行了,没有必要看它是如何实现的,我觉得你要是不看的话真的太可惜了,而侯先生则认为“从技术研究与本质提升的角度看,深究细节可以让你彻底掌握一切;不论是为了重温数据结构和算法,或是想要扮演轮子角色,或是想要进一步扩张别人的轮子,都可因此获得深厚扎实的基础。”
本专栏分为【容器】、【算法】、【迭代器】、【分配器】、【适配器】、【仿函数】等几个部分。第一篇讲解 STL 内置的一个算法:插入排序,它将用于 std::sort 中。普通的插入排序算法如下:
typedef int Type; // 程序中用到的 Type 都是由 traits 得来,这里简化了 template <class RandomAccessIterator> void insertion_sort(RandomAccessIterator first, RandomAccessIterator last) { if (first == last) { return ; } RandomAccessIterator p; for (RandomAccessIterator ite = first + 1; ite != last; ++ite) { Type tmp = *ite; for (p = ite; p != first && tmp < *(p - 1); --p) { *p = *(p - 1); } *p = tmp; } }
其中内循环的终止条件中有一关系表达式 p != first 用于判断是否越界,而在 STL 的实现中为了减小这一开销,在下面的 linear_insert 函数的开始就检测尾是否小于头,若不成立,就表明要插入的元素一定不会排在最前面,所以在后面的移动元素过程中就不用作越界检查了,它的作用类似于“哨兵”。STL 中插入排序的实现如下:
/******************************************************************** created: 2014/04/21 22:03 filename: insertion_sort.cpp author: Justme0 (http://blog.csdn.net/justme0) purpose: insertion sort *********************************************************************/ #include <cstdio> #include <cstdlib> #include <cstring> typedef int Type; // 程序中用到的 Type 都是由 traits 得来,这里简化了 /* ** 将[first, last)拷到[result-(last-first), result),从后向前复制 ** 这里简化了 std::copy_backward */ template <class T> inline T * copy_backward(const T *first, const T *last, T *result) { const ptrdiff_t num = last - first; memmove(result - num, first, sizeof(T) * num); return result - num; } /* ** 将 value 插到 last 前面(不包括 last)的区间 ** 此函数保证不会越界(主调函数已判断),因此以 unguarded_ 开头 */ template <class RandomAccessIterator, class T> void unguarded_linear_insert(RandomAccessIterator last, T value) { RandomAccessIterator next = last; --next; for (; value < *next; --next) { *last = *next; last = next; } *last = value; } /* ** 将 last 处的元素插到[first, last)的有序区间 */ template <class RandomAccessIterator> void linear_insert(RandomAccessIterator first, RandomAccessIterator last) { Type value = *last; if (value < *first) { // 若尾比头小,就将整个区间一次性向后移动一个位置 copy_backward(first, last, last + 1); *first = value; } else { unguarded_linear_insert(last, value); } } template <class RandomAccessIterator> void insertion_sort(RandomAccessIterator first, RandomAccessIterator last) { if (first == last) { return ; } for (RandomAccessIterator ite = first + 1; ite != last; ++ite) { linear_insert(first, ite); } } int main(void) { Type arr[] = {3, 1, 5, 2, 0, 4}; int size = sizeof arr / sizeof *arr; insertion_sort(arr, arr + size); for (Type *ite = arr; ite != arr + size; ++ite) { printf("%d ", *ite); // 0 1 2 3 4 5 } system("PAUSE"); return 0; }
可以看到,实现中将这个算法多次抽象,这是因为有的函数譬如 unguarded_insertion_sort 将用于其他算法,便于代码重用。STL 的源码编写是很有讲究的,比如上面的 value < *first 这个表达式,可不能写成 *first > value,因为迭代器所指的对象未必定义了大于这个操作,标准中规定要排序,客户端必须保证小于号的定义(或是传入仿函数作为比较标准),所以源码中就只用小于来判断。
相关文章推荐
- 算法总结JS版(三)—— 插入排序(Insertion Sort)
- 【算法】插入排序 insertion_sort
- 【算法导论学习-001】插入排序(InsertionSort)
- 算法-插入排序(Insertion Sort)
- 静态链表插入排序(List Insertion Sort)算法
- 【DS】排序算法之插入排序(Insertion Sort)
- 插入排序(insertion sort)算法实现
- 算法:插入排序(Insertion Sort)
- [算法练习]Insertion Sort 插入排序
- 【算法】插入排序(Insertion Sort)
- 算法:冒泡排序(Bubble Sort)、插入排序(Insertion Sort)和选择排序(Selection Sort)总结
- 算法学习记录-排序——插入排序(Insertion Sort)
- 【LeetCode-面试算法经典-Java实现】【147-Insertion Sort List(链表插入排序)】
- 经典算法(8)- 插入排序(Insertion Sort) 及三个基本排序算法的比较
- 算法从排序开始——插入排序(Insertion Sort)C语言及Java实现
- Python 数据结构与算法——插入排序(insertion sort)
- 插入排序 Insertion sort
- 排序——插入排序(insertionsort)
- insertion sort 插入排序
- 算法与数据结构--插入排序(InsertSort)