Java面试宝典系列之基础排序算法

1.介绍

排序是一个在编程中间是非常基础的和重要的,网上也有很多有关排序算法的文章,再次我也是总结学习别人的知识,将别人的知识转为自己的知识,因此做此笔记,以便更好地掌握java常见排序算法。

2.插入算法

2.1 基本思想
每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置(从后向前找到合适位置后),直到全部插入排序完为止。
2.2 实例
这里写图片描述
2.3 算法实现

public class SortSeries {

    static int data[] = {57, 68, 59, 52};

    public static void insertSort() {
        int tmp, j = 0;
        for (int k = 0; k < data.length; k++) {
            tmp = data[k];
            //比较前面所有的数字,如果有大于当前数字的,那个数字就往后移一位,空出来将temp插入
            for (j = k - 1; j >= 0 && tmp < data[j]; j--) {
                data[j + 1] = data[j];
            }
            //因为上面最后运行了一次j--,所有下面是data[j + 1]
            data[j + 1] = tmp;
        }
    }

    static void print() {
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
    }

    public static void main(String[] args) {
        insertSort();
        print();
    }
}

结果:52 57 59 68

3.选择排序

3.1 基本思想
与直接插入排序正好相反,选择排序是从待排序的数中选出最小的放在已经排好的后面,这个算法选数耗时。
3.2 实例
这里写图片描述
3.3 算法实现

public class SortSeries {

    static int data[] = {57, 68, 59, 52};

    public static void selectSort() {
        int i = 0;
        int j, k, tmp = 0;
        for (k = 0; k < data.length - 1; k++) {
            //每次默认起始比较k下标就是待比较数字中最小值i的下标
            i = k;
            //从当前数字开始比较,选择出后面数字最小的小标,存入i值
            for (j = k + 1; j < data.length; j++) {
                if (data[j] < data[i]) {
                    i = j;
                }
            }
            tmp = data[k];
            //当前位置放入从当前到最末位置最小值,即进项数字交换
            data[k] = data[i];
            data[i] = tmp;
        }
    }

    static void print() {
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
    }

    public static void main(String[] args) {
        selectSort();
        print();
    }
}

结果:52 57 59 68
通过循环,找出最小的数的下标,赋值于i,即i永远保持待排序数据中最小的数的下标,最后和当前位置k互换数据即可。

4.快速排序

4.1 基本思想
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
4.2 实例
快排的思路:
设置两个指针:i和j,分别指向第一个和最后一个,i像后移动,j向前移动,选第一个数为标准(一般这样做,当然快排的关键就是这个“标准”的选取,每一轮比较这个标准值是不变的),从后面开始,找到第一个比标准小的数,互换位置,然后再从前面,找到第一个比标准大的数,互换位置,第一趟的结果就是标准左边的都小于标准,右边的都大于标准(但不一定有序),分成两拨后,继续递归的使用上述方法,最终有序!
4.3 算法实现

public class SortSeries {

    /**
     * 查找中轴(初始默认最低位作为中轴)所在位置
     * @param numbers 排列数组
     * @param low 最小起始下标
     * @param high 最大起始下标
     * @return
     */
    public static int getMiddle(int[] numbers, int low, int high) {
        int temp = numbers[low]; //数组的第一个作为中轴
        while (low < high) {
            while (low < high && numbers[high] > temp) {
                high--;
            }
            numbers[low] = numbers[high];//比中轴小的记录移到低端
            while (low < high && numbers[low] < temp) {
                low++;
            }
            numbers[high] = numbers[low]; //比中轴大的记录移到高端
        }
        numbers[low] = temp; //中轴记录到尾
        return low; // 返回中轴的位置
    }

    /**
     * 递归形式的分治排序算法
     * @param numbers
     * @param low
     * @param high
     */
    public static void quickSort(int[] numbers, int low, int high) {
        if (low < high) {
            int middle = getMiddle(numbers, low, high); //将numbers数组进行一分为二   
            quickSort(numbers, low, middle - 1); //对低字段表进行递归排序   
            quickSort(numbers, middle + 1, high); //对高字段表进行递归排序
        }
    }

    static void print(int[] numbers) {
        for (int i = 0; i < numbers.length; i++) {
            System.out.print(numbers[i] + " ");
        }
    }

    public static void main(String[] args) {
        int[] numbers = {20, 9, 17, 33, 49, 24, 15, 56, 1};
        quickSort(numbers, 0, numbers.length - 1);
        print(numbers);
    }
}

结果:1 9 15 17 20 24 33 49 56
结合代码,我们分析一下一趟排序的过程,

待排列数组int[] numbers = {20, 9, 17, 33, 49, 24, 15, 56, 1},
首先选取20作为标准,然后比较标准20跟最后一位1,20>1,交换位置:1, 9, 17, 33, 49, 24, 15, 56, 20;
然后20从左往右找出第一个比它大的值33交换位置:
1, 9, 17, 20,49, 24, 15, 56, 33;
然后20从右往左找出第一个比它小的值15交换位置:
1, 9, 17, 15,49, 24, 20, 56, 33;
然后20从左往右找出第一个比它大的值49交换位置:
1, 9, 17, 15,20, 24, 49, 56, 33;
然后20从右往左找出比它小的值,此时没有了,从左往右找比它大的值也没有了,此时第一趟结束,然后以此对1, 9, 17, 15和24, 49, 56, 33重复该过程,知道最后有序!

