Java算法排序之冒泡/插入/选择/快速、二分查找 - 附动图

1. Java排序:冒泡排序 - 最简单

(1)比较前后相邻的二个数据,如果前面数据大于后面的数据,就将这二个数据交换。
(2)这样对数组的第 0 个数据到 N-1 个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
(3)N=N-1,如果 N 不为 0 就重复前面二步,否则排序完成。


Java冒泡排序

【逻辑】外层0 ~ 。相邻元素,比较大小,互换位置
【优点】稳定
【缺点】慢,每次只能移动相邻两个数据

public class TestArraySort{
    public static void main(String[] args) {
        // Test 冒泡
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        bubbleSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:冒泡排序
     * 说明:相邻元素,比较大小,互换位置
     * @param array 需要排序的无序整数类型数组
     */
    public static void bubbleSort(int[] array) {
        // 1. 参数合法性判断
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 冒泡排序主逻辑
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-1 - i; j++) {
                if (array[j] > array[j+1]) { // 相邻元素,升序
                //if (array[j] < array[j+1]) { // 相邻元素,降序
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
        }
    }
}

2. Java排序:插入排序 - 简单

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应的位置并插入。


Java插入排序

插入排序非常类似于整扑克牌。在开始摸牌时,左手是空的,牌面朝下放在桌上。接着,一次从桌上摸起一张牌,并将它插入到左手一把牌中的正确位置上。为了找到这张牌的正确位置,要将它与手中已有的牌从右到左地进行比较。无论什么时候,左手中的牌都是排好序的。
如果输入数组已经是排好序的话,插入排序出现最佳情况,其运行时间是输入规模的一个线性函数。如果输入数组是逆序排列的,将出现最坏情况。平均情况与最坏情况一样,其时间代价是(n2)。


Java插入排序

【逻辑】外层1 ~ 。第2个数开始,与前面的数逐个比较,插入位置
【优点】稳定,快
【缺点】比较次数不一定,比较次数越少,插入点后的数据移动越多,特别是当数据总量庞大的时候

public class TestArraySort{
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        insertSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:插入排序
     * 说明:第2个数开始,与前面的数逐个比较,插入位置
     * @param array 需要排序的无序整数类型数组
     */
    public static void insertSort(int[] array) {
        // 1. 参数合法性判断
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 插入排序主逻辑
        for (int i = 1; i < array.length; i++) { // 从第2个数temp开始
            for (int j = i; j > 0; j--) { // temp每次与前面的数比较,插入进去
                if (array[j] < array[j-1]) { // 升序
                //if (array[j] < array[j-1]) { // 降序
                    int temp = array[j];
                    array[j] = array[j-1];
                    array[j-1] = temp;
                }
            }
        }
    }
}

3. Java排序:选择排序 - 简单

选择排序(Selection sort)是一种简单直观的排序算法。
它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。
选择排序是不稳定的排序方法
原因是用数组实现的选择排序是不稳定的,用链表实现的选择排序是稳定的,因为数组内会破坏相同元素的位置,所以选择排序是不稳定的。
在《算法》第四版217页上作者已经说了,有很多办法可以将任意排序算法变成稳定的,但是,往往需要额外的时间或者空间。

Java选择排序

【逻辑】外层0 ~ 。固定值与其他值依次比较,互换位置
【优点】数据移动次数已知为(n-1)次
【缺点】比较次数多

public class TestArraySort {
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        selectSort(nums);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:选择排序
     * 说明:固定值与其他值依次比较,互换位置
     * @param array 需要排序的无序整数类型数组
     */
    public static void selectSort(int[] array) {
        // 1. 参数合法性判断
        if (null == array || array.length == 0) {
            return;
        }
        
        // 2. 选择排序主逻辑
        for (int i = 0; i < array.length-1; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if (array[i] > array[j]) { // 升序:选择1个数array[i]与i+1后面的数依次比较
                //if (array[i] < array[j]) { // 降序
                    int tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                }
            }
        }
    }
}

4. Java排序:快速排序 - 递归(难)

快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。
一次循环:从后往前比较,用基准值和最后一个值比较,如果比基准值小的交换位置,如果没有继续比较下一个,直到找到第一个比基准值小的值才交换。找到这个值之后,又从前往后开始比较,如果有比基准值大的,交换位置,如果没有继续比较下一个,直到找到第一个比基准值大的值才交换。直到从前往后的比较索引 > 从后往前比较的索引,结束第一次循环,此时,对于基准值来说,左右两边就是有序的了。

Java快速排序

