十大排序算法

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

排序算法概述

排序算法概述

冒泡排序

算法步骤

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

代码实现

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

选择排序

算法步骤

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

代码实现

public static void selectionSort1(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        int maxIndex = 0;
        for (int j = 1; j < arr.length - i; j++) {
            if (arr[j] > arr[maxIndex]) {
                maxIndex = j;
            }
        }
        swap(arr, maxIndex, arr.length - i - 1);
    }
}

public static void selectionSort2(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        int minIndex = i;
        for (int j = i; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        swap(arr, minIndex, i);
    }
}

public static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

插入排序

算法步骤

  1. 将未排序的元素一个一个地插入到有序的集合中,插入时把所有有序集合从后向前扫一遍,找到合适的位置插入。

代码实现

public static void insertionSort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        int tmp = arr[i];
        int newIndex = i;
        for (int j = i - 1; j >= 0; j--) {
            if (tmp < arr[j]) {
                arr[j + 1] = arr[j];
                newIndex = j;
            }
        }
        if (newIndex != i) {
            arr[newIndex] = tmp;
        }
    }
}

希尔排序

算法步骤

  1. 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
  2. 按增量序列个数 k,对序列进行 k 趟排序;
  3. 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

代码实现

public static void shellSort(int[] arr) {
    for (int step = arr.length / 2; step >= 1; step /= 2) {
        for (int i = step; i < arr.length; i++) {
            int tmp = arr[i];
            int newIndex = i;
            for (int j = i - step; j >= 0; j -= step) {
                if (tmp < arr[j]) {
                    arr[j + step] = arr[j];
                    newIndex = j;
                }
            }
            if (newIndex != i) {
                arr[newIndex] = tmp;
            }
        }
    }
}

归并排序

算法步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
  4. 重复步骤 3 直到某一指针达到序列尾;
  5. 将另一序列剩下的所有元素直接复制到合并序列尾。

代码实现

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

private static void mergeSort(int[] arr, int i, int j) {
    if (i >= j) {
        return;
    }
    int mid = (j + i) / 2;
    mergeSort(arr, i, mid);
    mergeSort(arr, mid + 1, j);
    merge(arr, i, mid, j);
}

private static void merge(int[] arr, int i, int mid, int j) {
    int[] res = new int[j - i + 1];
    int cur = 0;
    int p = i;
    int q = mid + 1;
    while (p <= mid && q <= j) {
        if (arr[p] > arr[q]) {
            res[cur++] = arr[q++];
        } else if (arr[p] < arr[q]) {
            res[cur++] = arr[p++];
        } else {
            res[cur++] = arr[q++];
            res[cur++] = arr[p++];
        }
    }
    while (p <= mid) {
        res[cur++] = arr[p++];
    }
    while (q <= j) {
        res[cur++] = arr[q++];
    }
    cur = 0;
    for (int k = i; k <= j; k++) {
        arr[k] = res[cur++];
    }
}

快速排序

算法步骤

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

代码实现

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

private static void quickSort(int[] arr, int i, int j) {
    if (i >= j) {
        return;
    }
    int pivot = arr[i];
    int p = i;
    int q = j;
    while (p <= q) {
        while (q >= 0 && arr[q] > pivot && p <= q) {
            q--;
        }
        while (p < arr.length && arr[p] <= pivot && p <= q) {
            p++;
        }
        if (p <= q) {
            int tmp = arr[p];
            arr[p] = arr[q];
            arr[q] = tmp;
        }
    }
    int tmp = arr[q];
    arr[q] = pivot;
    arr[i] = tmp;
    quickSort(arr, i, q - 1);
    quickSort(arr, q + 1, j);
}

堆排序

算法步骤

  1. 创建一个堆 H[0……n-1];
  2. 把堆首(最大值)和堆尾互换;
  3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置;
  4. 重复步骤 2,直到堆的尺寸为 1。

代码实现

private static void heapSort(int[] arr){
    for(int i = 0; i < arr.length; i++) {
        adjustHeap(arr, arr.length - i);
        swap(arr, 0, arr.length - i - 1);
    }
}

/**
 * 调整数组前n位成堆
 * @param arr 数组
 * @param toIndex 前n位的截止下标
 */
