排序-选择排序(Selection Sort)

描述

选择排序是一种简单的排序方法,每次从序列元素中选出最小的一个,顺序放在已排序的序列末尾,直到全部排序结束为止。

原理
  1. 从序列(N个元素)中找出最小元素,和第一个元素交换;
  2. 从剩下的序列中找出最小元素,和第二个元素交换;
  3. 重复(1)、(2)步,直到第N个元素被处理,排序结束。

下面图中给出了选择排序的详细过程:

性质
  1. 时间复杂度:O(N^2)
  2. 空间复杂度:O(1)
  3. 比较次数:N^2/2
  4. 交换次数:N

选择排序和初始输入数据无关。无论是正序、倒叙还是无序,都会按照上面的规则将所有数据一一比较找出最小元素,然后进行交换。

接口定义

为了方便后面学习排序,定义接口Sorted表示排序接口,在后面的学习中也会一致使用这个接口。

/**
 * 排序接口
 */
public interface Sorted {

    /**
     * 排序
     * @param arrays 待排序数组
     * @param <T>    限定类型为Comparable接口类型
     */
    <T extends Comparable<T>> void sort(T[] arrays);

}

另外,在选择排序中需要涉及两个操作:比较和交换。我们分别定义在AbstractSorted的less()方法和exch()方法中。在后续的排序分析中可能需要其他的方法,我们也会放到AbstractSorted抽象类中作为公共的父类方法使用。代码如下:

/**
 * 抽象排序类
 */
public abstract class AbstractSorted implements Sorted {

    /**
     * 判断v小于w
     * @param v
     * @param w
     */
    protected static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    /**
     * 交换数组a中第i个元素和第j个元素
     * @param a
     * @param i
     * @param j
     */
    protected static void exch(Object[] a, int i, int j) {
        if (i == j) {
            return;
        }
        if (i >= arrays.length || j >= arrays.length) {
            throw new ArrayIndexOutOfBoundsException();
        }
        Object swap = arrays[i];
        arrays[i] = arrays[j];
        arrays[j] = swap;
    }

}
选择排序
/**
 * 选择排序
 */
public class SelectionSorted extends AbstractSorted {

    public  <T extends Comparable<T>> void sort(T[] arrays) {

        // 每趟循环找一个最小元素
        for (int i = 0; i < arrays.length; i ++) {

            // 标记最小元素位置
            int minIndex = i;

            // 从剩余的元素中找最小元素
            for (int j = i + 1; j < arrays.length; j ++) {
                if(less(arrays[j], arrays[minIndex])) {
                    minIndex = j;
                }
            }

            // 交换
            exch(arrays, i, minIndex);

            String msg = String.format("第%2d次 ->:%s", i + 1,  Arrays.toString(arrays));
            System.out.println(msg);
        }
    }

}
测试代码
/**
 * 排序测试
 */
@RunWith(JUnit4.class)
public class SortedTest {

    private Integer[] data;

    @Before
    public void setUp() {
        Random random = new Random();
        data = new Integer[10];
        for (int i = 0; i < data.length; i ++) {
            data[i] = random.nextInt(10000);
        }
    }

    /**
     * 测试选择排序
     */
    @Test
    public void testSelectionSorted() {
        long start = System.currentTimeMillis();
        Sorted sorted = new SelectionSorted();
        System.out.println("选择排序前: " + Arrays.toString(data));
        sorted.sort(data);
        System.out.println("选择排序后: " + Arrays.toString(data));
        System.out.println("执行时间: " + (System.currentTimeMillis() - start) + " ms");
    }

}
测试结果
选择排序前: [6834, 3139, 9217, 5177, 7578, 116, 2807, 3348, 765, 1002]
第 1次 ->:[116, 3139, 9217, 5177, 7578, 6834, 2807, 3348, 765, 1002]
第 2次 ->:[116, 765, 9217, 5177, 7578, 6834, 2807, 3348, 3139, 1002]
第 3次 ->:[116, 765, 1002, 5177, 7578, 6834, 2807, 3348, 3139, 9217]
第 4次 ->:[116, 765, 1002, 2807, 7578, 6834, 5177, 3348, 3139, 9217]
第 5次 ->:[116, 765, 1002, 2807, 3139, 6834, 5177, 3348, 7578, 9217]
第 6次 ->:[116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
第 7次 ->:[116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
第 8次 ->:[116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
第 9次 ->:[116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
第10次 ->:[116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
选择排序后: [116, 765, 1002, 2807, 3139, 3348, 5177, 6834, 7578, 9217]
执行时间: 3 ms
参考资料

《Algorithms, 4th Edition》 https://algs4.cs.princeton.edu/21elementary/

转载于:https://my.oschina.net/xiaoqiyiye/blog/2240276

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值