【逻辑】选择第一个数位基准值,开始首尾比较,首[0]基准值开始的i++找 ≤ 首值的进行交换,尾[length-1]基准值开始的j--找 ≥ 尾值的进行交换,找到中间后,两半边各自递归
【优点】极快,数据移动少
【缺点】不稳定(原因同选择排序)

public class TestArraySort {
    public static void main(String[] args) {
        int[] nums = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        quickSort(nums, 0, nums.length-1);
        for (int i = 0; i < nums.length; i++) {
            System.out.print(nums[i] + " "); // 1 2 3 4 5 6 7 8 9
        }
    }
    
    /**
     * Java排序:快速排序
     * 说明:选一个数作为基数(一般为array[0]),大于基数的放到右边,小于这个基数的放到左边
     * @param array 需要排序的无序整数类型数组
     * @param low 最小基准位置,eg:0
     * @param high 最大基准位置,eg:length-1
     */
    public static void quickSort(int[] array, int low, int high) {
        // 1. 参数合法性判断
        if (null == array || array.length == 0) {
            return;
        }
        
        if (low > high) {
            return;
        }
        
        // 2. 快速排序主逻辑
        int i, j, temp, t;
        i = low;
        j = high;
        temp = array[low]; // temp就是基准位

        while (i < j) {
            while (temp <= array[j] && i < j) { // 升序:先看右边,依次往左递减
            //while (temp >= array[j] && i < j) { // 降序:先看右边,依次往左递递增
                j--;
            }
            while (temp >= array[i] && i < j) { // 升序:再看左边,依次往右递增
            //while (temp <= array[i] && i < j) { // 降序:再看左边,依次往右递减少
                i++;
            }
            if (i < j) { // 如果满足条件则交换
                t = array[j];
                array[j] = array[i];
                array[i] = t;
            }

        }
        // 最后将基准为与i和j相等位置的数字交换
        array[low] = array[i];
        array[i] = temp;
        
        quickSort(array, low, j - 1); // 递归调用左半边数组
        quickSort(array, j + 1, high); // 递归调用右半边数组
    }
}

5. Java算法:二分查找 - 升降序逻辑处理

又叫折半查找,要求待查找的序列有序。
默认升序逻辑说明:每次取中间位置的值与待查关键字比较,如果中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小,则在后半部分循环这个查找的过程。直到查找到了为止,否则序列中没有待查的关键字。

  • 示例代码:(严谨的判断、有序,升,降序的处理
public class TestBinarySearch {
    public static void main(String[] args) {
        int result = 0;
        
        // Test 升序
        int[] nums1 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
        result = binarySearch(nums1, 3);
        System.out.println(result); // 2

        // Test 降序
        int[] nums2 = {9, 8, 7, 6, 5, 4, 3, 2, 1};
        result = binarySearch(nums2, 3);
        System.out.println(result); // 6

        // Test 无序
        int[] nums3 = {1, 8, 3, 6, 2, 9, 7, 4, 5};
        result = binarySearch(nums3, 3);
        System.out.println(result); // -1
    }
    
    /**
     * Java算法:二分查找/折半查找
     * 说明:默认有序,但需判断知道其为升序还是降序
     * @param array 被查找的数组,要求默认有序
     * @param a 需要查找的数
     * @return int 下标位置
     */
    public static int binarySearch(int[] array, int a) {
        // 1. 参数合法性判断
        if (null == array || array.length == 0) {
            return -1;
        }
        
        // 2. 判断是否有序,以及升序 or 降序
        boolean up = false;
        for (int i = 0; i < array.length - 1; i++) {
            if (array[i] < array[i+1]) {
                if (i+1 == array.length-1) { // 遍历到最大下标才算
                    up = true; // 降序
                }
            } else if (array[i] > array[i + 1]) {
                if (i+1 == array.length - 1) { // 遍历到最大下标才算
                    up = false; // 升序
                }
            } else {
                return -1;
            }
        }
        
        // 3. 二分查找主逻辑循环
        int minIndex = 0;
        int maxIndex = array.length - 1;
        int midIndex;
        while (minIndex <= maxIndex) { // maxIndex/minIndex动态变化,折半遍历
            midIndex = (minIndex + maxIndex) / 2;
            if (array[midIndex] > a) {
                if (up) {
                    maxIndex = midIndex-1; // 升序左移
                } else {
                    minIndex = midIndex+1; // 降序右移
                }
            } else if (array[midIndex] < a) {
                if(up) {
                    minIndex = midIndex+1; // 升序右移
                } else {
                    maxIndex = midIndex-1; // 降序左移
                }
            } else { // array[midIndex] == a
                return midIndex;
            }
        }
        
        return -1;
    }
}

你可能感兴趣的:(Java算法排序之冒泡/插入/选择/快速、二分查找 - 附动图)