通过java实现八大排序的功能

这篇博客详细介绍了通过Java实现的八大排序算法:直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序和基数排序。对每种排序算法的基本思想、算法描述、动态效果、代码实现、复杂度分析以及稳定性进行了讲解。其中,直接插入排序在元素已部分有序时效率较高,希尔排序通过间隔排序提高效率,快速排序在大多数情况下表现优秀,归并排序则保证了稳定性和较高的效率。
摘要由CSDN通过智能技术生成

八大排序(java实现)

常见的排序算法如下:

  • 直接插入排序
  • 希尔排序
  • 简单选择排序
  • 堆排序
  • 冒泡排序
  • 快速排序
  • 归并排序
  • 基数排序

它们都属于内部排序,也就是只考虑数据量较小仅需要使用内存的排序算法,他们之间关系如下:
在这里插入图片描述

稳定与非稳定

如果一个排序算法能够保留数组中重复元素的相对位置则可以被称为是稳定的。反之,则是 非稳定 的。

1.直接插入排序

基本思想
通常人们整理桥牌的方法是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。在计算机的实现中,为了要给插入的元素腾出空间,我们需要将其余所有元素在插入之前都向右移动一位。
算法描述
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5
动态效果如下:
在这里插入图片描述
注意:
如果 比较操作 的代价比 交换操作 大的话,可以采用二分查找法来减少 比较操作 的数目。该算法可以认为是 插入排序 的一个变种,称为二分查找插入排序。

代码实现

/**
 * 通过交换进行插入排序,借鉴冒泡排序
 *
 * @param a
 */
public static void sort(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = i + 1; j > 0; j--) {
            if (a[j] < a[j - 1]) {
                int temp = a[j];
                a[j] = a[j - 1];
                a[j - 1] = temp;
            }
        }
    }
}

/**
 * 通过将较大的元素都向右移动而不总是交换两个元素
 *
 * @param a
 */
public static void sort2(int[] a) {
    for (int i = 1; i < a.length; i++) {
        int num = a[i];
        int j;
        for (j = i; j > 0 && num < a[j - 1]; j--) {
            a[j] = a[j - 1];
        }
        a[j] = num;
    }
}

复杂度分析
直接插入排序复杂度如下:

平均时间复杂度 最好情况 最坏情况 空间复杂度 是否稳定
O(n²) O(n) O(n²) O(1) 稳定

如果采用第二种方式,只移动大的元素,则最好情况的时间复杂度O(n)
比较与总结
插入排序所需的时间取决于输入元素的初始顺序。例如,对一个很大且其中的元素已经有序(或接近有序)的数组进行排序将会比随机顺序的数组或是逆序数组进行排序要快得多。

2.希尔排序

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法
希尔排序是基于插入排序的以下两点性质而提出改进方法的:

  • 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率
  • 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一

希尔排序是先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。


基本思想
将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次再将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。
可以看到步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。一般来说最简单的步长取值是初次取数组长度的一半为增量,之后每次再减半,直到增量为1。更好的步长序列取值可以参考维基百科。
算法描述
1.选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
2.按增量序列个数 k,对序列进行 k 趟排序;
3.每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
效果如下
在这里插入图片描述
代码实现
下面参考《算法》中给出的步长选择策略,《算法》中给出的解释是
下面代码中递增序列的计算和使用都很简单,和复杂递增序列的性能接近。当可以证明复 杂的序列在最坏情况下的性能要好于我们所使用的递增序列。更加优秀的递增序列有待我们去发现。

private static void shellSort(int[] arr){
		int length = arr.length;
		for (int gap = length/2;gap>0;gap= gap/2){
			for (int i = gap;i<length;i++){
				int pointer = arr[i];
				int j;
				for (j = i-gap;j>=0&&pointer<arr[j];j=j-gap){
					arr[j+gap] = arr[j];   //通过插入排序  将大的向后移
				}
				arr[j+gap] = pointer;
			}
		}
	}

时间复杂度和空间复杂度
由于希尔排序的时间复杂度是和增量相关的,目前使用最好的增量序列时,在最坏的情况下是O(n^1.3),在使用平分的增量序列时,最坏情况下是O(n²)。最好情况下是O(n*logn),空间复杂度为O(1)。
稳定性
不稳定:因为在排序的过程中不像直接插入排序,他是间隔进行直接插入排序(即跳跃性插入),所以有可能会破坏稳定性。
总结和思考
希尔排序更高效的原因是它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。

3.简单选择排序

基本思想
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值