八大排序(java版)

八大排序算法

 

1、冒泡排序

思想:

(1)相邻两个元素依次比较,保证右边元素大于左边(小于则交换位置),一轮结束后保证最后一个元素一定是最大的元素

(2)对剩下n-1个元素再次执行(1)

(3)第n-1轮执行后序列排序完成

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
冒泡 O(n) O(n^2) O(n^2) O(1) 数据量小,有序 稳定

 

实现代码:

public static void bubbleSort(int data[]) {
        boolean didSwap;
        for (int i = 0; i < data.length - 1; i++) {
            didSwap = false;
            for (int j = 0; j < data.length - i - 1; j++) {
                if (data[j + 1] < data[j] ) {//加等于则不稳定
                    int temp = data[j + 1];
                    data[j + 1] = data[j];
                    data[j] = temp;
                    didSwap = true;
                }
            }
            if (!didSwap) {
                return;
            }
        }
    }

 

2、 选择排序

思想:

(1)从序列中选出最大元素

(2)如果最大元素不是在最后一位,将其互换位置

(3)对剩下的n -1 个元素执行(1)(2)

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
直接选择 O(n^2) O(n^2) O(n^2) O(1) 数据量小 稳定

注:选择排序稳定性跟代码实现方式有关,这种写法为稳定

代码:

public static int[] selectionSort(int data[]){
    for (int i = 0; i < data.length -1; i++) {
        int maxIndex = 0;
        for (int j = 0; j < data.length - i; j++) {
            if (data[j] >= data [maxIndex]) {//加等于稳定
                maxIndex = j;
            }
        }
        if (maxIndex != data.length - i -1) {
            int temp = data[data.length - i -1];
            data[data.length - i -1] = data[maxIndex];
            data[maxIndex] = temp;
        }
    }
    return data;
}

 

3、直接插入排序

思想:

(1)将第i元素与排好序的n个数的序列做比较(默认第一个元素为有序),如果有序序列中有元素比第i个位置的元素大,互换位置,直至排好序的所有元素与第i个位置的元素比较过则前n+1个元素有序

(2)重复(1), 直至整个序列有序

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
直接插入 O(n) O(n^2) O(n^2) O(1) 数据量小,有序 稳定

代码:

public static int[] straightInsertionSort(int data[]) {
    for (int i = 1; i < data.length ; i++) {
        for (int j = 0; j < i; j++) {
            if (data[j] > data [i]) {
                int temp = data[j];
                data[j] = data[i];
                data[i]= temp;
            }
        }
    }
    return data;
}

 

4、希尔排序

思想:

(1)将元素通过步长分组,组内用直接插入排序使其有序

(2)随着步长逐渐减小,每个分组的记录数越来越多,当步长减为1时,所有记录合成一组,所有记录有序

 

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
希尔排序 O(n^1.3) O(n^2) O(n^2) O(1) 数据量大 不稳定

代码:

public static int[] shellSort(int data[]) {
    for (int gap = data.length/2; gap > 0; gap /=2) {
    //保证初始前面只有一个元素使其有序 然后每次插入和之前有序序列比较
        for (int i = gap; i < data.length; i++) {
            straightInsertionSort(data,i,gap);
        }
    }
    return data;
}
​
private static void straightInsertionSort(int[] data, int index, int gap) {
    for (int  j = index%gap; j <= index - gap; j += gap) {//同一组的和之前有序的元素比较交换
        if (data[index] < data [j]) {
            int temp = data[index];
            data[index] = data[j];
            data[j] = temp;
        }
    }
}

 

5、快速排序

思想:

(1)单次排序时,选择第一个元素为基准数,i,j分别指向第一个元素和最后一个元素,j先向前扫描,若data[j] 大于等于基准数,则继续往前扫描,当data[j]小于基准数时,基准数和data[j] 互换位置,i向后扫描,若data[i] 小于等于基准数,则继续往前扫描,当data[i]大于基准数时,基准数和data[i]] 互换位置,然后j继续向前扫描,i,j交替扫描,直至i == j,则一次排序完成

(2)一次排序使基准数左边小于基准数,右边大于基准数

(3)对于基准数左边和右边元素重复(1),(2)

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
快速排序 O(nlog2n) O(n^2) O(nlog2n) O(nlog2n) 数据量大 不稳定
public static void quickSort(int data[],int low,int high) {
    if (low < high) {
        int middleIndex = getMiddleIndex(data,low,high);
        quickSort(data,low,middleIndex - 1);
        quickSort(data,middleIndex + 1,high);
    }
}
​
private static int getMiddleIndex(int[] data, int low, int high) {
    int key = data[low];
    while (low < high) {
        while (data[high] > key && low < high){
            high --;
        }
        data[low] = data[high];
        while (data[low] <= key && low < high) {
            low ++;
        }
        data[high] = data[low];
    }
    data[low] = key;
    return low;
}

 

