常用排序算法及代码示例(Java)

既然容易忘记,那就记录一下,偶尔回头看看当初的起跑点

数据来源来极客时间王争哥的《数据结构与算法之美》

1.冒泡排序:通过每一次遍历获取最大/最小值,将最大值/最小值放在尾部/头部,然后除开最大值/最小值,剩下的数据在进行遍历获取最大/最小值

int[] arr = {9, 5, 8, 1, 2, 6};
int len = arr.length;
for (int i = 0; i < len; i++) {
    //内层循环一次,获取一个最大值
    for (int j = 0; j < len - i -1; j++) {
        if (arr[j] > arr[j + 1]) {
            int temp = arr[j + 1];
            arr[j + 1] = arr[j];
            arr[j] = temp;
        }
    }
}
/** 过程
5	8	1	2	6	9	
5	1	2	6	8	9	
1	2	5	6	8	9	
1	2	5	6	8	9	
1	2	5	6	8	9	
1	2	5	6	8	9
*/
  1. 选择排序:将第一个元素当作最小值,遍历后面的元素,若小于前面的最小值,则记录最小值和下标,遍历结束后查记录的下标与当前下标是否一致,不一致则交换最小值。
for (int i = 0; i < len; i++) {
    int min = arr[i];// 默认当前最小
    int index = i;// 记录下标

    for (int j = i + 1; j < len; j++) {
        // 若最小值大于遍历到的元素,则记录下标
        if (min > arr[j]) {
            min = arr[j];
            index = j;
        }
    }
    // 判断下标是否改变,改变则交换
    if (index != i) {
        int temp = arr[i];
        arr[i] = min;
        arr[index] = temp;
    }
}
/** 排序过程:
1	5	8	9	2	6	
1	2	8	9	5	6	
1	2	5	9	8	6	
1	2	5	6	8	9	
1	2	5	6	8	9	
1	2	5	6	8	9
*/
  1. 插入排序:将前面的数据看作是一个有序列表,从第二个元素开始,若比前面的数据小,则交换,否则退出
for (int i = 1; i < len; i++) {
    for (int j = i; j > 0; j--) {
        if (arr[j] < arr[j - 1]) {
            int temp = arr[j - 1];
            arr[j - 1] = arr[j];
            arr[j] = temp;
        } else {
            break;
        }
    }
}
/** 排序过程:
5	9	8	1	2	6	
5	8	9	1	2	6	
1	5	8	9	2	6	
1	2	5	8	9	6	
1	2	5	6	8	9
*/
  1. 希尔排序:基本上和插入排序一样的道理,不一样的地方在于,每次循环的步长,通过减半的方式来实现
//希尔排序(插入排序变种版)
for (int i = arr.length / 2; i > 0; i /= 2) {
    //i层循环控制步长
    for (int j = i; j < arr.length; j++) {
        //j控制无序端的起始位置
        for (int k = j; k > 0  && k - i >= 0; k -= i) {
            if (arr[k] < arr[k - i]) {
                int temp = arr[k - i];
                arr[k - i] = arr[k];
                arr[k] = temp;
            } else {
                break;
            }
        }
    }
    //j,k为插入排序,不过步长为i
}
/** 排序过程:
9	5	1	8	2	6	
9	5	1	2	8	6	
9	5	1	2	6	8	
5	9	1	2	6	8	
1	5	9	2	6	8	
1	2	5	9	6	8	
1	2	5	6	9	8	
1	2	5	6	8	9
*/
  1. 快速排序:选择一个中间值,可以是第一个也可以是最后一个,然后把数组里的元素以中间值进行划分,小的放左边,大的放右边,再递归的对左右两边的进行快速排序。
public void quickSort() {
    doQuickSort(arr, 0, len - 1);
    for (int m : arr) {
        System.out.print(m + "\t");
    }
}
public static void quickSort(int[] arr, int low, int high) {
    //如果指针在同一位置(只有一个数据时),退出
    if (high - low < 1) {
        return;
    }
    //标记,从高指针开始,还是低指针(默认高指针)
    boolean flag = true;
    //记录指针的起始位置
    int start = low;
    int end = high;
    //默认中间值为低指针的第一个值
    int midValue = arr[low];
    while (true) {
        //高指针移动
        if (flag) {
            //如果列表右方的数据大于中间值,则向左移动
            if (arr[high] > midValue) {
                high--;
            } else if (arr[high] < midValue) {
                //如果小于,则覆盖最开始的低指针值,并且移动低指针,标志位改成从低指针开始移动
                arr[low] = arr[high];
                low++;
                flag = false;
            }
        } else {
            //如果低指针数据小于中间值,则低指针向右移动
            if (arr[low] < midValue) {
                low++;
            } else if (arr[low] > midValue) {
                //如果低指针的值大于中间值,则覆盖高指针停留时的数据,并向左移动高指针。切换为高指针移动
                arr[high] = arr[low];
                high--;
                flag = true;
            }
        }
        //当两个指针的位置相同时,则找到了中间值的位置,并退出循环
        if (low == high) {
            arr[low] = midValue;
            break;
        }
    }
    //然后出现有,中间值左边的小于中间值。右边的大于中间值。
    //然后在对左右两边的列表在进行快速排序
    quickSort(arr, start, low -1);
    quickSort(arr, low + 1, end);
}
  1. 归并排序:将一个数组平均拆分成两个数组,然后再递归拆分,再将拆分的数组左边与右边进行比较进行排序放入一个临时数组(大小为两个数组之和),最后将排好序的临时数组按下标赋值给原数组并返回。需要额外空间
public void mergeSort() {
    doMergeSort(arr, 0, len - 1);
    for (int m : arr) {
        System.out.print(m + "\t");
    }
}

public void doMergeSort(int[] arr, int start, int end) {
    //判断拆分的不为最小单位
    if (end - start > 0) {
        int mid = (start + end) / 2;
        //再一次拆分,直到拆成一个一个的数据
        doMergeSort(arr, start, mid);
        doMergeSort(arr, mid + 1, end);
        //记录开始/结束位置
        int left = start;
        int right = mid + 1;
        //记录每个小单位的排序结果
        int index = 0;
        int[] result = new int[end - start + 1];
        //如果拆分后的两块数据,都还存在
        while (left <= mid && right <= end) {
            //比较两块数据的大小,然后赋值,并且移动下标
            if (arr[left] <= arr[right]) {
                result[index] = arr[left];
                left++;
            } else {
                result[index] = arr[right];
                right++;
            }
            //移动单位记录的下标
            index++;
        }
        //当某一块数据不存在了时
        while (left <= mid || right <= end) {
            //直接赋值到记录下标
            if (left <= mid) {
                result[index] = arr[left];
                left++;
            } else {
                result[index] = arr[right];
                right++;
            }
            index++;
        }
        //最后将新的数据赋值给原来的列表,并且是对应分块后的下标。
        for (int i = start; i <= end; i++) {
            arr[i] = result[i - start];
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值