Java 简单排序

一、冒泡排序


如图所示,如果有五个元素需要排序,那么需要排n-1趟,那么我们是不是可以写出一个循环出来,

for(int i = 1; i <= size-1; i++)
但是我们发现每一趟的比较次数随着趟数的增大而减小,所以我们是不是可以 修改一下循环呢

for(int i = size-1; i > 0; i--)
这样不就成了随着趟数的增大i在减小吗,现在我们算是写出了算法的框框了,我们还要比较元素,有图上分析可知,比较次数在逐趟减小,并且都是从下标为0开始比较的,于是,还需要一个循环来比较元素

for(int j =0; j < ?; j++)

此时,问题来了,临界值是什么,“?”是几呢,再分析一下,第一趟比较下标从0到4,第二趟比较下标从0到3发现小标的变化和i是一样的,并且可以等于i,于是修改循环

for(int j =0; j <= i; j++)
此时感觉很对了,但是仔细想想,这个for循环的内容是什么呢,应该是source[j] 和source[j+1]进行比较,然后交换,如果j可以等于i,那么j+1不就比i还大么,所以我们应该把等号去掉,变为
for(int j =0; j < i; j++)
为了使取名有意义,可以修改一下这两个循环

for(int outer = size - 1; outer > 0; outer--)
{
    for(int inner = 0; inner < outer; inner++)
    {
	//比较逻辑
        int temp = source[inner + 1];
        source[inner + 1] = array[inner];
        source[inner] = temp;
    }
}
完整程序如下所示:

package com.darren.test.sort;

public class BubbleSortTest {
    public static void main(String[] args) {
        int[] array = new int[] { 3, 5, 9, 8, 6, 4, 3, 1, 8, 7 };
        
        System.out.print("before sort:");
        print(array);
        System.out.println();
        
        int size = array.length;
        for (int outer = size - 1; outer >= 0; outer--) {
            for (int inner = 0; inner < outer; inner++) {
                if (array[inner] > array[inner + 1]) {
                    int temp = array[inner + 1];
                    array[inner + 1] = array[inner];
                    array[inner] = temp;
                }
            }
        }
        
        System.out.print("after sort:");
        print(array);
    }

    private static void print(int[] source) {
        for (Integer data : source) {
            System.out.print(data);
            System.out.print(", ");
        }
    }
}


二、插入排序


如图所示,如果有五个元素需要排序,那么需要排n-1趟,并且下标是从1到n-1,那么我们是不是可以写出一个循环出来

for(int i = 1; i < size; i++)
由图可知,我们每次都是把source[i]插入到左边,那么是不是应该把source[i]临时保存一下呢,我想是应该的

int temp = source[i];
那么算法内部是如何进行比较插入的呢,接下来进行分析,我们发现一直向左边插入,其实左边的序列一直是有序的,那么我们就会从右向左比较插入就行了,所以第二个for循环是倒着的
for(int j = ?; j >=0; j--)
从图上可知j可以为0,那么最大可以是多少呢,再分析一下,最大比i小1,所以修改for循环
for(int j = i - 1; j >=0; j--)
怎么比较呢
source[j] 和 source[j+1]进行比较。此时source[j+1]刚好等于source[i],因为j + 1 = i;

把变量取得有意义一点,结果为

for(int outer = 1; outer < size; outer++)
{
    int sentinel = source[i];
    for(int inner = outer - 1; inner >= 0; inner--)
    {
        if(source[inner] > source[inner + 1])
        {
            source[inner + 1] = source[inner];
            source[inner] = sentinel;
        }
    }
}
完整程序如下所示:

package com.darren.test.sort;

public class InsertSortTest {
    public static void main(String[] args) {
        int[] array = new int[] { 3, 5, 9, 8, 6, 4, 3, 1, 8, 7 };
        
        System.out.print("before sort:");
        print(array);
        System.out.println();
        
        int size = array.length;
        for (int i = 1; i < size; i++) {
            int sentinel = array[i];
            for (int j = i - 1; sentinel < array[j]; j--) {
                array[j + 1] = array[j];
                array[j] = sentinel;
                if (j == 0) {
                    break;
                }
            }
        }
        
        System.out.print("after sort:");
        print(array);
    }