5.冒泡排序

5.1 基本思想
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
5.2 实例
暂无
5.3 算法实现

public class SortSeries {

    static int[] data = {20, 9, 17, 33, 49, 24, 15, 56, 1};

    public static void bubbleSort() {
        int i, j, tmp = 0;
        for (i = 0; i < data.length - 1; i++) {
            for (j = data.length - 1; j > i; j--) {
                if (data[j - 1] > data[j]) {
                    tmp = data[j - 1];
                    data[j - 1] = data[j];
                    data[j] = tmp;
                }
            }
        }
    }

    static void print() {
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
    }

    public static void main(String[] args) {
        bubbleSort();
        print();
    }
}

结果:1 9 15 17 20 24 33 49 56

6.希尔算法

6.1 基本思想
希尔排序(缩小增量法) 属于插入类排序,是将整个无序列分割成若干小的子序列分别进行插入排序。希尔排序是对直接插入排序算法的优化和升级。
6.2 实例
以数组{26, 53, 67, 48, 57, 13, 48, 32, 60, 50 }为例,步长序列为{5,2,1}
这里写图片描述
6.2 算法实现

public class SortSeries {

    public static void shellsort(int[] data) {
        int j, tmp = 0;
        for (int increment = data.length / 2; increment > 0; increment /= 2) {
            System.out.println("当前步长序列increment:" + increment);
            for (int i = increment; i < data.length; i++) {
                tmp = data[i];
                for (j = i - increment; j >= 0; j -= increment) {
                    if (tmp < data[j]) {
                        data[j + increment] = data[j];
                    } else {
                        break;
                    }
                }
                //上面循环最后减去了increment,所以此时要加上
                data[j + increment] = tmp;
            }
            for (int i = 0; i < data.length; i++) {
                System.out.print(data[i] + " ");
            }
            System.out.println();
        }
    }

    static void print(int[] data) {
        System.out.println("-----最终排序结果-----");
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
    }

    public static void main(String[] args) {
        int[] data = {26, 53, 67, 48, 57, 13, 48, 32, 60, 50};
        shellsort(data);
        print(data);
    }
}

结果:

当前步长序列increment:5
13 48 32 48 50 26 53 67 60 57 
当前步长序列increment:2
13 26 32 48 50 48 53 57 60 67 
当前步长序列increment:1
13 26 32 48 48 50 53 57 60 67 
-----最终排序结果-----
13 26 32 48 48 50 53 57 60 67 

7.归并排序

7.1 基本思想
归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
7.2 工作原理
(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
(2)设定两个指针,最初位置分别为两个已经排序序列的起始位置;
(3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
(4)重复步骤3直到某一指针达到序列尾;
(5)将另一序列剩下的所有元素直接复制到合并序列尾;
7.3 算法实现

public class MergeSortTest {
    /**
     * 归并排序
     *
     * @param nums 待排序数组
     * @param low
     * @param high
     * @return 输出有序数组
     */
    public static int[] sort(int[] nums, int low, int high) {
        int mid = (low + high) / 2;
        if (low < high) {
            // 左边
            sort(nums, low, mid);
            // 右边
            sort(nums, mid + 1, high);
            // 左右归并
            merge(nums, low, mid, high);
//            System.out.println(Arrays.toString(nums));
        }
        return nums;
    }

    /**
     * 将数组中low到high位置的数进行排序
     *
     * @param nums 待排序数组
     * @param low  待排的开始位置
     * @param mid  待排中间位置
     * @param high 待排结束位置
     */
    public static void merge(int[] nums, int low, int mid, int high) {
        int[] temp = new int[high - low + 1];
        int i = low;// 左指针
        int j = mid + 1;// 右指针
        int k = 0;

        // 把较小的数先移到新数组中
        while (i <= mid && j <= high) {
            if (nums[i] < nums[j]) {
                temp[k++] = nums[i++];
            } else {
                temp[k++] = nums[j++];
            }
        }

        // 把左边剩余的数移入数组
        while (i <= mid) {
            temp[k++] = nums[i++];
        }

        // 把右边边剩余的数移入数组
        while (j <= high) {
            temp[k++] = nums[j++];
        }

        // 把新数组中的数覆盖nums数组
        for (int k2 = 0; k2 < temp.length; k2++) {
            nums[k2 + low] = temp[k2];
        }
    }

    public static void main(String[] args) {
        int a[] = {51, 46, 20, 18, 65, 97, 82, 30, 77, 50};
        sort(a, 0, a.length - 1);
        System.out.println("排序结果:" + Arrays.toString(a));
    }
}

结果:
排序结果:[18, 20, 30, 46, 50, 51, 65, 77, 82, 97]

8.堆排序

深入解析堆排序的算法思想及Java代码的实现演示

这里写图片描述

参考文章:
Java之美[从菜鸟到高手演变]之常见的几种排序算法-插入、选择、冒泡、快排、堆排等
必须知道的八大种排序算法【java实现】(二) 选择排序,插入排序,希尔算法【详解】
【排序算法】希尔排序原理及Java实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值