github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/sort/sort_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sort_test 6 7 import ( 8 "fmt" 9 "math" 10 "math/rand" 11 . "sort" 12 "strconv" 13 "testing" 14 ) 15 16 var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 17 var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} 18 var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} 19 20 func TestSortIntSlice(t *testing.T) { 21 data := ints 22 a := IntSlice(data[0:]) 23 Sort(a) 24 if !IsSorted(a) { 25 t.Errorf("sorted %v", ints) 26 t.Errorf(" got %v", data) 27 } 28 } 29 30 func TestSortFloat64Slice(t *testing.T) { 31 data := float64s 32 a := Float64Slice(data[0:]) 33 Sort(a) 34 if !IsSorted(a) { 35 t.Errorf("sorted %v", float64s) 36 t.Errorf(" got %v", data) 37 } 38 } 39 40 func TestSortStringSlice(t *testing.T) { 41 data := strings 42 a := StringSlice(data[0:]) 43 Sort(a) 44 if !IsSorted(a) { 45 t.Errorf("sorted %v", strings) 46 t.Errorf(" got %v", data) 47 } 48 } 49 50 func TestInts(t *testing.T) { 51 data := ints 52 Ints(data[0:]) 53 if !IntsAreSorted(data[0:]) { 54 t.Errorf("sorted %v", ints) 55 t.Errorf(" got %v", data) 56 } 57 } 58 59 func TestFloat64s(t *testing.T) { 60 data := float64s 61 Float64s(data[0:]) 62 if !Float64sAreSorted(data[0:]) { 63 t.Errorf("sorted %v", float64s) 64 t.Errorf(" got %v", data) 65 } 66 } 67 68 func TestStrings(t *testing.T) { 69 data := strings 70 Strings(data[0:]) 71 if !StringsAreSorted(data[0:]) { 72 t.Errorf("sorted %v", strings) 73 t.Errorf(" got %v", data) 74 } 75 } 76 77 func TestSortLarge_Random(t *testing.T) { 78 n := 1000000 79 if testing.Short() { 80 n /= 100 81 } 82 data := make([]int, n) 83 for i := 0; i < len(data); i++ { 84 data[i] = rand.Intn(100) 85 } 86 if IntsAreSorted(data) { 87 t.Fatalf("terrible rand.rand") 88 } 89 Ints(data) 90 if !IntsAreSorted(data) { 91 t.Errorf("sort didn't sort - 1M ints") 92 } 93 } 94 95 func TestReverseSortIntSlice(t *testing.T) { 96 data := ints 97 data1 := ints 98 a := IntSlice(data[0:]) 99 Sort(a) 100 r := IntSlice(data1[0:]) 101 Sort(Reverse(r)) 102 for i := 0; i < len(data); i++ { 103 if a[i] != r[len(data)-1-i] { 104 t.Errorf("reverse sort didn't sort") 105 } 106 if i > len(data)/2 { 107 break 108 } 109 } 110 } 111 112 type nonDeterministicTestingData struct { 113 r *rand.Rand 114 } 115 116 func (t *nonDeterministicTestingData) Len() int { 117 return 500 118 } 119 func (t *nonDeterministicTestingData) Less(i, j int) bool { 120 if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() { 121 panic("nondeterministic comparison out of bounds") 122 } 123 return t.r.Float32() < 0.5 124 } 125 func (t *nonDeterministicTestingData) Swap(i, j int) { 126 if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() { 127 panic("nondeterministic comparison out of bounds") 128 } 129 } 130 131 func TestNonDeterministicComparison(t *testing.T) { 132 // Ensure that sort.Sort does not panic when Less returns inconsistent results. 133 // See https://golang.org/issue/14377. 134 defer func() { 135 if r := recover(); r != nil { 136 t.Error(r) 137 } 138 }() 139 140 td := &nonDeterministicTestingData{ 141 r: rand.New(rand.NewSource(0)), 142 } 143 144 for i := 0; i < 10; i++ { 145 Sort(td) 146 } 147 } 148 149 func BenchmarkSortString1K(b *testing.B) { 150 b.StopTimer() 151 for i := 0; i < b.N; i++ { 152 data := make([]string, 1<<10) 153 for i := 0; i < len(data); i++ { 154 data[i] = strconv.Itoa(i ^ 0x2cc) 155 } 156 b.StartTimer() 157 Strings(data) 158 b.StopTimer() 159 } 160 } 161 162 func BenchmarkStableString1K(b *testing.B) { 163 b.StopTimer() 164 for i := 0; i < b.N; i++ { 165 data := make([]string, 1<<10) 166 for i := 0; i < len(data); i++ { 167 data[i] = strconv.Itoa(i ^ 0x2cc) 168 } 169 b.StartTimer() 170 Stable(StringSlice(data)) 171 b.StopTimer() 172 } 173 } 174 175 func BenchmarkSortInt1K(b *testing.B) { 176 b.StopTimer() 177 for i := 0; i < b.N; i++ { 178 data := make([]int, 1<<10) 179 for i := 0; i < len(data); i++ { 180 data[i] = i ^ 0x2cc 181 } 182 b.StartTimer() 183 Ints(data) 184 b.StopTimer() 185 } 186 } 187 188 func BenchmarkStableInt1K(b *testing.B) { 189 b.StopTimer() 190 for i := 0; i < b.N; i++ { 191 data := make([]int, 1<<10) 192 for i := 0; i < len(data); i++ { 193 data[i] = i ^ 0x2cc 194 } 195 b.StartTimer() 196 Stable(IntSlice(data)) 197 b.StopTimer() 198 } 199 } 200 201 func BenchmarkSortInt64K(b *testing.B) { 202 b.StopTimer() 203 for i := 0; i < b.N; i++ { 204 data := make([]int, 1<<16) 205 for i := 0; i < len(data); i++ { 206 data[i] = i ^ 0xcccc 207 } 208 b.StartTimer() 209 Ints(data) 210 b.StopTimer() 211 } 212 } 213 214 func BenchmarkStableInt64K(b *testing.B) { 215 b.StopTimer() 216 for i := 0; i < b.N; i++ { 217 data := make([]int, 1<<16) 218 for i := 0; i < len(data); i++ { 219 data[i] = i ^ 0xcccc 220 } 221 b.StartTimer() 222 Stable(IntSlice(data)) 223 b.StopTimer() 224 } 225 } 226 227 const ( 228 _Sawtooth = iota 229 _Rand 230 _Stagger 231 _Plateau 232 _Shuffle 233 _NDist 234 ) 235 236 const ( 237 _Copy = iota 238 _Reverse 239 _ReverseFirstHalf 240 _ReverseSecondHalf 241 _Sorted 242 _Dither 243 _NMode 244 ) 245 246 type testingData struct { 247 desc string 248 t *testing.T 249 data []int 250 maxswap int // number of swaps allowed 251 ncmp, nswap int 252 } 253 254 func (d *testingData) Len() int { return len(d.data) } 255 func (d *testingData) Less(i, j int) bool { 256 d.ncmp++ 257 return d.data[i] < d.data[j] 258 } 259 func (d *testingData) Swap(i, j int) { 260 if d.nswap >= d.maxswap { 261 d.t.Errorf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data)) 262 d.t.FailNow() 263 } 264 d.nswap++ 265 d.data[i], d.data[j] = d.data[j], d.data[i] 266 } 267 268 func min(a, b int) int { 269 if a < b { 270 return a 271 } 272 return b 273 } 274 275 func lg(n int) int { 276 i := 0 277 for 1<<uint(i) < n { 278 i++ 279 } 280 return i 281 } 282 283 func testBentleyMcIlroy(t *testing.T, sort func(Interface), maxswap func(int) int) { 284 sizes := []int{100, 1023, 1024, 1025} 285 if testing.Short() { 286 sizes = []int{100, 127, 128, 129} 287 } 288 dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"} 289 modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"} 290 var tmp1, tmp2 [1025]int 291 for _, n := range sizes { 292 for m := 1; m < 2*n; m *= 2 { 293 for dist := 0; dist < _NDist; dist++ { 294 j := 0 295 k := 1 296 data := tmp1[0:n] 297 for i := 0; i < n; i++ { 298 switch dist { 299 case _Sawtooth: 300 data[i] = i % m 301 case _Rand: 302 data[i] = rand.Intn(m) 303 case _Stagger: 304 data[i] = (i*m + i) % n 305 case _Plateau: 306 data[i] = min(i, m) 307 case _Shuffle: 308 if rand.Intn(m) != 0 { 309 j += 2 310 data[i] = j 311 } else { 312 k += 2 313 data[i] = k 314 } 315 } 316 } 317 318 mdata := tmp2[0:n] 319 for mode := 0; mode < _NMode; mode++ { 320 switch mode { 321 case _Copy: 322 for i := 0; i < n; i++ { 323 mdata[i] = data[i] 324 } 325 case _Reverse: 326 for i := 0; i < n; i++ { 327 mdata[i] = data[n-i-1] 328 } 329 case _ReverseFirstHalf: 330 for i := 0; i < n/2; i++ { 331 mdata[i] = data[n/2-i-1] 332 } 333 for i := n / 2; i < n; i++ { 334 mdata[i] = data[i] 335 } 336 case _ReverseSecondHalf: 337 for i := 0; i < n/2; i++ { 338 mdata[i] = data[i] 339 } 340 for i := n / 2; i < n; i++ { 341 mdata[i] = data[n-(i-n/2)-1] 342 } 343 case _Sorted: 344 for i := 0; i < n; i++ { 345 mdata[i] = data[i] 346 } 347 // Ints is known to be correct 348 // because mode Sort runs after mode _Copy. 349 Ints(mdata) 350 case _Dither: 351 for i := 0; i < n; i++ { 352 mdata[i] = data[i] + i%5 353 } 354 } 355 356 desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode]) 357 d := &testingData{desc: desc, t: t, data: mdata[0:n], maxswap: maxswap(n)} 358 sort(d) 359 // Uncomment if you are trying to improve the number of compares/swaps. 360 //t.Logf("%s: ncmp=%d, nswp=%d", desc, d.ncmp, d.nswap) 361 362 // If we were testing C qsort, we'd have to make a copy 363 // of the slice and sort it ourselves and then compare 364 // x against it, to ensure that qsort was only permuting 365 // the data, not (for example) overwriting it with zeros. 366 // 367 // In go, we don't have to be so paranoid: since the only 368 // mutating method Sort can call is TestingData.swap, 369 // it suffices here just to check that the final slice is sorted. 370 if !IntsAreSorted(mdata) { 371 t.Errorf("%s: ints not sorted", desc) 372 t.Errorf("\t%v", mdata) 373 t.FailNow() 374 } 375 } 376 } 377 } 378 } 379 } 380 381 func TestSortBM(t *testing.T) { 382 testBentleyMcIlroy(t, Sort, func(n int) int { return n * lg(n) * 12 / 10 }) 383 } 384 385 func TestHeapsortBM(t *testing.T) { 386 testBentleyMcIlroy(t, Heapsort, func(n int) int { return n * lg(n) * 12 / 10 }) 387 } 388 389 func TestStableBM(t *testing.T) { 390 testBentleyMcIlroy(t, Stable, func(n int) int { return n * lg(n) * lg(n) / 3 }) 391 } 392 393 // This is based on the "antiquicksort" implementation by M. Douglas McIlroy. 394 // See http://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info. 395 type adversaryTestingData struct { 396 data []int 397 keys map[int]int 398 candidate int 399 } 400 401 func (d *adversaryTestingData) Len() int { return len(d.data) } 402 403 func (d *adversaryTestingData) Less(i, j int) bool { 404 if _, present := d.keys[i]; !present { 405 if _, present := d.keys[j]; !present { 406 if i == d.candidate { 407 d.keys[i] = len(d.keys) 408 } else { 409 d.keys[j] = len(d.keys) 410 } 411 } 412 } 413 414 if _, present := d.keys[i]; !present { 415 d.candidate = i 416 return false 417 } 418 if _, present := d.keys[j]; !present { 419 d.candidate = j 420 return true 421 } 422 423 return d.keys[i] >= d.keys[j] 424 } 425 426 func (d *adversaryTestingData) Swap(i, j int) { 427 d.data[i], d.data[j] = d.data[j], d.data[i] 428 } 429 430 func TestAdversary(t *testing.T) { 431 const size = 100 432 data := make([]int, size) 433 for i := 0; i < size; i++ { 434 data[i] = i 435 } 436 437 d := &adversaryTestingData{data, make(map[int]int), 0} 438 Sort(d) // This should degenerate to heapsort. 439 } 440 441 func TestStableInts(t *testing.T) { 442 data := ints 443 Stable(IntSlice(data[0:])) 444 if !IntsAreSorted(data[0:]) { 445 t.Errorf("nsorted %v\n got %v", ints, data) 446 } 447 } 448 449 type intPairs []struct { 450 a, b int 451 } 452 453 // IntPairs compare on a only. 454 func (d intPairs) Len() int { return len(d) } 455 func (d intPairs) Less(i, j int) bool { return d[i].a < d[j].a } 456 func (d intPairs) Swap(i, j int) { d[i], d[j] = d[j], d[i] } 457 458 // Record initial order in B. 459 func (d intPairs) initB() { 460 for i := range d { 461 d[i].b = i 462 } 463 } 464 465 // InOrder checks if a-equal elements were not reordered. 466 func (d intPairs) inOrder() bool { 467 lastA, lastB := -1, 0 468 for i := 0; i < len(d); i++ { 469 if lastA != d[i].a { 470 lastA = d[i].a 471 lastB = d[i].b 472 continue 473 } 474 if d[i].b <= lastB { 475 return false 476 } 477 lastB = d[i].b 478 } 479 return true 480 } 481 482 func TestStability(t *testing.T) { 483 n, m := 100000, 1000 484 if testing.Short() { 485 n, m = 1000, 100 486 } 487 data := make(intPairs, n) 488 489 // random distribution 490 for i := 0; i < len(data); i++ { 491 data[i].a = rand.Intn(m) 492 } 493 if IsSorted(data) { 494 t.Fatalf("terrible rand.rand") 495 } 496 data.initB() 497 Stable(data) 498 if !IsSorted(data) { 499 t.Errorf("Stable didn't sort %d ints", n) 500 } 501 if !data.inOrder() { 502 t.Errorf("Stable wasn't stable on %d ints", n) 503 } 504 505 // already sorted 506 data.initB() 507 Stable(data) 508 if !IsSorted(data) { 509 t.Errorf("Stable shuffled sorted %d ints (order)", n) 510 } 511 if !data.inOrder() { 512 t.Errorf("Stable shuffled sorted %d ints (stability)", n) 513 } 514 515 // sorted reversed 516 for i := 0; i < len(data); i++ { 517 data[i].a = len(data) - i 518 } 519 data.initB() 520 Stable(data) 521 if !IsSorted(data) { 522 t.Errorf("Stable didn't sort %d ints", n) 523 } 524 if !data.inOrder() { 525 t.Errorf("Stable wasn't stable on %d ints", n) 526 } 527 } 528 529 var countOpsSizes = []int{1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6} 530 531 func countOps(t *testing.T, algo func(Interface), name string) { 532 sizes := countOpsSizes 533 if testing.Short() { 534 sizes = sizes[:5] 535 } 536 if !testing.Verbose() { 537 t.Skip("Counting skipped as non-verbose mode.") 538 } 539 for _, n := range sizes { 540 td := testingData{ 541 desc: name, 542 t: t, 543 data: make([]int, n), 544 maxswap: 1<<31 - 1, 545 } 546 for i := 0; i < n; i++ { 547 td.data[i] = rand.Intn(n / 5) 548 } 549 algo(&td) 550 t.Logf("%s %8d elements: %11d Swap, %10d Less", name, n, td.nswap, td.ncmp) 551 } 552 } 553 554 func TestCountStableOps(t *testing.T) { countOps(t, Stable, "Stable") } 555 func TestCountSortOps(t *testing.T) { countOps(t, Sort, "Sort ") } 556 557 func bench(b *testing.B, size int, algo func(Interface), name string) { 558 b.StopTimer() 559 data := make(intPairs, size) 560 x := ^uint32(0) 561 for i := 0; i < b.N; i++ { 562 for n := size - 3; n <= size+3; n++ { 563 for i := 0; i < len(data); i++ { 564 x += x 565 x ^= 1 566 if int32(x) < 0 { 567 x ^= 0x88888eef 568 } 569 data[i].a = int(x % uint32(n/5)) 570 } 571 data.initB() 572 b.StartTimer() 573 algo(data) 574 b.StopTimer() 575 if !IsSorted(data) { 576 b.Errorf("%s did not sort %d ints", name, n) 577 } 578 if name == "Stable" && !data.inOrder() { 579 b.Errorf("%s unstable on %d ints", name, n) 580 } 581 } 582 } 583 } 584 585 func BenchmarkSort1e2(b *testing.B) { bench(b, 1e2, Sort, "Sort") } 586 func BenchmarkStable1e2(b *testing.B) { bench(b, 1e2, Stable, "Stable") } 587 func BenchmarkSort1e4(b *testing.B) { bench(b, 1e4, Sort, "Sort") } 588 func BenchmarkStable1e4(b *testing.B) { bench(b, 1e4, Stable, "Stable") } 589 func BenchmarkSort1e6(b *testing.B) { bench(b, 1e6, Sort, "Sort") } 590 func BenchmarkStable1e6(b *testing.B) { bench(b, 1e6, Stable, "Stable") }