10种排序算法总结

这里把常见的排序算法做个总结,包括
1). SelectSort–选择排序
2). InsertSort–插入排序
3). BubbleSort–冒泡排序
4). ShellSort–希尔排序
5). MergeSort–归并排序
6). QuickSort–快速排序
7). HeapSort–堆排序
8). CountSort–计数排序
9). RadixSort–基数排序
10). BucketSort–桶排序

这里考虑从三个方面分析;
1. Time complexity:时间复杂度
2. Space requirement:空间要求
3. Stability:稳定性

1. SelectSort

2 层循环:
外层:共需要选择n-1次
内层:选择之后元素较小者索引,交换后左移。

public class SelectSort {
    public void selectSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[minIndex])
                    minIndex = j;
            }
            swap(arr, minIndex, i);
        }
    }

     private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
时间复杂度额外空间稳定性
O(n^2)constantstable

2. InsertSort

2层循环:左边元素为已排序数组,将新元素插入已排序数组中。
第一层:从第2个元素开始,依次插入;
第二层:找到插入位置。

public class InsertSort {
    public void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int temp = arr[i];
            int j = i - 1;
            for (; j >= 0 && arr[j] > temp; j--) {
                arr[j + 1] = arr[j];
            }
            // Why here arr[j+1] = arr[i] not available? The sequence is not
            // ordered then.
            arr[j + 1] = temp;
        }
    }
}
时间复杂度额外空间稳定性
O(n^2)constantstable

3. BubbleSort

2层循环:如果为无序状况,运行速度超级慢:因为要进行多次交换。
第一层:共需进行n-1次冒泡操作。
第二层:每次将当前剩余最大值下沉。

public class BubbleSort{
    public void bubbleSort(int[] arr){
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; i+j<arr.length-1; j++){
                if(arr[j]>arr[j+1])
                    swap(arr, j, j+1);
            }
        }
    }
    public void bubbleSortRevised(int[] arr){
        boolean sorted = true;
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; i+j<arr.length-1; j++){
                if(arr[j]>arr[j+1]){
                    swap(arr, j, j+1);
                    sorted = false;
                }
            }
            if(sorted)
                break;
        }
    }
    private void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
时间复杂度额外空间稳定性
O(n^2)constantstable

4. ShellSort

这是插入排序的一种变形; 基于2个原因提高了插入排序效率
1. 当待排序数组已经有序时,插入排序效率较高;
2. 插入排序整体效率较低,因为每次只移动一个元素。

public class ShellSort {
    public void shellSort(int[] arr) {
        for (int gap = arr.length / 2; gap >= 1; gap = (gap / 2 == 1) ? 1 : (int) (gap / 2.2)) {
            for (int i = gap; i < arr.length; i++) {
                int temp = arr[i];
                int j = i - gap;
                for (; j >= 0 && arr[j] > temp; j -= gap)
                    arr[j + gap] = arr[j];
                arr[j + gap] = temp;
            }
        }
    }
}
时间复杂度额外空间稳定性
O(nlgn)~O(n^1.5)constantstable

5. MergeSort

归并排序:思想是divide and conquer, 是一种递归的排序算法。

public class MergeSort {
    public void mergeSort(int[] arr) {
        if (arr.length < 2)
            return;
        int mid = arr.length / 2;
        int[] left = new int[mid];
        int[] right = new int[arr.length - mid];
        for (int i = 0; i < mid; i++) {
            left[i] = arr[i];
        }
        for (int i = mid; i < arr.length; i++) {
            right[i - mid] = arr[i];
        }
        mergeSort(left);
        mergeSort(right);
        merge(arr, left, right);
    }

    private void merge(int[] arr, int[] left, int[] right) {
        int i = 0, j = 0, k = 0;
        while (i < left.length && j < right.length) {
            if (left[i] <= right[j])
                arr[k++] = left[i++];
            else
                arr[k++] = right[j++];
        }
        while (i < left.length)
            arr[k++] = left[i++];
        while (j < right.length)
            arr[k++] = right[j++];
    }
}
时间复杂度额外空间稳定性
O(nlgn)O(n)stable

6. QuickSort

一种基于比较的递归排序算法,综合表现较好,故而名为‘快速排序算法’。

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

    private void quickSort(int[] arr, int low, int high) {
        if (low > high)
            return;
        int pivot = partition(arr, low, high);
        quickSort(arr, low, pivot - 1);
        quickSort(arr, pivot + 1, high);
    }

    private int partition(int[] arr, int low, int high) {
        int pivotIndex = low;
        int pivotValue = arr[high];
        for (int i = low; i < high; i++) {
            if (arr[i] < pivotValue)
                swap(arr, pivotIndex++, i);
        }
        swap(arr, pivotIndex, high);
        return pivotIndex;
    }
时间复杂度额外空间稳定性
O(nlgn)constantstable

7. HeapSort

堆排序是通过建立最大堆(最小堆),然后不断删除最大堆根节点元素实现排序的。是一种不稳定的排序算法。

