部分排序算法

1 篇文章 0 订阅
1 篇文章 0 订阅

排序

稳定性:在一个数组中,有相同两个元素,在排序后这两个元素的前后顺序不变

eg:

排序前:5,3,1,3,6

排序后:1,3,3,5,6

简单排序

1.冒泡排序

原理:数字大的就往下沉,数字小的就往上升

时间复杂度:O(n^2)

稳定性:稳定

private static void sort(int[] arr) {
        int len = arr.length;
        for (int i = len - 1; i >= 0; i--) {
            for (int j = 0; j < i; j++) {
                if (arr[i] < arr[j]) {
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }

2.选择排序

原理:遍历整个数组,默认i下标元素最小,再次遍历整个数组(从i+1下标开始),如果有遇到最小元素下标大于j下标元素,则更新最小下标,最后将i下标与最小元素下标进行交换。

时间复杂度:O(n^2)

稳定性:不稳定

private static void sort(int[] arr) {
        int length = arr.length;
        //从第一个元素开始,比到倒数第二个元素
        for (int i = 0; i < length - 1; i++) {
            //默认i位置的元素为最小元素
            int minIndex = i;
            //从i+1位置开始比较,比到最后一个元素
            for (int j = i + 1; j < length; j++) {
                //最小位置元素大于j索引位置的元素时,更新minIndex
                if (arr[j] < arr[minIndex]) {
                    minIndex = j;
                }
            }
            //默认位置的索引不是最小元素时,才进行交换
            if (minIndex != i) {
                //交换i和minIndex索引索引位置元素
                int temp = arr[i];
                arr[i] = arr[minIndex];
                arr[minIndex] = temp;
            }
        }
    }

3.插入排序

原理:将数组分成两组,前一组是排好序的,后一组是待排序的,每一次用待排序的第一个元素与排好序的最后一个元素比较,如果小于,则进行交换。继续比较下一个。

时间复杂度:O(n^2)

稳定性:稳定

private static void sort(int[] arr) {
        int length = arr.length;
        //从1号索引开始比较,0号索引自己与自己比,没实际意义
        for (int i = 1; i < length; i++) {
            //0到i索引之间的元素已经排好序的
            for (int j = i; j > 0; j--) {
                //j索引元素小于j-1索引位置,则需要交换
                if (arr[j] < arr[j - 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                } else {
                    //j索引元素大于j-1索引位置,j-1之前的元素不可能大于j了,跳出循环
                    break;
                }
            }
        }
    }

高级排序

1.希尔排序

原理:是插入排序的优化版,通过增量分组,然后对分组内的数据进行排序,然后增量减小一半,再对分组内的数据进行排序,直到增量小于1为止。

时间复杂度:O(n^(1.3-2))

稳定性:不稳定

private static void sort(int[] arr) {
        int length = arr.length;
        //增量
        int h = 1;
        int high = length / 2;
        //增量取值,固定写法
        while (h < high) {
            h = 2 * h + 1;
        }
        while (h >= 1) {
            //h下标是第一个需要排序的索引下标,在h之前的元素都是已经排好序的
            for (int i = h; i < length; i++) {
                //从i开始,慢慢往前移动,移动到h时,就是0索引
                for (int j = i; j >= h; j--) {
                    //j-h下标元素大于j下标元素,则需要移动
                    if (arr[j - h] > arr[j]) {
                        int temp = arr[j - h];
                        arr[j - h] = arr[j];
                        arr[j] = temp;
                    } else {
                        break;
                    }
                }
            }
            //固定写法,每一次循环完数组长度之后,增量减小一半
            h = h / 2;
        }
    }

2.归并排序

原理:将数组分到不能再分的n组,然后在将相邻的两个小数组进行合并同时排序

时间复杂度:O(nlogn)

稳定性:稳定

/**
* 临时数组,用于存放已经排好序的元素
*/
private static int[] temp;

private static void sort(int[] arr) {
        int low = 0;
        int length = arr.length;
        //初始化临时数组
        temp = new int[length];
        int high = length - 1;
        sort(arr, low, high);
    }

    /**
     * 将数组分隔为多个小数组
     */
    private static void sort(int[] arr, int low, int high) {
        //结束递归的条件
        if (high <= low) {
            return;
        }
        //取中间位置的索引
        int mid = (low + high) / 2;
        //将数组从中间位置分为2个数组
        sort(arr, low, mid);
        sort(arr, mid + 1, high);
        //合并数组并排序
        merge(arr, low, mid, high);
    }

    /**
     * 合并数组并排序
     */
    private static void merge(int[] arr, int low, int mid, int high) {
        //指向临时数组的指针
        int i = low;
        //指向arr左边数组的指针
        int p1 = low;
        //指向arr右边数组的指针
        int p2 = mid + 1;
        //左边数组指针下标索引大于左边数组长度或右边数组指针下标索引大于右边数组长度时,结束循环
        while (p1 <= mid && p2 <= high) {
            //将小的元素添加进临时数组中
            if (arr[p1] <= arr[p2]) {
                temp[i++] = arr[p1++];
            } else {
                temp[i++] = arr[p2++];
            }
        }
        //右边已经走完,而左边还有元素时,进入此循环
        while (p1 <= mid) {
            temp[i++] = arr[p1++];
        }
        //左边已经走完,而右边还有元素时,进入此循环
        while (p2 <= high) {
            temp[i++] = arr[p2++];
        }
        //将临时数组中的元素赋值给原数组
        if (high + 1 - low >= 0) {
            System.arraycopy(temp, low, arr, low, high + 1 - low);
        }
    }

3.快速排序

原理:默认选取第一个元素作为分界值,定义left和right指针,left指向第一个元素,right指向最后一个元素后一个位置,right–,直到找到比分界值小的数,指针停止移动,然后left++,直到找到比分界值大的元素,然后停止,然后交换left和right的值,重复上述操作,直到left>=right。最后交换分界值和right指向元素的值,重复此操作。

时间复杂度:O(nlogn)

稳定性:不稳定

private static void sort(int[] arr) {
    sort(arr, 0, arr.length - 1);
}

private static void sort(int[] arr, int lo, int hi) {
    if (lo >= hi) {
        return;
    }
    //分隔数组,返回分界值新的下标
    int partition = partition(arr, lo, hi);
    //对分界值左边的进行分组
    sort(arr, lo, partition - 1);
    //对分界值右边的进行分组
    sort(arr, partition + 1, hi);
}

/**
 * 对low索引和high索引之间的数组进行分组
 */
private static int partition(int[] arr, int low, int high) {
    int left = low, right = high + 1, key = arr[low];
    //当left和right在同一个元素上时,跳出循环
    while (left < right) {
        //分界值小于right指向的元素,继续往左移动,否则停在该元素上
        while (key <= arr[--right]) {
            //分界值是最小的
            if (left >= right) {
                break;
            }
        }
        //分界值大于left指向的元素,继续往右移动,否则停在该位置
        while (key >= arr[++left]) {
            //分界值是最大的
            if (left >= right) {
                break;
            }
        }
        if (left >= right) {
            break;
        } else {
            //交换left和right元素
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }
    }
    //交换分界值和right索引位置元素
    int keyIndex = arr[right];
    arr[right] = key;
    arr[low] = keyIndex;
    return right;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值