private static void adjustHeap(int[] arr, int toIndex) {
    for (int i = 0; i < toIndex; i++) {
        shiftUp(arr, i);
    }
}

/**
 * 对于大顶堆,如果指定节点的数值比父节点大的话,就交换位置,即上升,一直递归上升到合适的位置时结束
 * @param arr 数组
 * @param index 指定节点的下标
 */
private static void shiftUp(int[] arr, int index) {
    if (index > 0 && index < arr.length) {
        int parentIndex = (index - 1) / 2;
        if (arr[parentIndex] < arr[index]) {
            swap(arr, parentIndex, index);
        }
        shiftUp(arr, parentIndex);
    }
}

/**
 * 交换数组的两个指定位置的值
 * @param arr 数组
 * @param i1 指定位置下标1
 * @param i2 指定位置下标2
 */
private static void swap(int[] arr, int i1, int i2) {
    int tmp = arr[i1];
    arr[i1] = arr[i2];
    arr[i2] = tmp;
}

计数排序

算法步骤

  1. 找出待排序的数组中最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

代码实现

public static void countingSort(int[] arr){
    int max = 0;
    for(int i = 0; i < arr.length; i++){
        if(arr[i] > max){
            max = arr[i];
        }
    }
    int[] count = new int[max + 1];
    for (int value : arr) {
        count[value] += 1;
    }
    System.out.println(Arrays.toString(count));
    int cur = 0;
    for(int i = 0; i < count.length; i++){
        int num = count[i];
        for(int j = 0; j < num; j++){
            arr[cur++] = i;
        }
    }
}

桶排序

算法步骤

  1. 取序列中的最大值max和最小值min,取桶的个数 为(max-min)/arr.length+1个桶,桶的 范围是arr.length,其中的加1是为解决桶是(arr[i]-min)/arr.length作为索引,则当是最大值时,最大索引是(arr[i]-min)/arr.length,则总的数量为(arr[i]-min)/arr.length+1。
  2. 遍历序列,则将其放入到(arr[i]-min)/arr.length的桶中
  3. 每个桶中的元素分别做快速排序
  4. 遍历所有的桶,则完成了排序

代码实现

public static void bucketSort(int[] arr) {
    // 计算最大值与最小值
    int max = Integer.MIN_VALUE;
    int min = Integer.MAX_VALUE;
    for (int item : arr) {
        max = Math.max(max, item);
        min = Math.min(min, item);
    }

    // 计算桶的数量
    int bucketNum = (max - min) / arr.length + 1;
    ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
    for (int i = 0; i < bucketNum; i++) {
        bucketArr.add(new ArrayList<>());
    }

    // 将每个元素放入桶
    for (int value : arr) {
        int num = (value - min) / (arr.length);
        bucketArr.get(num).add(value);
    }

    // 对每个桶进行排序
    for (ArrayList<Integer> integers : bucketArr) {
        Collections.sort(integers);
    }

    // 将桶中的元素赋值到原序列
    int index = 0;
    for (ArrayList<Integer> integers : bucketArr) {
        for (Integer integer : integers) {
            arr[index++] = integer;
        }
    }
}

基数排序

算法步骤

  1. 确定数组中的最大元素有几位(MAX)(确定执行的轮数)
  2. 创建0 ~ 9个桶(桶的底层是队列),因为所有的数字元素都是由0 ~ 9的十个数字组成
  3. 依次判断每个元素的个位,十位至MAX位,存入对应的桶中,出队,存入原数组;直至MAX轮结束输出数组

代码实现

public static void radixSort(int[] arr) {
    int[][] bucket = new int[10][arr.length]; //排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
    int[] counts = new int[10]; //用于保存每个桶里有多少个数字

    int max = Integer.MIN_VALUE;
    for (int value : arr) {
        max = Math.max(max, value);
    }
    int n = 1;//代表位数对应的数:1,10,100...
    while (n < max) {
        for (int num : arr) {
            int digit = (num / n) % 10;
            bucket[digit][counts[digit]] = num;
            counts[digit]++;
        }
        int curIndex = 0;
        for (int j = 0; j < 10; j++) {
            for (int k = 0; k < counts[j]; k++) {
                arr[curIndex++] = bucket[j][k];
            }
            counts[j] = 0;//计数器置为0,用于下一次位排序
        }
        n *= 10;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值