Java内部排序之插入排序与交换排序详解

 更新时间:2023年12月08日 08:44:30   作者:菜鸟-小胖  
这篇文章主要介绍了Java内部排序之插入排序与交换排序详解,排序是将任意序列重新排列按照关键字有序,排序根基存储器的不同分为内部排序、外部排序,排序根据关键字分为稳定排序、不稳定排序,需要的朋友可以参考下

内部排序

排序:将任意序列重新排列按照关键字有序;

排序根基存储器的不同分为:内部排序、外部排序;(这里指的都是内部排序)

排序根据关键字分为:稳定排序、不稳定排序

排序根据不同的原则分为:插入排序、交换排序、选择排序、归并排序、基数排序;

排序根据时间复杂度分为:简单排序(O(N2))、先进排序(O(nlogn))、基数排序(O(d*n))

排序的操作:比较、移动 被称为基于比较的排序;

假设这里使用的存储结构均为:顺序存储结构;

内部排序:

1、插入排序:直接插入排序、折半插入、2-路插入排序、希尔排序

2、交换排序:冒泡排序、快速排序

3、选择排序:简单选择排序、堆排序

4、归并排序

5、基数排序

插入排序

1直接插入排序

由n-1趟排序组成; 对于P=1趟到P=N-1趟,插入排序保证从位置0到位置P上的元素为已排序状态;

第P趟,我们将位置P上的元素向左移动到它在前P+1个元素中正确位置上。(这里需要使用一个哨兵元素)

直接插入程序示例:

public class InserSort {
    public static void insertSort(int a[]){
      int temp;//哨兵
      int i;//执行趟数
      int j;
      for (i = 1; i < a.length; i++) {//执行N-1趟
          temp=a[i];
        for ( j = i-1; (j >=0)&&(a[j]>temp); j--) {
            a[j+1]=a[j];
        }
        a[j+1]=temp;
    }
    }
    public static void main(String[] args) {
        int a[]={9,6,3,2,7,5};
        InserSort.insertSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]);
        }
    }
}

算法分析:

排序的操作:比较、移动

1、空间复杂度: 只需要一个记录的辅助空间;

2、时间复杂度:O(N2) 如果已有序时间复杂度为:O(N)

3、适应场景:数据量不是很大 、基本有序

2 折半插入排序

将查找工作交与“折半查找”来实现。定位后,后续移动元素。

public class BInsertSort {
/**
* 折半插入排序
* @param a
*/
    public static void BinsertSort(int a[]){
        int temp;//哨兵
        for (int i = 1; i < a.length; i++) {
            temp=a[i];
            int low=0;
            int hight=i-1;
            //查询
            while (low<=hight) {
                int mad=(low+hight)/2;
                if (a[mad]>a[i]) {
                    hight=mad-1;
                }
                if (a[mad]<a[i]) {
                    low=mad+1;
                }
            }   
            //移动
            for (int k = i-1; k >=hight+1; k--) {
                a[k+1]=a[k];
            }
            a[hight+1]=temp;
        }
    }
    public static void main(String[] args) {
        int a[]={9,6,3,2,7,5};
        BInsertSort.BinsertSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]);
        }
    }
}

折半插入排序减少关键字的比较次数,但是记录的移动次数没有改变。

时间复杂度:O(N2)

3 希尔排序(缩小增量排序)

基本思想:先将整个待排序记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,在对整个记录进行一次直接插入排序。

希尔排序使用一个序列,叫做增量序列。

序列最终值为1 PS:增量序列中的值没有除1之外的公因子,并且最后一个增量必须等于1;

算法示例: 增量序列最流行的选择是使用shell建议的序列N/2

public class ShellSort {
    /**
     * 希尔排序
     * @param a
     */
    public static void shellSort(int a[]){
        int i,j;
        int inc;//增量
        int temp;//哨兵
        for ( inc = a.length/2; inc >0; inc/=2) {//设置增量队列
            //一趟希尔排序
            for ( i = inc; i < a.length; i++) {
                temp=a[i];
                for ( j = i; j >= inc; j-=inc) {
                    if (temp<a[j-inc]) {
                        a[j]=a[j-inc];
                    }else {
                        break;
                    }
                }
                a[j]=temp;
            }
        }
    }
    public static void main(String[] args) {
        int a[]={9,6,3,2,7,5};
        shellSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]);
        }
    }
}

算法分析: 希尔排序的运算时间依赖于增量序列的选择,最坏情况O(N2)

使用场景: 适度地大量的输入数据

交换排序

交换排序:冒泡排序、快速排序

1 冒泡排序

思路: 一趟排序:将第一个记录的关键字与第二个关键字进行比较,若为逆序记录交换,然后比较第二个与第三个,以此类推,直到地N-1个记录与N个记录比较位置。

其结果使得最大的记录安置在最后一个记录位置; 第二趟对n-1个记录进行冒泡排序。

判断冒泡排序结束的条件:在一趟排序中没有进行过交换记录的操作。 算法演示:

public class BubbleSort {
    /**
     * 冒泡排序
     * @param a
     */
    public static void bubbleSort(int a[]){
         int temp=0;
         int log=0;//1表示有交换 0表示没有交换  作为结束标识
        for (int i = a.length-1; i >1; i--) {
            for (int j = 0; j < i; j++) {
                if (a[j+1]<a[j]) {
                    temp=a[j+1];
                    a[j+1]=a[j];
                    a[j]=temp;
                    log=1;
                }
            }
            if (log==0) {
                break;
            }
        }
    }
    public static void main(String[] args) {
        int a[]={2,3,5,6,7,9};
        BubbleSort.bubbleSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]);
        }
    }
}

