排序算法复习笔记

排序算法一般都会有几个较为基础通用的方法,如下表

方法名作用
isSorted()判断数组是否有序
less(int item1, int item2)比较第一个参数是否小于等于第二个参数
exch(int a, int b)交换这两个索引位置的元素
show()打印数组
sort()具体待实现的排序算法

具体参考如下

public abstract class Sort {

    int[] mList;

    public Sort(int[] list) {
        this.mList = list;
    }

    public boolean isSorted() {
        if (mList.length > 1) {
            for (int i = 1; i < mList.length; i++)
                assert less(mList[i - 1], mList[i]);
        }
        return true;
    }

    public boolean less(int item1, int item2) {
        return item1 <= item2;
    }

    public void exch(int a, int b) {
        if (a != b) {
            int item = mList[a];
            mList[a] = mList[b];
            mList[b] = item;
        }
    }

    public void show() {
        for (Integer item : mList)
            System.out.print(item + " ");
    }

    public abstract void sort();
}

之前是用泛型来做的,后考虑学习算法主要的是理解逻辑,所以使用简单的int简单而且更直观

1 选择排序

主要过程是:首先找到数组中最小的那个元素,其次,将它和数组中低一个元素交换位置(若最小的元素是自己,则与自己交换一次)。然后在剩下的元素中依次找出最小的元素,与第二个位置的元素做交换。以此类推,直到排序到最后一个元素,则完成整个数组的排序。
最大的特点是,运行时间与输入无关,且数据移动是最少的。对于长度是N的数组,选择排序需要大约N²/2次比较和N次交换。

class ChoiceShort extends Sort {

    public ChoiceShort(int[] list) {
        super(list);
    }

    @Override
    public void sort() {
        for (int i = 0; i < mList.length; i++) {
            //最小元素的索引位置
            int min = i;
            for (int r = i + 1; r < mList.length; r++) {
                //若最小元素比当前元素大了,则更新最小元素的索引
                if (!less(mList[min], mList[r])) min = r;
            }
            exch(i, min);
        }
    }
}
2 插入排序

从第二个元素开始,依次从右往左比较,遇到比当前元素大的则交换位置,反之则为已经插入到了当前元素对应的位置,然后选取下一个元素开始下一轮的比较。

class InsertShort extends Sort {

    public InsertShort(int[] list) {
        super(list);
    }

    @Override
    public void sort() {
        for (int i = 1; i < mList.length; i++) {
            for (int r = i; r > 0 && !less(mList[r - 1], mList[r]); r--) {
            	//若当前位置元素比前一位置元素小,则交换这个两个位置的元素,反之则此次循环结束
                exch(r, r - 1);
            }
        }
    }
}

因为每个元素向前寻找对应的位置时都经历了多次比较以及交换,所以可以在内循环中先找到对应应该插入的位置,然后之间的元素都做一个向后移动即可。

    @Override
    public void sort() {
        for (int i = 1; i < mList.length; i++) {
        	//记录当前需要插入的元素以及对应的位置
            int item = mList[i];
            int pos = i;
            for (int r = i; r > 0 && !less(mList[r - 1], item); r--) {
            	//若当前元素是比需要插入的元素大的,则把当前元素向后移动,然后插入的位置改为当前元素的位置
                mList[r] = mList[r - 1];
                pos = r - 1;
            }
            //最后把item插入到对应的位置
            mList[pos] = item;
        }
    }

插入排序适合情况:

  1. 数组中每个元素距离它的最终位置都不远
  2. 一个有序的大数组接一个小数组
  3. 数组中只有几个元素的位置不正确

当倒置的数量很少时,插入排序很可能是最快的算法,总的来说插入排序适合部分有序的数组,也很适合小规模的数组,往往用于高级排序中分为小规模部分的排序。

3 希尔排序

因为在大规模乱序数组的插入排序很慢,因为它只会交换相邻的元素,所以希尔排序是在这个基础上进行的改进,使数组中任意间隔为h的元素都是有序的。意思为h个间隔为h的有序数组编制在一起组成的一个数组,进行排序时移动的距离和h的大小有关,也为更小的h有序创造方便。希尔排序更高效的原因是因为它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序只会子数组都是部分有序的,这两种情况都很适合插入排序。子数组部分有序的程度取决于递增序列的选择,透彻理解希尔排序的性能在今天也是一项挑战。

class ShellShort extends Sort {

    public ShellShort(int[] list) {
        super(list);
    }

    @Override
    public void sort() {
        int h = 0;
        int N = mList.length;
        while (h <= N / 3) h = 3 * h + 1;
        //直到进行h为1的插入排序
        while (h >= 1) {
            for (int i = h; i < N; i++) {
                //从h的位置开始,依次往后进行以h为间距的向前插入排序
                for (int r = i; r >= h && !less(mList[r - h], mList[r]); r -= h) {
                    exch(r - h, r);
                }
            }
            h = h / 3;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值