超详细的十大排序算法原理及java代码实现

这篇博客详细介绍了十种经典的排序算法,包括直接插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序、堆排序、计数排序和桶排序。每种算法都附带了Java代码实现,便于理解和实践。文章还对各种排序算法的特点、适用情况进行了简要说明,并提供了效率比较。
摘要由CSDN通过智能技术生成

注意:代码大同小异,最好自己理解了思想后自己写一遍

1.直接插入排序

顾名思义就是从数组中一个一个取元素,然后一个一个插入形成有序序列。比如说一个int型无序数组,从小到大排序。

特点:平均时间复杂度O(n2) 空间复杂度O(1) 稳定的
适用情况:数据量比较少的排序

步骤:
(1)选取第一个元素arr[0],因为只有一个元素,无须比较,直接插 入arr[0]的位置。
(2)选取第二个元素arr[1]插入前面已经排好顺序的序列中,这里前面排序好的序列里 面只有arr[0],所以只许将arr[1]和arr[0]进行比较,如果arr[1]<arr[0],则交换顺序,小的 排在前面。
(3)选取第三个元素arr[2]插入前面已经排好顺序的序列中(这里只有arr[0]arr[1]两个 元素),这里注意要从后往前比较,如果该元素比前面的小,则和前面一个元素换位置, 继续和更前面的元素比较,如果还比前面的小,还要跟前面继续换位置,直到到达正确 的顺序位置(这里就是升序嘛)就停止比较了,也不再需要跟更前面的元素比较了。
(5)选取第四个元素arr[3],同步骤
(6)以此类推……

Java实现代码:

//直接插入排序,从小到大
int[] arr = {2,5,6,1,3,0,9,8};
        //从第二个元素开始插入
        for(int i=1;i<arr.length;i++)
        {
            int value = i;
            int j = i-1;//第i个要插入的元素从后往前比较,即与i-1开始比较
            while(j>=0&&arr[value]<arr[j] )//要插入的元素比前面已经排好序的元素小
            {
                int temp;
                temp = arr[value];
                arr[value] = arr[j];
                arr[j] = temp;
                j--;
                value--;
            }
            
        }
        for(int a :arr)
        {
            System.out.println(a);
        }

控制台结果:
在这里插入图片描述

代码详解:这里定义了一个无序int数组,进行从小到大的排序
(1)for语句是从int=1,即第二个元素开始插入,因为第一个元素无需判断,所以从i=1到i=arr.length-1都要一个一个插入。
(2)Value变量的定义:这里为什么要定义一个中间变量value呢,因为在插入的过程中要一直比较新元素与前一个元素的大小来判断是否要互换位置,如果互换位置了,就需要value来保存互换位置后新元素的下标,也就是说value保存了整个变换过程中插入的新元素的位置。
(3)While语句判断j是否是>=0,如果j=0,表示要插入的新元素在arr[1]的位置,此时要比较arr[0]和新元素的大小来判断是否互换位置,完成这一步之后j=-1,所以不再循环,插入已经完成。(这里有个小细节就是while语句里的判断内容:j>=0要写在&&之前是因为当不满足j>=0时,编译器不会去判断后面的arr[value]<arr[j],也就不会抛出数组越界的异常,如果arr[value]<arr[j]放在&&前面挡j<0时就会有arr[-1],编译器就会报错)
(4)While语句里面互换元素位置后更新新元素的位置value(value–;)和j的位置(j–;),再继续比较。
(5)最后foreach语句打印查看结果。

2.折半插入排序(基于折半查找法,即二分查找法)

折半插入排序就是对直接插入排序的一个小变化,在已经完成排序的部分中找出第一个比即将插入的新元素大的元素位置,将新元素插入到该位置,该位置后面的元素一次向后移动一个位置。通俗点将就是找到一个位置将这个新元素插入进去,该位置之后的元素一次向后移动一个位置。怎样找到这个位置的,就是通过折半(二分)查找法。