6、堆排序

思想:

(1)将无序序列构造为大顶或者小顶堆,每次取出堆顶元素,将堆尾元素放在堆顶,再次调整为大顶堆或者小顶堆,直至堆只剩最后一个元素

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
堆排序 O(nlog2n) O(nlog2n) O(nlog2n) O(1) 数据量大 不稳定

代码:

public static void heapSort(int data[]) {
    //建堆
    //i 指向最后一个非叶子节点
    for (int i = data.length/2 - 1; i >= 0; i --) {
        adjustHeap(data,i,data.length);
    }
    for (int k = data.length -1; k > 0; k--) {
        //把最大元素放到堆尾,此时只需调整根节点
        swap(data,0,k);
        adjustHeap(data,0,k);
    }
}
​
 //每个非叶子节点都要调整堆使之成为大顶堆,并循环调整所有子树
private static void adjustHeap(int[] data, int i, int length) {
    for (int j = 2 * i + 1; j < length; j = 2 * j + 1) {
        //判断右子节点是否存在,j 指向子节点中较大的
        if (j + 1 < length && data[j] < data[j + 1]) {
            j++;
        }
        if (data[j] > data[i]) {
            swap(data,i,j);
            //循环检查子树 只调整结构改变的
            i = j;
        } else {
            break;
        }
    }
}
​
private static void swap (int data[],int i,int j) {
    int temp = data[i];
    data[i] = data[j];
    data[j] = temp;
}

 

7、归并排序

思想:

利用分治思想递归求解,先分解成有序序列(每组只剩一个元素),然后每个有序序列合并,直至整个序列有序

 

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
归并排序 O(nlog2n) O(nlog2n) O(nlog2n) O(n) 数据量大 稳定

代码:

public static void mergeSort (int data[],int left,int right,int temp[]) {
    if (left < right) {
        int mid = (left + right)/2;
        mergeSort(data,left,mid ,temp);
        mergeSort(data,mid+1,right,temp);
        merge(data,left,right,mid,temp);
    }
}
​
private static void merge(int[] data, int left, int right, int mid, int[] temp) {
    int i = left;
    int j = mid + 1;
    int k = left;
    while (i <= mid && j <= right) {
        temp[k++] = data[i] <= data[j] ? data[i++]:data[j++];
    }
    if (i > mid){
        while (k <= right) {
            temp[k++] = data[j++];
        }
    }
    if (j > right){
        while (k <= right) {
            temp[k++] = data[i++];
        }
    }
    for (int m = left; m <= right; m++) {
        data[m] = temp[m];
    }
}

 

8、基数排序

思想:

从个位开始将排序的元素按个位的值放入0~9编号的桶中,再将得到的子序列按十位的值放入桶中,一直到最高位为止

算法 最好复杂度 最差复杂度 平均复杂度 空间复杂度 适用场景 稳定性
基数排序 O(d*(n+r)) O(d*(n+r)) O(d*(n+r)) O(n+r) 数据量大 稳定

其中,d 为位数(代码中为count),r 为基数(10),n 为原数组个数(data.length)。

代码:

 public static void radixSort(int data[]){
        int places = getMaxPlaces(data);//最大数的位数
        int bucket[][] = new int [10][data.length]; //十个桶
        int bucketCount[] = new int[10];//每个桶数据量
        for (int i = 0; i < places; i++) {
            putBucket(data,i,bucketCount,bucket);
            getBucket(data,bucketCount,bucket);
        }
    }
​
    private static void getBucket(int[] data, int[] bucketCount, int[][] bucket) {
        int k = 0;
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < bucketCount[i]; j++) {
                data[k++] = bucket[i][j];
            }
            bucketCount[i] = 0;
        }
    }
​
    //按第i位入桶
    private static void putBucket(int[] data,int i,int bucketCount[],int bucket[][]) {
        int index = 0;
        for (int num : data) {
            index = (int)(num/Math.pow(10,i))%10;
            bucket[index][bucketCount[index]] = num;
            bucketCount[index]++;
        }
    }
​
    private static int getMaxPlaces(int[] data) {
        int max = data[0];
        for (int i = 1; i < data.length; i++) {
            if (data[i] > max){
                max = data[i];
            }
        }
        int count = 0;
        //取最大值的位数
        while (max > 0) {
            max = max/10;
            count ++;
        }
        return count;
    }

 

你可能感兴趣的:(算法)