java实现折半插入排序算法

前言

折半插入排序算法是一种排序的算法,它通过“折半查找”在比较区查找插入点的位置,这样可以减少比较的次数,移动的次数不变,时间复杂度仍为
O(n^2);

算法描述

  1. 将第一个元素当做一个查找区的元素,刚开始这个查找区仅含ary[0](第一个元素)
  2. 取出下一个元素(这里循环获取,从第二个元素开始),和查找区的中间元素(半查法)比较。注:查找区里面的元素都排好序了
  3. 如果新的元素小于中间元素,将查找区的右边界(right变量表示)向左移动一位,如果大于等于中间元素,将左边界(left变量表示)左移一位
  4. 重复步骤3,直到左边界大于右边界
  5. 判断左边界是否在查找区里面,如果是就从找到的索引位置开始,到该比较元素索引位置结束,向后移动一位。如果在右边界外面,则忽略这一步
  6. 将找到的位置元素用比较的元素(第二步取出的数据)覆盖
  7. 重复第二步

提示:上面从第二步开始到第7步结束,每一次循环比较区里面的右边界都在递增,直到递增结束

算法描述图

这里写图片描述

以上是在开始写这篇文章的基础知识,如果还是看不懂没关系,我找到一个讲解比较好的链接,请看下面的参考资料


为什么写这篇文章

这篇文章与其说是来记录折半排序算法,还不如说是一次总结,从后面我贴出的代码可以看出我特意在封装类中应用了泛型、内部类、以及提供2个Comparable与Comparator的实现类调用的重载的排序方法,算是对自己前面阶段巩固java基础一次检验,我也希望能对看到这篇文章的人有所帮助,由于自身水平的关系,如有错误的地方,希望能指出。


正文

在前言中我描述了折半排序算法的步骤以及原理,我下面从一个实现该算法的代码入手来分析一下

public void  binarySort(T[] obj , Comparator<T> comparator ) {
            //定义折半插入算法所需的一些变量     
            int left, right, mid;
           T curValue = null;
            for( int start = 1; start < obj. length; start++) {
                 curValue = obj[ start];
                 left = 0;
                 right = start - 1;
                 //下面代码在比较区使用半查法找出可以插入的位置
                 while( left <= right) {
                      //使用位运算找出比较区中间位置
                      mid = ( left + right) >> 1;
                      if( comparator.compare( curValue, obj[ mid]) < 0) {
                            //当curValue小于obj[mid],右边界左移
                            right -= 1;
                     } else {   
                            //这里需要注意一下,如果两个值相等也让左边界向左移动一位
                            left += 1;
                     }
                }
                 //结束循环以后left = right + 1; 且 left <= start
                 //left就是需要插入元素的位置,moveStep表示将left - start之间的元素后移一位
                 int moveStep = start - left;
                System. arraycopy(obj, left, obj, left+1, moveStep);
                 obj[ left] = curValue;
           }
     }

从上面我们可以看到代码有两个循环,第一个for循环是对应2-7步骤,第二个while循环对应2-4步骤,我们需要注意一下,start是从数组第二个元素开始的,第一个元素我设置成查找区间元素,右边界right和这个start有关,这样才能让查找区间不断的扩展。等while循环结束以后,表示我已经找到插入的位置了,接下去通过arraycopy函数,将符合条件的数组向右移动以后,然后用待比较数据去覆盖找到的索引上的值
我觉得有必要提醒一下就是半查法是针对已经排好序的数组,所以查找区间按照设定,不断扩张的以后,里面的数据也是排序好的

测试代码

package org.study.arithmetic;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;


public class BinarySortAc<T> {

