数组排序 —— 常用基础数组排序算法(冒泡、选择、插入、归并、快速、堆、希尔、计数、基数排序)

冒泡排序

解题思路
  1. 1 ~N个数字,”自己”与”下一位”比较,选中最大的放在”下一位”,再以”下一位”为”自己”与”下一位”比较,直到选出最大的数字放在最后
  2. 1~ N-1 个数字,重复第一步骤操作
  3. 直到剩下最后一个数字
代码思路
代码
 public int[] bubbleSort(int[] A, int n) {
        int temp = 0;
        // “需要排序”的个数
        for (int i = 0; i < n-1; i++){
            // 选出最大的一位放在“需要排序”的最后
            for (int j = 0; j < n-1-i; j++){
                if (A[j] > A[j+1]){
                    temp = A[j];
                    A[j] = A[j+1];
                    A[j+1] = temp;
                }
            }
        }
        return A;
    }

选择排序

解题思路
  1. 从1 ~ N 个数字中选择最小的数字放在”第一个”
  2. 从2 ~ N 个….(重复第一步骤)
  3. 直到剩下最后一个数字
代码思路
代码
 public int[] selectionSort(int[] A, int n) {
        int temp = 0;
        for (int i = 0; i < n-1; i++){
            for (int j = i; j < n; j++){
                if (A[i] > A[j]){
                    temp = A[i];
                    A[i] = A[j];
                    A[j] = temp;
                }
            }
        }
        return A;
    }

插入排序

解题思路
  1. 第2个数与第1个数比较,小的插入前边
  2. 第3个数与依次和前2个比较,插入比它小的位置
  3. 依次重复步骤2
  4. 直到剩下0个数
代码思路
代码
  public int[] insertionSort(int[] A, int n) {
        int temp = 0;
        for (int i = 1; i < n; i++){
            int current = i;
            for (int j = i-1; j >= 0; j--){
                if (A[current] < A[j]){
                    temp = A[current];
                    A[current] = A[j];
                    A[j] = temp;
                    current = j;
                }
            }
        }
        return A;
    }

归并排序

解题思路

分类:

  1. 按照递归方法,两两平分,直到长度为“1”;

合并:

  1. 相邻的两两数字 长度为“1”的合并区间,且排好序;
    1. 相邻的两两数字 长度为“2”的合并区间,且排好序;
    2. 相邻的两两数字 长度为“3”的合并区间,且排好序;
    3. 直到长度为“N”

提示:

两个有序数据的合并 排序算法。

代码思路
代码
  public int[] mergeSort(int[] A, int n) {
        sort(A, 0, n-1);
        return A;
    }

    public void sort(int[] A, int left, int right){
        if (left >= right)
            return ;
        int middle = (left + right) / 2;
        // 分类
        sort(A, left, middle);
        sort(A, middle+1 , right);
        // 合并且从小排序
        merge(A, left, middle, right);
    }

    public void merge(int[] A, int left, int middle, int right){
        // 缓存数组;
        int[] buffer = new int[right-left+1];        
        // 缓存索引;
        int bufferIndex = 0;
        // 左边索引
        int leftIndex = left;
        // 右边索引
        int rightIndex = middle+1;

        // 将最小的数字存进缓存数组( 两个有序数据的合并 排序算法)
        while (leftIndex <= middle && rightIndex <= right){
            if (A[leftIndex] < A[rightIndex]){
                buffer[bufferIndex++] = A[leftIndex++];
            }
            else{
                buffer[bufferIndex++] = A[rightIndex++];
            }
        }
        // 将左边还剩余的数字存入数组
        while (leftIndex <= middle){
            buffer[bufferIndex++] = A[leftIndex++];
        }
        // 将右边还剩余的数字存入数组
        while (rightIndex <= right){
            buffer[bufferIndex++] = A[rightIndex++];
        }        
        // 将缓存数组数据存进"A"源数组里
        bufferIndex = 0;
        for (int i = left; i <= right; i++){
            A[i] = buffer[bufferIndex++];
        }
    }

快速排序

解题思路
  1. 选中第一个数据(可随机数据),进行排序,小于该数据,放左边,大于放右右,且返回该数据最终所在的索引
  2. 如此进行遍历…

提示:

划分过程时间复杂度为O(N)

代码思路
代码
public int[] quickSort(int[] A, int n) {
        if (n > 0){
            quick(A, 0, n-1);
        }
        return A;
    }
    public void quick(int[] A, int low, int high){
        if (low < high){
            // 排序划分
            int middle = getMiddle(A, low, high);        
            quick(A, low, middle);
            quick(A, middle+1, high);
        }
    }
    public int getMiddle(int[] A, int low, int high){
        int temp = A[low];
        // 小于 temp 放左边,大于 temp 放右边
        while (low < high)
        {
            while (low < high && A[high] >= temp){
                high--;
            }
            A[low] = A[high];
            while (low < high && A[low] <= temp){
                low++;
            }
            A[high] = A[low];
        }
        A[low] = temp;
          return low;
    }

堆排序

解题思路

