Skip to content

Commit bdcd33e

Browse files
committed
improve chen sort
1 parent 7579c32 commit bdcd33e

File tree

1 file changed

+80
-19
lines changed

1 file changed

+80
-19
lines changed

example/chen_sort.dart

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ChenSortExample extends StatefulWidget {
1515
}
1616

1717
class ChenSortExampleState extends State<ChenSortExample> {
18-
int defaultNumberCount = 10000;
18+
int defaultNumberCount = 100000;
1919
late TextEditingController numberCountController =
2020
TextEditingController(text: '$defaultNumberCount');
2121
List<String> sortResult = [];
@@ -31,11 +31,12 @@ class ChenSortExampleState extends State<ChenSortExample> {
3131
),
3232
body: ConstraintLayout().open(() {
3333
const Text(
34-
'The time complexity is O(n), the space complexity is O(n), and it is stable',
34+
'The time complexity is O(n) at best and O(nlog2n) at worst, the space complexity is O(n), and it is stable',
3535
style: TextStyle(
3636
fontSize: 30,
3737
),
3838
).applyConstraint(
39+
maxWidth: 800,
3940
topCenterTo: parent,
4041
);
4142
TextField(
@@ -45,7 +46,7 @@ class ChenSortExampleState extends State<ChenSortExample> {
4546
),
4647
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
4748
).applyConstraint(
48-
width: 500,
49+
width: 800,
4950
outBottomCenterTo: sId(-1).topMargin(20),
5051
);
5152
ElevatedButton(
@@ -98,36 +99,93 @@ class ChenSortExampleState extends State<ChenSortExample> {
9899

99100
String compareSort(int numbers) {
100101
Random random = Random();
101-
var arr = [for (int i = 0; i < numbers; i++) random.nextInt(4294967296)];
102+
var arr = [
103+
for (int i = 0; i < numbers; i++) -2 ^ 63 + random.nextInt(2 ^ 63)
104+
];
102105
List copy = List.of(arr);
103106
Stopwatch stopwatch = Stopwatch()..start();
107+
stopwatch.reset();
104108
chenSort(arr);
105109
int chenSortTimeUsage = stopwatch.elapsedMicroseconds;
106110
stopwatch.reset();
107111
copy.sort();
108112
int quickSortTimeUsage = stopwatch.elapsedMicroseconds;
109113
double percent =
110114
((quickSortTimeUsage - chenSortTimeUsage) / quickSortTimeUsage) * 100;
111-
return 'chen sort time usage = $chenSortTimeUsage us, quick sort time usage = $quickSortTimeUsage us, ${percent.toStringAsFixed(2)}% faster';
115+
return 'Are the sorted results equal? ${listEquals(arr, copy)}, chen sort: $chenSortTimeUsage us, quick sort: $quickSortTimeUsage us, ${percent.toStringAsFixed(2)}%(${(quickSortTimeUsage / chenSortTimeUsage).toStringAsFixed(1)}x) faster';
112116
}
113117

118+
/// The essence of Chen Sort is an improved bucket sort
114119
void chenSort(List<int> list) {
115-
int max = -2 ^ 63;
116-
for (final element in list) {
117-
if (element > max) {
118-
max = element;
120+
if (list.length < 2) {
121+
return;
122+
}
123+
124+
int maxValue = list[0];
125+
int minValue = maxValue;
126+
for (final element in list.skip(1)) {
127+
if (element > maxValue) {
128+
maxValue = element;
129+
}
130+
if (element < minValue) {
131+
minValue = element;
119132
}
120133
}
134+
135+
/// All elements are the same and do not need to be sorted.
136+
if (maxValue == minValue) {
137+
return;
138+
}
139+
140+
/// Limit the maximum size of the bucket to ensure the performance of long list
141+
/// sorting, which can be adjusted according to the actual situation.
142+
///
143+
/// The essential difference between this and bucket sorting is that the size of
144+
/// the bucket is only related to the length of the list, not the range of element values.
145+
int bucketSize = min(list.length, 50000);
146+
int maxBucketIndex = bucketSize - 1;
147+
148+
List<List<int>?> buckets = List.filled(bucketSize, null);
121149
int slot;
122-
List<List<int>?> buckets = List.filled(list.length + 1, null);
123-
double factor = list.length / max;
124-
for (final element in list) {
125-
slot = (element * factor).toInt();
126-
if (buckets[slot] == null) {
127-
buckets[slot] = [];
150+
151+
/// Calculate the bucket in which the element is located based on the value of the element
152+
/// and the maximum and minimum values.
153+
154+
/// Overflow detection
155+
BigInt range = BigInt.from(maxValue - minValue);
156+
if (BigInt.from(range.toInt()) == range) {
157+
int range = maxValue - minValue;
158+
double factor = maxBucketIndex / range;
159+
for (final element in list) {
160+
// slot = (((element - minValue) / range) * maxBucketIndex).toInt();
161+
slot = ((element - minValue) * factor).toInt();
162+
if (buckets[slot] == null) {
163+
buckets[slot] = [];
164+
}
165+
buckets[slot]!.add(element);
166+
}
167+
} else {
168+
/// Overflowed(positive minus negative)
169+
int positiveRange = maxValue;
170+
int negativeRange = -minValue - 1;
171+
int positiveStartBucketIndex = maxBucketIndex ~/ 2 + 1;
172+
int positiveBucketLength = maxBucketIndex - positiveStartBucketIndex;
173+
int negativeBucketLength = positiveStartBucketIndex - 1;
174+
for (final element in list) {
175+
if (element < 0) {
176+
slot = (((element - minValue) / negativeRange) * negativeBucketLength)
177+
.toInt();
178+
} else {
179+
slot = positiveStartBucketIndex +
180+
((element / positiveRange) * positiveBucketLength).toInt();
181+
}
182+
if (buckets[slot] == null) {
183+
buckets[slot] = [];
184+
}
185+
buckets[slot]!.add(element);
128186
}
129-
buckets[slot]!.add(element);
130187
}
188+
131189
int compare(int left, int right) {
132190
return left - right;
133191
}
@@ -136,10 +194,13 @@ void chenSort(List<int> list) {
136194
for (final bucket in buckets) {
137195
if (bucket != null) {
138196
if (bucket.length > 1) {
197+
/// The sort method here represents the fastest comparison-type algorithm (Quick sort, Tim sort, etc.)
139198
bucket.sort(compare);
140-
}
141-
for (final element in bucket) {
142-
list[index++] = element;
199+
for (final element in bucket) {
200+
list[index++] = element;
201+
}
202+
} else {
203+
list[index++] = bucket[0];
143204
}
144205
}
145206
}

0 commit comments

Comments
 (0)