java實現各種排序演算法(非比較排序)
阿新 • • 發佈:2022-05-18
前言
之前學習了基於比較的各種排序演算法java實現各種排序演算法(比較排序),今天再學習一下非比較排序。
計數排序
程式碼實現
以對所有學生的成績排序為例
import java.util.Arrays; import java.util.Random; public class CountingSort { public void sort(int[] nums) { //成績的範圍為[0,100] int[] scores = new int[101]; for (int num : nums) { scores[num]++; } int index = 0; for (int score = 0; score < scores.length; score++) { //scores[score]的值為score分數的學生人數 for (int i = 0; i < scores[score]; i++) { nums[index++] = score; } } } public static void main(String[] args) { //生成一個包含50個元素的陣列(每個元素小於等於100) int[] arr = generateRandomArr(50, 101); System.out.println(Arrays.toString(arr)); new CountingSort().sort(arr); System.out.println(Arrays.toString(arr)); } private static int[] generateRandomArr(int n, int bound) { Random random = new Random(); int[] arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] = random.nextInt(bound); } return arr; } }
統統計出每個成績的學生個數,如60分學生有10個,61分學生有20個。計數排序適用於資料範圍比較小的情況,如學生成績,年齡等。時間複雜度O(N)。
應用
基數排序
import java.util.Arrays; public class LSDSort { public void sort(String[] arr) { if (arr.length == 0) { return; } int length = arr[0].length(); for (String s : arr) { if (s.length() != length) { throw new IllegalArgumentException("All Strings' length must be the same."); } } int R = 256; int[] counts = new int[R]; String[] temp = new String[arr.length]; int[] countIndexs = new int[R]; for (int r = length - 1; r >= 0; r--) { //對每一位進行計數排序 Arrays.fill(counts, 0); for (String s : arr) { counts[s.charAt(r)]++; } for (int i = 0; i < R; i++) { if (i == 0) { countIndexs[i] = 0; } else { countIndexs[i] = countIndexs[i - 1] + counts[i - 1]; } } for (String s : arr) { temp[countIndexs[s.charAt(r)]] = s; countIndexs[s.charAt(r)]++; } System.arraycopy(temp, 0, arr, 0, arr.length); } } public static void main(String[] args) { String[] arr = {"BCA", "CAB", "ACB", "BAC", "ABC", "CBA"}; new LSDSort().sort(arr); for (String s : arr) { System.out.println(s); } } }
從低位開始,對每一位進行計數排序,適用於等長字串,如車牌號,手機號等。
桶排序
還是以對所有學生的成績排序為例,分成10個桶,第一個桶成績區間為[0-9],第二個為[10-19],依次類推
import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class BucketSort { public void sort(int[] nums) { //成績的範圍為[0,100] 桶大小為10 11個桶 int bucketSize = 10; int scoreRange = 101; int bucketCount = scoreRange / bucketSize + (scoreRange % bucketSize == 0 ? 0 : 1); List<Integer>[] bucketList = new List[bucketCount]; for (int i = 0; i < bucketList.length; i++) { bucketList[i] = new LinkedList<>(); } for (int num : nums) { bucketList[getBucketIndex(num, bucketSize)].add(num); } List<Integer> res = new LinkedList<>(); for (List<Integer> list : bucketList) { int[] array = list.stream().mapToInt(x -> x).toArray(); insertSort(array); for (int val : array) { res.add(val); } } int index = 0; for (Integer val : res) { nums[index++] = val; } } private int getBucketIndex(int num, int bucketSize) { return num / bucketSize; } private void insertSort(int[] nums) { //[0,i)為已排序的,[i,n)為未排序的 for (int i = 1; i < nums.length; i++) { int insertValue = nums[i]; int j = i - 1; while (j >= 0 && insertValue < nums[j]) { nums[j + 1] = nums[j]; j--; } nums[j + 1] = insertValue; } } public static void main(String[] args) { int[] nums = {12, 56, 87, 99, 64, 5, 23}; new BucketSort().sort(nums); System.out.println(Arrays.toString(nums)); } }
學生成績區間為[0,100],每個桶區間為10,對每個桶內元素進行插入排序,然後所有桶中元素順序拿出來即可。桶排序適用於資料分佈均勻的情況。
總結
- 計數排序可以看做桶排序的特例,當每個桶大小為1時,就變成了計數排序。
- 基數排序可以看做多輪計數排序,對每個有效位都進行一次計數排序。
- 這三種排序演算法都需要額外的輔助空間,且對輸入資料有要求,只能在特定情況下使用。