大根堆,小根子
以下所建的堆是大根堆

  1. 构建堆,且每个节点为子节点的最大值(需要对每个节点进行排序)

    a)先比较子节点,选出一个最大值
    b)最大子节点与节点比较。
    c)如果节点小于子节点,交换,节点继续与字字节点比较,重复步骤a、b
    d)最终达到节点(包括交换后的子节点)为最大值的目的

  2. 把第一个值与最后一直交换,个数为n-1,继续重复步骤1(只需要对第一个节点排序)

  3. 直到只剩下最后一个数
代码思路
代码
 public static void buildHeap(int[] A, int node, int n) {

        int temp = A[node];
        // 因为从 0 开始,所以需要加上 1
        for (int i = node * 2 + 1; i < n; i = i*2 +1) {
            // 防止没有右节点
            if (i < n-1){
                // 左右节点比较
                if (A[i] < A[i + 1]){        
                    i++;
                }
            }
            // node节点与子节点比较,如果大于就不需要再比较了
            if (temp >= A[i]) {
                break;
            }
            A[node] = A[i];
            node = i;
        }
        A[node] = temp;
    }
 public static void swap(int[] A, int a, int b) {
        int temp = A[a];
        A[a] = A[b];
        A[b] = temp;
    }

    public static int[] heapSort(int[] A, int n) {

        // 开始的时候先排序,让每个节点为子节点的最大数
        for (int i = n / 2-1; i >= 0; i--) {
            buildHeap(A, i, n);

        }
        // 将第一位根节点最大数与最后一位交换,个数减一,接着构建根节点,再交换...
        for (int i = n-1; i > 0; i--) {
            swap(A, 0, i);            // i 为末尾数
            buildHeap(A, 0, i);        //    i 为还剩下的个数,包括 0 位,所以就不减一了!
        }
        return A;
    }


希尔排序

解题思路
  1. 根据 n/2 分组,直到组的长度为1(插入排序的分组为1,并且进行第二步)
  2. 一共有feet组,每组都进行头尾排序,且排序后的数据还得继续和前边距离feet长度进行收尾排序(n–, 重复步骤1、2)

提示:

插入排序的步长为1,从开始就和距离为1的比较。希尔排序是插入排序的优化版

代码思路
代码
  public int[] shellSort(int[] A, int n) {
      // 根据 n/2 分组,直到组的长度为1
        for (int feet = n/2; feet >= 1; feet = feet/2){
            // 一共有feet组,每组都进行头尾排序
            for (int i = 0; i < feet; i++){
                for (int j = i+feet; j < n; j = j+feet){
                    int temp = A[j];
                    int k = 0;
                    // 每组的头尾进行排序,且排序后的数据还得继续和前边距离feet长度进行收尾排序
                    for (k = j-feet; k >= 0 && A[k] > temp; k = k-feet){
                            A[k+feet] = A[k];
                    }
                    A[k+feet] = temp;
                }
            }
        }
    }

计数排序

解题思路
  1. 从数组A里获得最大与最小的值
  2. 根据最大最小值new 一个大小为 max-min 的数组B
  3. 将无序数组的元素根据 (值 - min) 放入数组B中
  4. 将数组B里元素有序地放入源无序数组中
代码思路
代码
  public int[] countingSort(int[] A, int n) {

        int min = A[0];
        int max = A[0];
        // 从数组里获得最大与最小的值
        for (int i = 1; i < n; i++){
            min = Math.min(min, A[i]);
            max = Math.max(max, A[i]);
        }
        // 根据最大最小值new 一个大小为 max-min 的数组B
        int[] B = new int[max-min+1];
        // 将无序数组的元素根据 (值 - min) 放入数组B中
        for (int i = 0; i < n; i++){
            B[A[i]-min] += 1;
        }
        // 将数组B里元素有序地放入源无序数组中
        int index = 0;
        for (int i = 0; i < B.length; i++){
            while(B[i] > 0){
                A[index++] = i+min;
                B[i]--;
            }
        }
         return A;  
    }

基数排序

解题思路
  1. 求出数组里最大数据,且根据最大数求出最大的位数
  2. 首先进行 d = 1 (个数) 分别装桶,然后按顺序倒出来
  3. 再进行 d = 2 (十数)分别装桶,然后按顺序倒出来
  4. 直到d = 最大的位数
代码思路
代码
 public int[] radixSort(int[] A, int n) {

        // 构建二维水桶
        int bucket[][] = new int[10][A.length];
        // 每个位数(0~9)装的数字个数
        int count[] = new int[10];

        /**
        *    取最大值,且求出最大的位数
        **/
        int max = A[0];
        for (int i = 1; i < A.length; i++){
            max = Math.max(max, A[i]);
        }
        int d = 1;            // 位数
        int a = 10;            // 10的倍数,求商
        while ((max / a) > 0){
            a *= 10;
            d++;
        }
        a = 1;
        int num = 0;

        while (d > 0){
            // 位数排序,例如 d = 1时,为个数排序, d = 2时,为十数排序...
            for (int i = 0; i < A.length; i++){
                num = A[i] / a % 10;
                bucket[num][count[num]++] = A[i];
            }
            // 将排序好的数据重新装到源A数组里
            int index = 0;
            for (int i = 0; i < 10; i++){
                for (int j = 0; j < count[i]; j++){
                    A[index++] = bucket[i][j];
                }
                count[i] = 0;
            }
            a *= 10;
            d--;
        }
        return A;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值