《编程珠玑》代码之路16:直观感受为何程序员需要学习经典算法

作为一名老年ACM菜鸡,经常见到周围除了调库啥也不会的程序员,还经常一脸正经的说:“程序员就是把人家写好的东西拿出来调用一下,顶多改改嘛。”。emmmm,在这个猫猫狗狗都能养活自己的年代,这么想确实没问题 ---- 如果你确定自己不用面临被淘汰的风险,或者在别的领域能首屈一指。

大家应该都了解插入排序和快速排序。

快速排序在后期其实是由一块一块接近有序的小块组成的数组,递归下去计算小块的成本其实挺大,如果在某个条件下停下来,就会得到一个接近有序的数组。此时,如果用人鬼都觉得没用的插入排序对整个中间数组排序,整体的效率要比快排要高。因为插入排序虽然是平方级算法,但它在数组接近有序时,性能线性的。

能发现递归效率低下时停止递归过程,看见人鬼都看不上的插入排序,提升整个算法的效率,这也许就是艺术了吧。


生活不止眼前的苟且,还有诗和远方。

远方和诗,不是调库就能感受到的,就像很多人识字,却感受不到诗歌的美。

有人编程只用脑,懂得编程之美的人,还知道要用心。

旅行如此,编程如此,恋爱如此,生活亦如此。


好了言归正传:

插入排序就是每次拿到一个数,给它插到合适的位置,emmmm,没毛病。

先看一段插入排序的代码:

for (int i = 0; i < n; ++i){
    int t = array[i];
    for (int j = i; j > 0 && array[j - 1] > t; --j){
        array[j] = array[j - 1];
    }
    array[j] = t;
}

至于快速排序大家也许都比较熟悉,就每次找一个支点,把数组调整为支点左边的都小于支点的值,右边的都大于等于支点的值,然后用分治的思想,把比当前支点小的部分和比当前支点大的部分分而治之。

对于如何把一个数组分成大于支点和小于支点的两部分,其实有很多方法,其中一个是,从右半部分找一个小于支点值的,然后从左半部分找一个大于支点值的,交换他们,不断重复这个过程。

下面实现的算法,实际已经要比直接调用C函数库快3-4倍。

void qSort(int left, int right){
	if (left >= right){
		return;
	}

	int t = array[left], i = left, j = right + 1;
	while(1){
		do{
			i++;
		}while(i <= right && array[i] < t);

		do{
			j--;
		}while(array[j] > t);

		if (i > j) break;
		swap(array[i], array[j]);
	}

	qSort(left, j - 1);
	qSort(j + 1, right);
}

 然而,简单的把快速排序和插入排序结合,还能继续让整个排序快近30%!!!

可以想象快速排序的递归树,最下面的几层,其实都是在用很大的开销算几个数字。。。

那么在某个时间段,比如rihgt - left <= cutoff 时,停止快排过程,然后调用插入排序。

cutoff的值因机器不尽相同,可以用不同的值在自己的电脑上测试,50左右是个不错的选择。

在快排上加个返回条件,应该没啥难度吧。。

所以这个排序函数,变成了这个样子:

sort(){

    qsort();

    insertSort();

}

在调用qsort后,紧跟着调用insertSort。

这样一来,我们就得到了一个,比书上和C函数库都要快的排序算法。

并不是什么时候,都有库可调,更不是库永远都是最好的,不仅仅会用库,还要超越库,才是一个优秀的程序员该做的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一部分 编 程 技 术 第1章 性能监视工具 3 1.1 计算素数 3 1.2 使用性能监视工具 7 1.3 一个专用的性能监视工具 8 1.4 开发性能监视工具 10 1.5 原理 11 1.6 习题 11 1.7 深入阅读 12 第2章 关联数组 13 2.1 Awk中的关联数组 13 2.2 有穷状态机模拟器 16 2.3 拓扑排序 17 2.4 原理 20 2.5 习题 21 2.6 深入阅读 22 第3章 程序员的忏悔 23 3.1 二分搜索 24 3.2 选择算法 26 3.3 子程序库 28 3.4 原理 30 3.5 习题 31 第4章 自描述数据 33 4.1 名字—值对 33 4.2 记录来历 36 4.3 排序实验 37 4.4 原理 39 4.5 习题 39 第二部分 实 用 技 巧 第5章 劈开戈尔迪之结 43 5.1 小测验 43 5.2 解答 44 5.3 提示 44 5.4 原理 47 5.5 习题 48 5.6 深入阅读 49 5.7 调试(边栏) 49 第6章 计算机科箴言集 51 6.1 编码 52 6.2 用户界面 53 6.3 调试 53 6.4 性能 54 6.5 文档 56 6.6 软件管理 56 6.7 其他 58 6.8 原理 58 6.9 习题 58 6.10 深入阅读 60 第7章 粗略估算 61 7.1 头脑热身 61 7.2 性能的经验法则 62 7.3 Little定律 64 7.4 原理 65 7.5 习题 66 7.6 深入阅读 67 7.7 日常速算(边栏) 67 第8章 人员备忘录 69 8.1 备忘录 69 8.2 原理 71 8.3 深入阅读 71 第三部分 人性化I/O 第9章 小语言 75 9.1 Pic语言 76 9.2 视角 79 9.3 Pic预处理器 81 9.4 用来实现Pic的小语言 83 9.5 原理 87 9.6 习题 88 9.7 深入阅读 89 第10章 文档设计 91 10.1 表格 92 10.2 三条设计原则 94 10.3 插图 94 10.4 文本 96 10.5 合适的媒介 98 10.6 原理 100 10.7 习题 101 10.8 深入阅读 101 10.9 次要问题目录(边栏) 101 第11章 图形化输出 103 11.1 实例研究 103 11.2 显示结果取样 105 11.3 原理 107 11.4 习题 108 11.5 深入阅读 110 11.6 拿破仑远征莫斯科(边栏) 110 第12章 对调查的研究 113 12.1 有关民意调查的问题 113 12.2 语言 114 12.3 图片 117 12.4 原理 119 12.5 习题 120 第四部分 算 法 第13章 绝妙的取样 123 13.1 取样算法一瞥 123 13.2 Floyd算法 124 13.3 随机排列 125 13.4 原理 127 13.5 习题 127 13.6 深入阅读 128 第14章 编写数值计算程序 129 14.1 问题 129 14.2 牛顿迭代 130 14.3 良好的起点 132 14.4 代码 133 14.5 原理 135 14.6 习题 135 14.7 深入阅读 137 14.8 数值算法的力量(边栏) 137 第15章 选择 141 15.1 问题 141 15.2 程序 142 15.3 运行时间分析 145 15.4 原理 148 15.5 习题 149 15.6 深入阅读 151 附录A C和Awk语言 153 附录B 一个子程序库 157 部分习题答案 165 索引 181
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值