     /**
      * 折半插入算法排序
      * @param 外面传递一个需要排序的数组引用
      */
     public void binarySort(T[] obj, Comparator<T> comparator) {
            //定义折半插入算法所需的一些变量     
            int left, right, mid;
           T curValue = null;
            for( int start = 1; start < obj. length; start++) {
                 curValue = obj[ start];
                 left = 0;
                 right = start - 1;
                 //下面代码在比较区使用半查法找出可以插入的位置
                 while( left <= right) {
                      //使用位运算找出比较区中间位置
                      mid = ( left + right) >> 1;
                      if( comparator.compare( curValue, obj[ mid]) < 0) {
                            //当curValue小于ojb[mid],右边界左移
                            right -= 1;
                     } else {   
                            //这里需要注意一下,如果两个值相等也让左边界向左移动一位
                            left += 1;
                     }
                }
                 //结束循环以后left = right + 1; 且 left <= start
                 //left就是需要插入元素的位置,moveStep表示将left - start之间的元素后移一位
                 int moveStep = start - left;
                System. arraycopy(obj, left, obj, left+1, moveStep);
                 obj[ left] = curValue;
           }
     }

     @SuppressWarnings({ "unchecked", "rawtypes" })
     /**
      * 排序重载的方法,这里我无法在使用泛型了,因为泛型由于无法调用compareTo方法
      * @param obj 需要比较的数据集合
      */
     public void binarySort(Object[] obj) {
            //定义折半插入算法所需的一些变量     
            int left, right, mid;
           Comparable curValue = null;
            for( int start = 1; start < obj. length; start++) {
                 curValue = (Comparable) obj[ start];
                 left = 0;
                 right = start - 1;
                 while( left <= right) {
                      mid = ( left + right) >> 1;
                      if( curValue.compareTo( obj[ mid]) < 0) {
                            right -= 1;
                     } else {
                            left += 1;
                     }
                }
                 //结束循环以后left = right + 1; 且 left <= start
                 //left就是需要插入元素的位置,moveStep表示将left - start之间的元素后移一位
                 int moveStep = start - left;
                System. arraycopy(obj, left, obj, left+1, moveStep);
                 obj[ left] = curValue;
           }
     }

     @SuppressWarnings("unchecked")
     /**
      * @return 返回一个具体的集合
      */
     public User<String>[] getList() {
           User<String>[] users = new User[10];
            for( int index = 0; index < 10; index++) {
                User<String> user = new User<String>();
                 user.setName( "Abigail"+ index);
                 user.setAge( new Random().nextInt(100));
                 users[ index] =  user;
           }
            return users;
     }

     /**
      *
      *
      * @param <T> User使用外围类的泛型参数
      */
     private static class User<V> {
            private V name;
            private int age;

            public V getName() {
                 return name;
           }
            public void setName(V name) {
                 this. name = name;
           }
            public int getAge() {
                 return age;
           }
            public void setAge( int age) {
                 this. age = age;
           }
            public String toString() {
                StringBuilder sbu = new StringBuilder();
                 return sbu.append( "[name:")
                        .append( name)
                        .append( ",age:")
                        .append( age)
                        .append( "]").toString();
           }
     }

     /**
      * @return 返回一个具体的比较器
      */
     public Comparator<User<String>> getComparator() {
            return new MyComparator();
     }
     /**
      * 内部类实现一个User的比较器
      * @param args
      */
     private class MyComparator implements Comparator<User<String>>{

            @Override
            /**
            * 用年龄来比较两个对象的大小
            */
            public int compare(User<String> o1, User<String> o2) {
                 return o1.getAge() - o2.getAge();
           }
     }


     public static void main(String[] args) {

           BinarySortAc<Integer> ite  = new BinarySortAc<Integer>();
           Integer[] ites = new Integer[] {5,2,10,6,4,3,1,5,10};
           System. out.format( "排序前%s\n", Arrays.toString(ites));
            ite.binarySort( ites);
           System. out.format( "排序后%s\n", Arrays.toString(ites));

           BinarySortAc<User<String>> ite1  = new BinarySortAc<User<String>>();
           User<String>[] users = ite1.getList();
           System. out.format( "排序前%s\n", Arrays.toString(users));
            ite1.binarySort( users, ite.getComparator());
           System. out.format( "排序后%s\n", Arrays.toString(users));

     }
}

参考资料

折半插入排序算法描述(左小右大)
http://wenku.baidu.com/link?url=16JgfPzd4KYlB8rMYULIINnnWSvTcAy916vgxlQpCE47H3D8x96k2wJx0CNaJ8urQyAQ70pKnHYVHeAxoeyK34tsKaasUgKkf5zSVgIZUJe

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值