ChenSort is an improved bucket sort, which is a general-purpose sorting algorithm.
The time complexity is O(n) at best and O(nlogn) at worst, the space complexity is O(n), and it is stable.
Randomly generate [1000,10000000] random numbers in the range [-2^63,2^63-1], average speed is 3 times faster than Quicksort, fastest is 20 times. Traditional bucket sort cannot handle such a large range of values, because the performance is much worse than quicksort due to the huge resource consumption.
All performance data is performed under a single thread, which can easily support multi-threading.
The demos are all built on Flutter.
Dart code:
/// The essence of Chen Sort is an improved bucket sort void chenSort(List<int> list) { if (list.length < 2) { return; } int maxValue = list[0]; int minValue = maxValue; for (final element in list.skip(1)) { if (element > maxValue) { maxValue = element; } if (element < minValue) { minValue = element; } } /// All elements are the same and do not need to be sorted. if (maxValue == minValue) { return; } /// Limit the maximum size of the bucket to ensure the performance of long list /// sorting, which can be adjusted according to the actual situation. /// /// The essential difference between this and bucket sorting is that the size of /// the bucket is only related to the length of the list, not the range of element values. int bucketSize = min(list.length, 50000); int maxBucketIndex = bucketSize - 1; List<List<int>?> buckets = List.filled(bucketSize, null); int slot; /// Calculate the bucket in which the element is located based on the value of the element /// and the maximum and minimum values. /// Overflow detection BigInt range = BigInt.from(maxValue) - BigInt.from(minValue); if (BigInt.from(range.toInt()) == range) { int range = maxValue - minValue; double factor = maxBucketIndex / range; for (final element in list) { // slot = (((element - minValue) / range) * maxBucketIndex).toInt(); slot = ((element - minValue) * factor).toInt(); if (buckets[slot] == null) { buckets[slot] = []; } buckets[slot]!.add(element); } } else { /// Overflowed(positive minus negative) int positiveRange = maxValue; int negativeRange = -minValue; int positiveStartBucketIndex = maxBucketIndex ~/ 2 + 1; int positiveBucketLength = maxBucketIndex - positiveStartBucketIndex; int negativeBucketLength = positiveStartBucketIndex - 1; for (final element in list) { if (element < 0) { slot = negativeBucketLength - ((-element / negativeRange) * negativeBucketLength).toInt(); } else { slot = positiveStartBucketIndex + ((element / positiveRange) * positiveBucketLength).toInt(); } if (buckets[slot] == null) { buckets[slot] = []; } buckets[slot]!.add(element); } } int compare(int left, int right) { return left - right; } int index = 0; for (final bucket in buckets) { if (bucket != null) { if (bucket.length > 1) { if (bucket.length >= 1000) { chenSort(bucket); } else { /// The sort method here represents the fastest comparison-type algorithm (Quick sort, Tim sort, etc.) bucket.sort(compare); } for (final element in bucket) { list[index++] = element; } } else { list[index++] = bucket[0]; } } } }
Java code(Multi-thread. The code just shows that this algorithm can easily support multi-threaded sorting, and the actual performance data is performed under a single thread):
static void chenSort(Integer[] list) { int length = list.length; if (length < 2) { return; } Integer maxValue = Integer.MIN_VALUE; Integer minValue = Integer.MAX_VALUE; for (Integer element : list) { if (element > maxValue) { maxValue = element; } if (element < minValue) { minValue = element; } } /// All elements are the same and do not need to be sorted. if (maxValue.equals(minValue)) { return; } /// Limit the maximum size of the bucket to ensure the performance of long list /// sorting, which can be adjusted according to the actual situation. /// /// The essential difference between this and bucket sorting is that the size of /// the bucket is only related to the length of the list, not the range of element values. int bucketSize = Math.min(length, 50000); int maxBucketIndex = bucketSize - 1; ArrayList<Integer>[] buckets = new ArrayList[bucketSize]; int slot; /// Calculate the bucket in which the element is located based on the value of the element /// and the maximum and minimum values. /// Overflow detection BigInteger bigRange = BigInteger.valueOf(maxValue).subtract(BigInteger.valueOf(minValue)); if (BigInteger.valueOf(bigRange.intValue()).equals(bigRange)) { double factor = maxBucketIndex * 1.0 / (maxValue - minValue); for (Integer element : list) { slot = (int) ((element - minValue) * factor); if (buckets[slot] == null) { buckets[slot] = new ArrayList<>(); } buckets[slot].add(element); } } else { /// Overflowed(positive minus negative) double positiveRange = maxValue; double negativeRange = -minValue; int positiveStartBucketIndex = maxBucketIndex / 2 + 1; int positiveBucketLength = maxBucketIndex - positiveStartBucketIndex; int negativeBucketLength = positiveStartBucketIndex - 1; Integer zero = 0; for (Integer element : list) { if (element < zero) { slot = negativeBucketLength - (int) ((-element / negativeRange) * negativeBucketLength); } else { slot = (int) (positiveStartBucketIndex + ((element / positiveRange) * positiveBucketLength)); } if (buckets[slot] == null) { buckets[slot] = new ArrayList<>(); } buckets[slot].add(element); } } Comparator<Integer> comparator = Comparator.comparingInt(left -> left); // Multi-thread sorting between buckets CountDownLatch countDownLatch = new CountDownLatch(buckets.length); for (ArrayList<Integer> bucket : buckets) { if (bucket != null) { if (bucket.size() > 1) { executor.execute(() -> { bucket.sort(comparator); countDownLatch.countDown(); }); } else { countDownLatch.countDown(); } } else { countDownLatch.countDown(); } } try { countDownLatch.await(); } catch (InterruptedException ignored) { } int index = 0; for (ArrayList<Integer> bucket : buckets) { if (bucket != null) { if (bucket.size() > 1) { for (Integer element : bucket) { list[index++] = element; } } else { list[index++] = bucket.get(0); } } } }
Performance(10 million random numbers sorted, single thread):
Random random = new Random(); Integer[] arr = new Integer[10000000]; long maxValue = Integer.MAX_VALUE; long minValue = Integer.MIN_VALUE; long range = maxValue - minValue + 1; for (int i = 0; i < arr.length; i++) { arr[i] = (int) (minValue + random.nextLong(range)); } Integer[] copy = new Integer[arr.length]; System.arraycopy(arr, 0, copy, 0, arr.length); long start = System.currentTimeMillis(); chenSort(arr); long chenSortTimeUsage = System.currentTimeMillis() - start; start = System.currentTimeMillis(); Arrays.sort(copy); long quickSortTimeUsage = System.currentTimeMillis() - start;
chen sort: 3384 ms, quick sort: 9366 ms, 63.869314541960286%(2.767730496453901x) faster chen sort: 3450 ms, quick sort: 7223 ms, 52.2359130555171%(2.093623188405797x) faster chen sort: 1693 ms, quick sort: 5000 ms, 66.14%(2.9533372711163617x) faster chen sort: 2306 ms, quick sort: 6267 ms, 63.204084889101644%(2.717692974848222x) faster chen sort: 2922 ms, quick sort: 10145 ms, 71.19763430261213%(3.471937029431896x) faster chen sort: 3285 ms, quick sort: 9211 ms, 64.33611985669309%(2.803957382039574x) faster chen sort: 2661 ms, quick sort: 9236 ms, 71.18882633174535%(3.4708756106726795x) faster chen sort: 2538 ms, quick sort: 6422 ms, 60.47960137028963%(2.530338849487786x) faster chen sort: 1749 ms, quick sort: 4928 ms, 64.50892857142857%(2.8176100628930816x) faster chen sort: 1775 ms, quick sort: 5254 ms, 66.21621621621621%(2.96x) faster chen sort: 1626 ms, quick sort: 5155 ms, 68.45780795344326%(3.1703567035670357x) faster chen sort: 2375 ms, quick sort: 4877 ms, 51.302029936436334%(2.0534736842105263x) faster chen sort: 1923 ms, quick sort: 5250 ms, 63.37142857142857%(2.730109204368175x) faster chen sort: 3028 ms, quick sort: 9237 ms, 67.21879398072967%(3.0505284015852046x) faster chen sort: 2692 ms, quick sort: 9030 ms, 70.18826135105205%(3.3543833580980684x) faster
XiSort The slowest sorting algorithm I've developed with the most efficient code execution in the world.
If it helps you a lot, consider sponsoring me a cup of milk tea, or giving a star. Your support is the driving force for me to continue to maintain.
Thanks to the following netizens for their sponsorship.
- 小小鸟 2022.06.08
- 孟焱 2022.06.08