注:关于排序算法,博主写过【数据结构排序算法系列】数据结构八大排序算法,基本上把所有的排序算法都详细的讲解过,而之所以单独将java集合中的排序算法拿出来讲解,是因为在阿里巴巴内推面试的时候面试官问过我,让我说说java集合框架中用的哪种排序算法,当时回答错了,(关于面试详细过程请参看:【阿里内推一面】记我人生的处女面)面试结束后看了一下java源码,用的是折半插入排序算法,本来早就打算写此博客,但是因为准备鹅厂的在线考试,而鹅厂在我心中的地位是最高的,为了准备鹅厂的在线考试,自己基本上把所有事情都搁置起来了,把全部的精力都投入到复习中去了,所以一直没动手写。既然java的天才程序员都采用了折半插入排序,那么“此人必有过人之处”,因此得好好了解一下折半插入排序。

我们先从c语言中的折半插入排序算法看起,在此基础之上在来看java集合框架中的源码。

#include<iostream>
using namespace std;
const int len=7;void binaryInsertSort(int * array,int len)
{for(int i=1;i<len;i++)//与普通的排序一样,外层for循环用来控制排序趟数{int x=array[i];int low=0,high=i-1;//low与high的初始化很重要,因为i从1开始,所以low=0,high=i-1,这样就能保证数组中的每一个//元素参与排序,教材上的low=1是错误的,因为教材上将数组中的第0位作为监视哨而未参与排序。while(low<=high)//寻找待插入的位置{int mid=(low+high)/2;if(x<array[mid])high=mid-1; elselow=mid+1;}for(int j=i-1;j>=low;j--)//将记录向后移动{array[j+1]=array[j];}array[low]=x;//插入记录}
}
int main()
{int a[len]={7,0,4,5,1,2,3};binaryInsertSort(a,len);for(int i=0;i<len;i++)cout<<a[i]<<' ';cout<<endl;
}

可以看到折半插入排序的思想是基于折半查找的,即对有序表进行折半查找,其性能较好,所以可将折半查找的思路运用到排序中一个数组中的元素虽然刚开始不是有序的,但是可以通过折半查找的同时构造有序表,即折半插入排序算法即是通过折半查找构造有序序列,然后在已构造的部分有序序列中运用折半查找插入元素,最终直至整个表排好序为止。

程序运行结果如下:

经过上述c语言代码的讲解,下面我们来看一下java的那些天才设计者们是如何java实现该算法的以及分析一个为何那些天才们看上的不是我们普通程序员最喜欢的快速排序而是折半插入排序。