特点:平均时间复杂度O(n2) 空间复杂度O(1) 稳定的
适用情况: 元素初始序列接近有序序列时

Java代码实现:

//折半插入排序
        int[] arr = {2,5,6,1,3,0,9,8};//待排序的数组
        int left ,right;//已经完成排序部分的左右边界
        int middle;
        for(int i=1;i<arr.length;i++)//遍历待排序的部分,一个一个插入
        {
            left = 0;
            right = i-1; 
            while(left<=right)
            {
                middle = (left + right)/2;
                if(arr[middle]>arr[i])
                {
                    right = middle-1;
                }
                else
                {
                    left = middle+1;
                }
            }
            
            int temp = arr[i];
            for(int j=i-1;j>=left;j--)
            {
                arr[j+1] = arr[j];
                
            }
            arr[left] = temp;
    
        }
        for(int a :arr)
        {
            System.out.println(a);
        }

代码详解
折半插入排序的重点就是折半查找,left和right用来指示新元素插入的区间,通过折半的方法逐渐缩小left和right之间的区间,while语句控制区间的缩小,边界条件是left=right=middle,也就是最终区间缩小到最后只剩一个元素,left和right同时指向该元素,此时判断如果arr[middle]>arr[i],此时right左移,新元素放在left位置上,也就是当前位置。如果arr[middle]<=arrileft右移一个单位,所以还是应该放在left位置上,但不是刚刚的当前位置了,而是此位置的下一个位置。求出来存放新元素的left位置及其之后的位置应该先一次后移一个位置,然后把新元素放到求出来的这个位置,即当前left指向的位置。

3.希尔排序

希尔排序是对直接插入排序的改进,在元素量较少或者初始数据接近有序的时候,直接插入排序效率较高。希尔排序就针对这两点进行了改进。首先是分组,将大量的数据分成了一组一组的,这样就实现了对少量数据的处理;其次是不断地慢慢的使数组序列变得接近有序。

特点:时间复杂度跟增量序列有关,极其复杂 空间复杂度O(1) 不稳定
在这里插入图片描述

Java代码实现:

int[] arr = {14,5,4,5,3,13,9,8};//待排序的数组
        int gap = arr.length;
        while(gap>,0)
        {
            gap = gap/2;
            for(int i=0;i<arr.length;i++)
            {
                int value = i;
                int j = value - gap;
                while(j>=0&&arr[j]>arr[value])
                {
                    int temp;
                    temp = arr[j];
                    arr[j] = arr[value];
                    arr[value] = temp;
                    value-=gap;
                    j-=gap;
                }
            }
            System.out.println(Arrays.toString(arr));

控制台结果:
在这里插入图片描述
代码详解
(1)希尔排序原理上跟直接插入排序是相同的,通俗点说,不同点就是在处理大量元素时,可以“分组”,将大量数据分组成几组少量数据,每一组数据之间又是有序的,所以等间隔抽取数据组成一组,这样所有数据合在一起的时候整个数据也是接近有序的,只需要做稍微变动即可完成排序。
(2)gap就是增量,也就是间隔取值量,所有元素将分成gap个组,gap越大,每个组中的元素就越少。分完组以后arr[i]不再是与arr[i-1]相比较了,而是跟arr[i-gap]比较,即跟同组内的前一个元素相比较。直到gap=1的时候表示的就是所有的元素分成一个组,也就是对所有的元素进行排序。因为前面已经经过多次不同gap值情况下的排序,所以这时候的元素基本上已经接近有序,只需要稍加改动即可完成排序。
(3)“分组”实际上是虚拟的分组,并不是真正意义上的分组。与直接插入排序相比,只是多了个控制器而已。
(4)为了形象的理解,举一个例子。军训的时候为了排列队形,教官说大家站成一排,从1-5循环报数,最后说,报1的出列,形成第一排;报2的出列,形成第二排&

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Operose-honeybee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值