Line data Source code
1 : //------------------------------------------------------------------------------
2 : // LG_qsort_template: quicksort of a K-by-n array
3 : //------------------------------------------------------------------------------
4 :
5 : // LAGraph, (c) 2019-2022 by The LAGraph Contributors, All Rights Reserved.
6 : // SPDX-License-Identifier: BSD-2-Clause
7 : //
8 : // For additional details (including references to third party source code and
9 : // other files) see the LICENSE file or contact permission@sei.cmu.edu. See
10 : // Contributors.txt for a full list of contributors. Created, in part, with
11 : // funding and support from the U.S. Government (see Acknowledgments.txt file).
12 : // DM22-0790
13 :
14 : // Contributed by Timothy A. Davis, Texas A&M University
15 :
16 : //------------------------------------------------------------------------------
17 :
18 : // This file is #include'd in LG_qsort*.c to create specific versions for
19 : // different kinds of sort keys and auxiliary arrays. Requires an inline or
20 : // macro definition of the LG_lt function. The LG_lt function has the form
21 : // LG_lt (A,i,B,j) and returns true if A[i] < B[j].
22 :
23 : // All of these functions are static; there will be versions of them in each
24 : // variant of LG_qsort*, and given unique names via #define's in the
25 : // #include'ing file.
26 :
27 : //------------------------------------------------------------------------------
28 : // LG_partition: use a pivot to partition an array
29 : //------------------------------------------------------------------------------
30 :
31 : // C.A.R Hoare partition method, partitions an array in-place via a pivot.
32 : // k = partition (A, n) partitions A [0:n-1] such that all entries in
33 : // A [0:k] are <= all entries in A [k+1:n-1].
34 :
35 526786 : static inline int64_t LG_partition
36 : (
37 : LG_args (A), // array(s) to partition
38 : const int64_t n, // size of the array(s) to partition
39 : uint64_t *seed, // random number seed, modified on output
40 : LG_void *tx
41 : )
42 : {
43 :
44 : // select a pivot at random
45 526786 : int64_t pivot = ((n < LG_RANDOM15_MAX) ?
46 526786 : LG_Random15 (seed) : LG_Random60 (seed)) % n ;
47 :
48 : // get the Pivot
49 526786 : int64_t Pivot_0 [1] ; Pivot_0 [0] = A_0 [pivot] ;
50 : #if LG_K > 1
51 423972 : int64_t Pivot_1 [1] ; Pivot_1 [0] = A_1 [pivot] ;
52 : #endif
53 : #if LG_K > 2
54 112526 : int64_t Pivot_2 [1] ; Pivot_2 [0] = A_2 [pivot] ;
55 : #endif
56 :
57 : // At the top of the while loop, A [left+1...right-1] is considered, and
58 : // entries outside this range are in their proper place and not touched.
59 : // Since the input specification of this function is to partition A
60 : // [0..n-1], left must start at -1 and right must start at n.
61 526786 : int64_t left = -1 ;
62 526786 : int64_t right = n ;
63 :
64 : // keep partitioning until the left and right sides meet
65 13413610 : while (true)
66 : {
67 : // loop invariant: A [0..left] < pivot and A [right..n-1] > pivot,
68 : // so the region to be considered is A [left+1 ... right-1].
69 :
70 : // increment left until finding an entry A [left] >= pivot
71 39729138 : do { left++ ; } while (LG_lt (A, left, Pivot, 0)) ;
72 :
73 : // decrement right until finding an entry A [right] <= pivot
74 41263801 : do { right-- ; } while (LG_lt (Pivot, 0, A, right)) ;
75 :
76 : // now A [0..left-1] < pivot and A [right+1..n-1] > pivot, but
77 : // A [left] > pivot and A [right] < pivot, so these two entries
78 : // are out of place and must be swapped.
79 :
80 : // However, if the two sides have met, the partition is finished.
81 13940396 : if (left >= right)
82 : {
83 : // A has been partitioned into A [0:right] and A [right+1:n-1].
84 : // k = right+1, so A is split into A [0:k-1] and A [k:n-1].
85 526786 : return (right + 1) ;
86 : }
87 :
88 : // since A [left] > pivot and A [right] < pivot, swap them
89 13413610 : LG_swap (A, left, right) ;
90 :
91 : // after the swap this condition holds:
92 : // A [0..left] < pivot and A [right..n-1] > pivot
93 : }
94 : }
95 :
96 : //------------------------------------------------------------------------------
97 : // LG_quicksort: recursive single-threaded quicksort
98 : //------------------------------------------------------------------------------
99 :
100 1055716 : static void LG_quicksort // sort A [0:n-1]
101 : (
102 : LG_args (A), // array(s) to sort
103 : const int64_t n, // size of the array(s) to sort
104 : uint64_t *seed, // random number seed
105 : LG_void *tx
106 : )
107 : {
108 :
109 1055716 : if (n < 20)
110 : {
111 : // in-place insertion sort on A [0:n-1], where n is small
112 5852040 : for (int64_t k = 1 ; k < n ; k++)
113 : {
114 13505041 : for (int64_t j = k ; j > 0 && LG_lt (A, j, A, j-1) ; j--)
115 : {
116 : // swap A [j-1] and A [j]
117 8181931 : LG_swap (A, j-1, j) ;
118 : }
119 : }
120 : }
121 : else
122 : {
123 : // partition A [0:n-1] into A [0:k-1] and A [k:n-1]
124 526786 : int64_t k = LG_partition (LG_arg (A), n, seed, tx) ;
125 :
126 : // sort each partition
127 526786 : LG_quicksort (LG_arg (A), k, seed, tx) ; // sort A [0:k-1]
128 526786 : LG_quicksort (LG_arg_offset (A, k), n-k, seed, tx) ; // sort A [k+1:n-1]
129 : }
130 1055716 : }
|