程序员那些必须掌握的排序算法(下) (2)

关于归并排序的算法思想确实比较绕,所以我也在代码中写了很多注释。
我们先来测试一下:

public static void main(String[] args) { int[] arr = { 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 }; int[] temp = new int[arr.length]; mergeSort(arr, 0, arr.length - 1, temp); System.out.println(Arrays.toString(arr)); }

运行结果:

[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

来分析一下吧,对于该排序算法,有两个部分组成,分解和合并。首先讲讲分解,在前面也说到了,我们需要将待排序的序列不停地进行分解,通过两个索引变量控制,一个初始索引,一个结尾索引。只有当两索引重合才结束分解。此时序列被分解成了十五个小份,这样分解工作就完成了。接下来是合并,合并操作也是最麻烦的,也是通过两个索引变量i,j。开始i在左边序列的第一个位置,j在右边序列的第一个位置,然后就是寻找左右两个序列中的最小值,放到新序列中,这时可能会出现一边的元素都放置完毕了,而另外一边还存在元素,此时只需将剩余的元素按顺序放进新序列即可,因为这时左右两边的序列已经是有序的了,最后将新序列复制到旧序列。这里也特别需要注意,因为合并的过程是分步的,而并非一次合并完成,所以数组的索引是在不断变化的。

在这里插入图片描述


自己手动画了个图,左右两个箭头就是索引变量i,j,当i所指的元素也就是1和j所指的元素也就是2进行比较,发现1小,就将1放到新数组的第一个位置,此时应该将i和新数组的索引都右移一位,然后继续比较,以此类推,相信这样大家应该能理解了吧。

3.基数排序

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O(nlog( r )m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。基数排序是用空间换时间的经典算法。
演示:

在这里插入图片描述


基数排序的基本思想是:
将所有待比较的数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成以后,数列就变为了一个有序序列。
这样说可能过于抽象,我们通过详细步骤来分析一下:
我们假设有一个待排序数组[53,3,542,748,14,214],那么如何使用基数排序对其进行排序呢?
首先我们有这样的十个一维数组,在基数排序中也叫桶。

在这里插入图片描述


那么第一轮排序开始,我们依次遍历每个元素,并得到元素的个位数。拿到的第一个元素为53,其个位数为3,所以将53放入编号为3的桶中,第二个元素3的个位数也是3,所以也放在编号为3的桶中,而第三个元素542的个位数为2,所以将542放入编号为2的桶中,以此类推。
所以结果为:

在这里插入图片描述


将元素全部放入桶中之后,我们需要按照桶的顺序(也就是一维数组的下标)依次取出数据,并放回原来的数组。
那么很简单,按顺序取出数据并放回原数组之后,原数组将变为[542,53,3,14,214,748]。
这样第一轮就完成了,接下来开始第二轮。
第二轮排序和第一轮类似,也要去遍历数组元素,但不同的是第二轮的存放顺序取决于十位数。
取出数据的第一个元素为542,十位数为4,所以放入编号为4的桶;第二个元素53,十位数为5,所以放入编号为5的桶;第三个元素3,十位数为0,所以放入编号为0的桶,以此类推。
所以结果为:

在这里插入图片描述


然后同样按照桶的顺序将数据从中取出并放入原数组,此时原数组变为[3,14,214,542,748,53]。
接下来又进行第三轮排序,以元素的百位数进行区分,结果为:

在这里插入图片描述


按顺序取出数据后,原数组变为[3,14,53,214,542,748]。这时的数组已经完成排序。
从中我们也可以知道,基数排序的排序轮数取决于数组元素中最大位数的元素。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdfgf.html