排序算法模板

排序算法模板

初级排序

初级排序 - O(n2)

1. 选择排序:每次找最小值,然后放到待排序数组的起始位置

public int[] selectionSort(int[] arr) {
    int len = arr.length;
    int minIndex, temp;
    for (int i = 0; i < len - 1; i++) {
        minIndex = i;
        for (int j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}

2. 插入排序:从前到后逐步构建有序序列;对于未排序数据,在已排序序列中从后往前扫描,找到相应位置并插入

public int[] insertionSort(int[] arr) {
    int len = arr.length;
    int preIndex,  current;
    for (int i = 1; i < len; i++) {
        preIndex = i - 1;	// 当前有序序列的最后一个元素
        current = arr[i];
        // 当前面的元素比当前元素大,则把前面的元素往后移
        while (preIndex >= 0 && arr[preIndex] > current) {
            arr[preIndex + 1] = arr[preIndex];
            preIndex--;
        }
        arr[preIndex + 1] = current;
    }
    return arr;
}

3. 冒泡排序:嵌套循环,每次查看相邻的元素如果逆序,则交换

public int[] bubbleSort(int[] arr) {
    int len = arr.length;
  	if (len < 2) return;
    for(int i = 1; i < len; i++) {
        for (int j = 0; j < len - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}

思考一下:如果冒泡排序还可以优化吗?
答案是肯定的。如果在最理想的状态下,数列本身就是有序的,同样要O(n2)的处理时间,那太浪费性能了。
优化思路:冒泡排序在第一次遍历之后,是一定可以确定末尾就是数列中的最大值(针对升序排序的场景),如果在内层循环的遍历中,没有发生换位操作,岂不是可以说明数列本身就是有序的,可以终止外层操作了呢?这样一来就可以把冒泡排序在最佳的情况下是O(n)的时间复杂度。

public int[] bubbleSort(int[] arr) {
    int len = arr.length;
  	if (len < 2) return;
  	// 增加换位标识,默认是未发生换位
  	boolean flag = false;
    for(int i = 1; i < len; i++) {
        for (int j = 0; j < len - i; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                // 已发生换位处理
                flag = true;
            }
        }

		// 如果未发生换位,则说明序列本身有序
        if (!flag) {
        	break;
        }
    }
    return arr;
}

高级排序 - O(N*LogN)

1. 快速排序

数组取标杆 privot,将小元素放 privot 左边, 大元素放右侧,然后依次对右边和右边的子数组继续快排,以达到整个序列有序。

public static void quickSort(int[] array, int begin, int end) {
    if (end <= begin) return;
    int pivot = partition(array, begin, end);
    quickSort(array, begin, pivot - 1);
    quickSort(array, pivot + 1, end);
}

public int partition(int[] a, int begin, int end) {
    int pivot = end, counter = begin;
    for (int i = begin; i < end; i++) {
        if (a[i] < a[pivot]) {
            int temp = a[counter]; a[counter] = a[i]; a[i] = temp;
            counter++;
        }
    }
    int temp = a[pivot]; a[pivot] = a[counter]; a[counter] = temp;
    return counter;
}

2. 归并排序 - 分治

1. 把长度为 n 的输入序列分成两个长度为 n/2的子序列;
2. 对这两个子序列分别采用归并排序;
3. 将两个排序好的子序列合并成一个最终的排序序列
public static void mergeSort(int[] array, int left, int right) {
    if (right <= left) return;
    int mid = (left + right) >> 1;
    mergeSort(array, left, mid);
    mergeSort(array, mid + 1, right);
    merge(array, left, mid, right);
}

public static void merge(int[] arr, int left, int mid, int right) {
    int[] temp = new int[right - left + 1]; // 中间数组
    // i 是左边数组的起始位置,j 是右边数组的起始位置,k 是temp数组已经填入的元素下标
    int i = left, j = mid + 1, k = 0;
    while (i <= mid && j <= right) {
        temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
    }
    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];
    
    // 将 temp copy 到了 arr 里面去 
    for (int p = 0; p < temp.lenght; p++) {
        arr[left + p] = temp[p];
    }
}
区分:
1. 归并 和 快排 具有相似性,但步骤顺序相反;
2. 归并:先排序左右子数组,然后合并两个有序子数组;
3. 快排:先调配出左右子数组,然后对于左右子数组进行排序

3. 堆排序 - 堆插入 O(logN),取最大/小值O(1)

1. 数组元素依次建立小顶堆
2. 依次取堆顶元素,并删除
public static void heapify(int[] array, int length, int i) {
    int left = 2 * i + 1, right = 2 * i + 2;
    int largest = i;
    
    if (left < length && arrray[left] > array[largest]) {
        largest = left;
    }
    if (left < length && arrray[right] > array[largest]) {
        largest = right;
    }
    
    if (largest != i) {
        int temp = array[i]; array[i] = array[largest]; array[largest] = temp;
        heapify(array, length, largest);
    }
}

public static void heapSort(int[] array) {
    if (array.length == 0) return;
    
    int length = array.length;
    for (int i = length / 2 - 1; i >= 0; i--)
        heapify(array, length, i);
    for (int i = length - 1; i >= 0; i--) {
        int temp = array[0]; array[0] = array[i]; array[i] = temp;
        heapify(array, i, 0);
    }
}

实战题目

有效字母异位词:https://leetcode-cn.com/problems/valid-anagram/

合并区间:https://leetcode-cn.com/problems/merge-intervals/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值