    private static void print(int[] source) {
        for (Integer data : source) {
            System.out.print(data);
            System.out.print(", ");
        }
    }
}

三、选择排序






如图所示,如果有五个元素需要排序,宏观上看需要排n-1趟,并且下标是从0到n-2(注意黑色下划线的起始位置),那么我们是不是可以写出一个循环出来

for(int i = 0; i < size - 1; i++)
第一个for循环并不关心具体是怎么选出一个最小的放左边的,只是先找到下标的变化规律,接着我们看内部是如何实现选出最小值放左边的,这个实现相对插入排序有所不同,只用圈圈不易表达,所以我们用一个具体例子来看。
对一个五个元素的数组进行排序:3 1 5 2 4

要比较,必须有一个参照物,我们假设每一趟中最左边元素(黑色下划线对应的最左边元素)为参照物(int minValueIndex = i),然后拿之后的一个元素(int j = i + 1)和它比较,如果比它小,那么就改变参照物,把新的最小的元素作为参照物,继续拿它之后的元素与之比较,直到本趟结束,因为要拿j和左边的元素比较而没有j + 1,所以j可取到n-1

for(int j = i + 1; j < size; j++)
这里有两个问题
1.选个元素作为参照物还是元素的下标?
2.每一趟比较完应该做些什么?

我们先回答第二个问题,每一趟比较完我们应该把最小的元素放到左边的位置上,需要进行一次元素交换

然后回答第一个问题,我们知道要进行元素交换,如果使用元素作为参照物,那么我只知道最小值是几,却不能和其他元素交换,因为我不知道最小值的下标,但是如果我们知道了最小值的下标,就能知道最小值,所以我们选用下标作为参照物

for(int outer = 0; outer < size - 1; outer++)
{
    // 设置参照物为最左边元素
    int min = outer;
    for(int inner = outer + 1; inner < size; inner++)
    {
        if(source[inner] < source[min])
        {
            // 更新参照物
            min = inner;
        }
    }

    // 交换最小值和最左边值
    int temp = source[outer];
    source[outer] = source[min];
    source[min] = temp;
}


完整程序如下所示:

package com.darren.test.sort;

public class SelectSortTest {
    public static void main(String[] args) {
        int[] array = new int[] { 3, 5, 9, 8, 6, 4, 3, 1, 8, 7 };
        
        System.out.print("before sort:");
        print(array);
        System.out.println();
        
        int size = array.length;
        for (int outer = 0; outer < size - 1; outer++) {
            int min = outer;
            for (int inner = outer + 1; inner < size; inner++) {
                if (array[inner] < array[min]) {
                    min = inner;
                }
            }
            int temp = array[outer];
            array[outer] = array[min];
            array[min] = temp;
        }
        
        System.out.print("after sort:");
        print(array);
    }

    private static void print(int[] source) {
        for (Integer data : source) {
            System.out.print(data);
            System.out.print(", ");
        }
    }
}

总结:

几种简单排序算法的比较
        一般情况下不使用冒泡排序,它过于简单了,以至于可以毫不费力的写出来,当数据很小的时候会有些使用价值。
        选择排序虽然把交换次数降到最低,但比较次数仍然很大,当数据量很小,并且交换数据相对于比较数据更耗时的情况下可是使用选择排序。
        大多数情况系,假设数据量比较小或基本有序时,插入排序算法是三种简单算法最好的选择,对于更大数据量来说,快速排序更好,以后会讲快速排序算法。


除了在速度方面比较算法外,还有一种对算法的衡量标准是算法需要的内存空间有多大。这三种简单算法除了初始的数组外几乎不需要其他内存空间。所有排序算法都
需要一个额外的变量来存储交换时的数据项。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值