算法 | Java 常见排序算法(纯代码)

汇总

序号 排序算法 平均时间 最好情况 最差情况 稳定度 额外空间 备注 相对时间
1 冒泡算法 O(n2) O(n) O(n2) 稳定 O(1) n 越小越好 182 ms
2 选择算法 O(n2) O(n2) O(n2) 不稳定 O(1) n 越小越好 53 ms
3 插入算法 O(n2) O(n) O(n2) 稳定 O(1) 大部分排序好时好 16 ms
4 快速算法 O(nlog2n) O(nlog2n) O(n2) 不稳定 O(nlog2n) n 大时好 719 ms
5 归并算法 O(nlog2n) O(nlog2n) O(nlog2n) 稳定 O(n) n 大时好 550 ms
6 希尔算法 O(nlog2n) O(n) O(n2) 不稳定 O(1) 197 ms/4 ms
7 堆排序 O(nlog2n) O(nlog2n) O(nlog2n) 不稳定 O(1) n 大时好 3 ms
8 计数排序 O(n+k) O(n+k) O(n+k) 稳定 O(n+k) k 是桶的数量 2 ms
9 桶排序 O(n+k) O(n) O(n2) 稳定 O(n+k) 11 ms
10 基数排序 O(n*k) O(n*k) O(n*k) 稳定 O(n+k) 4 ms
11 优先队列 不稳定 O(n) 9 ms
12 Java API O(1) 4 ms

1. 冒泡排序

每轮循环确定最值;

public void bubbleSort(int[] nums){
    int temp;
    boolean isSort = false; //优化,发现排序好就退出
    for (int i = 0; i < nums.length-1; i++) {
        for (int j = 0; j < nums.length-1-i; j++) {  //每次排序后能确定较大值
            if(nums[j] > nums[j+1]){
                isSort = true;
                temp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = temp;
            }
        }
        if(!isSort){
            return;
        } else {
            isSort = false;
        }
    }
}


2. 选择排序

每次选出最值,再交换到边上;

public void selectSort(int[] nums){
    for (int i = 0; i < nums.length-1; i++) {
        int index = i;
        int minNum = nums[i];
        for (int j = i+1; j < nums.length; j++) {
            if(nums[j] < minNum){
                minNum = nums[j];
                index = j;
            }
        }
        if(index != i){
            nums[index] = nums[i];
            nums[i] = minNum;
        }
    }
}


3. 插入排序

对循环的每个数找到属于自己的位置插入;

public void insertionSort(int[] nums){
    for (int i = 1; i < nums.length; i++) {
        int j = i;
        int insertNum = nums[i];
        while(j-1 >= 0 && nums[j-1] > insertNum){
            nums[j] = nums[j-1];
            j--;
        }
        nums[j] = insertNum;
    }
}


4. 快速排序

选一个基本值,小于它的放一边,大于它的放另一边;

public void quickSortDfs(int[] nums, int left, int right){
    if(left > right){
        return;
    }
    int l = left;
    int r = right;
    int baseNum = nums[left];
    while(l < r){
        //必须右边先走
        while(nums[r] >= baseNum && l < r){
            r--;
        }
        while(nums[l] <= baseNum && l < r){
            l++;
        }
        int temp = nums[l];
        nums[l] = nums[r];
        nums[r] = temp;
    }
    nums[left] = nums[l];
    nums[l] = baseNum;
    quickSortDfs(nums, left, r-1);
    quickSortDfs(nums, l+1, right);
}


5. 归并排序

分治算法;

//归
public void mergeSortDfs(int[] nums, int l, int r){
    if(l >= r){
        return;
    }
    int m = (l+r)/2;
    mergeSortDfs(nums, l, m);
    mergeSortDfs(nums, m+1, r);
    merge(nums, l, m, r);
}
//并
private void merge(int[] nums, int left, int mid, int right){
    int[] temp = new int[right-left+1];
    int l = left;
    int m = mid+1;
    int i = 0;
    while(l <= mid && m <= right){
        if(nums[l] < nums[m]){
            temp[i++] = nums[l++];
        } else {
            temp[i++] = nums[m++];
        }
    }
    while(l <= mid){
        temp[i++] = nums[l++];
    }
    while(m <= right){
        temp[i++] = nums[m++];
    }
    System.arraycopy(temp, 0, nums, left, temp.length);
}


6. 希尔排序

引入步长减少数字交换次数提高效率;

6.1 希尔-冒泡排序(慢)

public void shellBubbleSort(int[] nums){
    for (int step = nums.length/2; step > 0 ; step /= 2) {
        for (int i = step; i < nums.length; i++) {
            for (int j = i-step; j >= 0; j -= step) {
                if(nums[j] > nums[j+step]){
                    int temp = nums[j];
                    nums[j] = nums[j+step];
                    nums[j+step] = temp;
                }
            }
        }
    }
}

