zoukankan      html  css  js  c++  java
  • 八大排序算法

    排序算法

    排序算法之间的比较:

    排序算法 最差时间分析 平均时间复杂度 稳定度 空间复杂度
    冒泡排序 O(n^2) O(n^2) 稳定 O(1)
    选择排序 O(n^2) O(n^2) 不稳定 O(1)
    插入排序 O(n^2) O(n^2) 稳定 O(1)
    归并排序 O(nlogn) O(nlogn) 稳定 O(n)
    快速排序 O(n^2) O(nlogn) 不稳定 O(1)
    堆排序 O(n^2) O(n*logn) 不稳定 O(1)
    希尔排序 O(n^2) O(n^1.3) 不稳定 O(1)
    桶排序 O(n) O(n) 稳定 O(n)

    一、时间复杂度为O(n^2)的排序算法

    1.1 冒泡排序(bubbleSort)

    • 进行n-1轮排序,每轮排序数组中元素依次两两交换, 获取最大的元素;
    • 时间复杂度 O(n^2), 空间复杂度O(1);
    public class BubbleSort {
        public int[] bubbleSort(int[] A) {
            // write code here
            if(A == null || A.length < 2) return A;
            for(int i = 0; i < A.length - 1; i++){
                for(int j = 0; j < A.length - i - 1; j++){
                    if(A[j] > A[j+1]){
                        swap(A, j, j+1);
                    }
                }
            }
            return A;
        }
        
        public void swap(int[] A, int i1, int i2){
            int tmp = A[i1];
            A[i1] = A[i2];
            A[i2] = tmp;
        }
    }
    

    1.2 选择排序(selectionSort)

    • 进行n-1轮交换, 每轮交换获取最小的元素
    • 时间复杂度 O(n^2), 空间复杂度O(1);
    public class SelectionSort {
        public int[] selectionSort(int[] A) {
            // write code here
            if(A == null || A.length < 2) return A;
            for(int i = 0; i < A.length - 1; i++){
                for(int j = i + 1; j < A.length; j ++){
                    if(A[i] > A[j]){
                        swap(A, i, j);
                    }
                }
            }
            return A;
        }
         public void swap(int[] A, int i1, int i2){
            int tmp = A[i1];
            A[i1] = A[i2];
            A[i2] = tmp;
        }
    }
    

    1.3 插入排序(insertionSort)

    • 时间复杂度 O(n^2), 空间复杂度O(1);
    • 当数组元素有序, 时间复杂度O(n)
    public class InsertionSort {
        public int[] insertionSort(int[] A, int n) {
            // write code here
            for(int i = 1; i < A.length; i++){
                int key = A[i];
                int pre = i - 1;
                while(pre >= 0 && A[pre] > key){
                    A[pre+1] = A[pre--];
                }
                A[pre + 1] = key;
            }
            return A;
        }
    }
    

    二、时间复杂度为O(log(n))的排序算法

    2.1 归并排序(mergeSort)

    • 时间复杂度O(log(n)), 空间复杂度O(n)
    • 归并排序的时间复杂度与排序数组元素顺序无关;
    public class MergeSort {
        public int[] mergeSort(int[] A, int n) {
            // write code here
            if(A == null || A.length < 2) return A;
            int[] tmp = new int[A.length];
            divide(A, 0, A.length - 1, tmp);
            return A;
        }
        // 数组合并
        public void merge(int[] A, int left, int right, int mid, int[] tmp){
            for(int i = left; i <= right; i++){
                tmp[i] = A[i];
            }
            int l1 = left, l2 = mid+1, index = left;
            for(int i = left; i <= right; i++){
                if(l1 > mid){
                    A[index++] = tmp[l2++];
                }else if(l2 > right){
                    A[index++] = tmp[l1++];
                }else if(tmp[l1] < tmp[l2]){
                    A[index++] = tmp[l1++];
                }else{
                    A[index++] = tmp[l2++];
                }
            }
        }
        
        public void divide(int[] A, int left, int right, int[] tmp){
            if(left < right){
                // 与 mid = (left + right)/2 相比, 可以防止left+right超出int范围
                int mid = left + (right-left)/2;
                divide(A, left, mid, tmp);
                divide(A, mid+1, right, tmp);
                merge(A, left, right, mid, tmp);
            }
        }
    }
    

    2.2 快速排序(quickSort)

    最优情况: 元素分布均匀, 每次都能取到中间位置

    • 时间复杂度O(log(n)), 空间复杂度O(logn);

    最坏情况: 时间复杂度O(n^2), 空间复杂度O(n), 以下三种最坏情况

    • 数组已经是正序(same order)排过序的。
    • 数组已经是倒序排过序的。
    • 所有的元素都相同(1、2的特殊情况)
    public class QuickSort {
        public int[] quickSort(int[] A, int n) {
            // write code here
            quick(A, 0, A.length - 1);
            return A;
        }
        
        public void quick(int[] A, int left, int right){
            if(left >= right) return ;
            int key = A[left];
            int head = left, tail = right+1;
            while(true){
                while(A[++head] <= key) if(head == right) break;
                while(A[--tail] > key) if(tail == left) break;
                if(head >= tail) break;
                int tmp = A[head];
                A[head] = A[tail];
                A[tail] = tmp;
            }
            A[left] = A[tail];
            A[tail] = key;
            quick(A, left, tail-1);
            quick(A, tail + 1,right);
        }
    }
    

    2.3 堆排序

    • 时间复杂度O(nlog(n)), 空间复杂度O(1)

    • 最差情况, 数组元素已经是从小到大有序的, 时间复杂度O(n^2)

    public class HeapSort {
        public int[] heapSort(int[] A, int n) {
            // 建堆
            for(int i = A.length/2; i >= 0; i--){
                heapAdjust(A, i, A.length);
            }
            for(int i = A.length - 1; i >= 0; i--){
                int head = A[0];
                A[0] = A[i];
                A[i] = head;
                heapAdjust(A, 0, i);
            }
            return A;
        }
        // 堆调整 O(log(n))
        public void heapAdjust(int[] A, int parent, int len){
            int head = A[parent];
            while(parent*2+1 < len){
                int childLeft = parent*2 + 1;
                if(childLeft + 1 < len && A[childLeft + 1] > A[childLeft]){
                    childLeft++;
                }
                if(A[childLeft] < head) break;
                A[parent] = A[childLeft];
                parent = childLeft;
            }
            A[parent] = head;
        }
    }
    

    2.4 希尔排序(shellSort)

    • Shell排序比起QuickSort,MergeSort,HeapSort慢很多。适合于数据量在5000以下并且速度并不是特别重要的场合。它对于数据量较小的数列重复排序是非常好的。

    • 时间复杂度O(nlog(n)),空间复杂度O(1)

    public class ShellSort {
        public int[] shellSort(int[] A, int n) {
        	for(int i = n; i >= 1; i /= 2){
                for(int j = i; j < n; j++){
                    int key = A[j];
                    int pre = j - i;
                    while(pre >= 0 && A[pre] > key){
                        A[pre + i] = A[pre];
                        pre -= i;
                    }
                    A[pre + i] = key;
                }
            }
            return A;
        }
    }
    

    三、 桶排序(时间复杂度O(n))

    3.1 计数排序

    • 计数排序适用于元素在一定有限范围内的数组;
    • 时间复杂度O(n), 空间复杂度 O(m)
    import java.util.*;
    
    public class CountingSort {
        public int[] countingSort(int[] A, int n) {
            if(A == null || A.length < 2) return A;
            int min = A[0], max = A[0];
            for(int i = 0; i < A.length; i++){
                min = Math.min(min, A[i]);
                max = Math.max(max, A[i]);
            }
            int[] bucket = new int[max - min + 1];
            // 入桶
            for(int i = 0; i < A.length; i++){
                bucket[A[i] - min]++;
            }
            // 出桶
            int index = 0;
            for(int i = 0; i < bucket.length; i++){
                while(bucket[i]-- > 0){
                    A[index++] = i + min;
                }
            }
            return A;
        }
    }
    

    3.2 基数排序

    • 时间复杂度O(n), 空间复杂度O(n)
    // 保证元素均小于等于2000的基数排序
    public class RadixSort {
        public int[] radixSort(int[] A, int n) {
    		if(A == null || n < 2) return A;
    		int[][] bucket = new int[10][n]; // 创建10个桶,每个桶需要的长度都有可能为n
    		int[] count = new int[10];  // 记录每个对应桶中装入的元素个数
    		
    		for(int i = 1; i <= 1000; i *= 10) {
    			for(int k = 0; k < n; k++) {
    				int num = A[k] / i % 10; // 获取位数上对应数字
    				bucket[num][count[num]++] = A[k];
    			}
    			// 从bucket中将数据倒回A中
    			int index = 0;
    			for(int k = 0; k < 10; k++) {
    				for(int j = 0; j < count[k]; j++) {
    					A[index++] = bucket[k][j];
    				}
                    count[k] = 0; // 重置为0
    			}
    		}
    		return A;
    	}
    }
    
  • 相关阅读:
    浅谈最长上升子序列(LIS)
    浅谈树链剖分
    数字计数
    windy数
    骑士(树形dp)
    旅游规划
    皇宫看守
    k8s安装报错
    linux文件夹存储潜规则
    搭建覆盖率测试环境
  • 原文地址:https://www.cnblogs.com/jxkun/p/9384895.html
Copyright © 2011-2022 走看看