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插入排序与交换排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合Lucene实现全文检索的详细步骤

    SpringBoot整合Lucene实现全文检索的详细步骤

    全文搜索(Full-Text Search)是指对大规模存储在计算机系统中的文本数据进行检索和匹配的技术,它允许用户输入关键字,然后从海量的文本数据中快速找到相关的信息,本文介绍了SpringBoot整合Lucene实现全文检索的详细步骤,需要的朋友可以参考下
    2024-03-03
  • springboot 事件监听器的案例详解

    springboot 事件监听器的案例详解

    这篇文章主要介绍了springboot 事件监听器,springboot(spring)的事件监听器使用主要有两种方式,通过实现ApplicationListener接口,另一个就是在类上添加 @EventListener 注解来实现,接下来将对这两种方式逐一说明,需要的朋友可以参考下
    2022-06-06
  • 本地安装MinIO分布式对象存储服务器的详细步骤

    本地安装MinIO分布式对象存储服务器的详细步骤

    本地安装MinIO非常简单,MinIO提供了独立的二进制文件,无需额外的依赖,本文介绍如何在本地安装MinIO分布式对象存储服务器,感兴趣的朋友一起看看吧
    2024-01-01
  • IDEA报错"Cannot resolve symbol"问题的解决办法

    IDEA报错"Cannot resolve symbol"问题的解决办法

    早上来了,打开idea发现注解等都变红报错can’t resolvesymbol,由于这个错之前也报过,所以记录一下,这篇文章主要给大家介绍了关于IDEA报错"Cannot resolve symbol"问题的解决办法,需要的朋友可以参考下
    2023-11-11
  • SpringBoot集成单点登录CAS的方法实现

    SpringBoot集成单点登录CAS的方法实现

    本文主要介绍了SpringBoot集成单点登录CAS的方法实现,包括CAS的基本概念、集成步骤、具体代码示例等,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • Java获取年月日(格式:xxxx年xx月xx日)的方法详解

    Java获取年月日(格式:xxxx年xx月xx日)的方法详解

    在开发应用程序时,经常需要获取当前的年、月、日,并以特定格式进行展示或处理,本文将介绍如何获取年月日,并将其格式化为“xxxx年xx月xx日”的形式,帮助你在应用程序中处理日期信息,需要的朋友可以参考下
    2023-10-10
  • 详解在Spring中如何使用AspectJ来实现AOP

    详解在Spring中如何使用AspectJ来实现AOP

    这篇文章主要介绍了详解在Spring中如何使用AspectJ来实现AOP,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • mybatis之调用带输出参数的存储过程(Oracle)

    mybatis之调用带输出参数的存储过程(Oracle)

    这篇文章主要介绍了mybatis调用带输出参数的存储过程(Oracle),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 23种设计模式(22)java状态模式

    23种设计模式(22)java状态模式

    这篇文章主要为大家详细介绍了23种设计模式之java状态模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • java如何实现基于opencv全景图合成实例代码

    java如何实现基于opencv全景图合成实例代码

    全景图相信大家应该都不陌生,下面这篇文章主要给大家介绍了关于java如何实现基于opencv全景图合成的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-07-07

最新评论