6.2 希尔-插入排序(快)

public void shellInsertSort(int[] nums){
    for (int step = nums.length/2; step > 0; step /= 2) {
        for (int i = step; i < nums.length; i++) {
            int j = i;
            int insertNum = nums[i];
            while(j-step >= 0 && nums[j-step] > insertNum){
                nums[j] = nums[j-step];
                j-=step;
            }
            nums[j] = insertNum;
        }
    }
}


7. 堆排序

大顶堆实现升序,每次将最大值移到堆的最后一个位置上;

public void heapSort2(int[] nums) {
    for(int i = nums.length/2-1; i >= 0; i--){
        sift(nums, i, nums.length);
    }
    for (int i = nums.length-1; i > 0; i--) {
        int temp = nums[0];
        nums[0] = nums[i];
        nums[i] = temp;
        sift(nums, 0, i);
    }
}
private void sift(int[] nums, int parent, int len) {
    int value = nums[parent];
    for (int child = 2*parent +1; child < len; child = child*2 +1) {
        if(child+1 < len && nums[child+1] > nums[child]){
            child++;
        }
        if(nums[child] > value){
            nums[parent] = nums[child];
            parent = child;
        } else {
            break;
        }
    }
    nums[parent] = value;
}


8. 计数排序

按顺序统计每个数出现次数;

public void countSort(int[] nums){
    int max = Integer.MIN_VALUE;
    int min = Integer.MAX_VALUE;
    for(int num : nums){
        max = Math.max(max, num);
        min = Math.min(min, num);
    }

    int[] countMap = new int[max-min+1];
    for(int num : nums){
        countMap[num-min]++;
    }
    int i = 0;
    int j = 0;
    while(i < nums.length && j < countMap.length){
        if(countMap[j] > 0){
            nums[i] = j+min;
            i++;
            countMap[j]--;
        } else {
            j++;
        }
    }
}


9. 桶排序

类似计数排序,不同点在于统计的是某个区间(桶)里的数;

public void bucketSort(int[] nums){
    int max = Integer.MIN_VALUE;
    int min = Integer.MAX_VALUE;
    for(int num : nums){
        max = Math.max(max, num);
        min = Math.min(min, num);
    }
    int bucketCount = (max-min)/nums.length+1;
    List<List<Integer>> bucketList = new ArrayList<>();
    for (int i = 0; i < bucketCount; i++) {
        bucketList.add(new ArrayList<>());
    }

    for(int num : nums){
        int index = (num-min)/nums.length;
        bucketList.get(index).add(num);
    }
    for(List<Integer> bucket : bucketList){
        Collections.sort(bucket);
    }

    int j = 0;
    for(List<Integer> bucket : bucketList){
        for(int num : bucket){
            nums[j] = num;
            j++;
        }
    }
}


10. 基数排序

按个、十、百位依次归类排序;

public  void radixSort(int[] nums){
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;
    for (int num : nums) {
        min = Math.min(min, num);
        max = Math.max(max, num);
    }
    for (int i = 0; i < nums.length; i++) {
        nums[i] -= min;
    }
    max -= min;
    int maxLen = (max+"").length();

    int[][] bucket = new int[nums.length][10];
    int[] bucketCount = new int[10];

    for (int i = 0, n = 1; i < maxLen; i++, n*=10) {
        for (int num : nums) {
            int digitVal = num / n % 10;
            bucket[bucketCount[digitVal]][digitVal] = num;
            bucketCount[digitVal]++;
        }
        int index = 0;
        for (int j = 0; j < bucketCount.length; j++) {
            if(bucketCount[j] > 0){
                for (int k = 0; k < bucketCount[j]; k++) {
                    nums[index] = bucket[k][j];
                    index++;
                }
            }
            bucketCount[j] = 0;
        }
    }
    for (int i = 0; i < nums.length; i++) {
        nums[i] += min;
    }
}


11. 使用集合或 API

11.1 优先队列

public void priorityQueueSort(int[] nums){
    PriorityQueue<Integer> queue = new PriorityQueue<>();
    for(int num : nums){
        queue.offer(num);
    }
    for (int i = 0; i < nums.length; i++) {
        nums[i] = queue.poll();
    }
}

11.2 Java API

public void arraysApiSort(int[] nums){
    Arrays.sort(nums);
}



最后

\color{blue}{\rm\small{新人制作,如有错误,欢迎指出,感激不尽!}}

\color{blue}{\rm\small{欢迎关注我,并与我交流!}}

\color{blue}{\rm\small{如需转载,请标注出处!}}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容