排序归纳 Java版

根据 左神课程 整理补充的排序知识!
如果有帮助,记得三连哦!

排序归纳

  • 简单排序
    • 选择排序
    • 冒泡排序
    • 插入排序
  • 特殊排序
    • 归并排序
    • 快速排序(实际使用比堆排序快)
    • 堆排序
  • 桶排序
    • 计数排序
    • 基数排序

Created: November 17, 2022 10:53 AM

简单排序

选择排序

• 时间O(N^2) 、空间O(1)、不稳

   public void selectSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 0; i < arr.length; i++) { // i - N-1
            int minValue = i;
            for (int j = i + 1; j < arr.length; j++) { // i - N-1 找到最小值的下标
                minValue = arr[minValue] > arr[j] ? j : minValue;
            }
            swap(arr, minValue, i); //最小值放最左边
        }
    }

    private void swap(int[] arr, int minValue, int i) {
        int temp = arr[minValue];
        arr[minValue] = arr[i];
        arr[i] = temp;
    }

冒泡排序

• 时间O(N^2) 、空间O(1)、稳

		private void swap(int[] arr, int i, int j) {
        arr[i] = arr[i] ^ arr[j];
        arr[j] = arr[i] ^ arr[j];
        arr[i] = arr[i] ^ arr[j];
    }

    public void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = arr.length - 1; i > 0; i--) { // 玩N轮
            for (int j = 0; j < i; j++) { //每轮将当前和下一个比大小,谁大谁往右
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j, j + 1);
                }
            }
        }
    }

插入排序

  • 时间O(N^2) 、空间O(1)、稳
public void insertionSort(int[] arr) {
    if (arr == null || arr.length < 2) return;
		// 0~0上有序,0~i想有序
    for (int i = 0; i < arr.length; i++) { // 0 - i做到有序
        for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
            swap(arr, j, j + 1);
        }
    }
}
private void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
}

特殊排序

归并排序

• 时间O(NlogN)、空间O(N)、稳

		public void mergeSort(int arr[]) {
		        process(arr, 0, arr.length - 1);
		    }
		
    public void process(int[] arr, int L, int R) {
        if (L == R) return; //只有一个数字就不处理
        int mid = L + ((R - L) >> 1);//中点
        process(arr, L, mid); //左边排好序
        process(arr, mid + 1, R); //右边排好序
        merge(arr, L, mid, R);//利用外排序将左右两边排好序
    }

    private void merge(int[] arr, int L, int M, int R) {
        int[] help = new int[R- L + 1]; //外排序的辅助空间
        int i = 0; //外排序的索引
        int p1 = L; //左边排好序的索引
        int p2 = M + 1; //右边排好序的索引
        //左右比较,谁小放进去,总有一个会越界
        while (p1 <= M && p2 <= R) {
						//相等的情况下先左后右
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        //肯定有越界的情况,但是help肯定不满,下面情况只会中一个
        while (p1 <= M) {
            help[i++] = arr[p1++];
        }
        while (p2 <= R) {
            help[i++] = arr[p2++];
        }
        //将外排序的东西返回原数组
        for (int j = 0; j < help.length; j++) {
            arr[L + j] = help[j];
        }
    }

快速排序(实际使用比堆排序快)

• 时间O(NlogN) 、空间O(logN)、不稳

		public void quicksort(int arr[], int l, int r) {
        if (l < r) {
            //随机抽取一个放到最后面作为比较值
            swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
            //荷兰国旗问题,最后一个值作为v,p代表左右边界
            int[] p = partition(arr, l, r);
            //对<区域
            quicksort(arr, l, p[0] - 1);
            //对>区域
            quicksort(arr, p[1] + 1, r);
        }
    }

    public int[] partition(int arr[], int l, int r) {
        // input: 3,6,2,5,7,5
        int less = l - 1;//< 区域
        //这里r是因为,最后一个r表示荷兰问题中value
        //l ~ r-1 之前表示荷兰问题
        int more = r;//> 区域
        //结束条件是 指针和>区域相遇
        while (l < more) {
            if (arr[l] < arr[r]) {
                swap(arr, l++, ++less);
            } else if (arr[l] > arr[r]) {
                swap(arr, l, --more);
            }else {
                l++;
            }
        }
        // 荷兰问题之后:3, 2, 5, 7, 6, 5
        //将最后一个值和>区域的第一个值交换,因为最后一个是=区域的
        swap(arr,r,more);
        // 交换完之后: 3, 2, 5, 5, 6, 7
        return new int[]{less+1,more};
    }

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

堆排序

• 时间O(NlogN)、空间O(1)、不稳

public void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        //将数组变为堆
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }

        int heapsize = arr.length;
        //最大的在堆顶,放到后面,heapsize--,继续堆化调整
        swap(arr, 0, --heapsize);
        while (heapsize > 0) {
            heapify(arr, 0, heapsize);
            swap(arr, 0, --heapsize);
        }
}

