插入排序

插入排序的基本思想是将待排序的元素依次插入序列合适的位置,然后将这个位置后面的元素依次向后移动一位
位置1 2 3 4 5 6
序列5 4 2 1 8 3
设第1位为最初始的基础元素,也就是5,待排元素就是4,此时逻辑顺序是5|4 2 1 8 3(用“|”来表示排序到哪个位置了)
那么第一趟排序下来后,
序列变成:45|2183。
待排元素就是2,第2趟后,245|183
待排元素就是1,第3趟后,1245|83
待排元素就是8,第4趟后,12458|3
待排元素就是3,第5趟后,123458|
这样就排序成功了。

上面就是插入排序,数学逻辑上非常清晰,序列可以分为两个区,有序区和混乱区。第一步,我们要做的就是每次从混乱区取出一个混乱元素插入到有序区的序列排布中,那么如何插入呢?就要看第二步的内容了。

第一步如何取出元素呢?显然是要将每个元素(除去预置的那个)都取出一遍,那么用个for循环遍历整个序列就行。

伪代码

        for(int i = 1;i < arr.length;i++){
            temp = arr[i];

        }

第二步,执行插入步骤,这一步需要做两个事情,1寻找合适的位置,2插入后将其他元素往后移动一位

(1)如何寻找合适的位置呢?

有序区的元素默认都是从小到大排列的,都是有顺序的,那么就好办了,只要找到合适的位置就行,然后移动后面元素的位置就行。

例如
序列 12458|3
3先和1比较,不合适;
3再和2比较,不合适;
3再和4比较,合适,找到位置了。
3再和2比较,2小,不符合要求,不挪动;
3再和1比较,1小,不符合要求,不挪动;

实现这个逻辑最简单就是用一个for循环,设置一个条件和边界,去遍历一遍。

(2)接下来处理一个问题就是讲元素往后挪动一位。

既然我们已经找到这个边界了,那么只需要把这个边界后面的元素依次往后挪动一位就可以了。

这里就又是一个for循环,边界是“合适位置+1”到“当前待排元素的位置”。

所以这个排序就是一个for循环里面嵌入两个for循环

下面是伪代码

for(){//处理所有元素的遍历
    temp = 待处理的元素
    for(){//这个循环用来寻找合适的位置
    }
    for(){//这个循环用来将那些元素依次向后挪动
    }
}

这样确实可以实现,算法时间复杂度可以算做O(n^2),但是用两个for循环在里面,写起来有些冗长有没有更好的解决办法呢?将编写的复杂度下降一些呢?


解决办法就是在寻找合适位置这一步时,从后往前遍历,每对比到一个不合适的元素,就把这个元素往后挪动一位。

例如
序列 12458|3
temp = 3;
3先和8比较,不合适,挪动后1245 8;
3再和2比较,不合适,挪动后124 58;
3再和4比较,合适,找到位置了,挪动后123458;
3再和2比较,2小,不符合要求,不挪动;
3再和1比较,1小,不符合要求,不挪动;

这样边比较边挪动的做法,可以将寻找位置和挪动元素的操作结合起来,放到一个遍历循环中。

下面就不赘述了,放源码。

package com.chapter.five;
/**
 * 需求 直接插入排序法
 * 思路 1将一个数组,分成两个区,一个是有序区,一个是无序区
 * 2每次取出无序区的一个元素,到有序区排序
 * 3排序的原则是待排元素依次与有序区元素进行比较,插入到合适地方
 * 4插入时,待排元素放在该位置,后面的元素依次向后移一位
 * 排成从小到大
 * @author huxingyue
 *
 */

class InsertSort {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        InsertSort insert = new InsertSort();
        int[] arr = new int[]{10,1,9,2,8,3,7,4,6,5};
        System.out.print("数组排序前是:");
        for(int i:arr){
            System.out.print(i+" ");
        }

//      insert.funLowToHigh(arr);
        insert.funHighToLow(arr);

        System.out.print("数组排序后是:");
        for(int i:arr){
            System.out.print(i+" ");
        }

    }
    void funLowToHigh(int[] arr){   //这个插入排序是从小到大的
        int temp;   //用于存放临时元素
        for(int i = 1;i < arr.length;i++){
            temp = arr[i];//设temp为取出的待排混乱元素
            int j =0;
            for(j = i-1 ; j >= 0 && temp < arr[j];j--){
                arr[j+1] = arr[j];  //如果临时值与对比元素相比,临时值小,那对比元素就往后移动一位
            }
            arr[j+1] = temp;    // 这一步j已经自减1了

        }
    }

    void funHighToLow(int[] arr){   //这个插入排序是从大到小的
        int temp;
        for(int i = 1;i < arr.length;i++){
            temp = arr[i];
            int j = 0;
            for(j = i-1;j >= 0 && temp > arr[j];j--){
                arr[j+1] = arr[j];  //如果临时值与对比元素相比,临时值大,那对比元素就往后移动一位
            }
            arr[j+1] = temp;    // 这一步j已经自减1了
        }

    }

}

写在最后,讲一讲个人对插入排序的理解。