下面是java中TimSort类中的sort源码,而java集合中的类调用的sort方法最终会调用它

 static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,T[] work, int workBase, int workLen) {assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;int nRemaining  = hi - lo;if (nRemaining < 2)return;  // Arrays of size 0 and 1 are always sorted// If array is small, do a "mini-TimSort" with no mergesif (nRemaining < MIN_MERGE) {int initRunLen = countRunAndMakeAscending(a, lo, hi, c);binarySort(a, lo, hi, lo + initRunLen, c);return;}

可以看到在TimSort类中最终会调用binarySort方法,即折半插入排序,我们来看一下其源码:

/*** Sorts the specified portion of the specified array using a binary* insertion sort.  This is the best method for sorting small numbers* of elements.  It requires O(n log n) compares, but O(n^2) data* movement (worst case).** If the initial part of the specified range is already sorted,* this method can take advantage of it: the method assumes that the* elements from index {@code lo}, inclusive, to {@code start},* exclusive are already sorted.** @param a the array in which a range is to be sorted* @param lo the index of the first element in the range to be sorted* @param hi the index after the last element in the range to be sorted* @param start the index of the first element in the range that is*        not already known to be sorted ({@code lo <= start <= hi})* @param c comparator to used for the sort*/@SuppressWarnings("fallthrough")private static <T> void binarySort(T[] a, int lo, int hi, int start,Comparator<? super T> c) {assert lo <= start && start <= hi;if (start == lo)start++;for ( ; start < hi; start++) {T pivot = a[start];// Set left (and right) to the index where a[start] (pivot) belongsint left = lo;int right = start;assert left <= right;/** Invariants:*   pivot >= all in [lo, left).*   pivot <  all in [right, start).*/while (left < right) {int mid = (left + right) >>> 1;if (c.compare(pivot, a[mid]) < 0)right = mid;elseleft = mid + 1;}assert left == right;/** The invariants still hold: pivot >= all in [lo, left) and* pivot < all in [left, start), so pivot belongs at left.  Note* that if there are elements equal to pivot, left points to the* first slot after them -- that's why this sort is stable.* Slide elements over to make room for pivot.*/int n = start - left;  // The number of elements to move// Switch is just an optimization for arraycopy in default caseswitch (n) {case 2:  a[left + 2] = a[left + 1];case 1:  a[left + 1] = a[left];break;default: System.arraycopy(a, left, a, left + 1, n);}a[left] = pivot;}}

可以看到其实其代码一点也不复杂,与我们上面分析的c语言代码几乎完全相同,只不过它所排序的元素不再是简单的int型,比较规则也不再是简单的比较数的大小,而是通过java中的Comparator接口来规定的,可以看到注释远远多于代码量,一方面这是因为那些天才们用其高超的艺术大大的简化了代码,另一方面也是为了解释关于选择折半插入排序的原因:

 /*** Sorts the specified portion of the specified array using a binary* insertion sort.  This is the best method for sorting small numbers* of elements.  It requires O(n log n) compares, but O(n^2) data* movement (worst case)./** The invariants still hold: pivot >= all in [lo, left) and* pivot < all in [left, start), so pivot belongs at left.  Note* that if there are elements equal to pivot, left points to the* first slot after them -- that's why this sort is stable.* Slide elements over to make room for pivot.*/

从我截取的这两段注释来看,可以知道:
1折半插入排序是最好的算法对于排序小数量的元素This is the best method for sorting small numbers of elements.

2它只需要O(nlogn)的比较次数,但是其移动次数仍然为 O(n^2)。It requires O(n log n) compares, but O(n^2) data movement (worst case).

3它是稳定的排序算法。that's why this sort is stable.而快速排序不是稳定的排序。

分析到这我们就可以知道为何会选择折半插入排序,其中1和3是最主要的原因。

【java集合框架源码剖析系列】java源码剖析之java集合中的折半插入排序算法相关推荐

  1. java—三大框架详解,其发展过程及掌握的Java技术慨括

    Struts.Hibernate和Spring是我们Java开发中的常用关键,他们分别针对不同的应用场景给出最合适的解决方案.但你是否知道,这些知名框架最初是怎样产生的? 我们知道,传统的Java W ...

  2. java日志框架(一)JUL 学习 ,这个是什么,他在代码中如何使用,一篇文章讲清楚

    这里写目录标题 JUL 是什么 JUL组件介绍 代码中如何使用(控制台输出) 日志级别 自定义输出级别 输出日志到文件(磁盘文件中) 日志对象父子关系 配置文件 使用方法总结 JUL 是什么 JUL全 ...

  3. java开源框架jpeege,隆重向你推荐这 8 个开源 Java 类库

    在青铜时代群里看到读者朋友们在讨论 Java 最常用的工具类,我觉得大家推荐的确实都挺常见的,我自己用的频率也蛮高的.恰好我在 programcreek 上看到过一篇类似的文章,就想着梳理一下分享给大 ...

  4. java正则表达式爬虫_Java简单爬虫系列(3)---正则表达式和Java正则API的使用

    上一篇内容写了如何请求资源,那么资源请求下载之后我们就要对它就行解析了,解析之前我们先熟悉一下正则表达式 正则表达式在平常使用时还是很广泛的,比如说表单输入验证,验证手机号邮箱之类,Java的字符串匹 ...

  5. 一种Java Spring框架里将配置文件里定义的值注入到Java变量的简单办法

    假设我在classpath下的application.properties里定义了一些配置: 我想让这些配置自动注入到我Java代码里某个变量中去.最简单的方式就是使用注解@PropertySourc ...

  6. Java日志框架-logback的介绍及配置使用方法(纯Java工程)

    说明:内容估计有些旧,2011年的,但是大体意思应该没多大变化,最新的配置可以参考官方文档. 一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logback当前分 ...

  7. mybatis源码阅读系列之源码下载

    一.百度输入mybatis 二.选择Git 项目 三.选择 mybatis 四.拉到页面最下面,选择最新 下载jar包 下载源码

  8. 自动驾驶 Apollo 源码分析系列,感知篇(九):感知融合中的数据关联细节

    前一篇文章讲了,Apollo 6.0 中融合的代码逻辑流程,但那是基于软件的角度进行梳理和分析的,这一篇文章基于上篇的成果进一步对算法进行更详细的分析,因为代码量奇大,所以本文重点讨论数据关联的一些细 ...

  9. java 折半插入排序_[Java代码] Java实现直接插入排序和折半插入排序算法示例

    1 排序思想: 将待排序的记录Ri插入到已经排好序的记录R1,R2,--,R(N-1)中. 对于一个随机序列而言,就是从第二个元素开始,依次将这个元素插入到它之前的元素中的相应位置.它之前的元素已经排 ...

最新文章

  1. mac 完全卸载android studio
  2. Hibernate初学者教程
  3. 高仿真机器人助力临床医学发展
  4. Linux 免费学习路线大全,你想要的都在这里啦(持续更新,欢迎收藏❤️关注点赞加评论)
  5. jquery广告轮播插件
  6. python导入datetime模块_Python时间模块datetime用法
  7. 二进制BIN文件比较工具,也适合用来对比解析BIN文件,发现数据存储规律,更改数据。
  8. 一米优店宝-淘宝店铺优化软件v1.0官方
  9. Android app客户端性能测试工具Emmagee 浅析
  10. ADAS/AD控制器模块开发13 - Feature开发之LDWLKA
  11. 计算机网络和internet选项,小编教你电脑ie的internet选项在哪
  12. java 操作日志 log
  13. 学习新手给Android新手的一些学习建议
  14. python采集微信公众号_Python爬虫,微信公众号文章采集工具
  15. 阿里云数据库再获学术顶会认可,一文全览VLDB最新亮点
  16. java线程池newfi_Java 线程池中的线程复用是如何实现的?
  17. apicloud studio 怎么开启自动wifi同步?
  18. char *const p ,char const *p,const char *p的区别
  19. 强大的多媒体播放器:射手影音播放器SPlayer for Mac
  20. 智能语音技术:从哪儿来?往何处去?

热门文章

  1. 爱壁纸hd电脑版|爱壁纸hd电脑版下载
  2. Springboot(编程不良人)
  3. OneDrive两台电脑之间文件同步操作
  4. 太空狼人杀(Among US)只能QuickChat 更改年龄限制达到可以Free To chat方法
  5. 2020年蓝桥杯模拟赛解题报告(Python真香)
  6. 不可注册为ActiveX控件
  7. 侯捷老师整理||IT专业术语中英对照表
  8. 分步傅里叶算法_分布快速傅里叶算法,split-step fast fourier transformed,音标,读音,翻译,英文例句,英语词典...
  9. 如何做红烧肉好吃又不腻 教你做红烧肉
  10. 【漫画】员工当腻了,不如做领导!