public void heapInsert(int[] arr, int i) {
    while (arr[i] > arr[(i - 1) / 2]) {
        swap(arr, i, (i - 1) / 2);
        i = (i - 1) / 2;
    }
}

public void heapify(int[] arr, int i, int heapsize) {
    int left = i * 2 + 1;
    while (left < heapsize) {
        //孩子比较
        int largest = left + 1 < heapsize && arr[left + 1] > arr[left] ? left + 1 : left;
        //父子比较
        largest = arr[largest] > arr[i] ? largest : i;
        //父已经是最大,不用再调整了
        if (i == largest) break;
        //交换调整
        swap(arr, largest, i);
        //下一个调整位置
        i = largest;
        left = i * 2 + 1;
    }
}

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

桶排序

计数排序

  • 时间O(N+K)、空间O(N+K)、稳
public void countingSort(int[] arr) {
    int min = arr[0];
    int max = arr[0];
    for (int i = 0; i < arr.length; i++) {
        min = Math.min(arr[i], min);
        max = Math.max(arr[i], max);
    }
    //生成对应的词频表
    int[] words = new int[max - min + 1];
    for (int i = 0; i < arr.length; i++) {
        words[arr[i] - min]++;
    }
    //生成前缀和
    for (int i = 1; i < words.length; i++) {
        words[i] += words[i - 1];
    }
    int[] sorted = new int[arr.length];
    //逆序输出
    for (int i = arr.length - 1; i >= 0; i--) {
        //查询词汇表中,arr[i]的下标为词频数量--
        int index = --words[arr[i] - min];
        sorted[index] = arr[i];
    }
    for (int i = 0; i < arr.length; i++) {
        arr[i] = sorted[i];
    }
}

基数排序

  • 时间O(N*K)、空间O(N)、稳定
public void radixSort(int[] arr) {
        int max = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {
            max = Math.max(arr[i], max);
        }
        //求得最大值的位数
        int digit = 0;
        while (max != 0) {
            digit++;
            max /= 10;
        }
        //对每一个位进行操作
        for (int i = 0; i < digit; i++) {
            //辅助空间,入桶出桶操作
            int[] bucket = new int[arr.length];
            //每个数字的词频
            int[] words = new int[10];
            //该位上的进制
            int dev = (int) Math.pow(10, i);
            //统计所有数字的该位的词频
            for (int j = 0; j < arr.length; j++) {
                words[arr[j] / dev % 10]++;
            }
            //前缀和
            for (int j = 1; j < 10; j++) {
                words[j] += words[j - 1];
            }
            //逆序输出,查询词频表的数量--就是下标位置
            for (int j = arr.length - 1; j >= 0; j--) {
                bucket[--words[arr[j] / dev % 10]] = arr[j];
            }
            for (int j = 0; j < arr.length; j++) {
                arr[j] = bucket[j];
            }
        }
    }

你可能感兴趣的:(数据结构,java,算法,排序算法)