本质上来讲,插入排序和冒泡排序都属于一类排序,即比较相邻两个数,然后操作相邻数的一个过程。

如果一个序列中有两个数,a1和a2,且a1>a2,则命名为一个比较对,插入排序的算法和比较对的数量有关系,因为仅仅存在一个比较对的时候,才会进行操作,数据向后移动,也就是说,忽略验证内层循环条件的时间,那么确定了比较对的数量,插入排序的时间复杂度变成了一个一元线性的函数,设序列中有9个比较对,序列长度为n,那么总时间就是9n,而不是我们通常意味的n*n。

关于上面的描述很潦草,具体权威的描述可以参考《数据结构与算法java版》作者Mark Allen Weiss中,关于插入排序的解读,醍醐灌顶值得一看。

如果想改善这种算法的性能几乎不大可能,因为他总是比较相邻的元素,如果想提高性能,就要比较相隔远一点的元素,然后再操作,可以参考希尔排序。或者使用全新的排序方法,例如快速排序。

Java温故而知新-插入排序的更多相关文章

  1. Java温故而知新-杨辉三角形

    Java温故而知新-杨辉三角形 一. 先说需求 需求 打印输出杨辉三角形,行数可变,支持50行内的任意数. 预期结果如图所示 1 这是第几行呢,是第1 1 1 这是第几行呢,是第2 1 2 1 这是第 ...

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

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

  3. JAVA排序--[插入排序]

    package com.array; public class Sort_Insert { /* * 项目名称:插入排序 ; * 项目要求:用JAVA对数组进行排序,并运用插入排序算法; * 作者:S ...

  4. Java直接插入排序

    插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入. 算法步骤: 1)将第一待排序序列第一个元素看做一个有序序列,把第二 ...

  5. 【Java SE】如何用Java实现插入排序

    摘要:前面三期分别写了三篇简单排序的算法,今天来讲一点稍微难一点的排序算法-----插入排序. 基本思想: 设n个数据已经按照顺序排列好(假定从小排到大). 输入一个数据x,将其放在恰当的位置,使其顺 ...

  6. JAVA数据结构--插入排序

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

  7. Java实现插入排序

    package Sort; import java.util.Arrays; public class InsertionSort { public static int[] sort(int[] l ...

  8. java 用插入排序思想,对不规则数组排序。

    知道插入排序后,无意中发现,用插入排序思想,对不规则数组排序的排序 发现和许多大神写的不一样,大神写的简洁多了.--------

  9. Java算法-插入排序

    插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经排好序,本趟需要找到 i 对应的元素 x 的正确位置 k ,并且在寻找这个位置 k 的过程中逐个将比较过的 ...

随机推荐

  1. 关于使用JQuery追加Option标签时使用三元运算符添加选中属性的解决办法

    $(data.resultList).each(function () {                        var selectedFlag = ${sessionScope.userI ...

  2. 【SqlServer系列】集合运算

    1   概述 已发布[SqlServer系列]文章如下: [SqlServer系列]SQLSERVER安装教程 [SqlServer系列]数据库三大范式 [SqlServer系列]表单查询 [SqlS ...

  3. Storm源码阅读之SpoutOutputCollector

    不得不说storm是一个特别棒的实时计算框架.为了对后文理解的方便,先说几个storm中的术语: Topology:拓扑图或者拓扑结构.在storm中它通过消息分组的分式连接Spout和Bolt节点定 ...

  4. 初学 Python(十一)——切片

    初学 Python(十一)--切片 初学 Python,主要整理一些学习到的知识点,这次是切片. #-*- coding:utf-8 -*- ''''' 切片 ''' L = ['name','age ...

  5. java考试易错题大全

    常见的Java问题 1.什么是Java虚拟机?为什么Java被称作是"平台无关的编程语言"? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Ja ...

  6. 【分享】01. Eclipse for PHP + phpStudy 搭建php开发环境

    配置php编译器 配置phpStudy服务器项目发布目录 修改hosts文件127.0.0.1      www.350zx.cn 新建项目 启动的你的phpStudy  

  7. RSA简介(一)——数论原理

    RSA是最常用的非对称加密算法. 所谓非对称加密,就是说有两个密钥,一个密钥加密只可以用另外一个密钥解密,一般一个作为公钥,公开给所有人用来加密用,而另一个用来解密其他拥有公钥的加密结果,叫做私钥.另 ...

  8. HttpRequest 类

    关于此类的介绍:查看HttpRequest类 点击查看:HttpRequest中方法的封装 跟这个类对应的HttpResponse类 定义:使 ASP.NET 能够读取客户端在 Web 请求期间发送的 ...

  9. 用java调用.net的wcf其实还是很简单的

      前些天和我们的一个邮件服务商对接,双方需要进行一些通讯,对方是java团队,而作为.net团队的我们,只能公布出去的是一个wcf的basicbinding,想不 到问题来了,对方不知道怎么去调用这 ...

  10. Java restful web service 开发入门

    可用的框架有不少,我用的是jersey. 直接上代码,其实,如果你会web service 这个restful的就很好理解了,自己跑一遍就OK了 用到的类 User.java package demo ...