public class HeapSort {
    public void heapSort(int[] arr) {
        int n = arr.length;
        for (int k = n / 2; k >= 1; k--)
            percolateDown(arr, k, n);
        while (n > 1) {
            swap(arr, 1, n--);
            percolateDown(arr, 1, n);
        }
    }

    private void percolateDown(int[] arr, int k, int n) {
        while (2 * k <= n) {
            int j = 2 * k;
            if (j < n && arr[j - 1] < arr[j]) // off-by-one
                j++;
            if (arr[k - 1] >= arr[j - 1]) // off-by-one
                break;
            swap(arr, k, j);
            k = j;
        }
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i - 1];
        arr[i - 1] = arr[j - 1];
        arr[j - 1] = temp;
    }
}
时间复杂度额外空间稳定性
O(nlgn)constantunstable

8. CountSort

之前所有的排序算法时间复杂度接近于nlgn, 空间要求一般为常量或O(n), 接下来的三种排序算法:计数排序、基数排序、桶排序都是在某种情况下性能为O(n)。
但为什么这几个排序算法并没有MergeSort、 QuickSort等出名呢?原因在于其时间复杂度和空间要求上:
1. O(n+k): 如果这里的k很大,则复杂度可能会比传统的归并、快高;
2. O(k): 这里的 k 是最大值,如果k值过大,则可能导致空间要求异常巨大;
3. 且这里排序要求条件是:非负数

public void countSort(int[] arr) {
        // 1. Initialize maxValue to buckets array.
        int maxValue = arr[0];
        for (int val : arr) {
            if (val > maxValue)
                maxValue = val;
        }
        int[] buckets = new int[maxValue + 1];

        // 2. Scatter elements into buckets.
        for (int val : arr) {
            buckets[val]++;
        }

        // 3. Gather elements back.
        int index = 0;
        int[] sortedArr = new int[arr.length];
        for (int i = 0; i < buckets.length; i++) {
            for (int j = 0; j < buckets[i]; j++)
                sortedArr[index++] = i;
        }
        System.arraycopy(sortedArr, 0, arr, 0, arr.length);
    }
时间复杂度额外空间稳定性
O(n+k)O(k)stable

9. RadixSort

计数排序中每个数据分配一个位置,而基数排序不同点是,多个元素分到基数个桶中,并按位进行排序。
时间复杂度:O(nw), 其中n代表的是数组的大小, w表示数据所占的位数。
空间复杂度:O(w+N),最差情形,考虑

public void radixSort(int[] arr) {
        final int bucketCnt = 10;
        // 1. Initialize bucketCnt buckets.
        LinkedList<Integer>[] buckets = new LinkedList[bucketCnt];
        for (int i = 0; i < bucketCnt; i++)
            buckets[i] = new LinkedList<Integer>();

        // 2. Scatter and Gather for a few iterations.
        int exp = 1;
        boolean sorted = false;
        while (!sorted) {
            sorted = true;
            for (int item : arr) {
                int bucket = item / exp % 10;
                buckets[bucket].add(item);
                if (bucket > 0)
                    sorted = false;
            }
            exp *= 10;
            int index = 0;
            for (LinkedList<Integer> list : buckets) {
                while (!list.isEmpty())
                    arr[index++] = list.remove();
            }
        }
    }
时间复杂度额外空间稳定性
O(wn)O(n+w)stable

10. BucketSort

桶排序:是一种泛化的计数排序算法,当桶排序的bucketCnt选择为最大元素个数时,即为计数排序。桶排序主要通过将数据映射到相应桶中、对每个桶进行排序、将排序后的数据收集到原数组中。这样就实现了数组的排序。
1. 确定桶排序中桶的数量,并初始化桶;
2. 将数组中数据以某种散列规则映射到桶中;
3. 将所有的桶中元素进行排序;
4. 将排序好的桶中元素收集到原数组中,这样就实现了排序。

public void bucketSort(int[] arr) {
        // 1. Initialize the buckets.
        final int bucketCnt = 10;
        LinkedList<Integer>[] buckets = new LinkedList[bucketCnt];
        for (int i = 0; i < bucketCnt; i++)
            buckets[i] = new LinkedList<Integer>();

        // 2. Scatter elements to buckets.
        int minValue = arr[0], maxValue = arr[0];
        for (int val : arr) {
            if (val < minValue)
                minValue = val;
            if (val > maxValue)
                maxValue = val;
        }
        double interval = ((double) (maxValue - minValue + 1)) / bucketCnt;
        for (int val : arr) {
            int bucket = (int) ((val - minValue) / interval);
            buckets[bucket].add(val);
        }
        // 3. Sort each collection.
        for (int i = 0; i < bucketCnt; i++)
            Collections.sort(buckets[i]);

        // 4. Gather the elements.
        int index = 0;
        for (int i = 0; i < bucketCnt; i++) {
            while (!buckets[i].isEmpty())
                arr[index++] = buckets[i].remove();
        }
    }
时间复杂度额外空间稳定性
O(n+k)O(n+k)stable
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值