算法分析: 时间复杂度:O(N2)

2快速排序

快速排序(Quick Sort)的基本思想:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

首先选择一个记录(可选择第一个记录,不是最佳的做法)作为支点(pivot),然后按下述原则重新排列其余记录:将所有关键字较它小的记录都安置在它的位置之前,将所有关键字较它大的记录都安置在它位置之后。

由此可以该支点记录最后所落的位置i作为分界线,这就是一趟快速排序。 具体做法:附设两个指针low和high,它们的初值分别指向序列的前端与后端,设支点的记录关键字为pivotkey,则首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和支点记录交换,然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和支点记录相互交换,重复这两步直到low=high为止。

算法示例:

public class QuickSort {
    /**
     * 一趟快排序
     */
    public static int partition(int a[],int low ,int high) {
        int temp = a[low];// 支点
        while (low < high) {
            while ((low < high)&&(a[high] >= temp) ) {
                high--;
            }
            a[low]=a[high];
            while ((low < high)&&(a[low] <= temp)) {
                low++;
            }
            a[high]=a[low];
        }
        a[low]=temp;
        return low;
    }
    /**
     * 递归排序
     * @param a
     * @param low
     * @param high
     */
    public static void QSort(int a[],int low,int high){
        //对子序列进行排序
        if (low<high) {
            int pivot=partition(a, low , high);
            QSort(a,low, pivot-1);
            QSort(a,pivot+1,high);
        }
    }
    /**
     * 快速排序
     * @param a
     */
    public static void QuickSort(int a[]){
            QSort(a, 0, a.length-1);
    }
    //测试
    public static void main(String[] args) {
        int a[]={7,6,3,8,4,9,7};
        QuickSort.QuickSort(a);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]);
        }
    }
}

算法分析:

1、时间复杂度: 快速排序的平均时间为:O(nlogn) 就平均时间而言,快排序是目前被认为最好的一种内部排序方法; 较坏的情况:当关键字基本有序或者有序时,快速排序将托变为冒泡排序,时间复杂度:O(n2); 支点的选取可以优化该算法,一般认为“三者取中”的做法最合适:即a[i],a[j],a[(i+j)/2],取三者的中值。这样可以改善最坏情况下的性能。

2、空间复杂度: 平均空间复杂度为:O(log2N) 因为快速排序需要一个栈空间来实现递归。 一般如果一趟排序记录均匀分布在支点两侧,栈的深度为log2N+1 最坏情况,一趟排序后,都跑到一端空间,深度为N 降低空间复杂度的方法: 在一趟排序之后比较分割所得两部分的长度,且先对长度短的子序列中的记录进行快速排序,则栈的最大深度可降为O(logn).

到此这篇关于Java内部排序之插入排序与交换排序详解的文章就介绍到这了,更多相关Java插入排序与交换排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA Spring Boot 自动配置实现原理详解

    JAVA Spring Boot 自动配置实现原理详解

    这篇文章主要介绍了详解SpringBoot自动配置原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-09-09
  • java String校招面试题过程详解

    java String校招面试题过程详解

    这篇文章主要介绍了java String校招面试题过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • springboot中使用redis并且执行调试lua脚本

    springboot中使用redis并且执行调试lua脚本

    今天有个项目需要使用redis,并且有使用脚本的需求,本文主要介绍了springboot中使用redis并且执行调试lua脚本,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Java注解详解之@Override注解

    Java注解详解之@Override注解

    这篇文章主要给大家介绍了关于Java注解之@Override注解的相关资料,@Override是Java中的一个注解,表示一个方法是重写(Override)了父类中的方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Spring Boot项目维护全局json数据代码实例

    Spring Boot项目维护全局json数据代码实例

    这篇文章主要介绍了Spring Boot项目维护全局json数据代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Spring boot 启动流程及外部化配置方法

    Spring boot 启动流程及外部化配置方法

    平时我们开发Spring boot 项目的时候,一个SpringBootApplication注解加一个main方法就可以启动服务器运行起来,那它到底是怎么运行起来的呢?这篇文章主要介绍了Spring boot 启动流程及外部化配置,需要的朋友可以参考下
    2022-12-12
  • 浅谈Java多线程编程中Boolean常量的同步问题

    浅谈Java多线程编程中Boolean常量的同步问题

    这篇文章主要介绍了浅谈Java多线程编程中Boolean常量的同步问题,主要针对线程之间同步了不同的布尔对象的问题,需要的朋友可以参考下
    2015-10-10
  • Java的Spring AOP详细讲解

    Java的Spring AOP详细讲解

    章主要为大家详细介绍了Java的Spring AOP,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • 解决因jdk版本引起的TypeNotPresentExceptionProxy异常

    解决因jdk版本引起的TypeNotPresentExceptionProxy异常

    这篇文章介绍了解决因jdk版本引起的TypeNotPresentExceptionProxy异常的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • 你所不知道的Spring自动注入详解

    你所不知道的Spring自动注入详解

    这篇文章主要给大家介绍了关于你所不知道的Spring自动注入的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10

最新评论