准备写个《STL 源代码剖析》的读书笔记,开个专栏。名为《STL 的实现》,将源代码整理一遍。非常喜欢侯捷先生写在封底的八个字:天下大事。必作于细。他在书中写到:“我开玩笑地对朋友说,这本书出版,给大学课程中的「数据结构」和「算法」两门授课老师出了个难题。差点儿全部可能的作业题目(复杂度证明题除外),本书都有了详尽的解答。

然而,假设学生可以从庞大的SGI STL源代码中干净抽出某一部份,加上自己的包装,做为呈堂作业,也足以证明你有资格获得学分和高分。其实。追踪一流作品并于当中吸取养份,远比自己关起门来写个三流作品,价值高得多—我的确觉得99.99%的程序猿所写的程序,在SGI
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,由于迭代器所指的对象未必然义了大于这个操作,标准中规定要排序。client必须保证小于号的定义(或是传入仿函数作为比較标准)。所以源代码中就仅仅用小于来推断。

【算法】插入排序 insertion_sort的更多相关文章

  1. 经典排序算法 – 插入排序Insertion sort

    经典排序算法 – 插入排序Insertion sort  插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕. 插入排序方法分直接插入排序和折半插入排序两种, ...

  2. 排序算法--插入排序(Insertion Sort)_C#程序实现

    排序算法--插入排序(Insertion Sort)_C#程序实现 排序(Sort)是计算机程序设计中的一种重要操作,也是日常生活中经常遇到的问题.例如,字典中的单词是以字母的顺序排列,否则,使用起来 ...

  3. 数据结构和算法(Golang实现)(21)排序算法-插入排序

    插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...

  4. 使用 js 实现十大排序算法: 插入排序

    使用 js 实现十大排序算法: 插入排序 插入排序 // 双重循环 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  5. Python排序算法——插入排序

    有趣的事,Python永远不会缺席! 如需转发,请注明出处:小婷儿的python https://www.cnblogs.com/xxtalhr/p/10787464.html 一.插入排序(Inse ...

  6. 疯狂的Java算法——插入排序,归并排序以及并行归并排序

    从古至今的难题 在IT届有一道百算不厌其烦的题,俗称排序.不管是你参加BAT等高端笔试,亦或是藏匿于街头小巷的草根笔试,都会经常见到这样一道百年难得一解的问题. 今天LZ有幸与各位分享一下算法届的草根 ...

  7. [算法] 插入排序 Insertion Sort

    插入排序(Insertion Sort)是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常采用in-pla ...

  8. 插入排序(insertion_sort)

    最简单的排序算法,又称插值排序,原理类似于打扑克牌时把摸到的牌插入手中已有序牌的过程. void insertion_sort(int* A ,int n){ int i,j,key; ;i < ...

  9. 排序算法 - 插入排序(Insertion sort)

    插入排序对于少量元素的排序是很高效的,而且这个排序的手法在每个人生活中也是有的哦. 你可能没有意识到,当你打牌的时候,就是用的插入排序. 概念 从桌上的牌堆摸牌,牌堆内是杂乱无序的,但是我们摸上牌的时 ...

随机推荐

  1. JavaScript总结(二) 系统分析

    学习Javascript的时候.遇到了一个问题. 看了牛腩的视频,感觉讲的太简单和基础,像认识一位新朋友.但仅有一面之缘就结束了. 再看姜浩的视频.又看得迷迷糊糊,让我找到了当初看两位台湾专家讲VB. ...

  2. Win32多线程编程(3) — 线程同步与通信

      一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...

  3. Python安装后在CMD命令行下出现“应用程序无法启动.............”问题

    问题存在之一:系统是刚刚重做的精简版服务器系统(阉割版) AN就是在阿里云上刚开的Windows Server 2008 系统上碰到的  吓尿了都 症状:            正常安装python环 ...

  4. jquery悬停tab2

    <style> *{ margin:0; padding:0;} body { font:12px/19px Arial, Helvetica, sans-serif; color:#66 ...

  5. Jquery:强大的选择器<一>

    今天回家之后,学习的是Jquery的选择器.选择器作为Jquery的优势之一,确实让我感觉到了它的强大.Jquery选择器分为基本选择器.层次选择器.过滤选择器和表单选择器,下面我一一介绍这四种选择器 ...

  6. Java数据库缓存思路

    为什么要用缓存?如果问这个问题说明你还是新手,数据库吞吐量毕竟有限,每秒读写5000次了不起了,如果不用缓存,假设一个页面有100个数据库操作,50个用户并发数据库就歇菜,这样最多能支撑的pv也就50 ...

  7. 修改UITextfield的Placeholder字体的颜色

    - (void)viewDidLoad { [super viewDidLoad]; self.title=@"修改UITextField的placeholder字体颜色"; UI ...

  8. iOS_SN_BlueTooth (二)iOS 连接外设的代码实现

    原文:http://www.cocoachina.com/ios/20150917/13456.html?utm_source=tuicool&utm_medium=referral 上一篇文 ...

  9. 快速搭建Android 开发环境-使用ADT Bundle

    一.搭建Android开发环境 近日要学Android开发基础,就着手搭建Windows下的Android开发环境. 找了一些相关的博文参考,基本上都是要分别下载和安装JDK, Eclipse, An ...

  10. js 框架及uI框架

    转载自:http://www.techweb.com.cn/network/system/2015-12-23/2245809.shtml 这篇文章主要描述现今流行的一些 Javascript web ...