UNIVERSITY OF CINCINNATI

Date: 8/21/2007

I, Spencer Morgan, hereby submit this work as part of the requirements for the degree of: Master of Science in: Computer Science It is entitled: Reduced Assignment

This work and its defense approved by:

Chair: John Franco

Fred Annexstein

Jerome Paul

Dieter Schmidt

Reduced Assignment Sorting

A thesis submitted to

the University of Cincinnati in partial fulfillment of the requirements for the degree of

Master of Science

from the Department of Computer Science

of the College of Engineering

Successfully defended August 21, 2007

by

Spencer Morgan

BS Information Technology, University of Cincinnati, 1997

[email protected]

513-251-6790

Committee Chair: Dr. John Franco Dr. Fred Annexstein Dr. Jerome Paul Dr. Dieter Schmidt

Abstract:

A new comparison-based is presented that can reorder the elements in the fewest possible assignments (which is never greater than 3n/2), with a comparison complexity of O(nlogn)

1 Copyright  2007 Spencer Morgan

2 Dedication

I dedicate this work to the late Dr. Marceline A. Barron, who motivated, inspired, and encouraged me throughout my life. If it were not for her assistance I might not have pursued a career with computers.

Acknowledgements

First, I thank Dr. Dieter Schmidt who planted the seed of inspiration in that algorithms course many years ago. The ideas which germinated, and were cultivated after I left academia, are now, upon my return, bearing fruit as this thesis.

I would like to thank the Department of Computer Science for the University Graduate

Scholarship which allowed me to focus on my studies.

I thank my advisor, Dr. John Franco, for his patience and guidance through what turned out to be a more arduous task than I had originally envisioned.

I want to thank my committee for taking the time to read my thesis and listen to my defense.

Dr. Naoyuki Tokuda should be thanked for providing me with his paper “An Improved

Shellsort.”

And for proofreading help and criticism I want to thank Narasiman Villori, Bill

Nicholson, Manohar Balapa, Gardner Coughlen, and, last but not least, Betty Kaiser.

3 Table of Contents

Abstract:...... 1 Copyright  2007 Spencer Morgan...... 2 Dedication ...... 3 Acknowledgements...... 3 Table of Contents ...... 4 Table of Figures...... 6 Table of Tables ...... 6 1. Introduction ...... 8 1.1. Notable Algorithms ...... 9 1.1.1. ...... 10 1.1.2. ...... 10 1.1.3. Shell Sort...... 11 1.1.4. Quick Sort...... 11 1.1.5. ...... 12 1.1.6. Heap Sort ...... 12 1.2. Theoretical Bounds ...... 13 2. Theoretical Lower Bounds for Assignments...... 14 2.1. Average Lower Bound of Assignments ...... 16 2.2. Worst-Case Lower Bound of Assignments ...... 17 3. Reduced Assignment Sort (RAS) Algorithm ...... 18 3.1. Stage 1 – Finding an Ordering...... 19 3.2. Stage 2 – Mapping each Element...... 20 3.2.1. Unstable Assignments ...... 22 3.2.2. Optimal Assignments ...... 23 3.3. Stage 3 – Moving the Elements ...... 24 3.4. Storage Overhead...... 25 3.5. Complexity ...... 25 4. Analyzing Sorts...... 26 4.1. Analyzing Assignments...... 26 4.1.1. Random Data...... 26 4.1.2. Special Data ...... 27 4.2. Analyzing Comparisons...... 28 4.2.1. Random Data...... 28 4.2.2. Special Data ...... 29 4.3. Assignments and Comparisons ...... 29 4.4. Analyzing Time...... 30 4.5. Limitations ...... 31 5. Future Enhancements...... 32 5.1. Optimize Comparisons ...... 32 5.2. Avoid Comparisons...... 32 5.3. Reimplement Problems as a Sort...... 32 5.3.1. Defragmentation...... 33 5.3.2. Inventory Management...... 33 6. Summary...... 34

4 Appendix A - Sort Tester...... 35 Informational Counting...... 36 Display...... 36 DataSet ...... 37 SortTypes ...... 39 ...... 39 Insertion Sort...... 39 SMInsert...... 40 Bingo Sort...... 40 J Sort...... 41 Shell Sort...... 41 Heap Sort ...... 44 Merge Sort ...... 44 Quick Sort...... 45 RAS – Reduced Assignment Sort...... 47 RAS16 – 16 bit Reduced Assignment Sort...... 50 Appendix B – Sorts.mdb database of results...... 51 Table SortsCsv...... 51 Form frmAddNew...... 51 Form frmActive...... 51 Query qryAssignCnt ...... 51 Query qryCompareCnt...... 51 Query qryBothCnt ...... 51 Query qryExtraTime ...... 51 Appendix C – Shell Sort...... 52 Assignments ...... 52 Comparisons ...... 59 Both Assignments and Comparisons...... 65 Appendix D – variations contested ...... 71 Using Insertion Sort as a Secondary Sort ...... 71 Deferring Insertion Sort until the end...... 72 Appendix E – Assignments for Random Data...... 76 Not Unique Elements ...... 76 Unique Elements...... 80 Appendix F – Assignments for Special Data...... 83 Appendix G Comparisons for Random Data ...... 85 Not Unique Elements ...... 85 Unique Elements...... 89 Appendix H –Comparisons for Special Data...... 92 Appendix I – Both Assignments and Comparisons for Special Data ...... 94 Appendix J – Time for Random Data ...... 96 RAS algorithm with BPMerge Stage 1...... 96 SMerge Stable Assignments ...... 99 SMerge Optimal Assignments...... 100 References: ...... 103 Table of Source Code Contents...... 105

5

Table of Figures

Figure 1 Example of 2 element circuit...... 14 Figure 2 Example of 3 element circuit...... 14 Figure 3 Example of 2 element circuit among 3 elements...... 15 Figure 4 Bipartite Graph of a Permutation...... 15 Figure 5 Example of a stable sort...... 21 Figure 6 Example of an unstable sort...... 22 Figure 7 Example of an optimal assignment sort...... 24 Figure 8 Assignments per Element ...... 27 Figure 9 Comparisons per Element...... 28 Figure 10 Assignments and Comparisons per Element ...... 29 Figure 11 Screen Capture of Sort Tester...... 36

Table of Tables

Table 1 Theoretical Bounds ...... 13 Table 2 Complexity of RAS algorithm without optimal assignments ...... 25 Table 3 Complexity of RAS algorithm with optimal assignments ...... 25 Table 4 Shellsort assigns for 100 random elements...... 53 Table 5 Shellsort assigns for 100 unique random elements...... 54 Table 6 Shellsort assigns for 1,000 random elements...... 55 Table 7 Shellsort assigns for 1,000 unique random elements...... 56 Table 8 Shellsort assigns for 10,000 random elements...... 57 Table 9 Shellsort assigns for 10,000 unique random elements...... 57 Table 10 Shellsort assigns for 100,000 random elements...... 58 Table 11 Shellsort assigns for 100,000 unique random elements...... 58 Table 12 Shellsort assigns for 1,000,000 random elements...... 58 Table 13 Shellsort assigns for 1,000,000 unique random elements...... 58 Table 14 Shellsort assigns for 10,000,000 random elements...... 58 Table 15 Shellsort assigns for 10,000,000 unique random elements...... 58 Table 16 Shellsort compares for 100 random elements ...... 59 Table 17 Shellsort compares for 100 unique random elements ...... 60 Table 18 Shellsort compares for 1,000 random elements ...... 61 Table 19 Shellsort compares for 1,000 unique random elements ...... 62 Table 20 Shellsort compares for 10,000 random elements ...... 63 Table 21 Shellsort compares for 10,000 unique random elements ...... 63 Table 22 Shellsort compares for 100,000 random elements ...... 64 Table 23 Shellsort compares for 100,000 unique random elements ...... 64 Table 24 Shellsort compares for 1,000,000 random elements ...... 64 Table 25 Shellsort compares for 1,000,000 unique random elements ...... 64 Table 26 Shellsort compares for 10,000,000 random elements ...... 64 Table 27 Shellsort compares for 10,000,000 unique random elements ...... 64

6 Table 28 Shellsort assigns & compares for 100 random elements ...... 65 Table 29 Shellsort assigns & compares for 100 unique random elements...... 66 Table 30 Shellsort assigns & compares for 1,000 random elements ...... 67 Table 31 Shellsort assigns & compares for 1,000 unique random elements...... 68 Table 32 Shellsort assigns & compares for 10,000 random elements ...... 69 Table 33 Shellsort assigns & compares for 10,000 unique random elements...... 69 Table 34 Shellsort assigns & compares for 100,000 random elements ...... 70 Table 35 Shellsort assigns & compares for 100,000 unique random elements...... 70 Table 36 Shellsort assigns & compares for 1,000,000 random elements ...... 70 Table 37 Shellsort assigns & compares for 1,000,000 unique random elements...... 70 Table 38 Shellsort assigns & compares for 10,000,000 random elements ...... 70 Table 39 Shellsort assigns & compares for 10,000,000 unique random elements...... 70 Table 40 Quick switching to Insertion on 1,000 random elements...... 72 Table 41 Quick switching to Insertion on 1,000 unique random elements...... 72 Table 42 Quick switching to Insertion at end on 1,000 random elements...... 73 Table 43 Quick switching to Insertion at end on 1,000 unique random elements ...... 74 Table 44 Quick switching to Insertion at end on 1,000,000 random elements...... 74 Table 45 Quick switching to Insertion at end on 1,000,000 unique random elements ..... 75 Table 46 Assigns for 1,000 random elements...... 76 Table 47 Assigns for 10,000 random elements...... 77 Table 48 Assigns for 100,000 random elements...... 78 Table 49 Assigns for 1,000,000 random elements...... 79 Table 50 Assigns for 10,000,000 random elements...... 79 Table 51 Assigns for 1,000 unique random elements ...... 80 Table 52 Assigns for 10,000 unique random elements ...... 81 Table 53 Assigns for 100,000 unique random elements ...... 81 Table 54 Assigns for 1,000,000 unique random elements ...... 82 Table 55 Assigns for 10,000,000 unique random elements ...... 82 Table 56 Assigns for 1,000 unique reverse ordered elements...... 83 Table 57 Assigns for 1,000 elements in WorstAssign dataset ...... 84 Table 58 Compares for 1,000 random elements ...... 85 Table 59 Compares for 10,000 random elements ...... 86 Table 60 Compares for 100,000 random elements ...... 87 Table 61 Compares for 1,000,000 random elements ...... 87 Table 62 Compares for 10,000,000 random elements ...... 88 Table 63 Compares for 1,000 unique random elements...... 89 Table 64 Compares for 10,000 unique random elements...... 90 Table 65 Compares for 100,000 unique random elements...... 90 Table 66 Compares for 1,000,000 unique random elements...... 91 Table 67 Compares for 10,000,000 unique random elements...... 91 Table 68 Compares for 1,000 unique reverse ordered elements...... 92 Table 69 Compares for 1,000 elements in WorstAssign dataset...... 93 Table 70 Assigns and compares for 1,000 unique reverse ordered elements ...... 94 Table 71 Assigns and compares for 1,000 elements in WorstAssign dataset...... 95 Table 72 Extra Time for RAS BPMerge with 1,000 random elements ...... 96 Table 73 Extra Time for RAS BPMerge with 1,000 unique random elements ...... 96

7 Table 74 Extra Time for RAS BPMerge with 10,000 random elements ...... 96 Table 75 Extra Time for RAS BPMerge with 10,000 unique random elements ...... 97 Table 76 Extra Time for RAS BPMerge with 100,000 random elements ...... 97 Table 77 Extra Time for RAS BPMerge with 100,000 unique random elements ...... 97 Table 78 Extra Time for RAS BPMerge with 1,000,000 random elements ...... 97 Table 79 Extra Time for RAS BPMerge with 1,000,000 unique random elements ...... 97 Table 80 Extra Time for RAS BPMerge with 10,000,000 random elements ...... 98 Table 81 Extra Time for RAS BPMerge with 10,000,000 unique random elements ...... 98 Table 82 Extra Time for RAS SMerge Stable with 1,000 random elements...... 99 Table 83 Extra Time for RAS SMerge Stable with 10,000 random elements...... 99 Table 84 Extra Time for RAS SMerge Stable with 100,000 random elements...... 99 Table 85 Extra Time for RAS SMerge Stable with 1,000,000 random elements...... 99 Table 86 Extra Time for RAS SMerge Stable with 10,000,000 random elements...... 100 Table 87 Extra Time for RAS SMerge Optimal with 1,000 random elements...... 100 Table 88 Extra Time for RAS SMerge Optimal with 10,000 random elements...... 101 Table 89 Extra Time for RAS SMerge Optimal with 100,000 random elements...... 101 Table 90 Extra Time for RAS SMerge Optimal with 1,000,000 random elements...... 102 Table 91 Extra Time for RAS SMerge Optimal with 10,000,000 random elements...... 102

1. Introduction

In comparison-based sorting the only information known about elements is the balanced ternary, or binary, result of a comparison of two elements. Because comparison operations dominate most comparison-based algorithms almost all analyses of sorting have focused on the complexity of comparison operations.

In-place sorting is where the output overwrites the input by having a sequence of assignment operations that reorder the data. This is useful because accessing data sequentially is more efficient than random access for many external storage devices. It is, therefore, often beneficial to reorder the data. The complexity of assignments has been mostly ignored in analyses of sorting. However, it could become of primary importance when assignments are costly, which will be shown (in Chapter 4) could be little more

8 than a few nanoseconds. For instance, moving records to reorganize the internal storage of a database would be costly because of the disk access that would be necessary.

There are even some applications that could benefit from reimplementation as a sort, such as defragmentation of a disk drive since moving clusters would be costly, or moving physical items to optimize inventory placement in a warehousing or shipping environment.

This thesis proposes a new comparison-based in-place sorting algorithm that will be called Reduced Assignment Sort (RAS), which has a maximum of 3n/2 assignments and can achieve the minimum number of assignments possible with any data set. With datasets having no equal elements, the average number of assignments is n + Hn – 2,

th where Hn is the n harmonic number; the best-case comparison complexity

B(n) ≥ (n/2)( log2n-1) and worst-case W(n) ≤ n log2n which is order optimal complexity for any comparison based sorting algorithm [1, page 48].

In the remainder of this Introduction, a variety of notable sorting algorithms will be surveyed and the theoretical bounds will be compared.

1.1. Notable Algorithms

Each algorithm will be described and the worst and average complexity of both comparisons and assignments will be identified.

9 1.1.1. Merge Sort

Merge Sort is an algorithm discovered in 1945 by John von Neumann [1, pages 45] with

O(nlogn) comparisons. The in-place versions, however, like the one in Berman and

Paul’s Algorithms book [1, pages 46-47], require between 2nlogn and 2nlogn assignments and require n temporary locations in all cases. Merge Sort works by, recursively, sorting the first and last halves of a list and then merging them. By moving all elements to temporary locations during the merge, there will be 2n assignments for each merge operation, instead of the O(n2) that could be necessary if only a single temporary location were used. Note that Merge Sort implementations that use linked lists do not have the need for the temporary locations but they are not in-place algorithms.

1.1.2. Insertion Sort

Insertion Sort is a well-known algorithm that is considered efficient on small data sets.

Sedgewick has suggested using it as a secondary sort for “small subfiles” (maybe smaller than 10 elements) in conjunction with Quick Sort [3, pages 328-329]. See appendix D for a challenge to its usefulness when reducing assignments would be beneficial.

Insertion Sort works by comparing adjacent elements. When an inversion is detected the smaller element is inserted into the sorted part of the list. This is done by moving the element to a temporary location, successively moving all larger elements into the free location(s) and moving the temporary element into the correct location in the sorted part of the list. However, with a reverse ordered list there are O(n2) comparisons and assignments. Even the average complexity is O(n2) [1, pages 195-196] for both comparisons and assignments.

10

1.1.3. Shell Sort

Shell Sort was discovered by Donald Shell in 1959 [4]. It increases the efficiency of

Insertion Sort by having an increment (or gap) between the elements compared. It was originally called the Diminishing Increment Sort. It performs multiple passes, or rounds, successively reducing the increment until adjacent elements are compared which will ensure all items are in order. The efficiency is sensitive to the sequence of increments used. Shell initially proposed starting with an increment of n/2 and dividing it by 2 with each pass until it reaches 1. Weiss has shown that this still has a worst case of O(n2) comparisons [5, page 252] but is still much better than Insertion Sort in the average case.

There are many possible increment sequences proposed by Sedgewick which improve the worst case performance to O(n4/3) which are conjectured to have O(n7/6) average case complexity. There is also a sequence by Pratt that has O(n(logn)2) but may not be the best increment unless the dataset is large, or, as Knuth said, “astronomical.” [2, vol 3 page 91]. See the Shell Sort section of Appendix A for information on a number of suggested sequences, and Appendix C to see why a version optimized for assignments with the Tokuda [6] sequence of increments is used for comparison with other algorithms.

1.1.4. Quick Sort

Quick Sort was discovered by Tony Hoare in 1961 [7]. It has comparison complexity of

O(nlogn) in the average case but is O(n2) in the worst case. It recursively partitions the data around an element so that all elements to one side of it are equal or larger and all

11 elements on the other side are equal or smaller. Hsien-Kuei and Neininger [8] have shown assignments to have a negative correlation to comparisons with a worst case assignment complexity of O(nlogn). There are many variations of Quick Sort. Some try to have potential performance improvements, such as using median of 3 partitioning, or switching to a secondary sort when the number of elements is smaller than some number.

Others try to avoid worst-case situations like choosing the partition element randomly.

Due to its good average case performance it is one of the most used sorts.

1.1.5. Selection Sort

Selection Sort works by repetitively moving the smallest (or largest) of the unsorted elements to the sorted part of the list. This reduces the assignments at the expense of many more comparisons. Selection sort defers movement until the smallest element is known, which requires a comparison pass through the unsorted elements for each element moved. Sedgewick [3, pages 283 & 290] has shown that there will be less than n swaps.

Because it swaps elements into their final position, and each swap takes three assignments, the number of assignments will be less than 3n. This is notable because of the reduced assignment complexity. However, the number of comparisons is Θ(n2).

1.1.6. Heap Sort

Heap Sort was discovered in1964 by John W. J. Williams [9]. Heap Sort works like

Selection Sort except it reorganizes the data into a heap to make selection of the largest

(or smallest) element more efficient. The largest element is successively moved to the end and the heap is restructured. This reduces the comparison complexity to O(nlogn)

12 but increases the assignment complexity to O(nlogn). Often other algorithms are preferred due to better performance in the average case.

1.2. Theoretical Bounds

The RAS algorithm is the only one that achieves optimal assignments; also the complexity of comparisons is order optimal.

Assigns Compares Sort Best Avg Worst Best Avg Worst

Merge ≥2nlog2n ≥2nlog2n ≥2nlog2n O(nlogn) O(nlogn) O(nlogn) Insertion 0 O(n2) O(n2) n-1 O(n2) O(n2) Shell 0 O(n7/6)* O(n4/3)* O(n)** O(n7/6)* O(n4/3)* Heap 3(n-1) O(nlogn) O(nlogn) 3(n-2) O(nlogn) O(nlogn) Quick 0 O(nlogn) O(nlogn) O(nlogn) O(nlogn) O(n2) Selection 0 O(n) 3(n-1) Θ(n2) Θ(n2) Θ(n2)

RAS 0 n+Hn-2 3n/2 n-1 O(nlogn) ≤n log2n Table 1 Theoretical Bounds

* The theoretical bounds for Shell Sort has an acute dependence on the increment used but in the worst-case could be as bad as O(n2) but can be as good as O(n4/3) and Weiss says it is conjectured to be as good as O(n7/6) in the average case[5, page 254].

** The best case comparisons for Shell Sort will be based on the number of rounds which will, again, be dependent on the sequence.

Since Shell Sort could be implemented with only two increments the best case could be less than 2n.

In chapter 2, the lower bound for worst-case complexity of assignments will be shown to be 3n/2. The RAS algorithm will be described in chapter 3, while in chapter 4, assignments, comparisons, and time will be compared for a variety of sorting algorithms, which will identify some limitations of the RAS algorithm. Suggestions for possible improvements will be presented in chapter 5 and chapter 6 draws conclusions and summarizes the results.

13 2. Theoretical Lower Bounds for Assignments

Knuth [2, vol 3 page 25], has observed that “every permutation of a set has a unique representation as a product of disjoint cycles.” When Sedgewick [3, pages 468-472] described in-situ permutations he showed that any cycle of n elements can be put into place in n assignments once one element is moved to a temporary location. So, any cycle of n elements can be put into place with n + 1 assignments. Since a singleton cycle does not need to be moved to and from a temporary location it therefore takes zero assignments. Let us define a circuit as a non-singleton cycle which means a circuit is a set of two or more out-of-place elements that can be put into place with only one assignment to and from a temporary location and all other assignments put an element directly into place.

Figure 1 Example of 2 element circuit Figure 2 Example of 3 element circuit

Figures 1 and 2 are examples of two and three element circuits. Note that the permutation

3, 2, 1, in figure 3, has a single two element circuit (3 & 1) and that element 2 is not part of a circuit since it is already in place and therefore would be a singleton cycle.

14 3 2 1

132

1 to temp 1 direct 1 from temp

Figure 3 Example of 2 element circuit among 3 elements

Because, in a permutation, the cycles are disjoint (and therefore the circuits) the minimum number of assignments to put any permutation into order is the number of elements in circuits plus the number of circuits.

So, using a bipartite graph for illustration, consider the list [5, 1, 6, 4, 2, 7, 3]:

1 2 3 4 5 6 7

5 1 6 4 2 7 3

Figure 4 Bipartite Graph of a Permutation

This permutation can be represented as product of the two cycles (1, 5, 2) (3, 6, 7).

The singleton cycle (4) was not written. Since singleton cycles are not conventionally written in cycle notation, only circuits are explicitly identified making the calculation of

15 the minimal number of assignments easy. In this case, there are six elements in two circuits so the minimum number of assignments to put this permutation in order is 6 + 2 or 8 assignments.

If all elements are unique, there is only one permutation of the original order that will result in a sorted list. A search for a lower bound of worst case assignments, therefore, can be limited to permutations. If there are equal elements, however, there will be multiple reordering permutations that will result in a sorted list. Choosing an alternate reordering permutation can be part of the process to achieve minimal assignments and will be seen in the next chapter.

2.1. Average Lower Bound of Assignments

The average lower bound of assignments is n + Hn – 2. Knuth has shown that the

th average number of cycles in a permutation is Hn [2, vol 1 page 179], where Hn is the n harmonic number, and the average number of singleton cycles is 1 [2, vol 1 page 181].

Therefore, the average number of circuits (or non-singleton cycles) is Hn – 1. Also, the average number of elements out of place will be n – 1 which is the number of elements

(n) minus the average number of singleton cycles (1).

16

2.2. Worst-Case Lower Bound of Assignments

The lower bound for assignments in the worst-case is n + n/2 or 3n/2. The worst case for assignments is when:

1. the permutation is, what Knuth [2, vol 1 page 180] calls, a derangement, which is

where all elements are out of place (there are no singleton cycles), and

2. the number of circuits is maximized (because each circuit requires an extra

assignment).

To maximize the number of circuits, each circuit would be as small as possible, having two elements. If the number of elements is odd there would need to be one circuit with three elements. Therefore, the maximum number of circuits for any data set is n/2 because there are at least two elements in every circuit.

17 3. Reduced Assignment Sort (RAS) Algorithm

The Reduced Assignment Sort (RAS) algorithm has three distinct stages. Each stage will be analyzed in turn and the sum of the operations of each stage will be used to determine overall complexity.

An overview of the process is: Stage 1 finds an ordering that will be valid. Stage 2 creates a mapping from where the elements are and their final position. If knowledge of equal elements is acquired in stage 1, adjustments can be made to the order of equal elements to reduce the number of assignments. Finally, in stage 3 the mapping is used to move the elements where they belong. This is similar to the in-place rearrangement (or in situ permutation) suggested by Sedgewick [3, pages 468-472]. However, the creation of the index which is needed for his rearrangement is incorporated into stage 1; and the non-in-place version of Merge Sort that is used in stage 1 is better for this purpose than using Quick Sort to generate the index as he suggested [3, page 471] because of the reduced worst-case complexity of comparisons and the absence of the assignments necessary with Quick Sort which is inherently in-place. Also, this thesis suggests ways to reduce assignments when there are equal elements by possibly using a different in situ permutation which would still result in a valid sort. Because all comparisons occur before any element is moved, the current location can be used to determine the ordering of equal elements to achieve a stable sort.

Since all comparisons occur in stage one and all assignments occur in stage three, the analysis for those operations can be limited to those stages. The only other concern is to ensure that there is no other operation that is of a greater order of complexity.

18 3.1. Stage 1 – Finding an Ordering

This stage is where all the comparisons will occur and will result in data structures that have an ordering. Equal elements must be identified in this stage if the minimal number of assignments is to be assured in stage 2. The data structures needed in each stage are a storage concern and the requirements will be identified as the various options are examined.

There are many options determining how the ordering will be achieved in the Sort

Testing program. There are two classes of orderings that have been implemented: One is tree based, that uses a binary tree with a linked list of equal elements at each node. This includes some variations of the splay trees or semisplay trees that were presented by

Sleator and Tarjan[10]. The other, is merge based that uses a non-in-place version of

Merge Sort to obtain the ordering. See Appendix A for details on each of the ordering methods implemented.

For storage requirements, if a word consists of enough bytes to identify the number of elements plus one (to address the temporary location), then for up to 255 elements a word would be one byte, for 256 to 65535 elements a word would be two bytes and for 65,536 to 4,294,967,295 elements a word would be four bytes. In this stage, the Tree classes of ordering use four words of storage for each element, and the Merge classes of ordering use one word (plus a Boolean in the SMerge version) for each element. In addition to these storage requirements there will be stack space for the recursive calls which will be logn for the Merge versions and up to n-1 for Tree versions. If the storage requirements

19 are too great, a version of Quick Sort could be used that switches to the new RAS sort when the partition gets below some point. If that point is 255 the extra storage requirements for this stage could be as little as 256 bytes; or if the point is 65,535, as little as 131,072 bytes. Later stages will add 1 or 2 (for optimal assignments) additional words of storage for each element. See the tables in Appendix D for examples of performance.

The merge classes of ordering could be performed in parallel like other versions of Merge

Sort.

3.2. Stage 2 – Mapping each Element

Once the ordering is determined, a mapping is created, which will take one word of additional storage per element. This is done by making a single pass through the final ordering, marking the final location of each element. There are no comparisons or assignments in this stage and there are only Θ(n) other operations. It is at this stage that an alternate ordering of equal elements could be used to reduce the number of assignments. So for example, using the data set:

Location 1 2 3 4 5

Data 2, 1, 3, 3, 2 (which will be used for future examples as well)

Subscripting equal elements will allow determination of the original order.

Location 1 2 3 4 5

Data 21, 1, 31, 32, 22

20 The values 21 and 22 are equal and their relative order would not affect whether the elements were considered sorted. The same is true of 31 and 32.

In order to achieve a stable ordering, the mapping will be:

Location 1 2 3 4 5

Data 21, 1, 31, 32, 22

Mapping 2 1 5 3 4

Which will result in:

Location 1 2 3 4 5

Data 1, 21, 22, 31, 32

21 1 31 32 22

1 21 22 31 32

Figure 5 Example of a stable sort

The elements in locations 1 and 2 are on one circuit and elements in locations 3, 4, and 5 are on another circuit. Each circuit will take an assignment for each element plus one for the extra assignment to/from the temporary location. In our example, the first circuit (21

& 1) will take three assignments and the second circuit (31, 32, & 22) will take four assignments for a total of seven assignments.

21 3.2.1. Unstable Assignments

If some elements are already in a valid location (32 in our example) there is no need to move them. So we could leave them where they are. This selects a reordering permutation that maximizes the number of singleton cycles. In our example, this will result in:

Location 1 2 3 4 5

Data 21, 1, 31, 32, 22

Mapping 2 1 5 4 3

After sorting we will have:

Location 1 2 3 4 5

Data 1, 21, 22, 32, 31

21 1 31 32 22

1 21 22 32 31

Figure 6 Example of an unstable sort

This is the Unstable assignment option for the RAS algorithm in the Sort Testing program. Now the first circuit is 21 & 1 (taking three assignments) and the second circuit is 31 & 22 (taking three assignments) for a total of six assignments. This is accomplished during the single pass of stage 2 by examining equal elements (which need to be

22 identified in stage 1) to see if any of them are already in a valid location. This adds some additional processing (being in stage 2 there are no comparisons or assignments) but will only have a worst case added complexity of Θ(n).

The potential savings is, at most, the number of equal elements in circuits (some might be in place already) minus the number of circuits. See the Stability data set in appendix A for an example of the maximum savings.

3.2.2. Optimal Assignments

Additional reductions in assignments can be achieved when there are multiple circuits containing equal elements by connecting those circuits.

By starting with our unstable ordering:

Location 1 2 3 4 5

Data 1, 21, 22, 32, 31

We can again examine blocks of equal elements and determine that locations 2 and 3 are equal and are on different circuits. Therefore, if the final locations are switched, the circuits will be combined. This selects a reordering permutation that combines multiple cycles, if possible. The result is the following mapping:

Location 1 2 3 4 5

Data 21, 1, 31, 32, 22

Mapping 2 5 1 4 3

23

Which will result in the following final sorting:

Location 1 2 3 4 5

Data 1, 22, 21, 32, 31

21 1 31 32 22

1 22 21 32 31

Figure 7 Example of an optimal assignment sort

This is the Optimal assignment option for the RAS algorithm in the Sort Testing program. Now all of the elements that are not in the correct place (21, 1, 31 & 22) are all on the same circuit (taking five assignments). This requires another pass of processing

Θ(n) and requires n additional words of storage to keep the inverted tree to determine the circuits.

The potential savings is, at most, the number circuits with equal elements but less than the number of circuits.

3.3. Stage 3 – Moving the Elements

After the mapping is determined, it is only a matter of placing the elements in their correct position. The elements are put in place by making a single pass through the map and placing (or reordering) each circuit as it is encountered. If there are multiple circuits,

24 the placement of each circuit could be done in parallel by using a temporary location for each placement process. Additionally, the entire placement process could be performed by a completely different machine. Or, an itemization of movements could be generated that would be performed by humans in inventory/shipping operations.

3.4. Storage Overhead

In addition to the local variables, the extra storage overhead for the new RAS algorithm is

2n words of storage at a minimum. If equal elements are possible, comparisons can be reduced by adding n Booleans to keep track of equal elements. If equal elements are known, n additional words of storage can be used to ensure optimal assignments.

3.5. Complexity

To calculate the overall complexity we add the complexity of the stages.

Operations Assigns Compares Other Storage Stage 1 0 O(nlogn) O(nlogn) nw + O(logn) Stage 2 0 0 Θ(n) nw + O(1) Stage 3 ≤3n/2 0 Θ(n) O(1) Total ≤3n/2 O(nlogn) O(nlogn) 2nw + O(logn) Table 2 Complexity of RAS algorithm without optimal assignments

Operations Assigns Compares Other Storage Stage 1 0 O(nlogn) O(nlogn) nw + nb + O(logn) Stage 2 0 0 Θ(n) 2nw + O(1) Stage 3 ≤3n/2 0 Θ(n) O(1) Total ≤3n/2 O(nlogn) O(nlogn) 3nw + nb + O(logn) Table 3 Complexity of RAS algorithm with optimal assignments

* The storage items: w is words and b is booleans

25 4. Analyzing Sorts

Due to the variations in performance of Shell Sort with different gap sequences, the

SOptimized version with the Tokuda A108870 sequence is used. See Appendix C Shell

Sort for justification and explanation.

4.1. Analyzing Assignments

4.1.1. Random Data

The benefits of O(n) complexity of assignments is easily seen in Appendix E. With random data the number of assignments is usually close to n for the RAS algorithm.

However, the difference between the optimal assignments and a stable ordering is usually small. So the extra overhead to achieve optimal assignments may not be worthwhile unless the cost of assignments is very high. See Analyzing Time later in this chapter and

Appendix J to help determine when it would be worthwhile.

The only other algorithm examined with O(n) complexity of assignments is Bingo Sort which usually has a little less than 3n assignments for the original version and a little less than 2n assignments with the versions optimized for assignments.

The drawback of having complexity worse than O(n) is illustrated with the next best algorithm as the dataset size increases. Quick Spencer1M increases from about 4.3n with

1,000 elements to over 10n with 10,000,000 elements.

The assignments needed by Merge Sort (2nlogn) increases from just under 20n with

1,000 elements to over 46n with 10,000,000 elements.

26 Figure 8 illustrates how the algorithms with greater than O(n) assignments are substantially worse than the RAS.

50 Heap 45 40 35 Merge 30 25 20 Quick 15 10 RAS 5 0

Shell 00 07 00 0 1000 0 10 100000 1E+ 1000

Figure 8 Assignments per Element

4.1.2. Special Data

There are some datasets that cause some sorts to exhibit extreme behavior. Appendix F has tables showing the results with some of these data sets.

For assignments, a reverse ordered list with an even number of elements has the lower bound of 3n/2 assignments necessary.

The WorstAssign dataset is almost sorted but is another instance of a dataset with a lower bound of 3n/2 assignments

Many of the sort algorithms achieve the lower bound of 3n/2 assignments. We will see later that many suffer from a large number of comparisons.

27 4.2. Analyzing Comparisons

4.2.1. Random Data

If there are equal elements in random data, using the SMerge ordering of the RAS

algorithm requires the fewest number of comparisons. If all elements are unique, it has

the same number of comparisons as the regular Merge Sort. See Appendix G for tables

that show this. When a version of Merge Sort is used to get the ordering there are no

extreme datasets that would require more than the O(nlogn) comparisons as there is with

many other algorithms. The various tree methods of ordering (including the splay

version) have roughly the same number of comparisons as some of the Quick Sorts.

Shell Sort using the Tokuda sequence is a little better than Heap Sort.

The O(n2) comparison complexity of Insertion Sort does not perform well and Bingo Sort

is even worse.

It is easily seen in figure 9 that RAS and Merge sorts are best in terms of comparisons

since they overlap.

50 Heap 45 40 35 Merge 30

25 20 Quick 15 10 RAS 5 0 Shell

+07 1000 000 10 100000 1E 1000000

Figure 9 Comparisons per Element

28 4.2.2. Special Data

Many of the algorithms that achieved the lower bound on assignments performed poorly on comparisons. Appendix H has tables showing the results with some of these data sets.

While there are a few algorithms that do marginally better than RAS in these special cases, they perform much worse in other situations. See appendix I for both assignments and comparisons combined.

4.3. Assignments and Comparisons

If assignments and comparisons are both counted, the benefits of the RAS are made obvious in figure 10.

90 Heap 80 70 Merge 60

50 Quick 40

30 RAS 20 10 Shell 0

0 0 0 07 0 + 1000 10 00000 0000 1 1E 10 Figure 10 Assignments and Comparisons per Element

29

4.4. Analyzing Time

For various data sets, the point it would be more efficient to use the RAS algorithm is calculated. This is based on a theoretical increase in the amount of time it takes to perform an assignment, or a comparison, or both. So for a data set and type (assignment, comparison, or both) the point is:

T1 + X * C1 = T2 + X * C2 or X = (T1 – T2) / (C2 – C1) Where:

T1 is the measured execution time with algorithm 1

C1 is the count of operations with algorithm 1

T2 is the measured execution time with algorithm 2

C2 the count of operations with algorithm 2

X is the extra time for each operation

Appendix J shows tables that indicate the time increase of assignments and comparisons necessary to make faster sorts equal to the RAS algorithm using BPMerge (also SMerge

Stable, and SMerge Optimal for datasets that have equal elements) with various random datasets.

From the tables you will note that the 16 bit RAS algorithm is fastest due to less memory overhead but is limited to 65535 elements. It does the same comparisons and assignments as the RAS (which does not have the data set size limitation) using BPMerge for stage 1 with Stable assignments which is the fastest for many data sets and would be faster than all non-RAS algorithms for all the data sets if assignments and comparisons took a mere 85 nanoseconds.

30

While the potential benefits of optimal assignments are dependant on the nature of the dataset, the assignment time needed to justify the use of Optimal assignments increases with the dataset size. The increase needed grows from about 19 microseconds with 1,000 elements, to 316 microseconds with 10,000 elements, to 2,159 microseconds with

100,000 elements, to 34,172 microseconds with 1,000,000 elements, to 301 milliseconds with 10,000,000 elements. This is due to the usually very small reduction in assignments which consists of: a) equal elements that can be rearranged so they do not need to be moved, and b) equal elements that are on multiple circuits which can be rearranged to connect the circuits.

4.5. Limitations

There is both storage and processing overhead when using the RAS algorithm.

Therefore, if assignments or comparisons are not expensive (like an array of integers) the extra overhead may exceed any time saved in the reduction of assignments and comparisons.

31 5. Future Enhancements

5.1. Optimize Comparisons

Since comparisons and assignments have been separated in the RAS algorithm, the comparison part of the process could be optimized as was done with the assignment part of the process. Therefore, if comparisons are costly, a version that uses merge for the comparison stage would be able to use a specialized optimal comparison process provided that one is known. Peczarski has recently shown [11] that if the number of elements is less than 47 the Ford-Johnson algorithm [12] is unbeaten. Therefore, the new four Ford-Johnson (4FJ) algorithm [13] could be used to determine the sequence of comparisons. For larger partitions some of the methods suggested by Manacher, Bui, and

Mai [14] may be applicable like using the Forward-Testing-Backward-Insertion algorithm by Christen [14]. All the recent research into reducing comparisons can be easily incorporated into stage 1 of the RAS algorithm and will have the benefit of O(n) assignments.

5.2. Avoid Comparisons

Could the comparisons be avoided altogether? By using a non-comparison based sort

(like ) to obtain the ordering, the O(nlogn) comparison complexity might be avoided.

5.3. Reimplement Problems as a Sort

There are some problems that are not normally thought of as sorting appications that may benefit from envisioning them as a sort.

32 5.3.1. Defragmentation

When defragmenting a hard drive, clusters are moved so files are contiguously stored and files that are likely accessed from the same application are stored close to each other.

Defragmentation could be implemented as an in-place comparison-based sort by using the directory, file, and position within the file to do the comparisons. The assignments would be done by reading a cluster, writing it to a new location, and updating directory entries and allocation information.

5.3.2. Inventory Management

When items leave inventory, having them conveniently placed will increase efficiency.

This is similar to having the clusters placed for efficient access in the previous example.

In order to have the items placed efficiently, a sort would be performed periodically that would move the items that will leave the inventory within that period of time near the exit point. Items that are expected to remain in the inventory beyond the period would be considered equal to each other and greater than the items that would leave within the period. The items that will leave soon can be further organized for efficient LIFO (Last

In First Out) loading of trucks if necessary.

33 6. Summary

If assignments or comparisons are expensive, some version of the RAS algorithm is preferable. For datasets with no elements considered equal, the straight Merge Sort ordering of the RAS algorithm would have less overhead. If equal elements are possible, the version that accounts for equal elements may be best. Using optimal assignments is probably only warranted if assignments are very expensive due to the extra processing required for what is usually a very small reduction in assignments.

If assignments and comparisons are inexpensive, some of the other algorithms may perform faster because of their lower overhead.

34 Appendix A - Sort Tester

The Sort Tester program was developed to allow analysis of various in-place comparison- based sorting algorithms by precisely counting the numbers of assignments and comparisons and to give a conceptual understanding of the algorithms by animating the sort graphically as it performs. Using the same data sets in the same environment allows precise objective comparisons of various algorithms to determine which is best for a particular situation. While it does time the runs, execution time has not been of primary concern because the time to make an assignment or a comparison could dwarf the computational overhead of the algorithms. This would need to be accounted for in deciding which algorithm would be best for a particular situation. The focus of this thesis is on applications in which the time to perform assignments and comparisons is relatively great, and could be due to slow access to secondary storage, or network latency, etc.

All sorting is logged to a Sorts.log text file. Additionally, if a sort is performed on a loaded file, an entry will be made in a Sorts.csv comma delimited file that can be used to import the data into the Sorts.mdb database to analyze the data, which is described in appendix B.

Starting at the bottom right of the screen, as shown in figure 11, and working left the various functions of the program will be described.

35

Figure 11 Screen Capture of Sort Tester

Informational Counting

At the bottom right of the screen (it could be near the middle if you have high resolution), there is various counting information which show the count of various types of assignments, comparisons, etc.

Display

The display control determines what will be displayed during the sort, with the following meanings:

None – Nothing is displayed and counting is turned off. This is the most minimal display option to make the sort time as short as possible.

36 Off – The elements are not displayed but counting is done which is displayed after the sort completes.

Start/End – The elements are displayed in their original order and when the sort completes they are redisplayed in their sorted positions.

Delayed – As each element is compared or moved a line or dot is drawn or erased which animates the sort. However, updates to the display are delayed. If this option is selected, there is a slider which allows adjustment of the delay so that updates to the display occur between 1 and 60 (default is 30) times per second.

All – As each element is compared or moved a line or dot is drawn or erased and the display is updated. This greatly reduces the sort speed (which can be thought of as simulating a sort where comparisons and assignments are time consuming).

Dot – This selects whether lines or dots are drawn. For small data sets, lines make the animation more noticeable. For large data sets (more than the horizontal resolution), dots make more data visible but will not make comparisons as obvious.

DataSet

Various types of data sets can be generated.

Quantity – is the number of elements.

Range – is the range of values for the elements. If the range is high the number of equal elements will be reduced. If the range is low there can be many elements that are equal to other elements.

Save – will save a particular data set to a file.

Load – will load a previously saved data set from a file.

37 Fill – will generate a data set based on the selected options (Quantity, Range, type, etc).

Unique – forces all elements to be unique. When this option is checked the range will equal the quantity.

Random – a data set of elements with values within will be randomly generated.

Equal – a data set of elements with all equal values will be generated.

Half Equal – a data set of elements with values within will be generated with half being random and half equal to the middle of the range.

Ordered – a data set of elements that are already in order will be generated.

This is one of the worst cases for some sorting algorithms.

Reversed – a data set of elements that are in reverse order will be generated.

This is one of the worst cases for some sorting algorithms.

SplayKiller – a data set will be generated with (as you progress through) each element alternating between being larger than all previous elements and being smaller than all previous elements. This is the worst case for some of the splay tree versions of my sorting algorithms.

PreMerge – a data set will be generated with the first half and last half are already in order. Similar to the intermediate data set during a merge sort before the final merge.

WorstAssign – a data set will be generated that is almost in order but has the maximum number of circuits so at least 3/2 assignments will be necessary to put the data set in order. Sort results with this data set are shown in appendix F.

WorstShell – a data set will be generated that has the largest elements interspersed with smaller elements. The elements are in order relative to elements that have the same index

38 type (even, or odd). When the number of elements is a power of 2, the original sequence proposed by Shell will not detect an inversion until the increment is 1. Therefore, in effect, many comparisons are done and then an Insertion Sort is performed.

Stability – a data set will be generated in which all elements are equal except for one larger element that is at the beginning. This can be used to illustrate the difference in assignments between a stable algorithm (which requires n + 1 assignments) and a non- stable algorithm (which can be done in 3 assignments).

SortTypes

Bubble Sort

Bubble Sort is an example of a bad sorting algorithm with a worst case of O(n2) comparisons and assignments.

Insertion Sort

Insertion Sort is somewhat efficient on very small data sets and may be used as a secondary sort in conjunction with Quick Sort. However, with worst case data there are

O(n2) comparisons and assignments. Insertion is from Berman and Paul’s Algorithms book [1, page 42]. The SOptimized version avoids a few unnecessary assignments to and from temporary locations by doing direct comparisons and only moving an element into a temporary location if it is definitely going to move. The reduction in assignments is usually less than 1% and some of the comparisons to temporary locations will be direct comparisons. There is no special storage overhead or concerns with this algorithm.

39 SMInsert

SMInsert is a variation on Insertion Sort that first swaps opposite elements if they are out of order, and then from the center outward inserts two elements at a time into the sorted elements using a binary search to determine the placement of each element. There is no special storage overhead or concerns with this algorithm. It is only included because it was used to illustrate (in a seminar) some of the steps taken developing this thesis.

Bingo Sort

Bingo Sort is a variation of Selection Sort that performs best if the number of distinct elements is small (many elements are equal to other elements). This version modifies the version in Berman and Paul’s Algorithms book [1, page 173] to make it comparison- based. The sort works by making the smallest element in the list the bingo element and moving all elements equal to the bingo to the sorted part of the list at the beginning of the elements. The bingo element is progressively increased until the list is sorted. While the number of assignments will be less than 3n, the number of comparisons is Θ(n2) if there are no equal elements. The SOptimized version leaves an element in the temporary location and uses the free element to make room as elements are moved; this is instead of swapping elements. The result is fewer assignments but the comparisons can increase since an element that has been compared once may be compared again if it is moved later in the list. The Bidirectional version extends the SOptimized version in that it moves the smallest elements to the beginning of the list and the largest elements to the end of the list with each pass. This results in fewer passes and fewer comparisons. There could be

40 some possible improvements by skipping comparisons that have already been made, but the time and effort is not justified because the RAS algorithm performs better in all cases.

J Sort

J Sort is a sort by Jason Morrison that does two build heap operations in order to make a final Insertion Sort more efficient [15]. While it is more efficient than Insertion Sort it is not good for large data sets. There is no special storage overhead or concerns with this algorithm. Note that this is not the J Sort by John Cohen (also named Quick-er Sort by

Théodore Myshrall) which uses Strand and Shuffle Sorts.

Shell Sort

Shell Sort was discovered by Donald Shell in 1959 [4]. It increases the efficiency of

Insertion Sort by having a. increment (or gap) between the elements compared. It successively reduces the increment until all items are in order. The efficiency is acutely dependent on the sequence of increments used. Shell is from Berman and Paul’s

Algorithms book [1, pages 168-169]. There are many possible increment sequences:

(sequences can be found using A###### at http://www.research.att.com/~njas/sequences/)

Shell – was the sequence initially proposed by Shell to use an increment of n/2 and dividing it by 2 with each pass. It still has worst-case comparison complexity of O(n2).

Weiss – by Weiss uses an increment of n/2.2 and dividing it by 2.2 with each pass but making sure there is a 1 increment [16].

41 Hibbard A000225 – by Hibbard in 1963 [17] is 2k-1 to derive the sequence (1, 3, 7, 15,

31, 63, 127, 255, 511, 1023, 2047, 4095…) which reduces the running time to O(n3/2) [2, vol 3 page 91].

Papernov A000051 – by A. A. Papernov and G. V. Stasevich in 1965 [2, vol 3 page 91] is 2k+1 to derive the sequence (1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049…).

Pratt A003586 – by Vaughan Pratt in 1971 is all 2p3q to derive the sequence (1, 2, 3, 4,

6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54…) which has running time of O(n(logn)2)[2, vol

3 page 91]. However, there is substantial comparison overhead due to multiple passes but may be the best increment if the dataset is large, or, as Knuth said, “astronomical.”

Therefore, other “Pratt-like” sequences are sometimes used (like 5p11q and 7p13q) [2, vol

3 page 93]. However, this sequence can reduce assignments if unnecessary assignments to temporary locations are avoided. The SOptimized version of Shell Sort does this. And the efficiency of assignments can be seen in Appendix C.

4^(n+1)+3*2^n+1 A036562 – mentioned by R. Sedgewick in 1996 [18] as the upper bound in 1982 is 4(n+1)+3*2n+1 to derive the sequence (1, 8, 23, 77, 281, 1073, 4193,

16577, 65921, 262913…).

Incerpi-Sedgewick A036569 – by Janet Incerpi and Robert Sedgewick in 1985 [19] begins with (1, 3, 7, 21, 48, 112, 336, 861, 1968…).

Sedgewick A033622 – by R. Sedgewick in 1986 [20] is 9*2n-9*2(n/2) +1 if n is even;

8*2n-6*2((n+1)/2) +1 if n is odd to derive the sequence (1, 5, 19, 41, 109, 209, 505, 929,

2161, 3905, 8929, 16001…) which reduces the running time to O(n4/3)[2, vol 3 page 93].

Tokuda A108870 – by N. Tokuda in 1992 [6] developed the formula: ceiling( (9 * (9/4) n

- 4) / 5) to derive the sequence (1, 4, 9, 20, 46, 103, 233, 525, 1182…) which performs

42 very well and will be the sequence used to compare Shell Sort with other algorithms. See

Appendix C for an explanation of why.

Ciura A102549 – by Marcin Ciura in 2001 [21] used sequential analysis to develop a sequence (1, 4, 10, 23, 57, 132, 301, 701, 1750) that may be optimal for comparisons up to several thousand elements. However, larger data sets suffer because the largest number in the sequence is 1750.

(3n - 1)/2 A003462 – is (3n-1)/2 [22] to derive the sequence (1, 4, 13, 40, 121, 364, 1093,

3280, 9841, 29524, 88573…).

2n-45, n >= 6 A036564 – is 2n-45, n >= 6 [23] to derive the sequence (1, 19, 83, 211, 467,

979, 2003, 4051, 8147, 16339, 32723…). a(0)=1, a(i)= Prime[i^3] A055875 [24] to derive the sequence (1, 2, 19, 103, 311, 691,

1321, 2309, 3671, 5519, 7919…). round[ 1 + e^(n-2) ] A055876 [25] to derive the sequence (1, 2, 4, 8, 21, 56, 149, 404,

1098, 2982, 8104, 22027…).

SOptimized is a slight modification made to the algorithm which prevents some unnecessary assignments to temporary locations by doing direct comparisons and only moving an element into a temporary location if it is definitely going to move. Because each pass has successively made the elements more ordered, it is common that the elements will not need to be moved. Therefore a substantial reduction in the number of assignments is possible. Using a good increment like Tokuda A108870 the reduction is usually greater than 30%. While the Pratt A003586 increment has other drawbacks, my optimization can reduce assignments over 80% because the increments are very fine and

43 the likelihood of an element not needing to be moved is increased. For the opposite extreme, using the 2n-45, n >= 6 A036564 increment the reduction is usually less than

10% because the increments are very coarse. There is no special storage overhead or concerns with Shell Sort. With the number of variations in implementation (sequences,

SOptimized , etc), to provide consistency the SOptimized version with the Tokuda

A108870 sequence will be used as representative of Shell Sort. See Appendix C on Shell

Sort for explanation of why.

Heap Sort

Heap Sort is consistently O(nlogn) in all cases. Heap Sort works like Selection Sort except it reorganizes the data into a heap during processing to make selection of the largest element more efficient. The largest element is successively moved to the end and the heap is restructured. This reorganization results in overhead in assignments. Often other algorithms are used in practice due to greater performance in the average case.

There are three versions of Heap Sort included: BermanPaul which is from Berman and

Paul’s Algorithms book [1, pages 149-153], BermanPaul with SOptimized which avoids some unnecessary assignments (usually about 1 to 2%), and Wikipedia [26] which is an entirely different version. There is no special storage overhead or concerns with this algorithm.

Merge Sort

Merge Sort is an algorithm with O(nlogn) comparisons. The in-place versions however, like this Merge from Berman and Paul’s Algorithms book [1, pages 46-47], have a

44 relatively high number of assignments (2nlogn) and require n temporary locations while all the other algorithms mentioned use only one temporary location. The high number of temporary locations needed is a storage concern. Note that Merge Sort implementations that use linked lists do not have the need for the temporary locations but they are not in- place algorithms. Because the sort divides the problem into two smaller sorts and a merge, the smaller sorts could be performed in parallel.

Quick Sort

Quick Sort was discovered by Tony Hoare in 1961 [7]. It has comparison complexity of

O(nlogn) in the average case but is O(n2) in the worst case. There are many versions included: BermanPaul is from Berman and Paul’s Algorithms book [1, pages 50-51],

Qinjian Deng from Qinjian Deng’s 1996 Master’s Thesis [27] which does median of 3 partitioning and stops when the list size is less than 10 with a final Insertion Sort at the end. Qinjian Deng with SOptimized avoids the comparison of an element with itself.

SedgewickBentley is from Sedgewick and Bentley’s 2001 presentation “Quicksort is

Optimal” [28] that implements a version with 3-way partitioning that is intended to improve performance when there are equal elements. Spencer1 is my version, Spencer2 partitions around the center element, and Spencer3 does a median of three to determine the partition element. The stack space required for the recursion, or additional storage for non-recursive versions (like QinjianDeng), could be a concern.

The Spencer1 version uses the first element as a partitioning element and alternates between processing the top and bottom of the list. The partitioning element will end up

45 at the point where the top and bottom processing meet. Spencer2 uses the center element as the partitioning element by moving it into the temporary location and moving the first element to the center. Spencer3 uses a median of three by similar adjustment.

My three versions are included to show that partitioning on the center element (Spencer2) is effective in avoiding the typical worst case scenarios like in-order and reverse-order.

While using median of three (Spencer3) there is poor performance with reverse ordered elements.

There is also an option of how to handle equal elements during the partition. If there are elements equal to the partition element, MinMove will use greedy avoidance of assignments by leaving equal elements on the side of the partition element where they originated. This typically results in fewer assignments. MinComp will move equal elements to one side of the partition element regardless of the side on which they were originally located. Therefore, those elements will be processed in only one of the subsequent subsorts instead of both. This typically results in fewer comparisons.

When the three Spencer versions are used, a break point can be set in which a secondary sort will be used when the number of elements is less than some point. If the secondary sort is Insertion, there is an option to defer the Insertion Sort until Quick Sort completes the partitioning.

46 Because Quick Sort partitions the elements into two smaller sets and sorts them individually, the smaller sorts could be performed in parallel.

The RAS algorithm evolved out of attempts to design an algorithm that would be used for small data sets in cooperation with Quick Sort. If the algorithm were more efficient, the point at which the small data set algorithm was used could be raised and there would be an overall increase in efficiency. After trying many variations of using a binary search

(see SMInsert) of the already ordered portion of the data, eventually a variation of a Tree

Sort was implemented with the addition of steps two and three. This algorithm was more efficient on all data set sizes, so the use of Quick Sort as the primary sort was abandoned.

However, RAS could be used as a secondary sort for Quick Sort and could be implemented to have storage efficiencies if the breakpoint is set to 255 or 65535 elements because the data structures could be reduced in size. See the tables in Appendix D to get an idea of the potential benefits.

RAS – Reduced Assignment Sort

Comparison type – finding an ordering

Tree adds elements to a binary tree. The worst case is O(n2) comparisons when the elements are in order or reverse order and added sequentially. When the ordered (or reverse ordered) elements are added dithered (or not sequentially) the result will be a balanced binary tree; but there is still the same worst case O(n2) for another data set that in practice is very unlikely.

47 Splay adds elements to a binary tree performing rotations to splay the tree to have an adjacent element at the root before the element is added. The splaying of the tree can find patterns in the data making comparisons more efficient. However, there are cases where the splaying of the tree can create worst case situations. An instance is where data alternates extremes with every other element alternating between being greater than all previous elements and the next being less than all previous elements. In this case the entire tree will be rotated through every element with each new element.

Splay1 performs a similar rotation but only on the root element. This way the tree will adjust slowly if a pattern emerges but will not have the extreme reaction to an element that does not fit the pattern.

Splay/2 is similar to splay but only performs rotates on every other node. This is something in between Splay and Splay1. It allows greater restructuring of the splay tree than Splay1 but only half as much as Splay. When an element is added, the root will be rotated. And when another element is added the nodes that were not rotated will be in position to be rotated.

When processing is sequential, all the splay versions mentioned so far perform identically on ordered or reverse ordered elements because they are best cases.

48 SplayX is the same as Splay except that when the adjacent element is at the root the new element is made into the root with the adjacent element as a child. This is even more efficient for ordered or reverse ordered elements but is less efficient on average.

BPMerge uses a linked list version of Berman and Paul’s Merge Sort. You will notice that the number of comparisons will be identical to the standalone version of Merge.

Also, equal elements are not identified so improvements to assignment by using the unstable or optimal options are not available. However, if it is known that all elements are unique this would be more efficient in both speed and space.

SMerge is a modification of the linked list version of Merge Sort that keeps track of equal elements. If all elements are unique, it will have the same number of comparisons as BPMerge. However, if there are equal elements there can be a reduction of the order by up to logn comparisons. So instead of O(nlogn) comparisons there could be only n-1 comparisons if all elements are equal.

Assignment type – moving the items

Regardless of the assignment type the number of assignments will never be more than

3n/2.

Stable – equal elements will retain their relative position. This option has the least processing overhead but can result in a greater number of assignments (sort a Stability data set as an example).

49 Unstable – equal elements that are already in a valid location will not be moved during the sort.

Optimal – the order of equal elements that are on different circuits will be switched in order to connect the circuits. Each time a circuit is combined with another, one assignment is saved but there is greater processing and storage overhead.

RAS16 – 16 bit Reduced Assignment Sort

This is a 16 bit self contained version of the RAS algorithm which does a stable sort and does not identify equal elements. It is limited to data sets with a maximum of 65535 elements.

50 Appendix B – Sorts.mdb database of results

An access database was used to record and analyze the results of sorting.

Table SortsCsv

SortsCsv links to data from newly performed sorts that can be imported into this database. The SortsCsv table must link to the Sorts.csv file created by the Sort Tester program.

Form frmAddNew

To import data open the form frmAddNew and click Start. It will identify new information and prompt for approval to add it to the database.

Form frmActive

Use frmActive to select what files, sorts, etc to use in analysis.

Query qryAssignCnt

Use qryAssignCnt to show how many assignments there were for the active files & sorts.

Query qryCompareCnt

Use qryCompareCnt to show how many comparisons there were for the active files & sorts.

Query qryBothCnt

Use qryBothCnt to show how many assignments and comparisons there were for the active files & sorts.

Query qryExtraTime

Use qryExtraTime to calculate the extra time of assignments, comparisons, and both assignments and comparisons when it would be more efficient to use a selected reference algorithm.

51 Appendix C – Shell Sort

To compare Shell Sort with other sorting algorithms the SOptimized version with the

Tokuda A108870 sequence is used. To justify this, first how the sequences and

SOptimization affect the count of assignments will be examined, and then the same will be done for comparisons, and finally a combination as if assignments and comparisons are of equal importance. The SOptimized version with the Tokuda A108870 sequence performs well in all cases and any other sequences that are more efficient in a particular case are less efficient in other situations, however, Weiss’ proposed sequence also performs very well.

Assignments

As the following tables show the SOptimized version with the Pratt A003586 sequence is most efficient for assignments while the same sequence that is not SOptimized is the worst. In fact, the SOptimization is more important in regards to assignments than the choice of sequence. You will notice that the SOptimized version with the Tokuda

A108870 sequence is always near the top and often just behind the SOptimized version with the Pratt A003586 sequence.

52

Shell Sort AssignCnt for a100r.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 209 209 209 0 627 Shell Tokuda A108870 SOptimized 188 188 300 0 676 Shell Papernov A000051 SOptimized 226 226 274 0 726 Shell Weiss N/2.2 SOptimized 198 198 336 0 732 Shell Shell N/2 SOptimized 204 204 335 0 743 Shell Ciura A102549 SOptimized 201 201 347 0 749 Shell (3^n - 1)/2 A003462 SOptimized 194 194 385 0 773 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 212 212 350 0 774 Shell Incerpi-Sedgewick A036569 Soptimized 211 211 359 0 781 Shell Hibbard A000225 SOptimized 221 221 347 0 789 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 176 176 472 0 824 Shell Sedgewick A033622 Soptimized 198 198 492 0 888 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 170 170 651 0 991 Shell 4^(n+1)+3*2^n+1 A036562 291 291 472 0 1054 Shell (3^n - 1)/2 A003462 342 342 385 0 1069 Shell Tokuda A108870 420 420 300 0 1140 Shell Ciura A102549 405 405 347 0 1157 Shell Sedgewick A033622 334 334 492 0 1160 Shell Weiss N/2.2 421 421 336 0 1178 Shell Incerpi-Sedgewick A036569 420 420 359 0 1199 Shell a(0)=1; a(i)= Prime[i^3] A055875 278 278 651 0 1207 Shell 2^n-45; n >= 6 A036564 SOptimized 137 137 936 0 1210 Shell Hibbard A000225 480 480 347 0 1307 Shell 2^n-45; n >= 6 A036564 197 197 936 0 1330 Shell Shell N/2 503 503 335 0 1341 Shell round[ 1 + e^(n-2) ] A055876 508 508 350 0 1366 Shell Papernov A000051 665 665 274 0 1604 Shell Pratt A003586 1387 1387 209 0 2983 Table 4 Shellsort assigns for 100 random elements

53

Shell Sort AssignCnt for a100u.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 249 249 249 0 747 Shell Papernov A000051 SOptimized 231 231 295 0 757 Shell Tokuda A108870 SOptimized 215 215 363 0 793 Shell Hibbard A000225 SOptimized 229 229 345 0 803 Shell Shell N/2 SOptimized 225 225 361 0 811 Shell (3^n - 1)/2 A003462 SOptimized 200 200 417 0 817 Shell Ciura A102549 SOptimized 214 214 389 0 817 Shell Sedgewick A033622 Soptimized 183 183 469 0 835 Shell Weiss N/2.2 SOptimized 217 217 407 0 841 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 235 235 385 0 855 Shell Incerpi-Sedgewick A036569 Soptimized 235 235 409 0 879 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 181 181 647 0 1009 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 181 181 685 0 1047 Shell (3^n - 1)/2 A003462 342 342 417 0 1101 Shell Sedgewick A033622 334 334 469 0 1137 Shell Ciura A102549 405 405 389 0 1199 Shell Tokuda A108870 420 420 363 0 1203 Shell 4^(n+1)+3*2^n+1 A036562 291 291 647 0 1229 Shell a(0)=1; a(i)= Prime[i^3] A055875 278 278 685 0 1241 Shell Incerpi-Sedgewick A036569 420 420 409 0 1249 Shell Weiss N/2.2 421 421 407 0 1249 Shell 2^n-45; n >= 6 A036564 SOptimized 143 143 971 0 1257 Shell Hibbard A000225 480 480 345 0 1305 Shell 2^n-45; n >= 6 A036564 197 197 971 0 1365 Shell Shell N/2 503 503 361 0 1367 Shell round[ 1 + e^(n-2) ] A055876 508 508 385 0 1401 Shell Papernov A000051 665 665 295 0 1625 Shell Pratt A003586 1387 1387 249 0 3023 Table 5 Shellsort assigns for 100 unique random elements

54

Shell Sort AssignCnt for a1kr.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 3988 3988 3988 0 11964 Shell Weiss N/2.2 SOptimized 3456 3456 6216 0 13128 Shell Tokuda A108870 SOptimized 3484 3484 6255 0 13223 Shell Ciura A102549 SOptimized 3468 3468 6456 0 13392 Shell Sedgewick A033622 Soptimized 3256 3256 7283 0 13795 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 3529 3529 6826 0 13884 Shell Incerpi-Sedgewick A036569 Soptimized 3501 3501 7143 0 14145 Shell Hibbard A000225 SOptimized 3769 3769 6805 0 14343 Shell Papernov A000051 SOptimized 4001 4001 6575 0 14577 Shell Shell N/2 SOptimized 3834 3834 7157 0 14825 Shell (3^n - 1)/2 A003462 SOptimized 3345 3345 8689 0 15379 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 3077 3077 11150 0 17304 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 2852 2852 13123 0 18827 Shell (3^n - 1)/2 A003462 5457 5457 8689 0 19603 Shell Sedgewick A033622 6182 6182 7283 0 19647 Shell Ciura A102549 6771 6771 6456 0 19998 Shell Incerpi-Sedgewick A036569 6611 6611 7143 0 20365 Shell 4^(n+1)+3*2^n+1 A036562 4610 4610 11150 0 20370 Shell Tokuda A108870 7059 7059 6255 0 20373 Shell Weiss N/2.2 7174 7174 6216 0 20564 Shell round[ 1 + e^(n-2) ] A055876 7355 7355 6826 0 21536 Shell Hibbard A000225 7987 7987 6805 0 22779 Shell a(0)=1; a(i)= Prime[i^3] A055875 4873 4873 13123 0 22869 Shell Shell N/2 8006 8006 7157 0 23169 Shell Papernov A000051 9966 9966 6575 0 26507 Shell 2^n-45; n >= 6 A036564 SOptimized 2690 2690 23118 0 28498 Shell 2^n-45; n >= 6 A036564 4240 4240 23118 0 31598 Shell Pratt A003586 30955 30955 3988 0 65898 Table 6 Shellsort assigns for 1,000 random elements

55

Shell Sort AssignCnt for a1ku.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 4227 4227 4227 0 12681 Shell Ciura A102549 SOptimized 3477 3477 6609 0 13563 Shell Weiss N/2.2 SOptimized 3633 3633 6507 0 13773 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 3581 3581 6789 0 13951 Shell Papernov A000051 SOptimized 4013 4013 5995 0 14021 Shell Tokuda A108870 SOptimized 3727 3727 6695 0 14149 Shell Hibbard A000225 SOptimized 3884 3884 6547 0 14315 Shell Sedgewick A033622 Soptimized 3448 3448 7841 0 14737 Shell Incerpi-Sedgewick A036569 Soptimized 3616 3616 7597 0 14829 Shell Shell N/2 SOptimized 3927 3927 7329 0 15183 Shell (3^n - 1)/2 A003462 SOptimized 3445 3445 8949 0 15839 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 3071 3071 11101 0 17243 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 2924 2924 13331 0 19179 Shell (3^n - 1)/2 A003462 5457 5457 8949 0 19863 Shell Ciura A102549 6771 6771 6609 0 20151 Shell Sedgewick A033622 6182 6182 7841 0 20205 Shell 4^(n+1)+3*2^n+1 A036562 4610 4610 11101 0 20321 Shell Tokuda A108870 7059 7059 6695 0 20813 Shell Incerpi-Sedgewick A036569 6611 6611 7597 0 20819 Shell Weiss N/2.2 7174 7174 6507 0 20855 Shell round[ 1 + e^(n-2) ] A055876 7355 7355 6789 0 21499 Shell Hibbard A000225 7987 7987 6547 0 22521 Shell a(0)=1; a(i)= Prime[i^3] A055875 4873 4873 13331 0 23077 Shell Shell N/2 8006 8006 7329 0 23341 Shell 2^n-45; n >= 6 A036564 SOptimized 2635 2635 19853 0 25123 Shell Papernov A000051 9966 9966 5995 0 25927 Shell 2^n-45; n >= 6 A036564 4240 4240 19853 0 28333 Shell Pratt A003586 30955 30955 4227 0 66137 Table 7 Shellsort assigns for 1,000 unique random elements

56

Shell Sort AssignCnt for a10kr.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 60681 60681 60681 0 182043 Shell Tokuda A108870 SOptimized 50724 50724 95069 0 196517 Shell Weiss N/2.2 SOptimized 51241 51241 94538 0 197020 Shell Sedgewick A033622 Soptimized 49614 49614 105675 0 204903 Shell Ciura A102549 SOptimized 50129 50129 106708 0 206966 Shell Papernov A000051 SOptimized 61053 61053 123239 0 245345 Shell Shell N/2 SOptimized 57216 57216 149110 0 263542 Shell (3^n - 1)/2 A003462 SOptimized 49549 49549 165076 0 264174 Shell Ciura A102549 87021 87021 106708 0 280750 Shell Sedgewick A033622 93187 93187 105675 0 292049 Shell Tokuda A108870 99232 99232 95069 0 293533 Shell Weiss N/2.2 101679 101679 94538 0 297896 Shell (3^n - 1)/2 A003462 75243 75243 165076 0 315562 Shell Shell N/2 120005 120005 149110 0 389120 Shell Papernov A000051 133602 133602 123239 0 390443 Shell Pratt A003586 550711 550711 60681 0 1162103 Table 8 Shellsort assigns for 10,000 random elements

Shell Sort AssignCnt for a10ku.srt SortName ToTemp FromTemp Direct Self Assigns Shell Pratt A003586 SOptimized 63980 63980 63980 0 191940 Shell Tokuda A108870 SOptimized 51610 51610 97696 0 200916 Shell Weiss N/2.2 SOptimized 52412 52412 99124 0 203948 Shell Sedgewick A033622 Soptimized 49523 49523 107842 0 206888 Shell Ciura A102549 SOptimized 50433 50433 108726 0 209592 Shell Papernov A000051 SOptimized 62859 62859 128044 0 253762 Shell (3^n - 1)/2 A003462 SOptimized 49225 49225 159194 0 257644 Shell Shell N/2 SOptimized 58252 58252 152886 0 269390 Shell Ciura A102549 87021 87021 108726 0 282768 Shell Sedgewick A033622 93187 93187 107842 0 294216 Shell Tokuda A108870 99232 99232 97696 0 296160 Shell Weiss N/2.2 101679 101679 99124 0 302482 Shell (3^n - 1)/2 A003462 75243 75243 159194 0 309680 Shell Shell N/2 120005 120005 152886 0 392896 Shell Papernov A000051 133602 133602 128044 0 395248 Shell Pratt A003586 550711 550711 63980 0 1165402 Table 9 Shellsort assigns for 10,000 unique random elements

57

Shell Sort AssignCnt for a100kr.srt SortName ToTemp FromTemp Direct Self Assigns Shell Weiss N/2.2 SOptimized 678059 678059 1276941 0 2633059 Shell Tokuda A108870 SOptimized 670520 670520 1310812 0 2651852 Shell Sedgewick A033622 Soptimized 659538 659538 1375059 0 2694135 Shell Ciura A102549 SOptimized 584422 584422 2833052 0 4001896 Table 10 Shellsort assigns for 100,000 random elements

Shell Sort AssignCnt for a100ku.srt SortName ToTemp FromTemp Direct Self Assigns Shell Weiss N/2.2 SOptimized 688305 688305 1312842 0 2689452 Shell Tokuda A108870 SOptimized 678609 678609 1341316 0 2698534 Shell Sedgewick A033622 Soptimized 664620 664620 1409044 0 2738284 Shell Ciura A102549 SOptimized 589128 589128 2779824 0 3958080 Table 11 Shellsort assigns for 100,000 unique random elements

Shell Sort AssignCnt for a1mr.srt SortName ToTemp FromTemp Direct Self Assigns Shell Tokuda A108870 SOptimized 8339830 8339830 16683072 0 33362732 Shell Sedgewick A033622 Soptimized 8334960 8334960 17147392 0 33817312 Shell Weiss N/2.2 SOptimized 8475339 8475339 17093657 0 34044335 Table 12 Shellsort assigns for 1,000,000 random elements

Shell Sort AssignCnt for a1mu.srt SortName ToTemp FromTemp Direct Self Assigns Shell Tokuda A108870 SOptimized 8395309 8395309 16892812 0 33683430 Shell Sedgewick A033622 Soptimized 8347183 8347183 17392528 0 34086894 Shell Weiss N/2.2 SOptimized 8547388 8547388 17319914 0 34414690 Table 13 Shellsort assigns for 1,000,000 unique random elements

Shell Sort AssignCnt for a10mr.srt SortName ToTemp FromTemp Direct Self Assigns Shell Tokuda A108870 SOptimized 99808443 99808443 203023373 0 402640259 Shell Weiss N/2.2 SOptimized 102624088 102624088 234089831 0 439338007 Table 14 Shellsort assigns for 10,000,000 random elements

Shell Sort AssignCnt for a10mu.srt SortName ToTemp FromTemp Direct Self Assigns Shell Tokuda A108870 SOptimized 100412153 100412153 205537322 0 406361628 Shell Weiss N/2.2 SOptimized 102867994 102867994 235172748 0 440908736 Table 15 Shellsort assigns for 10,000,000 unique random elements

58 Comparisons

As the following tables show the SOptimized version has the same number of comparisons with a given sequence but some of the comparisons are direct rather than all of them being to temp. You will notice that the Pratt A003586 sequence is always worst and that Tokuda A108870 is almost always best in regards to comparisons.

Shell Sort CompareCnt for a100r.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 262 420 0 682 Shell Tokuda A108870 682 0 0 682 Shell (3^n - 1)/2 A003462 SOptimized 341 342 0 683 Shell (3^n - 1)/2 A003462 683 0 0 683 Shell Weiss N/2.2 SOptimized 287 421 0 708 Shell Weiss N/2.2 708 0 0 708 Shell Ciura A102549 713 0 0 713 Shell Ciura A102549 SOptimized 308 405 0 713 Shell 4^(n+1)+3*2^n+1 A036562 725 0 0 725 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 434 291 0 725 Shell Incerpi-Sedgewick A036569 Soptimized 307 420 0 727 Shell Incerpi-Sedgewick A036569 727 0 0 727 Shell Hibbard A000225 SOptimized 296 480 0 776 Shell Hibbard A000225 776 0 0 776 Shell Sedgewick A033622 Soptimized 449 334 0 783 Shell Sedgewick A033622 783 0 0 783 Shell Shell N/2 786 0 0 786 Shell Shell N/2 SOptimized 283 503 0 786 Shell round[ 1 + e^(n-2) ] A055876 814 0 0 814 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 306 508 0 814 Shell Papernov A000051 SOptimized 222 665 0 887 Shell Papernov A000051 887 0 0 887 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 626 278 0 904 Shell a(0)=1; a(i)= Prime[i^3] A055875 904 0 0 904 Shell 2^n-45; n >= 6 A036564 SOptimized 914 197 0 1111 Shell 2^n-45; n >= 6 A036564 1111 0 0 1111 Shell Pratt A003586 1533 0 0 1533 Shell Pratt A003586 SOptimized 146 1387 0 1533 Table 16 Shellsort compares for 100 random elements

59

Shell Sort CompareCnt for a100u.srt SortName ToTemp Direct Self Compares Shell (3^n - 1)/2 A003462 SOptimized 369 342 0 711 Shell (3^n - 1)/2 A003462 711 0 0 711 Shell Tokuda A108870 SOptimized 315 420 0 735 Shell Tokuda A108870 735 0 0 735 Shell Ciura A102549 747 0 0 747 Shell Ciura A102549 SOptimized 342 405 0 747 Shell Sedgewick A033622 760 0 0 760 Shell Sedgewick A033622 Soptimized 426 334 0 760 Shell Hibbard A000225 SOptimized 294 480 0 774 Shell Hibbard A000225 774 0 0 774 Shell Weiss N/2.2 779 0 0 779 Shell Weiss N/2.2 SOptimized 358 421 0 779 Shell Incerpi-Sedgewick A036569 Soptimized 359 420 0 779 Shell Incerpi-Sedgewick A036569 779 0 0 779 Shell Shell N/2 814 0 0 814 Shell Shell N/2 SOptimized 311 503 0 814 Shell round[ 1 + e^(n-2) ] A055876 852 0 0 852 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 344 508 0 852 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 604 291 0 895 Shell 4^(n+1)+3*2^n+1 A036562 895 0 0 895 Shell Papernov A000051 SOptimized 246 665 0 911 Shell Papernov A000051 911 0 0 911 Shell a(0)=1; a(i)= Prime[i^3] A055875 936 0 0 936 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 658 278 0 936 Shell 2^n-45; n >= 6 A036564 SOptimized 944 197 0 1141 Shell 2^n-45; n >= 6 A036564 1141 0 0 1141 Shell Pratt A003586 SOptimized 184 1387 0 1571 Shell Pratt A003586 1571 0 0 1571 Table 17 Shellsort compares for 100 unique random elements

60

Shell Sort CompareCnt for a1kr.srt SortName ToTemp Direct Self Compares Shell Ciura A102549 12790 0 0 12790 Shell Ciura A102549 SOptimized 6019 6771 0 12790 Shell Tokuda A108870 SOptimized 5781 7059 0 12840 Shell Tokuda A108870 12840 0 0 12840 Shell Weiss N/2.2 SOptimized 5760 7174 0 12934 Shell Weiss N/2.2 12934 0 0 12934 Shell Sedgewick A033622 12974 0 0 12974 Shell Sedgewick A033622 Soptimized 6792 6182 0 12974 Shell Incerpi-Sedgewick A036569 Soptimized 6739 6611 0 13350 Shell Incerpi-Sedgewick A036569 13350 0 0 13350 Shell (3^n - 1)/2 A003462 SOptimized 8278 5457 0 13735 Shell (3^n - 1)/2 A003462 13735 0 0 13735 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 6406 7355 0 13761 Shell round[ 1 + e^(n-2) ] A055876 13761 0 0 13761 Shell Hibbard A000225 SOptimized 6282 7987 0 14269 Shell Hibbard A000225 14269 0 0 14269 Shell Shell N/2 14661 0 0 14661 Shell Shell N/2 SOptimized 6655 8006 0 14661 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 10779 4610 0 15389 Shell 4^(n+1)+3*2^n+1 A036562 15389 0 0 15389 Shell Papernov A000051 SOptimized 6038 9966 0 16004 Shell Papernov A000051 16004 0 0 16004 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 12735 4873 0 17608 Shell a(0)=1; a(i)= Prime[i^3] A055875 17608 0 0 17608 Shell 2^n-45; n >= 6 A036564 SOptimized 22672 4240 0 26912 Shell 2^n-45; n >= 6 A036564 26912 0 0 26912 Shell Pratt A003586 34150 0 0 34150 Shell Pratt A003586 SOptimized 3195 30955 0 34150 Table 18 Shellsort compares for 1,000 random elements

61

Shell Sort CompareCnt for a1ku.srt SortName ToTemp Direct Self Compares Shell Ciura A102549 12930 0 0 12930 Shell Ciura A102549 SOptimized 6159 6771 0 12930 Shell Weiss N/2.2 SOptimized 6032 7174 0 13206 Shell Weiss N/2.2 13206 0 0 13206 Shell Tokuda A108870 SOptimized 6177 7059 0 13236 Shell Tokuda A108870 13236 0 0 13236 Shell Sedgewick A033622 13501 0 0 13501 Shell Sedgewick A033622 Soptimized 7319 6182 0 13501 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 6336 7355 0 13691 Shell round[ 1 + e^(n-2) ] A055876 13691 0 0 13691 Shell Incerpi-Sedgewick A036569 Soptimized 7168 6611 0 13779 Shell Incerpi-Sedgewick A036569 13779 0 0 13779 Shell (3^n - 1)/2 A003462 SOptimized 8510 5457 0 13967 Shell (3^n - 1)/2 A003462 13967 0 0 13967 Shell Hibbard A000225 SOptimized 6001 7987 0 13988 Shell Hibbard A000225 13988 0 0 13988 Shell Shell N/2 14846 0 0 14846 Shell Shell N/2 SOptimized 6840 8006 0 14846 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 10734 4610 0 15344 Shell 4^(n+1)+3*2^n+1 A036562 15344 0 0 15344 Shell Papernov A000051 SOptimized 5441 9966 0 15407 Shell Papernov A000051 15407 0 0 15407 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 12923 4873 0 17796 Shell a(0)=1; a(i)= Prime[i^3] A055875 17796 0 0 17796 Shell 2^n-45; n >= 6 A036564 SOptimized 19379 4240 0 23619 Shell 2^n-45; n >= 6 A036564 23619 0 0 23619 Shell Pratt A003586 34384 0 0 34384 Shell Pratt A003586 SOptimized 3429 30955 0 34384 Table 19 Shellsort compares for 1,000 unique random elements

62

Shell Sort CompareCnt for a10kr.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 90146 99232 0 189378 Shell Tokuda A108870 189378 0 0 189378 Shell Ciura A102549 190269 0 0 190269 Shell Ciura A102549 SOptimized 103248 87021 0 190269 Shell Weiss N/2.2 SOptimized 89456 101679 0 191135 Shell Weiss N/2.2 191135 0 0 191135 Shell Sedgewick A033622 193862 0 0 193862 Shell Sedgewick A033622 Soptimized 100675 93187 0 193862 Shell (3^n - 1)/2 A003462 SOptimized 160672 75243 0 235915 Shell (3^n - 1)/2 A003462 235915 0 0 235915 Shell Papernov A000051 SOptimized 117966 133602 0 251568 Shell Papernov A000051 251568 0 0 251568 Shell Shell N/2 263981 0 0 263981 Shell Shell N/2 SOptimized 143976 120005 0 263981 Shell Pratt A003586 SOptimized 50555 550711 0 601266 Shell Pratt A003586 601266 0 0 601266 Table 20 Shellsort compares for 10,000 random elements

Shell Sort CompareCnt for a10ku.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 92914 99232 0 192146 Shell Tokuda A108870 192146 0 0 192146 Shell Ciura A102549 192438 0 0 192438 Shell Ciura A102549 SOptimized 105417 87021 0 192438 Shell Weiss N/2.2 SOptimized 94258 101679 0 195937 Shell Weiss N/2.2 195937 0 0 195937 Shell Sedgewick A033622 196290 0 0 196290 Shell Sedgewick A033622 Soptimized 103103 93187 0 196290 Shell (3^n - 1)/2 A003462 SOptimized 155022 75243 0 230265 Shell (3^n - 1)/2 A003462 230265 0 0 230265 Shell Papernov A000051 SOptimized 122949 133602 0 256551 Shell Papernov A000051 256551 0 0 256551 Shell Shell N/2 267982 0 0 267982 Shell Shell N/2 SOptimized 147977 120005 0 267982 Shell Pratt A003586 SOptimized 54323 550711 0 605034 Shell Pratt A003586 605034 0 0 605034 Table 21 Shellsort compares for 10,000 unique random elements

63

Shell Sort CompareCnt for a100kr.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 1264001 1277286 0 2541287 Shell Weiss N/2.2 SOptimized 1227075 1316680 0 2543755 Shell Sedgewick A033622 Soptimized 1323724 1266128 0 2589852 Shell Ciura A102549 SOptimized 2825796 897021 0 3722817 Table 22 Shellsort compares for 100,000 random elements

Shell Sort CompareCnt for a100ku.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 1296151 1277286 0 2573437 Shell Weiss N/2.2 SOptimized 1264645 1316680 0 2581325 Shell Sedgewick A033622 Soptimized 1359523 1266128 0 2625651 Shell Ciura A102549 SOptimized 2772825 897021 0 3669846 Table 23 Shellsort compares for 100,000 unique random elements

Shell Sort CompareCnt for a1mr.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 16211757 15602142 0 31813899 Shell Sedgewick A033622 Soptimized 16630916 15871693 0 32502609 Shell Weiss N/2.2 SOptimized 16590364 16166683 0 32757047 Table 24 Shellsort compares for 1,000,000 random elements

Shell Sort CompareCnt for a1mu.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 16441069 15602142 0 32043211 Shell Sedgewick A033622 Soptimized 16896915 15871693 0 32768608 Shell Weiss N/2.2 SOptimized 16839272 16166683 0 33005955 Table 25 Shellsort compares for 1,000,000 unique random elements

Shell Sort CompareCnt for a10mr.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 198292070 184077449 0 382369519 Shell Weiss N/2.2 SOptimized 229064961 191666685 0 420731646 Table 26 Shellsort compares for 10,000,000 random elements

Shell Sort CompareCnt for a10mu.srt SortName ToTemp Direct Self Compares Shell Tokuda A108870 SOptimized 201017974 184077449 0 385095423 Shell Weiss N/2.2 SOptimized 230359750 191666685 0 422026435 Table 27 Shellsort compares for 10,000,000 unique random elements

64 Both Assignments and Comparisons

As the following tables show the SOptimized version using the Tokuda A108870 sequence is almost always most efficient if Assignments and Comparisons are of equal importance. Only Ciura and Weiss were occasionally better. Ciura loses the efficiency when the data set size gets large but Weiss was a close contender.

Shell Sort Assign & Compare Cnt for a100r.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 676 682 1358 Shell Weiss N/2.2 SOptimized 732 708 1440 Shell (3^n - 1)/2 A003462 SOptimized 773 683 1456 Shell Ciura A102549 SOptimized 749 713 1462 Shell Incerpi-Sedgewick A036569 Soptimized 781 727 1508 Shell Shell N/2 SOptimized 743 786 1529 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 824 725 1549 Shell Hibbard A000225 SOptimized 789 776 1565 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 774 814 1588 Shell Papernov A000051 SOptimized 726 887 1613 Shell Sedgewick A033622 Soptimized 888 783 1671 Shell (3^n - 1)/2 A003462 1069 683 1752 Shell 4^(n+1)+3*2^n+1 A036562 1054 725 1779 Shell Tokuda A108870 1140 682 1822 Shell Ciura A102549 1157 713 1870 Shell Weiss N/2.2 1178 708 1886 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 991 904 1895 Shell Incerpi-Sedgewick A036569 1199 727 1926 Shell Sedgewick A033622 1160 783 1943 Shell Hibbard A000225 1307 776 2083 Shell a(0)=1; a(i)= Prime[i^3] A055875 1207 904 2111 Shell Shell N/2 1341 786 2127 Shell Pratt A003586 SOptimized 627 1533 2160 Shell round[ 1 + e^(n-2) ] A055876 1366 814 2180 Shell 2^n-45; n >= 6 A036564 SOptimized 1210 1111 2321 Shell 2^n-45; n >= 6 A036564 1330 1111 2441 Shell Papernov A000051 1604 887 2491 Shell Pratt A003586 2983 1533 4516 Table 28 Shellsort assigns & compares for 100 random elements

65

Shell Sort Assign & Compare Cnt for a100u.srt SortName Assigns Compares Both Shell (3^n - 1)/2 A003462 SOptimized 817 711 1528 Shell Tokuda A108870 SOptimized 793 735 1528 Shell Ciura A102549 SOptimized 817 747 1564 Shell Hibbard A000225 SOptimized 803 774 1577 Shell Sedgewick A033622 Soptimized 835 760 1595 Shell Weiss N/2.2 SOptimized 841 779 1620 Shell Shell N/2 SOptimized 811 814 1625 Shell Incerpi-Sedgewick A036569 Soptimized 879 779 1658 Shell Papernov A000051 SOptimized 757 911 1668 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 855 852 1707 Shell (3^n - 1)/2 A003462 1101 711 1812 Shell Sedgewick A033622 1137 760 1897 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 1009 895 1904 Shell Tokuda A108870 1203 735 1938 Shell Ciura A102549 1199 747 1946 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 1047 936 1983 Shell Incerpi-Sedgewick A036569 1249 779 2028 Shell Weiss N/2.2 1249 779 2028 Shell Hibbard A000225 1305 774 2079 Shell 4^(n+1)+3*2^n+1 A036562 1229 895 2124 Shell a(0)=1; a(i)= Prime[i^3] A055875 1241 936 2177 Shell Shell N/2 1367 814 2181 Shell round[ 1 + e^(n-2) ] A055876 1401 852 2253 Shell Pratt A003586 SOptimized 747 1571 2318 Shell 2^n-45; n >= 6 A036564 SOptimized 1257 1141 2398 Shell 2^n-45; n >= 6 A036564 1365 1141 2506 Shell Papernov A000051 1625 911 2536 Shell Pratt A003586 3023 1571 4594 Table 29 Shellsort assigns & compares for 100 unique random elements

66

Shell Sort Assign & Compare Cnt for a1kr.srt SortName Assigns Compares Both Shell Weiss N/2.2 SOptimized 13128 12934 26062 Shell Tokuda A108870 SOptimized 13223 12840 26063 Shell Ciura A102549 SOptimized 13392 12790 26182 Shell Sedgewick A033622 Soptimized 13795 12974 26769 Shell Incerpi-Sedgewick A036569 Soptimized 14145 13350 27495 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 13884 13761 27645 Shell Hibbard A000225 SOptimized 14343 14269 28612 Shell (3^n - 1)/2 A003462 SOptimized 15379 13735 29114 Shell Shell N/2 SOptimized 14825 14661 29486 Shell Papernov A000051 SOptimized 14577 16004 30581 Shell Sedgewick A033622 19647 12974 32621 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 17304 15389 32693 Shell Ciura A102549 19998 12790 32788 Shell Tokuda A108870 20373 12840 33213 Shell (3^n - 1)/2 A003462 19603 13735 33338 Shell Weiss N/2.2 20564 12934 33498 Shell Incerpi-Sedgewick A036569 20365 13350 33715 Shell round[ 1 + e^(n-2) ] A055876 21536 13761 35297 Shell 4^(n+1)+3*2^n+1 A036562 20370 15389 35759 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 18827 17608 36435 Shell Hibbard A000225 22779 14269 37048 Shell Shell N/2 23169 14661 37830 Shell a(0)=1; a(i)= Prime[i^3] A055875 22869 17608 40477 Shell Papernov A000051 26507 16004 42511 Shell Pratt A003586 SOptimized 11964 34150 46114 Shell 2^n-45; n >= 6 A036564 SOptimized 28498 26912 55410 Shell 2^n-45; n >= 6 A036564 31598 26912 58510 Shell Pratt A003586 65898 34150 100048 Table 30 Shellsort assigns & compares for 1,000 random elements

67

Shell Sort Assign & Compare Cnt for a1ku.srt SortName Assigns Compares Both Shell Ciura A102549 SOptimized 13563 12930 26493 Shell Weiss N/2.2 SOptimized 13773 13206 26979 Shell Tokuda A108870 SOptimized 14149 13236 27385 Shell round[ 1 + e^(n-2) ] A055876 SOptimized 13951 13691 27642 Shell Sedgewick A033622 Soptimized 14737 13501 28238 Shell Hibbard A000225 SOptimized 14315 13988 28303 Shell Incerpi-Sedgewick A036569 Soptimized 14829 13779 28608 Shell Papernov A000051 SOptimized 14021 15407 29428 Shell (3^n - 1)/2 A003462 SOptimized 15839 13967 29806 Shell Shell N/2 SOptimized 15183 14846 30029 Shell 4^(n+1)+3*2^n+1 A036562 SOptimized 17243 15344 32587 Shell Ciura A102549 20151 12930 33081 Shell Sedgewick A033622 20205 13501 33706 Shell (3^n - 1)/2 A003462 19863 13967 33830 Shell Tokuda A108870 20813 13236 34049 Shell Weiss N/2.2 20855 13206 34061 Shell Incerpi-Sedgewick A036569 20819 13779 34598 Shell round[ 1 + e^(n-2) ] A055876 21499 13691 35190 Shell 4^(n+1)+3*2^n+1 A036562 20321 15344 35665 Shell Hibbard A000225 22521 13988 36509 Shell a(0)=1; a(i)= Prime[i^3] A055875 Soptimized 19179 17796 36975 Shell Shell N/2 23341 14846 38187 Shell a(0)=1; a(i)= Prime[i^3] A055875 23077 17796 40873 Shell Papernov A000051 25927 15407 41334 Shell Pratt A003586 SOptimized 12681 34384 47065 Shell 2^n-45; n >= 6 A036564 SOptimized 25123 23619 48742 Shell 2^n-45; n >= 6 A036564 28333 23619 51952 Shell Pratt A003586 66137 34384 100521 Table 31 Shellsort assigns & compares for 1,000 unique random elements

68

Shell Sort Assign & Compare Cnt for a10kr.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 196517 189378 385895 Shell Weiss N/2.2 SOptimized 197020 191135 388155 Shell Ciura A102549 SOptimized 206966 190269 397235 Shell Sedgewick A033622 Soptimized 204903 193862 398765 Shell Ciura A102549 280750 190269 471019 Shell Tokuda A108870 293533 189378 482911 Shell Sedgewick A033622 292049 193862 485911 Shell Weiss N/2.2 297896 191135 489031 Shell Papernov A000051 SOptimized 245345 251568 496913 Shell (3^n - 1)/2 A003462 SOptimized 264174 235915 500089 Shell Shell N/2 SOptimized 263542 263981 527523 Shell (3^n - 1)/2 A003462 315562 235915 551477 Shell Papernov A000051 390443 251568 642011 Shell Shell N/2 389120 263981 653101 Shell Pratt A003586 SOptimized 182043 601266 783309 Shell Pratt A003586 1162103 601266 1763369 Table 32 Shellsort assigns & compares for 10,000 random elements

Shell Sort Assign & Compare Cnt for a10ku.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 200916 192146 393062 Shell Weiss N/2.2 SOptimized 203948 195937 399885 Shell Ciura A102549 SOptimized 209592 192438 402030 Shell Sedgewick A033622 Soptimized 206888 196290 403178 Shell Ciura A102549 282768 192438 475206 Shell (3^n - 1)/2 A003462 SOptimized 257644 230265 487909 Shell Tokuda A108870 296160 192146 488306 Shell Sedgewick A033622 294216 196290 490506 Shell Weiss N/2.2 302482 195937 498419 Shell Papernov A000051 SOptimized 253762 256551 510313 Shell Shell N/2 SOptimized 269390 267982 537372 Shell (3^n - 1)/2 A003462 309680 230265 539945 Shell Papernov A000051 395248 256551 651799 Shell Shell N/2 392896 267982 660878 Shell Pratt A003586 SOptimized 191940 605034 796974 Shell Pratt A003586 1165402 605034 1770436 Table 33 Shellsort assigns & compares for 10,000 unique random elements

69

Shell Sort Assign & Compare Cnt for a100kr.srt SortName Assigns Compares Both Shell Weiss N/2.2 SOptimized 2633059 2543755 5176814 Shell Tokuda A108870 SOptimized 2651852 2541287 5193139 Shell Sedgewick A033622 Soptimized 2694135 2589852 5283987 Shell Ciura A102549 SOptimized 4001896 3722817 7724713 Table 34 Shellsort assigns & compares for 100,000 random elements

Shell Sort Assign & Compare Cnt for a100ku.srt SortName Assigns Compares Both Shell Weiss N/2.2 SOptimized 2689452 2581325 5270777 Shell Tokuda A108870 SOptimized 2698534 2573437 5271971 Shell Sedgewick A033622 Soptimized 2738284 2625651 5363935 Shell Ciura A102549 SOptimized 3958080 3669846 7627926 Table 35 Shellsort assigns & compares for 100,000 unique random elements

Shell Sort Assign & Compare Cnt for a1mr.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 33362732 31813899 65176631 Shell Sedgewick A033622 Soptimized 33817312 32502609 66319921 Shell Weiss N/2.2 SOptimized 34044335 32757047 66801382 Table 36 Shellsort assigns & compares for 1,000,000 random elements

Shell Sort Assign & Compare Cnt for a1mu.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 33683430 32043211 65726641 Shell Sedgewick A033622 Soptimized 34086894 32768608 66855502 Shell Weiss N/2.2 SOptimized 34414690 33005955 67420645 Table 37 Shellsort assigns & compares for 1,000,000 unique random elements

Shell Sort Assign & Compare Cnt for a10mr.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 402640259 382369519 785009778 Shell Weiss N/2.2 SOptimized 439338007 420731646 860069653 Table 38 Shellsort assigns & compares for 10,000,000 random elements

Shell Sort Assign & Compare Cnt for a10mu.srt SortName Assigns Compares Both Shell Tokuda A108870 SOptimized 406361628 385095423 791457051 Shell Weiss N/2.2 SOptimized 440908736 422026435 862935171 Table 39 Shellsort assigns & compares for 10,000,000 unique random elements

70 Appendix D – Quicksort variations contested

There are two Quick Sort optimizations suggested by Sedgewick [3, pages 328-329] that can be contested: that below some number of elements (usually 10) Insertion Sort is more efficient than Quick Sort; and that after using Quick Sort to partition the data in sets smaller than some point (usually 10) that Insertion Sort should be called as a final step to avoid the overhead of many function calls. While there are situations were this could be beneficial, if assignments or comparisons are costly it will be counterproductive.

Using Insertion Sort as a Secondary Sort

First, the point at which another sort becomes more efficient is dependant on the efficiency of both sorts. Using the Spencer1 version of Quick Sort, it is usually not more efficient to switch to Insertion Sort but it is with RAS. With random data and Insertion

Sort, the number of assignments increases as the breakpoint increases and the number of comparisons decrease until the breakpoint is about 4 or 5. The increase in assignments is always greater than the decrease in comparisons.

71

Quick switching to Insertion on a1kr.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS SMerge Stable 1009 8745 9754 Quick Spencer1M Break:65535 RAS BPMerge Stable 1009 10984 11993 Quick Spencer1M Break:255 RAS SMerge Stable 2339 9735 12074 Quick Spencer1M Break:255 RAS BPMerge Stable 2339 10872 13211 Quick Spencer1M 4333 11314 15647 Quick Spencer1M Break:2 Insertion SOptimized 4395 11291 15686 Quick Spencer1M Break:3 Insertion SOptimized 4507 11276 15783 Quick Spencer1M Break:4 Insertion SOptimized 4605 11241 15846 Quick Spencer1M Break:5 Insertion SOptimized 4717 11226 15943 Quick Spencer1M Break:6 Insertion SOptimized 4949 11249 16198 Quick Spencer1M Break:7 Insertion SOptimized 5083 11247 16330 Quick Spencer1M Break:8 Insertion SOptimized 5180 11263 16443 Quick Spencer1M Break:9 Insertion SOptimized 5290 11277 16567 Quick Spencer1M Break:10 Insertion SOptimized 5419 11331 16750 Table 40 Quick switching to Insertion on 1,000 random elements

Quick switching to Insertion on a1ku.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS BPMerge Stable 1005 12375 13380 Quick Spencer1M Break:255 RAS BPMerge Stable 2243 11909 14152 Quick Spencer1M 4805 10852 15657 Quick Spencer1M Break:2 Insertion SOptimized 4881 10860 15741 Quick Spencer1M Break:3 Insertion SOptimized 4959 10864 15823 Quick Spencer1M Break:4 Insertion SOptimized 5081 10864 15945 Quick Spencer1M Break:5 Insertion SOptimized 5241 10893 16134 Quick Spencer1M Break:6 Insertion SOptimized 5405 10915 16320 Quick Spencer1M Break:7 Insertion SOptimized 5523 10927 16450 Quick Spencer1M Break:8 Insertion SOptimized 5607 10955 16562 Quick Spencer1M Break:9 Insertion SOptimized 5741 10985 16726 Quick Spencer1M Break:10 Insertion SOptimized 5841 11035 16876 Table 41 Quick switching to Insertion on 1,000 unique random elements

Deferring Insertion Sort until the end

Second, if the unsorted subsets are sorted immediately, the Insertion Sort will be bounded and will be not compare elements outside of the subset since they are unnecessary as

Quick Sort had already determined their relative order. If the Insertion Sort is deferred until Quick Sort is done partitioning, the Insertion Sort will compare elements between

72 each adjacent subset. Thus, there will be an increase in comparisons of at least (n/B)-1; where n is the number of elements and B is the break point where a secondary sort is used. For example, if there are 100 elements and a secondary sort is used when there are

10 or fewer elements, the least number of unsorted subsets is 10 (each subset having 10 elements) and there would be 9 comparisons between elements in adjacent subsets.

However, Quick Sort could have smaller subsets than the break point, which would result in more subsets and therefore more unnecessary comparisons.

While there will be additional function calls (and the associated overhead) to sort each subset individually, there will be fewer comparisons, however, which is relevant since my analysis concerns sorting where assignments and/or comparisons are expensive.

Quick switching to Insertion w/After on a1kr.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS SMerge Stable 1009 8745 9754 Quick Spencer1M Break:65535 RAS BPMerge Stable 1009 10984 11993 Quick Spencer1M Break:255 RAS SMerge Stable 2339 9735 12074 Quick Spencer1M Break:255 RAS BPMerge Stable 2339 10872 13211 Quick Spencer1M 4333 11314 15647 Quick Spencer1M Break:2 Insertion SOptimized 4395 11291 15686 Quick Spencer1M Break:3 Insertion SOptimized 4507 11276 15783 Quick Spencer1M Break:4 Insertion SOptimized 4605 11241 15846 Quick Spencer1M Break:5 Insertion SOptimized 4717 11226 15943 Quick Spencer1M Break:6 Insertion SOptimized 4949 11249 16198 Quick Spencer1M Break:2 Insertion SOptimized After 4395 12077 16472 Quick Spencer1M Break:4 Insertion SOptimized After 4605 11887 16492 Quick Spencer1M Break:3 Insertion SOptimized After 4507 11992 16499 Quick Spencer1M Break:5 Insertion SOptimized After 4717 11808 16525 Quick Spencer1M Break:6 Insertion SOptimized After 4949 11791 16740 Table 42 Quick switching to Insertion at end on 1,000 random elements

73

Quick switching to Insertion w/After on a1ku.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS BPMerge Stable 1005 12375 13380 Quick Spencer1M Break:255 RAS BPMerge Stable 2243 11909 14152 Quick Spencer1M 4805 10852 15657 Quick Spencer1M Break:2 Insertion SOptimized 4881 10860 15741 Quick Spencer1M Break:3 Insertion SOptimized 4959 10864 15823 Quick Spencer1M Break:4 Insertion SOptimized 5081 10864 15945 Quick Spencer1M Break:5 Insertion SOptimized 5241 10893 16134 Quick Spencer1M Break:6 Insertion SOptimized 5405 10915 16320 Quick Spencer1M Break:2 Insertion SOptimized After 4881 11688 16569 Quick Spencer1M Break:3 Insertion SOptimized After 4959 11611 16570 Quick Spencer1M Break:4 Insertion SOptimized After 5081 11558 16639 Quick Spencer1M Break:5 Insertion SOptimized After 5241 11546 16787 Quick Spencer1M Break:6 Insertion SOptimized After 5405 11503 16908 Table 43 Quick switching to Insertion at end on 1,000 unique random elements

Quick switching to Insertion w/After on a1mr.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS SMerge Stable 3240305 20205331 23445636 Quick Spencer1M Break:65535 RAS BPMerge Stable 3240305 25730513 28970818 Quick Spencer1M Break:255 RAS SMerge Stable 6896041 23269493 30165534 Quick Spencer1M Break:255 RAS BPMerge Stable 6896041 24344645 31240686 Quick Spencer1M 9068490 24711481 33779971 Quick Spencer1M Break:2 Insertion SOptimized 9122265 24680898 33803163 Quick Spencer1M Break:3 Insertion SOptimized 9213783 24651556 33865339 Quick Spencer1M Break:4 Insertion SOptimized 9327877 24632628 33960505 Quick Spencer1M Break:5 Insertion SOptimized 9456103 24626458 34082561 Quick Spencer1M Break:6 Insertion SOptimized 9591925 24631593 34223518 Quick Spencer1M Break:3 Insertion SOptimized After 9213783 25356789 34570572 Quick Spencer1M Break:2 Insertion SOptimized After 9122265 25461471 34583736 Quick Spencer1M Break:4 Insertion SOptimized After 9327877 25276600 34604477 Quick Spencer1M Break:5 Insertion SOptimized After 9456103 25219730 34675833 Quick Spencer1M Break:6 Insertion SOptimized After 9591925 25182904 34774829 Table 44 Quick switching to Insertion at end on 1,000,000 random elements

74

Quick switching to Insertion w/After on a1mu.srt SortName Assigns Compares Both Quick Spencer1M Break:65535 RAS BPMerge Stable 3114650 27045093 30159743 Quick Spencer1M Break:255 RAS BPMerge Stable 6834764 25449866 32284630 Quick Spencer1M 9332204 24801266 34133470 Quick Spencer1M Break:2 Insertion SOptimized 9398280 24801186 34199466 Quick Spencer1M Break:3 Insertion SOptimized 9498990 24806876 34305866 Quick Spencer1M Break:4 Insertion SOptimized 9616738 24820588 34437326 Quick Spencer1M Break:5 Insertion SOptimized 9744960 24842538 34587498 Quick Spencer1M Break:6 Insertion SOptimized 9876534 24871249 34747783 Quick Spencer1M Break:2 Insertion SOptimized After 9398280 25634058 35032338 Quick Spencer1M Break:3 Insertion SOptimized After 9498990 25567750 35066740 Quick Spencer1M Break:4 Insertion SOptimized After 9616738 25520068 35136806 Quick Spencer1M Break:5 Insertion SOptimized After 9744960 25490035 35234995 Quick Spencer1M Break:6 Insertion SOptimized After 9876534 25474580 35351114 Table 45 Quick switching to Insertion at end on 1,000,000 unique random elements

75 Appendix E – Assignments for Random Data

Sorting the same data set using different algorithms give the following results:

Not Unique Elements

AssignCnt for a1kr.srt SortName ToTemp FromTemp Direct Self Assigns RAS SMerge Optimal 1 1 997 0 999 RAS SMerge Unstable 10 10 988 0 1008 RAS SMerge Stable 10 10 989 0 1009 Bingo Soptimized 8 8 1958 0 1974 Bingo Bidirectional 8 8 1967 0 1983 Bingo 990 990 990 0 2970 Quick Spencer1M 427 427 3479 0 4333 Quick Spencer1C 418 418 3583 0 4419 Quick Spencer3C 432 432 3948 0 4812 Quick Spencer3M 444 444 3946 0 4834 Quick Spencer2M 577 577 4072 0 5226 Quick Spencer2C 566 566 4138 0 5270 Quick BermanPaul 2275 2275 2275 0 6825 Quick SedgewickBentley 2509 2509 2509 0 7527 Quick Qinjian Deng SOptimized 2810 2810 2923 0 8543 Quick Qinjian Deng 2858 2858 2923 48 8687 Shell Tokuda A108870 SOptimized 3484 3484 6255 0 13223 Heap BermanPaul SOptimized 2407 2407 9165 0 13979 Heap BermanPaul 2498 2498 9165 0 14161 Merge 9976 9976 0 0 19952 Heap Wikipedia 9761 9761 9761 0 29283 JSort 2996 2996 67195 3 73190 SMInsert 1206 1206 167727 0 170139 Insertion SOptimized 989 989 232489 0 234467 Insertion 999 999 232489 0 234487 Table 46 Assigns for 1,000 random elements

76 Insertion Sorts (including SMInsert), and JSort have been excluded the due to their worsening performance.

AssignCnt for a10kr.srt SortName ToTemp FromTemp Direct Self Assigns RAS SMerge Optimal 1 1 9997 0 9999 RAS SMerge Unstable 6 6 9992 0 10004 RAS SMerge Stable 7 7 9992 0 10006 Bingo Bidirectional 9 9 19944 0 19962 Bingo Soptimized 7 7 19956 0 19970 Bingo 9994 9994 9994 0 29982 Quick Spencer1M 4316 4316 51303 0 59935 Quick Spencer1C 4176 4176 52149 0 60501 Quick Spencer3M 4528 4528 56093 0 65149 Quick Spencer3C 4320 4320 57094 0 65734 Quick Spencer2M 5734 5734 56728 0 68196 Quick Spencer2C 5513 5513 58162 0 69188 Quick BermanPaul 31233 31233 31233 0 93699 Quick SedgewickBentley 32778 32778 32778 0 98334 Quick Qinjian Deng SOptimized 36758 36758 38159 0 111675 Quick Qinjian Deng 37265 37265 38159 507 113196 Heap BermanPaul SOptimized 23893 23893 124180 0 171966 Heap BermanPaul 24998 24998 124180 0 174176 Shell Tokuda A108870 SOptimized 50724 50724 95069 0 196517 Merge 133616 133616 0 0 267232 Heap Wikipedia 129491 129491 129491 0 388473 Table 47 Assigns for 10,000 random elements

77 While performing very well in regards to assignments, Bingo Sorts are now excluded due to poor performance in regards to comparisons (which you will see in a later section).

AssignCnt for a100kr.srt SortName ToTemp FromTemp Direct Self Assigns RAS SMerge Optimal 1 1 99996 0 99998 RAS SMerge Unstable 11 11 99986 0 100008 RAS SMerge Stable 11 11 99988 0 100010 Quick Spencer1M 43209 43209 662274 0 748692 Quick Spencer1C 41809 41809 673420 0 757038 Quick Spencer3M 45331 45331 710094 0 800756 Quick Spencer3C 43484 43484 722684 0 809652 Quick Spencer2C 55224 55224 727019 0 837467 Quick Spencer2M 57326 57326 725093 0 839745 Quick BermanPaul 387085 387085 387085 0 1161255 Quick SedgewickBentley 409785 409785 409785 0 1229355 Quick Qinjian Deng SOptimized 442298 442298 456511 0 1341107 Quick Qinjian Deng 447187 447187 456511 4889 1355774 Heap BermanPaul SOptimized 239294 239294 1575227 0 2053815 Heap BermanPaul 249998 249998 1575227 0 2075223 Shell Tokuda A108870 SOptimized 670520 670520 1310812 0 2651852 Merge 1668928 1668928 0 0 3337856 Heap Wikipedia 1629567 1629567 1629567 0 4888701 Table 48 Assigns for 100,000 random elements

78 The Wikipedia version of Heap Sort is now excluded and only the ‘M’ versions of my

Quick Sort will be used.

AssignCnt for a1mr.srt SortName ToTemp FromTemp Direct Self Assigns RAS SMerge Optimal 1 1 999997 0 999999 RAS SMerge Unstable 12 12 999986 0 1000010 RAS SMerge Stable 12 12 999988 0 1000012 Quick Spencer1M 432380 432380 8203730 0 9068490 Quick Spencer3M 453275 453275 8703805 0 9610355 Quick Spencer2M 573070 573070 8709563 0 9855703 Quick BermanPaul 4666806 4666806 4666806 0 14000418 Quick SedgewickBentley 4799369 4799369 4799369 0 14398107 Quick Qinjian Deng SOptimized 5235784 5235784 5381909 0 15853477 Quick Qinjian Deng 5285354 5285354 5381909 49570 16002187 Heap BermanPaul SOptimized 2393118 2393118 19048938 0 23835174 Heap BermanPaul 2499998 2499998 19048938 0 24048934 Shell Tokuda A108870 SOptimized 8339830 8339830 16683072 0 33362732 Merge 19951424 19951424 0 0 39902848 Table 49 Assigns for 1,000,000 random elements

AssignCnt for a10mr.srt SortName ToTemp FromTemp Direct Self Assigns RAS SMerge Optimal 1 1 9999996 0 9999998 RAS SMerge Unstable 18 18 9999979 0 10000015 RAS SMerge Stable 18 18 9999981 0 10000017 Quick Spencer1M 4321495 4321495 96663434 0 105306424 Quick Spencer3M 4530457 4530457 102318136 0 111379050 Quick Spencer2M 5732766 5732766 102289709 0 113755241 Quick BermanPaul 54035146 54035146 54035146 0 162105438 Quick SedgewickBentley 55922486 55922486 55922486 0 167767458 Quick Qinjian Deng SOptimized 60068711 60068711 61533458 0 181670880 Quick Qinjian Deng 60561650 60561650 61533458 492939 183149697 Heap BermanPaul SOptimized 23933102 23933102 223830527 0 271696731 Heap BermanPaul 24999998 24999998 223830527 0 273830523 Shell Tokuda A108870 SOptimized 99808443 99808443 203023373 0 402640259 Merge 233222784 233222784 0 0 466445568 Table 50 Assigns for 10,000,000 random elements

79 Unique Elements

Since all elements are unique the Stable (including BPMerge), Unstable, and Optimal versions of RAS all have the same number of assignments. Also, for the same reason, the

‘C’ and ‘M’ versions of my versions of my Quick Sorts are not different.

AssignCnt for a1ku.srt SortName ToTemp FromTemp Direct Self Assigns RAS BPMerge Stable 5 5 995 0 1005 Bingo Soptimized 5 5 1965 0 1975 Bingo Bidirectional 4 4 1973 0 1981 Bingo 995 995 995 0 2985 Quick Spencer1M 499 499 3807 0 4805 Quick Spencer3M 514 514 4179 0 5207 Quick Spencer2M 568 568 4259 0 5395 Quick SedgewickBentley 2215 2215 2215 0 6645 Quick BermanPaul 2229 2229 2229 0 6687 Quick Qinjian Deng SOptimized 2815 2815 3139 0 8769 Quick Qinjian Deng 2865 2865 3139 50 8919 Heap BermanPaul SOptimized 2402 2402 9107 0 13911 Heap BermanPaul 2498 2498 9107 0 14103 Shell Tokuda A108870 Soptimized 3727 3727 6695 0 14149 Merge 9976 9976 0 0 19952 Heap Wikipedia 9661 9661 9661 0 28983 JSort 2996 2996 69431 4 75427 SMInsert 1223 1223 160811 0 163257 Insertion Soptimized 988 988 243121 0 245097 Insertion 999 999 243121 0 245119 Table 51 Assigns for 1,000 unique random elements

80

AssignCnt for a10ku.srt SortName ToTemp FromTemp Direct Self Assigns RAS BPMerge Stable 7 7 9992 0 10006 Bingo Bidirectional 11 11 19950 0 19972 Bingo Soptimized 13 13 19954 0 19980 Bingo 9992 9992 9992 0 29976 Quick Spencer1M 4996 4996 51816 0 61808 Quick Spencer3M 4958 4958 58304 0 68220 Quick Spencer2M 5806 5806 58038 0 69650 Quick BermanPaul 29694 29694 29694 0 89082 Quick SedgewickBentley 29796 29796 29796 0 89388 Quick Qinjian Deng SOptimized 36504 36504 39662 0 112670 Quick Qinjian Deng 36969 36969 39662 465 114065 Heap BermanPaul SOptimized 24029 24029 124590 0 172648 Heap BermanPaul 24998 24998 124590 0 174586 Shell Tokuda A108870 Soptimized 51610 51610 97696 0 200916 Merge 133616 133616 0 0 267232 Heap Wikipedia 130596 130596 130596 0 391788 Table 52 Assigns for 10,000 unique random elements

AssignCnt for a100ku.srt SortName ToTemp FromTemp Direct Self Assigns RAS BPMerge Stable 12 12 99986 0 100010 Quick Spencer1M 50213 50213 676148 0 776574 Quick Spencer3M 49931 49931 739446 0 839308 Quick Spencer2M 58389 58389 729326 0 846104 Quick BermanPaul 372046 372046 372046 0 1116138 Quick SedgewickBentley 372056 372056 372056 0 1116168 Quick Qinjian Deng SOptimized 440925 440925 470674 0 1352524 Quick Qinjian Deng 445753 445753 470674 4828 1367008 Heap BermanPaul SOptimized 240194 240194 1578856 0 2059244 Heap BermanPaul 249998 249998 1578856 0 2078852 Shell Tokuda A108870 Soptimized 678609 678609 1341316 0 2698534 Merge 1668928 1668928 0 0 3337856 Heap Wikipedia 1638766 1638766 1638766 0 4916298 Table 53 Assigns for 100,000 unique random elements

81

AssignCnt for a1mu.srt SortName ToTemp FromTemp Direct Self Assigns RAS BPMerge Stable 17 17 999982 0 1000016 Quick Spencer1M 499908 499908 8332388 0 9332204 Quick Spencer3M 500040 500040 8985646 0 9985726 Quick Spencer2M 583890 583890 8876892 0 10044672 Quick BermanPaul 4502652 4502652 4502652 0 13507956 Quick SedgewickBentley 4523432 4523432 4523432 0 13570296 Quick Qinjian Deng SOptimized 5198598 5198598 5499888 0 15897084 Quick Qinjian Deng 5245820 5245820 5499888 47222 16038750 Heap BermanPaul SOptimized 2402836 2402836 19089226 0 23894898 Heap BermanPaul 2499998 2499998 19089226 0 24089222 Shell Tokuda A108870 Soptimized 8395309 8395309 16892812 0 33683430 Merge 19951424 19951424 0 0 39902848 Table 54 Assigns for 1,000,000 unique random elements

AssignCnt for a10mu.srt SortName ToTemp FromTemp Direct Self Assigns RAS BPMerge Stable 14 14 9999982 0 10000010 Quick Spencer1M 4999939 4999939 98262722 0 108262600 Quick Spencer3M 5000188 5000188 104786600 0 114786976 Quick Spencer2M 5833515 5833515 103878904 0 115545934 Quick BermanPaul 52466652 52466652 52466652 0 157399956 Quick SedgewickBentley 52805346 52805346 52805346 0 158416038 Quick Qinjian Deng SOptimized 59418970 59418970 62426084 0 181264024 Quick Qinjian Deng 59894673 59894673 62426084 475703 182691133 Heap BermanPaul SOptimized 24029641 24029641 224238332 0 272297614 Heap BermanPaul 24999998 24999998 224238332 0 274238328 Shell Tokuda A108870 Soptimized 100412153 100412153 205537322 0 406361628 Merge 233222784 233222784 0 0 466445568 Table 55 Assigns for 10,000,000 unique random elements

82 Appendix F – Assignments for Special Data

These are data sets that have the worst case lower bound of 3n/2 assignments.

AssignCnt for a1kb.srt SortName ToTemp FromTemp Direct Self Assigns Quick BermanPaul 500 500 500 0 1500 RAS SMerge Stable 500 500 500 0 1500 SMInsert 500 500 500 0 1500 Quick Spencer1M 500 500 500 0 1500 Quick SedgewickBentley 500 500 500 0 1500 Bingo Bidirectional 500 500 500 0 1500 Bingo Soptimized 1 1 1498 0 1500 Bingo 500 500 500 0 1500 Quick Spencer3M 494 494 1984 0 2972 Quick Spencer2M 595 595 1986 0 3176 Quick Qinjian Deng 2480 2480 1498 0 6458 Shell Tokuda A108870 SOptimized 3542 3542 4174 0 11258 Heap BermanPaul SOptimized 1996 1996 8316 0 12308 Heap BermanPaul 2498 2498 8316 0 13312 Merge 9976 9976 0 0 19952 Heap Wikipedia 8316 8316 8316 0 24948 JSort 2996 2996 110730 4 116726 Insertion 999 999 499500 0 501498 Table 56 Assigns for 1,000 unique reverse ordered elements

83

AssignCnt for a1kw.srt SortName ToTemp FromTemp Direct Self Assigns SMInsert 500 500 500 0 1500 Quick Spencer1M 500 500 500 0 1500 Quick SedgewickBentley 500 500 500 0 1500 Quick BermanPaul 500 500 500 0 1500 RAS SMerge Stable 500 500 500 0 1500 Bingo Soptimized 500 500 500 0 1500 Bingo Bidirectional 250 250 1000 0 1500 Bingo 500 500 500 0 1500 Shell Tokuda A108870 SOptimized 500 500 500 0 1500 Quick Spencer3M 581 581 1174 0 2336 Quick Spencer2M 586 586 1182 0 2354 Insertion 999 999 500 0 2498 Quick Qinjian Deng 1332 1332 1266 0 3930 JSort 2996 2996 500 3 6495 Heap BermanPaul SOptimized 2496 2496 9760 0 14752 Heap BermanPaul 2498 2498 9760 0 14756 Merge 9976 9976 0 0 19952 Heap Wikipedia 15474 15474 15474 0 46422 Table 57 Assigns for 1,000 elements in WorstAssign dataset

84 Appendix G Comparisons for Random Data

In the RAS algorithm the assignment type has no effect on the comparison count.

Not Unique Elements

CompareCnt for a1kr.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 7988 0 7988 Merge 0 8745 0 8745 RAS Tree Stable 0 9245 0 9245 SMInsert 0 9629 0 9629 RAS Splay/2 Stable Sequential 0 10185 0 10185 RAS Tree Stable Sequential 0 10397 0 10397 Quick Spencer3M 8906 1737 0 10643 RAS Splay Stable Sequential 0 10715 0 10715 Quick Spencer3C 9001 1801 0 10802 Quick Spencer1C 9323 1704 0 11027 Quick Spencer2M 10932 165 0 11097 Quick Spencer2C 11142 168 0 11310 Quick Spencer1M 9506 1808 0 11314 Quick Qinjian Deng 2111 9296 0 11407 Shell Tokuda A108870 SOptimized 5781 7059 0 12840 Quick BermanPaul 0 13095 0 13095 Quick SedgewickBentley 0 15669 0 15669 Heap BermanPaul SOptimized 6970 9953 0 16923 Heap BermanPaul 8468 8455 0 16923 Heap Wikipedia 0 17405 0 17405 JSort 68863 1754 1 70618 Insertion SOptimized 232483 999 0 233482 Insertion 233482 0 0 233482 Bingo Bidirectional 1976 654579 0 656555 Bingo Soptimized 7768 649898 0 657666 Bingo 0 665410 0 665410 Table 58 Compares for 1,000 random elements

85

CompareCnt for a10kr.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 112095 0 112095 Merge 0 120373 0 120373 Quick Spencer3C 121643 17702 0 139345 RAS Tree Stable 0 140345 0 140345 Quick Spencer3M 123575 17781 0 141356 Quick Qinjian Deng 21398 122297 0 143695 Quick Spencer2C 143469 1697 0 145166 RAS Splay/2 Stable Sequential 0 147174 0 147174 Quick Spencer1C 133231 16893 0 150124 Quick Spencer1M 132749 17609 0 150358 Quick Spencer2M 150182 1659 0 151841 Quick BermanPaul 0 156081 0 156081 RAS Tree Stable Sequential 0 161847 0 161847 RAS Splay Stable Sequential 0 177378 0 177378 Shell Tokuda A108870 SOptimized 90146 99232 0 189378 Quick SedgewickBentley 0 230166 0 230166 Heap BermanPaul 117706 117696 0 235402 Heap BermanPaul SOptimized 102708 132694 0 235402 Heap Wikipedia 0 239273 0 239273 Bingo Soptimized 29983 62634228 0 62664211 Bingo 0 62750531 0 62750531 Bingo Bidirectional 18954 62979041 0 62997995 Table 59 Compares for 10,000 random elements

86

CompareCnt for a100kr.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 1454229 0 1454229 Merge 0 1536418 0 1536418 Quick Spencer3C 1637779 177309 0 1815088 RAS Tree Stable 0 1851356 0 1851356 Quick Spencer3M 1679359 177866 0 1857225 Quick Qinjian Deng 214209 1693642 0 1907851 RAS Splay/2 Stable Sequential 0 1926590 0 1926590 Quick Spencer2M 1942038 16746 0 1958784 Quick Spencer2C 2006509 17108 0 2023617 Quick Spencer1C 1855787 170506 0 2026293 Quick Spencer1M 1876053 175493 0 2051546 RAS Tree Stable Sequential 0 2065521 0 2065521 Quick BermanPaul 0 2100190 0 2100190 RAS Splay Stable Sequential 0 2320149 0 2320149 Shell Tokuda A108870 SOptimized 1264001 1277286 0 2541287 Quick SedgewickBentley 0 2870309 0 2870309 Heap BermanPaul 1510093 1510075 0 3020168 Heap BermanPaul SOptimized 1360095 1660073 0 3020168 Heap Wikipedia 0 3060517 0 3060517 Table 60 Compares for 100,000 random elements

CompareCnt for a1mr.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 17856789 0 17856789 Merge 0 18674961 0 18674961 Quick Qinjian Deng 2146122 20254737 0 22400859 Quick Spencer3M 20751766 1777543 0 22529309 RAS Tree Stable Sequential 0 22883205 0 22883205 RAS Splay/2 Stable Sequential 0 23859088 0 23859088 RAS Tree Stable 0 23966164 0 23966164 Quick Spencer1M 22961275 1750206 0 24711481 Quick Spencer2M 24775596 167894 0 24943490 Quick BermanPaul 0 25030292 0 25030292 RAS Splay Stable Sequential 0 26138361 0 26138361 Shell Tokuda A108870 SOptimized 16211757 15602142 0 31813899 Quick SedgewickBentley 0 35611875 0 35611875 Heap BermanPaul 18397226 18397200 0 36794426 Heap BermanPaul SOptimized 16897228 19897198 0 36794426 Table 61 Compares for 1,000,000 random elements

87

CompareCnt for a10mr.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 211928179 0 211928179 Merge 0 220102431 0 220102431 Quick Qinjian Deng 21464742 249076200 0 270540942 Quick Spencer3M 252897770 17756592 0 270654362 RAS Splay/2 Stable Sequential 0 284650610 0 284650610 RAS Tree Stable 0 289608591 0 289608591 RAS Tree Stable Sequential 0 294862387 0 294862387 Quick Spencer2M 297841370 1681251 0 299522621 Quick BermanPaul 0 301326295 0 301326295 Quick Spencer1M 289982339 17552813 0 307535152 RAS Splay Stable Sequential 0 330024851 0 330024851 Shell Tokuda A108870 SOptimized 198292070 184077449 0 382369519 Quick SedgewickBentley 0 431579271 0 431579271 Heap BermanPaul 217318540 217318515 0 434637055 Heap BermanPaul SOptimized 202318542 232318513 0 434637055 Table 62 Compares for 10,000,000 random elements

88 Unique Elements

CompareCnt for a1ku.srt SortName ToTemp Direct Self Compares Merge 0 8728 0 8728 RAS SMerge Stable 0 8728 0 8728 SMInsert 0 9642 0 9642 RAS Tree Stable 0 10560 0 10560 RAS Tree Stable Sequential 0 10737 0 10737 Quick Qinjian Deng 2320 8491 0 10811 Quick Spencer1M 9418 1434 0 10852 RAS Splay/2 Stable Sequential 0 10858 0 10858 Quick Spencer3M 9319 1549 0 10868 Quick Spencer2M 11014 164 0 11178 Quick BermanPaul 0 11255 0 11255 RAS Splay Stable Sequential 0 12301 0 12301 Shell Tokuda A108870 SOptimized 6177 7059 0 13236 Quick SedgewickBentley 0 14966 0 14966 Heap BermanPaul SOptimized 6951 9934 0 16885 Heap BermanPaul 8449 8436 0 16885 Heap Wikipedia 0 17281 0 17281 JSort 71066 1764 2 72832 Insertion SOptimized 243113 999 0 244112 Insertion 244112 0 0 244112 Bingo Bidirectional 3026 998135 0 1001161 Bingo Soptimized 3957 1002007 0 1005964 Bingo 0 1007982 0 1007982 Table 63 Compares for 1,000 unique random elements

89

CompareCnt for a10ku.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 120480 0 120480 Merge 0 120480 0 120480 Quick Spencer3M 128328 15499 0 143827 Quick Qinjian Deng 23154 121567 0 144721 Quick Spencer2M 151367 1664 0 153031 RAS Splay/2 Stable Sequential 0 154753 0 154753 RAS Tree Stable Sequential 0 157832 0 157832 RAS Tree Stable 0 157947 0 157947 Quick Spencer1M 151824 14904 0 166728 Quick BermanPaul 0 170975 0 170975 RAS Splay Stable Sequential 0 173980 0 173980 Shell Tokuda A108870 SOptimized 92914 99232 0 192146 Quick SedgewickBentley 0 212592 0 212592 Heap BermanPaul SOptimized 102895 132876 0 235771 Heap BermanPaul 117893 117878 0 235771 Heap Wikipedia 0 240524 0 240524 Bingo Bidirectional 30009 99981705 0 100011714 Bingo Soptimized 188552 99982991 0 100171543 Bingo 0 100190308 0 100190308 Table 64 Compares for 10,000 unique random elements

CompareCnt for a100ku.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 1536024 0 1536024 Merge 0 1536024 0 1536024 Quick Spencer3M 1668939 156059 0 1824998 Quick Qinjian Deng 229747 1644648 0 1874395 RAS Tree Stable 0 1973492 0 1973492 RAS Splay/2 Stable Sequential 0 2005576 0 2005576 Quick Spencer2M 2021080 16628 0 2037708 RAS Tree Stable Sequential 0 2056682 0 2056682 Quick Spencer1M 1911703 150285 0 2061988 Quick BermanPaul 0 2164840 0 2164840 RAS Splay Stable Sequential 0 2274337 0 2274337 Shell Tokuda A108870 SOptimized 1296151 1277286 0 2573437 Quick SedgewickBentley 0 2872199 0 2872199 Heap BermanPaul 1511958 1511940 0 3023898 Heap BermanPaul SOptimized 1361960 1661938 0 3023898 Heap Wikipedia 0 3070199 0 3070199 Table 65 Compares for 100,000 unique random elements

90 CompareCnt for a1mu.srt SortName ToTemp Direct Self Compares Merge 0 18674279 0 18674279 RAS SMerge Stable 0 18674279 0 18674279 Quick Spencer3M 20373575 1561384 0 21934959 Quick Qinjian Deng 2301286 20277757 0 22579043 RAS Tree Stable Sequential 0 24068083 0 24068083 RAS Splay/2 Stable Sequential 0 24664659 0 24664659 RAS Tree Stable 0 24799901 0 24799901 Quick Spencer1M 23300166 1501100 0 24801266 Quick Spencer2M 24827692 166546 0 24994238 Quick BermanPaul 0 25425220 0 25425220 RAS Splay Stable Sequential 0 27563242 0 27563242 Shell Tokuda A108870 SOptimized 16441069 15602142 0 32043211 Quick SedgewickBentley 0 33428997 0 33428997 Heap BermanPaul SOptimized 16918561 19918541 0 36837102 Heap BermanPaul 18418559 18418543 0 36837102 Table 66 Compares for 1,000,000 unique random elements

CompareCnt for a10mu.srt SortName ToTemp Direct Self Compares RAS SMerge Stable 0 220101488 0 220101488 Merge 0 220101488 0 220101488 Quick Spencer3M 251919468 15605482 0 267524950 Quick Qinjian Deng 23007111 252193016 0 275200127 RAS Splay/2 Stable Sequential 0 292691799 0 292691799 Quick Spencer2M 292338735 1666931 0 294005666 Quick Spencer1M 284154041 14975884 0 299129925 RAS Tree Stable Sequential 0 300454213 0 300454213 RAS Tree Stable 0 304636347 0 304636347 Quick BermanPaul 0 305959163 0 305959163 RAS Splay Stable Sequential 0 330901792 0 330901792 Shell Tokuda A108870 SOptimized 201017974 184077449 0 385095423 Quick SedgewickBentley 0 398957216 0 398957216 Heap BermanPaul SOptimized 202532680 232532650 0 435065330 Heap BermanPaul 217532678 217532652 0 435065330 Table 67 Compares for 10,000,000 unique random elements

91 Appendix H –Comparisons for Special Data

CompareCnt for a1kb.srt SortName ToTemp Direct Self Compares RAS SplayX Stable Sequential 0 999 0 999 SMInsert 0 1500 0 1500 RAS Splay/2 Stable Sequential 0 1997 0 1997 RAS Splay Stable Sequential 0 1997 0 1997 RAS SMerge Stable 0 4932 0 4932 Merge 0 4932 0 4932 RAS Tree Stable 0 7987 0 7987 Quick Spencer2M 8050 111 0 8161 Shell Tokuda A108870 SOptimized 3321 7059 0 10380 Heap BermanPaul 7991 7974 0 15965 Heap BermanPaul SOptimized 6493 9472 0 15965 Heap Wikipedia 0 15965 0 15965 Quick Spencer3M 66727 1492 0 68219 JSort 112141 1858 2 114001 Quick Qinjian Deng 1016 128157 0 129173 Insertion 499500 0 0 499500 Quick Spencer1M 249500 250000 0 499500 RAS Tree Stable Sequential 0 499500 0 499500 Quick BermanPaul 0 500499 0 500499 Quick SedgewickBentley 0 500499 0 500499 Table 68 Compares for 1,000 unique reverse ordered elements

92

CompareCnt for a1kw.srt SortName ToTemp Direct Self Compares RAS Splay/2 Stable Sequential 0 1498 0 1498 Insertion 1498 0 0 1498 RAS SplayX Stable Sequential 0 1997 0 1997 JSort 2495 996 1 3492 RAS SMerge Stable 0 5288 0 5288 Merge 0 5288 0 5288 SMInsert 0 5738 0 5738 Shell Tokuda A108870 SOptimized 499 7059 0 7558 Quick Spencer2M 7913 245 0 8158 Quick Qinjian Deng 1931 7261 0 9192 Quick Spencer3M 7815 1464 0 9279 RAS Tree Stable 0 9793 0 9793 Heap BermanPaul 8801 8742 0 17543 Heap BermanPaul SOptimized 7303 10240 0 17543 Heap Wikipedia 0 22462 0 22462 Quick Spencer1M 0 250000 0 250000 RAS Tree Stable Sequential 0 250000 0 250000 Quick BermanPaul 0 250999 0 250999 Quick SedgewickBentley 0 250999 0 250999 Table 69 Compares for 1,000 elements in WorstAssign dataset

93 Appendix I – Both Assignments and Comparisons for Special Data

Since many algorithms achieved the lower bound of assignments here the assignments and comparisons are combined to help differentiate the better algorithms for these situations.

Assign & Compare Cnt for a1kb.srt SortName Assigns Compares Both RAS SplayX Stable Sequential 1500 999 2499 SMInsert 1500 1500 3000 RAS Splay/2 Stable Sequential 1500 1997 3497 RAS Splay Stable Sequential 1500 1997 3497 RAS SMerge Stable 1500 4932 6432 RAS Tree Stable 1500 7987 9487 Quick Spencer2M 3176 8161 11337 Shell Tokuda A108870 SOptimized 11258 10380 21638 Merge 19952 4932 24884 Heap BermanPaul SOptimized 12308 15965 28273 Heap BermanPaul 13312 15965 29277 Heap Wikipedia 24948 15965 40913 Quick Spencer3M 2972 68219 71191 Quick Qinjian Deng 6458 129173 135631 JSort 116726 114001 230727 Quick Spencer1M 1500 499500 501000 RAS Tree Stable Sequential 1500 499500 501000 Quick BermanPaul 1500 500499 501999 Quick SedgewickBentley 1500 500499 501999 Insertion 501498 499500 1000998 Table 70 Assigns and compares for 1,000 unique reverse ordered elements

94

Assign & Compare Cnt for a1kw.srt SortName Assigns Compares Both RAS Splay/2 Stable Sequential 1500 1498 2998 RAS SplayX Stable Sequential 1500 1997 3497 Insertion 2498 1498 3996 RAS SMerge Stable 1500 5288 6788 SMInsert 1500 5738 7238 Shell Tokuda A108870 SOptimized 1500 7558 9058 JSort 6495 3492 9987 Quick Spencer2M 2354 8158 10512 RAS Tree Stable 1500 9793 11293 Quick Spencer3M 2336 9279 11615 Quick Qinjian Deng 3930 9192 13122 Merge 19952 5288 25240 Heap BermanPaul SOptimized 14752 17543 32295 Heap BermanPaul 14756 17543 32299 Heap Wikipedia 46422 22462 68884 Quick Spencer1M 1500 250000 251500 RAS Tree Stable Sequential 1500 250000 251500 Quick BermanPaul 1500 250999 252499 Quick SedgewickBentley 1500 250999 252499 Table 71 Assigns and compares for 1,000 elements in WorstAssign dataset

95 Appendix J – Time for Random Data

The following tables show the time in microseconds (Elapsed) that various algorithms took to sort a particular dataset and the amount of extra time per assignment and comparison (XBoth) when it would be better to use the RAS algorithm. AvgTime is the amount of time per assignment/comparison if there were no other processing time.

TotTime is the AvgTime plus XBoth which indicates that if assignments/comparisons take that much time the RAS version would definitely be faster. All times are in microseconds. The tests were run on an IBM Thinkpad Z60m with a 1.86 GHz Intel

Pentium M and 1 GB of ram running Windows XP with Service Pack 2. The Sort Tester sorts elements that are eight byte data structures.

RAS algorithm with BPMerge Stage 1

ExtraTime for a1kr.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 578 19 9754 0 0.00 0.06 0.06 RAS BPMerge Stable 597 0 9754 0 0.00 0.06 0.06 Table 72 Extra Time for RAS BPMerge with 1,000 random elements

ExtraTime for a1ku.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 572 26 9733 0 0.00 0.06 0.06 RAS BPMerge Stable 598 0 9733 0 0.00 0.06 0.06 Table 73 Extra Time for RAS BPMerge with 1,000 unique random elements

ExtraTime for a10kr.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 7433 51 130379 0 0.00 0.06 0.06 RAS BPMerge Stable 7484 0 130379 0 0.00 0.06 0.06 Table 74 Extra Time for RAS BPMerge with 10,000 random elements

96

ExtraTime for a10ku.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 7386 31 130486 0 0.00 0.06 0.06 RAS BPMerge Stable 7417 0 130486 0 0.00 0.06 0.06 Table 75 Extra Time for RAS BPMerge with 10,000 unique random elements

ExtraTime for a100kr.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS BPMerge Stable 95657 0 1636428 0 0.00 0.06 0.06 Table 76 Extra Time for RAS BPMerge with 100,000 random elements

ExtraTime for a100ku.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS BPMerge Stable 94985 0 1636034 0 0.00 0.06 0.06 Table 77 Extra Time for RAS BPMerge with 100,000 unique random elements

ExtraTime for a1mr.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Qinjian Deng 708410 455261 38403046 -18728073 0.02 0.02 0.04 Quick Spencer1M 729993 433678 33779971 -14104998 0.03 0.02 0.05 Quick Spencer2M 748296 415375 34799193 -15124220 0.03 0.02 0.05 Quick Qinjian Deng SOptimized 787696 375975 38254336 -18579363 0.02 0.02 0.04 Quick Spencer3M 806800 356871 32139664 -12464691 0.03 0.03 0.05 Quick BermanPaul 828669 335002 39030710 -19355737 0.02 0.02 0.04 Quick SedgewickBentley 992361 171310 50009982 -30335009 0.01 0.02 0.03 RAS BPMerge Stable 1163671 0 19674973 0 0.00 0.06 0.06 Table 78 Extra Time for RAS BPMerge with 1,000,000 random elements

ExtraTime for a1mu.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Spencer3M 678907 474007 31920685 -12246390 0.04 0.02 0.06 Quick Qinjian Deng 717428 435486 38617793 -18943498 0.02 0.02 0.04 Quick Spencer2M 740001 412913 35038910 -15364615 0.03 0.02 0.05 Quick Spencer1M 744559 408355 34133470 -14459175 0.03 0.02 0.05 Quick Qinjian Deng SOptimized 763709 389205 38476127 -18801832 0.02 0.02 0.04 Quick BermanPaul 811304 341610 38933176 -19258881 0.02 0.02 0.04 Quick SedgewickBentley 904584 248330 46999293 -27324998 0.01 0.02 0.03 RAS BPMerge Stable 1152914 0 19674295 0 0.00 0.06 0.06 Table 79 Extra Time for RAS BPMerge with 1,000,000 unique random elements

97

ExtraTime for a10mr.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Spencer3M 7703931 9550705 382033412 -151930964 0.06 0.02 0.08 Quick Qinjian Deng SOptimized 7873493 9381143 452211822 -222109374 0.04 0.02 0.06 Quick Qinjian Deng 7960838 9293798 453690639 -223588191 0.04 0.02 0.06 Quick Spencer1M 8006047 9248589 412841576 -182739128 0.05 0.02 0.07 Quick Spencer2M 8097555 9157081 413277862 -183175414 0.05 0.02 0.07 Quick BermanPaul 8536246 8718390 463431733 -233329285 0.04 0.02 0.06 Quick SedgewickBentley 10424327 6830309 599346729 -369244281 0.02 0.02 0.04 Merge 14267629 2987007 686547999 -456445551 0.01 0.02 0.03 Shell Tokuda A108870 16412561 842075 785009778 -554907330 0.00 0.02 0.02 Soptimized RAS BPMerge Stable 17254636 0 230102448 0 0.00 0.07 0.07 Table 80 Extra Time for RAS BPMerge with 10,000,000 random elements

ExtraTime for a10mu.srt to RAS BPMerge SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Spencer3M 7716111 9396163 382311926 -152210428 0.06 0.02 0.08 Quick Qinjian Deng SOptimized 7861255 9251019 456464151 -226362653 0.04 0.02 0.06 Quick Spencer1M 7862893 9249381 407392525 -177291027 0.05 0.02 0.07 Quick Qinjian Deng 7954146 9158128 457891260 -227789762 0.04 0.02 0.06 Quick Spencer2M 7960290 9151984 409551600 -179450102 0.05 0.02 0.07 Quick BermanPaul 8447237 8665037 463359119 -233257621 0.04 0.02 0.06 Quick SedgewickBentley 9689302 7422972 557373254 -327271756 0.02 0.02 0.04 Merge 14188069 2924205 686547056 -456445558 0.01 0.02 0.03 Shell Tokuda A108870 16524724 587550 791457051 -561355553 0.00 0.02 0.02 Soptimized RAS BPMerge Stable 17112274 0 230101498 0 0.00 0.07 0.07 Table 81 Extra Time for RAS BPMerge with 10,000,000 unique random elements

98 SMerge Stable Assignments

ExtraTime for a1kr.srt to RAS SMerge Stable SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 578 79 9754 -757 0.10 0.06 0.16 RAS BPMerge Stable 597 60 9754 -757 0.08 0.06 0.14 RAS SMerge Stable 657 0 8997 0 0.00 0.07 0.07 Table 82 Extra Time for RAS SMerge Stable with 1,000 random elements

ExtraTime for a10kr.srt to RAS SMerge Stable SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 7433 1261 130379 -8278 0.15 0.06 0.21 RAS BPMerge Stable 7484 1210 130379 -8278 0.15 0.06 0.20 RAS SMerge Stable 8694 0 122101 0 0.00 0.07 0.07 Table 83 Extra Time for RAS SMerge Stable with 10,000 random elements

ExtraTime for a100kr.srt to RAS SMerge Stable SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS BPMerge Stable 95657 9944 1636428 -82189 0.12 0.06 0.18 RAS SMerge Stable 105601 0 1554239 0 0.00 0.07 0.07 Table 84 Extra Time for RAS SMerge Stable with 100,000 random elements

ExtraTime for a1mr.srt to RAS SMerge Stable SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Qinjian Deng 708410 577365 38403046 -19546245 0.03 0.02 0.05 Quick Spencer1M 729993 555782 33779971 -14923170 0.04 0.02 0.06 Quick Spencer2M 748296 537479 34799193 -15942392 0.03 0.02 0.06 Quick Qinjian Deng SOptimized 787696 498079 38254336 -19397535 0.03 0.02 0.05 Quick Spencer3M 806800 478975 32139664 -13282863 0.04 0.03 0.06 Quick BermanPaul 828669 457106 39030710 -20173909 0.02 0.02 0.04 Quick SedgewickBentley 992361 293414 50009982 -31153181 0.01 0.02 0.03 RAS BPMerge Stable 1163671 122104 19674973 -818172 0.15 0.06 0.21 Merge 1253691 32084 58577809 -39721008 0.00 0.02 0.02 RAS SMerge Stable 1285775 0 18856801 0 0.00 0.07 0.07 Table 85 Extra Time for RAS SMerge Stable with 1,000,000 random elements

99

ExtraTime for a10mr.srt to RAS SMerge Stable SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Spencer3M 7703931 12149336 382033412 -160105216 0.08 0.02 0.10 Quick Qinjian Deng 7873493 11979774 452211822 -230283626 0.05 0.02 0.07 SOptimized Quick Qinjian Deng 7960838 11892429 453690639 -231762443 0.05 0.02 0.07 Quick Spencer1M 8006047 11847220 412841576 -190913380 0.06 0.02 0.08 Quick Spencer2M 8097555 11755712 413277862 -191349666 0.06 0.02 0.08 Quick BermanPaul 8536246 11317021 463431733 -241503537 0.05 0.02 0.07 Quick SedgewickBentley 10424327 9428940 599346729 -377418533 0.02 0.02 0.04 Merge 14267629 5585638 686547999 -464619803 0.01 0.02 0.03 Shell Tokuda A108870 16412561 3440706 785009778 -563081582 0.01 0.02 0.03 Soptimized RAS BPMerge Stable 17254636 2598631 230102448 -8174252 0.32 0.07 0.39 RAS SMerge Stable 19853267 0 221928196 0 0.00 0.09 0.09 Table 86 Extra Time for RAS SMerge Stable with 10,000,000 random elements

SMerge Optimal Assignments

ExtraTime for a1kr.srt to RAS SMerge Optimal SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 578 261 9754 -767 0.34 0.06 0.40 RAS BPMerge Stable 597 242 9754 -767 0.32 0.06 0.38 RAS SMerge Stable 657 182 8997 -10 18.20 0.07 18.27 Quick Spencer1M 679 160 15647 -6660 0.02 0.04 0.07 Quick Spencer1C 686 153 15446 -6459 0.02 0.04 0.07 Quick Spencer2M 703 136 16323 -7336 0.02 0.04 0.06 RAS SMerge Unstable 705 134 8996 -9 14.89 0.08 14.97 Quick Spencer3M 713 126 15477 -6490 0.02 0.05 0.07 Quick Spencer2C 721 118 16580 -7593 0.02 0.04 0.06 Quick Spencer3C 726 113 15614 -6627 0.02 0.05 0.06 Quick Qinjian Deng SOptimized 752 87 19950 -10963 0.01 0.04 0.05 Quick Qinjian Deng 760 79 20094 -11107 0.01 0.04 0.04 RAS SMerge Optimal 839 0 8987 0 0.00 0.09 0.09 Table 87 Extra Time for RAS SMerge Optimal with 1,000 random elements

100

ExtraTime for a10kr.srt to RAS SMerge Optimal SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS16 7433 2896 130379 -8285 0.35 0.06 0.41 RAS BPMerge Stable 7484 2845 130379 -8285 0.34 0.06 0.40 RAS SMerge Stable 8694 1635 122101 -7 233.57 0.07 233.64 RAS SMerge Unstable 8751 1578 122099 -5 315.60 0.07 315.67 Quick Spencer1M 8968 1361 210293 -88199 0.02 0.04 0.06 Quick Spencer3C 9185 1144 205079 -82985 0.01 0.04 0.06 Quick Spencer2C 9202 1127 214354 -92260 0.01 0.04 0.06 Quick Spencer3M 9234 1095 206505 -84411 0.01 0.04 0.06 Quick Spencer1C 9355 974 210625 -88531 0.01 0.04 0.06 Quick Spencer2M 9372 957 220037 -97943 0.01 0.04 0.05 Quick Qinjian Deng SOptimized 9543 786 255370 -133276 0.01 0.04 0.04 Quick Qinjian Deng 9604 725 256891 -134797 0.01 0.04 0.04 RAS SMerge Optimal 10329 0 122094 0 0.00 0.08 0.08 Table 88 Extra Time for RAS SMerge Optimal with 10,000 random elements

ExtraTime for a100kr.srt to RAS SMerge Optimal SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime RAS BPMerge Stable 95657 35847 1636428 -82201 0.44 0.06 0.49 RAS SMerge Stable 105601 25903 1554239 -12 2158.58 0.07 2158.65 RAS SMerge Unstable 112803 18701 1554237 -10 1870.10 0.07 1870.17 Quick Spencer3M 116973 14531 2657981 -1103754 0.01 0.04 0.06 Quick Spencer3C 117242 14262 2624740 -1070513 0.01 0.04 0.06 Quick Spencer1C 117274 14230 2783331 -1229104 0.01 0.04 0.05 Quick Spencer1M 117417 14087 2800238 -1246011 0.01 0.04 0.05 Quick Spencer2M 118621 12883 2798529 -1244302 0.01 0.04 0.05 Quick Spencer2C 119959 11545 2861084 -1306857 0.01 0.04 0.05 Quick Qinjian Deng 121262 10242 3263625 -1709398 0.01 0.04 0.04 Quick Qinjian Deng SOptimized 122734 8770 3248958 -1694731 0.01 0.04 0.04 Quick BermanPaul 128115 3389 3261445 -1707218 0.00 0.04 0.04 RAS SMerge Optimal 131504 0 1554227 0 0.00 0.08 0.08 Table 89 Extra Time for RAS SMerge Optimal with 100,000 random elements

101

ExtraTime for a1mr.srt to RAS SMerge Optimal SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Qinjian Deng 708410 979102 38403046 -19546258 0.05 0.02 0.07 Quick Spencer1M 729993 957519 33779971 -14923183 0.06 0.02 0.09 Quick Spencer2M 748296 939216 34799193 -15942405 0.06 0.02 0.08 Quick Qinjian Deng SOptimized 787696 899816 38254336 -19397548 0.05 0.02 0.07 Quick Spencer3M 806800 880712 32139664 -13282876 0.07 0.03 0.09 Quick BermanPaul 828669 858843 39030710 -20173922 0.04 0.02 0.06 Quick SedgewickBentley 992361 695151 50009982 -31153194 0.02 0.02 0.04 RAS BPMerge Stable 1163671 523841 19674973 -818185 0.64 0.06 0.70 Merge 1253691 433821 58577809 -39721021 0.01 0.02 0.03 RAS SMerge Stable 1285775 401737 18856801 -13 30902.85 0.07 30902.91 RAS SMerge Unstable 1311623 375889 18856799 -11 34171.73 0.07 34171.80 Heap BermanPaul 1335356 352156 60843360 -41986572 0.01 0.02 0.03 Shell Tokuda A108870 1347553 339959 65176631 -46319843 0.01 0.02 0.03 Soptimized Heap BermanPaul SOptimized 1350330 337182 60629600 -41772812 0.01 0.02 0.03 RAS SMerge Optimal 1687512 0 18856788 0 0.00 0.09 0.09 Table 90 Extra Time for RAS SMerge Optimal with 1,000,000 random elements

ExtraTime for a10mr.srt to RAS SMerge Optimal SortName Elapsed TimeDif Both BothDif XBoth AvgTime TotTime Quick Spencer3M 7703931 17852636 382033412 -160105235 0.11 0.02 0.13 Quick Qinjian Deng 7873493 17683074 452211822 -230283645 0.08 0.02 0.09 SOptimized Quick Qinjian Deng 7960838 17595729 453690639 -231762462 0.08 0.02 0.09 Quick Spencer1M 8006047 17550520 412841576 -190913399 0.09 0.02 0.11 Quick Spencer2M 8097555 17459012 413277862 -191349685 0.09 0.02 0.11 Quick BermanPaul 8536246 17020321 463431733 -241503556 0.07 0.02 0.09 Quick SedgewickBentley 10424327 15132240 599346729 -377418552 0.04 0.02 0.06 Merge 14267629 11288938 686547999 -464619822 0.02 0.02 0.05 Shell Tokuda A108870 16412561 9144006 785009778 -563081601 0.02 0.02 0.04 Soptimized RAS BPMerge Stable 17254636 8301931 230102448 -8174271 1.02 0.07 1.09 RAS SMerge Stable 19853267 5703300 221928196 -19 300173.68 0.09 300173.77 RAS SMerge Unstable 20643519 4913048 221928194 -17 289002.82 0.09 289002.92 Heap BermanPaul 20983997 4572570 708467578 -486539401 0.01 0.03 0.04 Heap BermanPaul 21477848 4078719 706333786 -484405609 0.01 0.03 0.04 SOptimized RAS SMerge Optimal 25556567 0 221928177 0 0.00 0.12 0.12 Table 91 Extra Time for RAS SMerge Optimal with 10,000,000 random elements

102 References:

[1] K. A. Berman and J. L. Paul, Algorithms: Sequential, Parallel, and Distributed. Boston, Mass.: Thomson/Course Technology, pp. 962, 2005.

[2] D. E. Knuth, The Art of Computer Programming, 3rd ed., Reading, Mass.: Addison- Wesley, 1997.

[3] R. Sedgewick, Algorithms in Java, Parts 1-4, 3rd ed., vol. 1, Boston: Addison- Wesley, pp. 737, 2003.

[4] D. L. Shell, "A high-speed sorting procedure," Commun ACM, vol. 2, pp. 30-32, 1959.

[5] M. A. Weiss, "Data structures and algorithm analysis in Java,” pp. xviii, 555 p, 2007.

[6] N. Tokuda, "An improved Shellsort,” IFIP Transactions A, vol. 12, pp. 449-457, 1992.

[7] Hoare, Charles Antony Richard, "Quicksort,” The Computer Journal, vol. 5, pp. 10- 16, January 1. 1962.

[8] H. Hsien-Kuei, "Phase change of limit laws in the quicksort recurrence under varying toll functions," SIAM Journal on Computing, vol. 31, pp. 1687, 2002.

[9] Williams, John William Joseph, "Algorithm 232: ,” CACM, vol. 7, pp. 347- 348, 1964.

[10] D. D. Sleator and R. E. Tarjan, "Self-adjusting binary search trees," Journal of the Association for Computing Machinery, vol. 32, pp. 652-686, 1985.

[11] M. Peczarski, "The Ford-Johnson algorithm still unbeaten for less than 47 elements,” Information Processing Letters, vol. 101, pp. 126-128, 2007.

[12] Ford, Lester Randolph, Jr. and S. M. Johnson, "A Tournament Problem,” The American Mathematical Monthly, vol. 66, pp. 387-389, May. 1959.

[13] M. Ayala-Rincón, de Abreu, Bruno T. and J. de Siqueira, "A variant of the Ford- Johnson algorithm that is more space efficient," Information Processing Letters, vol. 102, pp. 201-207, 2007.

[14] G. K. Manacher, T. D. Bui and T. Mai, "Optimum combinations of sorting and merging,” Journal of the ACM (JACM), vol. 36, pp. 290-334, 1989.

[15] P. Morin, "JSort Algorithm," http://cg.scs.carleton.ca/~morin/misc/sortalg/JSortAlgorithm.java, 2007.

103 [16] M. A. Weiss, "Data structures and problem solving using Java,” pp. xxxiv, 886 p, 2002.

[17] T. N. Hibbard, "An empirical study of minimal storage sorting," Commun ACM, vol. 6, pp. 206-213, 1963.

[18] R. Sedgewick, "Analysis of Shellsort and related algorithms,” pp. 1-11, 1996.

[19] J. Incerpi and R. Sedgewick, "Improved upper bounds on Shellsort,” J. Comput. System Sci., vol. 31, 1985.

[20] R. Sedgewick, "A new upper bound for Shellsort,” Journal of Algorithms, vol. 7, pp. 159-173, 1986.

[21] M. Ciura, "Best Increments for the Average Case of Shellsort,” Lecture Notes in Computer Science, vol. 2138, pp. 106-117, 2001.

[22] njas, "A003462 is (3^n - 1)/2," http://www.research.att.com/~njas/sequences/A003462, 2007.

[23] njas, "A036564 is 2^n-45, n >= 6,” http://www.research.att.com/~njas/sequences/A036564, 2007.

[24] S. Pigeon, "A055875 is a(0)=1, a(i)= Prime[i^3]," http://www.research.att.com/~njas/sequences/A055875, 2007.

[25] S. Pigeon, "A055876 is round[ 1 + e^(n-2) ]," http://www.research.att.com/~njas/sequences/A055876, 2007.

[26] Wikipedia contributors, "Heapsort,” http://en.wikipedia.org/wiki/Heapsort, 2007.

[27] Q. Deng, "Bottom-up insertion-mergesort,” Masters Thesis, University of Cincinnati, 1996.

[28] R. Sedgewick and J. Bentley, "Quicksort is optimal," in Knuthfest, 2002.

104 Table of Source Code Contents

Notes on Implementation...... 106 SortTypes.h Header used by all Sorts...... 106 ras.h Header for 16 bit Reduced Assignment Sort...... 106 ras.cpp Source for 16 bit Reduced Assignment Sort ...... 107 Spencer.h Header for Reduced Assignment Sort...... 109 Spencer.cpp Source for Reduced Assignment Sort ...... 111 Bubble.h Header for Bubble Sort ...... 125 Bubble.cpp Source for Bubble Sort ...... 126 Insert.h Header for Insertion Sort...... 126 Insert.cpp Source for Insertion Sort ...... 127 SSort.h Header for SMInsert Sort ...... 128 SSort.cpp Source for SMInsert Sort ...... 128 JSort.h Header for JSort...... 130 JSort.cpp Source for JSort ...... 130 Bingo.h Header for Bingo Sort...... 132 Bingo.cpp Source for Bingo Sort ...... 133 BiBingo.h Header for Bidirectional Bingo Sort ...... 137 BiBingo.cpp Source for Bidirectional Bingo Sort ...... 137 Shell.h Header for Shell Sort ...... 145 Shell.cpp Source for Shell Sort...... 145 BPHeap.h Header for Berman & Paul’s Heap Sort...... 149 BPHeap.cpp Source for Berman & Paul’s Heap Sort ...... 150 Heap.h Header for Wikipedia Heap Sort...... 152 Heap.cpp Source for Wikipedia Heap Sort ...... 152 Merge.h Header for Merge Sort ...... 154 Merge.cpp Source for Merge Sort ...... 154 BPQuick.h Header for Berman & Paul’s Quick Sort ...... 158 BPQuick.cpp Source for Berman & Paul’s Quick Sort ...... 159 QDQuick.h Header for Qinjian Deng’s Quick Sort ...... 160 QDQuick.cpp Source for Qinjian Deng’s Quick Sort ...... 160 SBQuick.h Header for Sedgewick & Bentley’s Quick Sort...... 164 SBQuick.cpp Source for Sedgewick & Bentley’s Quick Sort ...... 165 SQuick.h Header for Spencer’s Quick Sorts...... 166 SQuick.cpp Source for Spencer’s Quick Sorts...... 167 frmSorts.h Header for Sort Tester Form...... 172 frmSorts.cpp Source for Sort Tester Form...... 175 frmSorts.dfm Delphi Form for Sort Tester...... 220

Source is included in PDF version

105 Notes on Implementation

The Sort Tester program is written in Borland C++ Builder 5 which I had available to me when I ported it from the TopSpeed Modula-2 with which I had originally developed the algorithm on the DOS platform. Because the original development was on a 16 bit machine, I chose to use unsigned integers and use 0 as the temporary location. Now signed integers are used which allow implementation of the

Merge Sort with multiple temporary locations (using negative numbers) but zero is still a temporary location. A 16 bit version of the RAS algorithm is in ras.h and ras.cpp which may be easier to understand than the version in spencer.h and spencer.cpp which contains many options and variations.

SortTypes.h Header used by all Sorts

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited #ifndef _SortTypes_H_ #define _SortTypes_H_ typedef char SortCompareResult; // (-1=Less, 0=Equal, 1=More); typedef SortCompareResult __fastcall (__closure *CompareProc) ( long a, long b) ; typedef void __fastcall (__closure *MoveProc) ( long from, long to) ; // 0 is temporary typedef void __fastcall (__closure *SwapProc) ( long from, long to) ; // 0 is temporary

#endif ras.h Header for 16 bit Reduced Assignment Sort

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited // SpencerSort is the Reduced Assignment Sort developed entirely by me.

#ifndef _ras_H_ #define _ras_H_ #include "SortTypes.h" class RASort { private: unsigned short *place; unsigned short *next; unsigned short p; long start; CompareProc RCmp; MoveProc RMv;

106 void __fastcall FillMergeStable(unsigned short cnt); void __fastcall WriteArray(unsigned short st, unsigned short en); unsigned short __fastcall MSort(unsigned short st, unsigned short en); unsigned short __fastcall MergeStable(unsigned short low, unsigned short x); public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); __fastcall RASort(); __fastcall ~RASort(); }; #endif

ras.cpp Source for 16 bit Reduced Assignment Sort

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited // SpencerSort is the Reduced Assignment Sort developed entirely by me.

#include #include #include "ras.h"

//------__fastcall RASort::RASort() { place = new unsigned short[65536]; next = new unsigned short[65536]; } //------__fastcall RASort::~RASort() { if (place) delete [] place; if (next) delete [] next; } //------void __fastcall RASort::FillMergeStable(unsigned short cnt) { unsigned short node = next[0]; while (cnt) { place[p] = node; node = next[node]; p++; cnt--; } } // FillMergeStable; //------void __fastcall RASort::WriteArray(unsigned short st, unsigned short en) { unsigned short q, r;

if (st < en) { p = st;

107 for (;;) { if (place[p] != p) { RMv(p+start, 0); q = p; r = place[q]; do { RMv(start+r, start+q); place[q] = q; q = r; r = place[q]; } while (p != r); RMv(0, q+start); place[q] = q; } if (p == en) return; p++; } } } // WriteArray; //------unsigned short __fastcall RASort::MergeStable(unsigned short low, unsigned short x) { unsigned short CurPos1 = low, CurPos2 = x;

unsigned short ret = 0; unsigned short last = 0; while (CurPos1 && CurPos2) { if (RCmp(start+CurPos1, start+CurPos2) != 1) { if (!ret) ret = CurPos1; else next[last] = CurPos1; last = CurPos1; CurPos1 = next[CurPos1]; } else { if (!ret) ret = CurPos2; else next[last] = CurPos2; last = CurPos2; CurPos2 = next[CurPos2]; } } if (CurPos1) next[last] = CurPos1; else if (CurPos2) next[last] = CurPos2; return ret; }

108 //------unsigned short __fastcall RASort::MSort(unsigned short st, unsigned short en) { if (st < en) { unsigned short mid = (unsigned short) (((long) st + (long) en)/2); unsigned short first1 = MSort(st,mid); unsigned short first2 = MSort((unsigned short) (mid+1),en); return MergeStable(first1,first2); } else return st; } //------int __fastcall RASort::Sort(long st, long en, CompareProc Cmp, MoveProc Mv) { if ((1+en-st > 65535) || !place || !next) return false;

start = st-1;

unsigned short newen = (unsigned short) (en - start);

RCmp = Cmp; RMv = Mv;

setmem(place, (newen+1) * sizeof(unsigned short), 0); setmem(next, (newen+1) * sizeof(unsigned short), 0);

next[0] = MSort(1, newen); p = 1; FillMergeStable(newen); // (unsigned short) (en-st+1));

WriteArray(1, newen);

return true; } // Sort;

Spencer.h Header for Reduced Assignment Sort

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited // SpencerSort is the Reduced Assignment Sort developed entirely by me. // However it does use known data structures and the Merge versions rely upon // and utilize non-in-place versions of MergeSort (in merge.c).

#ifndef _spencer_H_ #define _spencer_H_ #include "SortTypes.h" #include "merge.h" class SpencerSort { typedef struct tNodeType {

109 long num, less, more; long equal; } NodeType; typedef void __fastcall (__closure *AddProc) ( void) ; private: tNodeType *root; long nodeCnt; long *place; long *circuit; long start; long p, p2; long equalCnt, eqStart, eqEnd; long tmpPlace, tmpPtr, tmpCircuit; CompareProc TCmp; MoveProc TMv; AddProc Add; int splayType; long *next; bool *equal; void __fastcall RotateLess(long n); void __fastcall RotateMore(long n); void __fastcall AddRegular(); void __fastcall AddSplay(); void __fastcall DitherAdd(long st, long en); void __fastcall SequentialAdd(long st, long en); void __fastcall CountEqual(long eqroot); void __fastcall CountMergeEqual(long node); void __fastcall FillMergeCorrectEqual(long node); void __fastcall FillMergeIncorrectEqual(long node); void __fastcall FillMergeIncorrectEqualOptimal(long node); long __fastcall Circuit(long n); void __fastcall FillCorrectEqual(long eqroot); void __fastcall FillIncorrectEqual(long eqroot); void __fastcall FillMoreIncorrectEqual(long eqroot); void __fastcall FillIncorrectEqualOptimal(long eqroot); void __fastcall FillMoreIncorrectEqualOptimal(long eqroot); void __fastcall FillArrayEqual(long eqroot); void __fastcall FillArray(long en); void __fastcall FillMerge(long cnt); void __fastcall FillMergeStable(long cnt); void __fastcall FillMergeOptimal(long cnt); void __fastcall FillArrayStable(long en); void __fastcall FillArrayOptimal(long en); void __fastcall FindEqualOptimal(long eqroot); void __fastcall FindOptimalSubstitution(long en); void __fastcall FindMergeEqualOptimal(long node); void __fastcall FindMergeOptimalSubstitution(long cnt); void __fastcall WriteArray(long st, long en); public: long rotateCnt; char assignType; char compareType; bool sequential; int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); __fastcall SpencerSort();

110 }; #endif

Spencer.cpp Source for Reduced Assignment Sort

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited // SpencerSort is the Reduced Assignment Sort developed entirely by me. // However it does use known data structures and the Merge versions rely upon // and utilize non-in-place versions of MergeSort (in merge.c).

#include #include #include "spencer.h"

//------__fastcall SpencerSort::SpencerSort() { rotateCnt = 0; } //------void __fastcall SpencerSort::RotateLess(long n) { tNodeType tmpNode; long l; tmpNode = root[n]; l = tmpNode.less; root[n] = root[l]; root[l] = tmpNode;

root[l].less = root[n].more; root[n].more = l;

rotateCnt++; } //------void __fastcall SpencerSort::RotateMore(long n) { tNodeType tmpNode; long m; tmpNode = root[n]; m = tmpNode.more; root[n] = root[m]; root[m] = tmpNode;

root[m].more = root[n].less; root[n].less = m;

rotateCnt++; } //------void __fastcall SpencerSort::AddSplay() { nodeCnt++; root[nodeCnt].num = p; int splay = splayType;

111 if (nodeCnt > 1) { long n = 1; long *node = &n; // this is done so the parent can point to node long *fallback = 0; bool less = false; do { SortCompareResult cmp = TCmp(p, root[*node].num); if (cmp < 0) { if (fallback && !less) { node = fallback; fallback = 0; } else if (root[*node].less && splay) { RotateLess(*node); fallback = &root[root[*node].more].less; less = true; splay &= 0x0c; } else { splay = (splayType & 0x0e); node = &root[*node].less; fallback = 0; } } else if (cmp > 0) { if (fallback && less) { node = fallback; fallback = 0; } else if (root[*node].more && splay) { RotateMore(*node); fallback = &root[root[*node].less].more; less = false; splay &= 0x0c; } else { splay = (splayType & 0x0e); node = &root[*node].more; fallback = 0; } } else { if (p < root[*node].num) { root[nodeCnt].num = root[*node].num; root[*node].num = p;

112 } node = &root[*node].equal; while (*node && (p < root[*node].num)) node = &root[*node].equal; root[nodeCnt].equal = *node; *node = 0; } } while (*node); *node = nodeCnt; if (splayType == -2) { if (root[1].more == p) RotateMore(1); else if (root[1].less == p) RotateLess(1); } } } // AddSplay //------void __fastcall SpencerSort::AddRegular() { nodeCnt++; root[nodeCnt].num = p; if (nodeCnt > 1) { long n = 1; long *node = &n; // this is done so the parent can point to node do { SortCompareResult cmp = TCmp(p, root[*node].num); if (cmp < 0) { node = &root[*node].less; } else if (cmp > 0) { node = &root[*node].more; } else { if (p < root[*node].num) { root[nodeCnt].num = root[*node].num; root[*node].num = p; } node = &root[*node].equal; while (*node && (p < root[*node].num)) node = &root[*node].equal; root[nodeCnt].equal = *node; *node = 0; } } while (*node); *node = nodeCnt; } } // AddRegular //------void __fastcall SpencerSort::DitherAdd(long st, long en)

113 { long m;

for (;;) { m = (st+en) / 2; p = m; Add();

if (m > st) DitherAdd(st, m-1);

if (m >= en) return;

st = m + 1; } } // DitherAdd; //------void __fastcall SpencerSort::SequentialAdd(long st, long en) { for (p = st; p <= en; p++) Add(); } // SequentialAdd; //------void __fastcall SpencerSort::CountEqual(long eqroot) { while (root[eqroot].equal) { equalCnt++; eqroot = root[eqroot].equal; } } //------void __fastcall SpencerSort::FillCorrectEqual(long eqroot) { do { if (((root[eqroot].num >= eqStart) && (root[eqroot].num <= eqEnd))) place[root[eqroot].num] = root[eqroot].num; eqroot = root[eqroot].equal; } while (eqroot); } //------void __fastcall SpencerSort::FillIncorrectEqual(long eqroot) { if (((root[eqroot].num < eqStart) || (root[eqroot].num > eqEnd))) { place[p] = root[eqroot].num; p++; while (place[p] == p) p++; }

FillMoreIncorrectEqual(root[eqroot].equal); }

114 //------void __fastcall SpencerSort::FillMoreIncorrectEqual(long eqroot) { if (root[eqroot].equal) FillMoreIncorrectEqual(root[eqroot].equal);

if (((root[eqroot].num < eqStart) || (root[eqroot].num > eqEnd))) { place[p] = root[eqroot].num; p++; while ((p < nodeCnt+start) && (place[p] == p)) p++; } } //------void __fastcall SpencerSort::FillIncorrectEqualOptimal(long eqroot) { if (((root[eqroot].num < eqStart) || (root[eqroot].num > eqEnd))) { long c = Circuit(root[eqroot].num); if (c != p) circuit[p] = c;

place[p] = root[eqroot].num; p++; while (place[p] == p) p++; } FillMoreIncorrectEqualOptimal(root[eqroot].equal); } //------void __fastcall SpencerSort::FillMoreIncorrectEqualOptimal(long eqroot) { if (root[eqroot].equal) FillMoreIncorrectEqualOptimal(root[eqroot].equal);

if (((root[eqroot].num < eqStart) || (root[eqroot].num > eqEnd))) { long c = Circuit(root[eqroot].num); if (c != p) circuit[p] = c;

place[p] = root[eqroot].num; p++; while ((p < nodeCnt+start) && (place[p] == p)) p++; } } //------void __fastcall SpencerSort::FillArray(long n) { while (n) { if (root[n].less) { FillArray(root[n].less); }

115 if (root[n].equal) { equalCnt = 1; CountEqual(root[n].equal); eqStart = p; eqEnd = p + equalCnt; FillCorrectEqual(n); while ((p < nodeCnt+start) && (place[p] == p)) p++; FillIncorrectEqual(n); } else { place[p] = root[n].num; p++; } n = root[n].more; } } // FillArray; //------long __fastcall SpencerSort::Circuit(long n) { long max = n; while (circuit[n]) { n = circuit[n]; max = n; } return max; } // Circuit //------void __fastcall SpencerSort::FillArrayOptimal(long n) { while (n) { if (root[n].less) { FillArrayOptimal(root[n].less); } if (root[n].equal) { equalCnt = 1; CountEqual(root[n].equal); eqStart = p; eqEnd = p + equalCnt; FillCorrectEqual(n); while ((p < nodeCnt+start) && (place[p] == p)) p++; FillIncorrectEqualOptimal(n); } else { if (root[n].num != p) { long c = Circuit(root[n].num); if (c != p) circuit[p] = c;

116 } place[p] = root[n].num; p++; } n = root[n].more; } } // FillArrayOptimal; //------void __fastcall SpencerSort::FindEqualOptimal(long eqroot) { if (root[eqroot].equal) FindEqualOptimal(root[eqroot].equal);

if (place[root[eqroot].num] != root[eqroot].num) { long ec = Circuit(root[eqroot].num); if (tmpCircuit) { if (ec != tmpCircuit) { place[tmpPtr] = place[p]; tmpPtr = p; if (ec > tmpCircuit) { circuit[tmpCircuit] = ec; tmpCircuit = ec; } else circuit[ec] = tmpCircuit; } } else { tmpPtr = p; tmpPlace = place[tmpPtr]; tmpCircuit = ec; } p++; } p2++; } //------void __fastcall SpencerSort::FindOptimalSubstitution(long n) { while (n) { if (root[n].less) { FindOptimalSubstitution(root[n].less); } if (root[n].equal) { if (place[root[n].num] != root[n].num) { tmpPtr = p; tmpPlace = place[tmpPtr]; tmpCircuit = Circuit(root[n].num);

117 } else tmpPtr = tmpCircuit = 0; p++; p2 = p; FindEqualOptimal(root[n].equal); if (tmpPtr) { place[tmpPtr] = tmpPlace; } p = p2; } else p++; n = root[n].more; } } // FindOptimalSubstitution; //------void __fastcall SpencerSort::FillArrayEqual(long eqroot) { if (root[eqroot].equal) FillArrayEqual(root[eqroot].equal);

place[p] = root[eqroot].num; p++; } //------void __fastcall SpencerSort::FillArrayStable(long en) { bool done = false; long n = 1; long *nodeList = new long[en]; long nCnt = 0;

do { while (root[n].less) { nodeList[nCnt] = n; nCnt++; n = root[n].less; } place[p] = root[n].num; p++; if (root[n].equal) FillArrayEqual(root[n].equal); while (nCnt && !root[n].more) { nCnt--; n = nodeList[nCnt]; place[p] = root[n].num; p++; if (root[n].equal) FillArrayEqual(root[n].equal); } if (root[n].more) n = root[n].more;

118 else done = true; } while (!done); delete[] nodeList; } // FillArrayStable; //------void __fastcall SpencerSort::CountMergeEqual(long node) { while (node && equal[node]) { equalCnt++; node = next[node]; } } // CountMergeEqual //------void __fastcall SpencerSort::FillMergeCorrectEqual(long node) { do { if ((node >= eqStart) && (node < eqEnd)) place[node] = node; node = next[node]; } while (node && equal[node]); } // FillMergeCorrectEqual //------void __fastcall SpencerSort::FillMergeIncorrectEqual(long node) { do { if ((node < eqStart) || (node >= eqEnd)) { place[p] = node; p++; while ((p < nodeCnt+start) && (place[p] == p)) p++; } node = next[node]; } while (node && equal[node]); } // FillMergeIncorrectEqual //------void __fastcall SpencerSort::FillMergeIncorrectEqualOptimal(long node) { do { if ((node < eqStart) || (node >= eqEnd)) { long c = Circuit(node); if (c != p) circuit[p] = c; place[p] = node; p++; while ((p < nodeCnt+start) && (place[p] == p)) p++; } node = next[node]; } while (node && equal[node]); } // FillMergeIncorrectEqualOptimal

119 //------void __fastcall SpencerSort::FillMerge(long cnt) { nodeCnt = cnt; long node = next[0]; while (cnt) { if (equal[next[node]]) { equalCnt = 1; CountMergeEqual(next[node]); eqStart = p; eqEnd = p + equalCnt; FillMergeCorrectEqual(node); while ((p < nodeCnt+start) && (place[p] == p)) p++; FillMergeIncorrectEqual(node); if (cnt <= equalCnt) return; cnt -= equalCnt; do { node = next[node]; } while (equal[node]); } else { place[p] = node; p++; node = next[node]; cnt--; } } } // FillMerge; //------void __fastcall SpencerSort::FillMergeStable(long cnt) { long node = next[0]; while (cnt) { place[p] = node; node = next[node]; p++; cnt--; } } // FillMergeStable; //------void __fastcall SpencerSort::FillMergeOptimal(long cnt) { long node = next[0]; nodeCnt = cnt; while (cnt) { if (equal[next[node]]) { equalCnt = 1; CountMergeEqual(next[node]);

120 eqStart = p; eqEnd = p + equalCnt; FillMergeCorrectEqual(node); while ((p < nodeCnt+start) && (place[p] == p)) p++; FillMergeIncorrectEqualOptimal(node); if (cnt <= equalCnt) return; cnt -= equalCnt; do { node = next[node]; } while (equal[node]); } else { if (node != p) { long c = Circuit(node); if (c != p) circuit[p] = c; } place[p] = node; p++; node = next[node]; cnt--; } } } // FillMergeOptimal; //------void __fastcall SpencerSort::FindMergeEqualOptimal(long node) { long p2 = p; do { if (place[node] != node) { long ec = Circuit(node); if (tmpCircuit) { if (ec != tmpCircuit) { place[tmpPtr] = place[p2]; tmpPtr = p2; if (ec > tmpCircuit) { circuit[tmpCircuit] = ec; tmpCircuit = ec; } else circuit[ec] = tmpCircuit; } } else { tmpPtr = p2; tmpPlace = place[p2];

121 tmpCircuit = ec; } p2++; } node = next[node]; } while (node && equal[node]); } // FindMergeEqualOptimal //------void __fastcall SpencerSort::FindMergeOptimalSubstitution(long cnt) { p = 1; long node = next[0]; while (cnt) { if (equal[next[node]]) { tmpPtr = tmpCircuit = 0; FindMergeEqualOptimal(node); if (tmpPtr) { place[tmpPtr] = tmpPlace; }

do { node = next[node]; cnt--; p++; } while (node && equal[node]);

} else { node = next[node]; cnt--; p++; } } } // FindOptimalSubstitution; //------void __fastcall SpencerSort::WriteArray(long st, long en) { long q, r;

if (st < en) { p = st; for (;;) { if (place[p] != p) { TMv(p, 0); q = p; r = place[q]; do { TMv(r, q);

122 place[q] = q; q = r; r = place[q]; } while (p != r); TMv(0, q); place[q] = q; } if (p == en) return; p++; } } } // WriteArray //------int __fastcall SpencerSort::Sort(long st, long en, CompareProc Cmp, MoveProc Mv) { int ret = false;

place = new long[en+1];

if (place) { TCmp = Cmp; TMv = Mv; start = st;

setmem(place, (en+1) * sizeof(long), 0); if (compareType < 0 || compareType >= 5) { BPMergeSort *bpm; bpm = new BPMergeSort; bpm->optimal = (compareType < 0) ||(compareType == 6); bpm->Sort(st, en, Cmp); next = bpm->next; equal = bpm->equal; p = st; switch (assignType) { case 1 : FillMerge(en-st+1); break; case 2 : circuit = new long[en+1]; setmem(circuit, (en+1) * sizeof(long), 0); FillMergeOptimal(en-st+1); for (long n = en-1; n; n--) { if (circuit[n]) circuit[n] = Circuit(circuit[n]); } FindMergeOptimalSubstitution(en-st+1); delete[] circuit; break; default : FillMergeStable(en-st+1); break; }

123 delete bpm; } else { root = new tNodeType[en+1];

if (root) { setmem(root, (en+1) * sizeof(tNodeType), 0);

switch (compareType) { case 1: // Splay Add = AddSplay; splayType = -1; break; case 2: // Splay1 Add = AddSplay; splayType = 1; break; case 3: // Splay/2 Add = AddSplay; splayType = 2; break; case 4: // SplayX Add = AddSplay; splayType = -2; break; default: // Tree Add = AddRegular; }

nodeCnt = 0;

if (sequential) SequentialAdd(st, en); else DitherAdd(st, en);

p = st; switch (assignType) { case 1 : FillArray(1); break; case 2 : circuit = new long[en+1]; setmem(circuit, (en+1) * sizeof(long), 0); FillArrayOptimal(1); for (long n = en-1; n; n--) if (circuit[n]) { circuit[n] = Circuit(circuit[n]); } p = 1; FindOptimalSubstitution(1); delete[] circuit;

124 break; default : FillArrayStable(en); break; } delete[] root; } else { delete[] place; return false; } } WriteArray(st, en);

ret = true; delete[] place; } return ret; } // Sort;

Bubble.h Header for Bubble Sort

// SortTester by Spencer Morgan // BubbleSort is a poor sorting algorithm

#ifndef _bubble_H_ #define _bubble_H_ #include "SortTypes.h" class BubbleSort { public: int __fastcall Sort(long st, long en, CompareProc Cmp, SwapProc Swap); }; #endif

125 Bubble.cpp Source for Bubble Sort

// SortTester by Spencer Morgan // BubbleSort is a poor sorting algorithm

#include #include "bubble.h" //------int __fastcall BubbleSort::Sort(long st, long en, CompareProc Compare, SwapProc Swap) { long a, b; char out_of;

out_of = true; b = en; while (out_of) { out_of = false; a = st; while (a < b) { if (Compare(a+1,a) < 0) { Swap(a+1,a); out_of = true; } a++; } b--; }

return true; }

Insert.h Header for Insertion Sort

// SortTester by Spencer Morgan // InsertionSort is based on pseudo-code on page 42 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _insert_H_ #define _insert_H_ #include "SortTypes.h" class InsertionSort { public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); int __fastcall SortBP(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

126 Insert.cpp Source for Insertion Sort

// SortTester by Spencer Morgan // InsertionSort is based on pseudo-code on page 42 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include #include "insert.h" //------int __fastcall InsertionSort::Sort(long st, long en, CompareProc Compare, MoveProc Move) { for (long i = st+1; i<=en; i++) { if (Compare(i-1,i) > 0) { long j = i - 1; Move(i,0); do { Move(j, j+1); j--; } while ((j>=st) && (Compare(j,0) > 0)); Move(0, j+1); } } return true; } //------int __fastcall InsertionSort::SortBP(long st, long en, CompareProc Compare, MoveProc Move) { for (long i = st+1; i<=en; i++) { Move(i,0); long p = i - 1; while ((p >= st) && (Compare(0,p) < 0)) { Move(p, p+1); p--; } Move(0, p+1); } return true; } //------

127 SSort.h Header for SMInsert Sort

// SortTester by Spencer Morgan // SpencerInsertSort is higly modified extension of InsertionSort that I developed.

#ifndef _ssort_H_ #define _ssort_H_

#include "SortTypes.h" class SpencerInsertSort { private: CompareProc Cmp; MoveProc Mv; long l, h; void __fastcall Pan(long st,long en); void __fastcall Place(long st, long en); public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

SSort.cpp Source for SMInsert Sort

// SortTester by Spencer Morgan // SpencerInsertSort is higly modified extension of InsertionSort that I developed.

#include #include "ssort.h"

//------void __fastcall SpencerInsertSort::Pan(long st,long en) { l = st; h = en; while (h > l) { if (Cmp(h,l) < 0) { Mv(l,0); Mv(h,l); Mv(0,h); } l++; h--; } } //------void __fastcall SpencerInsertSort::Place(long st, long en) { long l,h,t;

if (Cmp(st+1, st) < 0) { l = st + 1;

128 h = en; while ((h - l) > 1) { t = (h+l) / 2; if (Cmp(st,t) <= 0) h = t; else l = t; } Mv(st, 0); do { Mv(st+1, st); st++; } while (st < l); Mv(0, st); } if (Cmp(en, en-1) < 0) { l = st; h = en - 1; while ((h - l) > 1) { t = (h+l) / 2; if (Cmp(en,t) < 0) h = t; else l = t; } Mv(en, 0); do { Mv(en-1, en); en--; } while (en > h); Mv(0, en); } } //------int __fastcall SpencerInsertSort::Sort(long st, long en, CompareProc CP, MoveProc MP) { Cmp = CP; Mv = MP; Pan(st,en); while (l > st) { l--; h++; Place(l, h); } return true; } //------

129 JSort.h Header for JSort

// SortTester by Spencer Morgan // JSort is adapted from JSortAlgorithm.java with the disclaimer // Patrick Morin takes no responsibility for anything. So there. // The JSort algorithm is due to Jason Morrison // // although I have seen attribution to John Cohen

#ifndef _jsort_H_ #define _jsort_H_ #include "SortTypes.h" class JSort { private: CompareProc JCmp; MoveProc JMv; void __fastcall reheap (int length, int i); void __fastcall invreheap (int length, int i); public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

JSort.cpp Source for JSort

// SortTester by Spencer Morgan // JSort is adapted from JSortAlgorithm.java with the disclaimer // Patrick Morin takes no responsibility for anything. So there. // The JSort algorithm is due to Jason Morrison // // although I have seen attribution to John Cohen

#include #include "jsort.h"

CompareProc JCmp; MoveProc JMv; //------void __fastcall JSort::reheap (int length, int i) { boolean done = false; JMv(i, 0); int parent = i; int child = 2*(i+1)-1; while ((child < length) && (!done)) { if (child < length - 1) { if (JCmp(child, child + 1) >= 0) { child += 1; } } if (JCmp(0, child) < 0)

130 { done = true; } else { JMv(child, parent); parent = child; child = 2*(parent+1)-1; } } JMv(0, parent); } //------void __fastcall JSort::invreheap (int length, int i) { boolean done = false; JMv(length - 1 - i, 0);

int parent = i; int child = 2*(i+1)-1; while ((child < length) && (!done)) { if (child < length - 1) { if (JCmp(length - 1 - child, length - 1 - (child + 1)) <= 0) { child += 1; } } if (JCmp(0, length - 1 - child) > 0) { done = true; } else { JMv(length - 1 - child, length - 1 - parent); parent = child; child = 2*(parent+1)-1; } } JMv(0, length - 1 - parent); } //------int __fastcall JSort::Sort(long st, long en, CompareProc Compare, MoveProc Move) { JCmp = Compare; JMv = Move; // Heapify bottom up for (long i = en-1; i >= st; i--) reheap (en, i);

// Heapify top down for (long i = en-1; i >= st; i--) invreheap (en, i);

// Do an insertion sort on the almost sorted array for (long j = st + 1; j <= en; j++)

131 { JMv(j, 0); long i = j - 1; while ((i >= st) && (JCmp(i, 0) > 0)) { JMv(i, i + 1); i -= 1; } JMv(0, i + 1); } return true; }

Bingo.h Header for Bingo Sort

// SortTester by Spencer Morgan // BingoSort is based on pseudo-code on pages 39, 40, & 173 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _bingo_H_ #define _bingo_H_ #include "SortTypes.h" class BingoSort { private: long bingo; long nextBingo; long nextAvail; long free; long min, max; CompareProc BCmp; MoveProc BMv; void __fastcall MM(long a, long b, long *max, long *min); void __fastcall MaxMin3(long en); void __fastcall Check(long i); void __fastcall CheckTemp(); public: int __fastcall BPSort(long st, long en, CompareProc Cmp, SwapProc Swap); int __fastcall SMSort(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

132 Bingo.cpp Source for Bingo Sort

// SortTester by Spencer Morgan // BingoSort is based on pseudo-code on pages 39, 40, & 173 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include #include "bingo.h" //------void __fastcall BingoSort::MM(long a, long b, long *max, long *min) { SortCompareResult res = BCmp(a,b); if (res > 0) { *max = a; *min = b; } else if (res < 0) { *min = a; *max = b; } else { *min = a; *max = a; } } //------void __fastcall BingoSort::MaxMin3(long en) { long a, b, i; if (en & 1) // odd number of elements { min = max = 1; for (i = 2; i < en; i +=2) { MM(i,i+1,&b,&a); if (BCmp(a,min) < 0) min = a; if (BCmp(b,max) > 0) max = b; } } else { MM(1,2,&max,&min); for (i = 3; i < en; i +=2) { MM(i,i+1,&b,&a); if (BCmp(a,min) < 0) min = a; if (BCmp(b,max) > 0) max = b; }

133 } } //------int __fastcall BingoSort::BPSort(long st, long en, CompareProc Compare, SwapProc Swap) { BCmp = Compare;

MaxMin3(en);

bingo = min; nextAvail = st; nextBingo = max; while ((bingo != max)) // && (BCmp(bingo, max) < 0)) { for (long i = nextAvail; i <= en; i++) { if (i == bingo) { if (i != nextAvail) { Swap(i, nextAvail); if (nextAvail == max) max = i; bingo = nextAvail; } nextAvail++; } else if (i != max) { if (BCmp(i, bingo) == 0) { if (i != nextAvail) { Swap(i, nextAvail); if (nextAvail == max) max = i; } nextAvail++; } else { if (BCmp(i, nextBingo) < 0) // if ((i != nextBingo) && (BCmp(i, nextBingo) < 0)) nextBingo = i; } } } bingo = nextBingo; nextBingo = max; }

return true; } //------void __fastcall BingoSort::Check(long i) {

134 if (i == bingo) { if (i != nextAvail) { if (nextAvail != free) { BMv(nextAvail, free); if (nextAvail == max) max = free; } BMv(i, nextAvail); free = i; bingo = nextAvail; } nextAvail++; } else if (i != max) { if (BCmp(i, bingo) == 0) { if (i != nextAvail) { if (nextAvail != free) { BMv(nextAvail, free); if (nextAvail == max) max = free; } BMv(i, nextAvail); free = i; } nextAvail++; } else { if (BCmp(i, nextBingo) < 0) // if ((i != nextBingo) && (BCmp(i, nextBingo) < 0)) nextBingo = i; } } } //------void __fastcall BingoSort::CheckTemp() { if (bingo == 0) { if (nextAvail != free) { BMv(nextAvail, free); if (nextAvail == max) max = free; } BMv(0, nextAvail); free = 0; bingo = nextAvail; nextAvail++; }

135 else if (max && (BCmp(0, nextBingo) < 0)) nextBingo = 0; /* else if (max) { if (BCmp(0, bingo) == 0) { if (nextAvail != free) { BMv(nextAvail, free); if (nextAvail == max) max = free; } BMv(0, nextAvail); free = 0; nextAvail++; } else { if ((nextBingo != 0) && (BCmp(0, nextBingo) < 0)) nextBingo = 0; } } */ } //------int __fastcall BingoSort::SMSort(long st, long en, CompareProc Compare, MoveProc Mv) { BCmp = Compare; BMv = Mv;

MaxMin3(en); bingo = min; nextAvail = st; nextBingo = max; free = 0; while ((bingo != max)) // && (BCmp(bingo, max) < 0)) { if (free) CheckTemp(); for (long i = nextAvail; i <= en; i++) { if (i != free) Check(i); } bingo = nextBingo; nextBingo = max; } if (free) Mv(0, free);

return true; } //------

136 BiBingo.h Header for Bidirectional Bingo Sort

// SortTester by Spencer Morgan // BingoSort is based on pseudo-code on pages 39, 40, & 173 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _bibingo_H_ #define _bibingo_H_ #include "SortTypes.h" class BiBingoSort { private: long bingoMin, bingoMax; long nextBingoMin, nextBingoMax; long nextAvailMin, nextAvailMax; long free; long min, max; CompareProc BCmp; MoveProc BMv; void __fastcall MM(long a, long b, long *max, long *min); void __fastcall MaxMin3(long en); int __fastcall Check(long i); void __fastcall CheckTemp(); void __fastcall CheckNext(); void __fastcall CheckNextMin(); void __fastcall CheckNextMax(); void __fastcall BBMv(long a, long b); public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

BiBingo.cpp Source for Bidirectional Bingo Sort

// SortTester by Spencer Morgan // BingoSort is based on pseudo-code on pages 39, 40, & 173 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include #include "bibingo.h" //------void __fastcall BiBingoSort::MM(long a, long b, long *max, long *min) { SortCompareResult res = BCmp(a,b); if (res > 0) { *max = a; *min = b; } else if (res < 0) { *min = a; *max = b;

137 } else { *min = a; *max = a; } } //------void __fastcall BiBingoSort::MaxMin3(long en) { long a, b, i; if (en & 1) // odd number of elements { min = max = 1; for (i = 2; i < en; i +=2) { MM(i,i+1,&b,&a); if (BCmp(a,min) < 0) min = a; if (BCmp(b,max) > 0) max = b; } } else { MM(1,2,&max,&min); for (i = 3; i < en; i +=2) { MM(i,i+1,&b,&a); if (BCmp(a,min) < 0) min = a; if (BCmp(b,max) > 0) max = b; } } } //------void __fastcall BiBingoSort::CheckNextMin() { while ((free != nextAvailMin) && ((nextAvailMin == bingoMin) || (BCmp(nextAvailMin, bingoMin) == 0))) nextAvailMin++; } //------void __fastcall BiBingoSort::CheckNextMax() { while ((free != nextAvailMax) && ((nextAvailMax == bingoMax) || (BCmp(nextAvailMax, bingoMax) == 0))) nextAvailMax--; } //------void __fastcall BiBingoSort::CheckNext() { SortCompareResult res; CheckNextMin(); CheckNextMax();

138 if (nextAvailMin >= nextAvailMax) return; long nin, nax; do { nin = nextAvailMin; nax = nextAvailMax; if (free != nextAvailMax) { if (nextAvailMax == bingoMin) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(nextAvailMax, nextAvailMin); free = nextAvailMax; bingoMin = nextAvailMin; nextAvailMin++; CheckNextMin(); } else { res = BCmp(nextAvailMax, bingoMin); if (res == 0) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(nextAvailMax, nextAvailMin); free = nextAvailMax; // bingoMin = nextAvailMin; nextAvailMin++; CheckNextMin(); } } if (nextAvailMin >= nextAvailMax) return; }

if (free != nextAvailMin) { if (nextAvailMin == bingoMax) { if (nextAvailMax != free) BBMv(nextAvailMax, free); BBMv(nextAvailMin, nextAvailMax); free = nextAvailMin; bingoMax = nextAvailMax; nextAvailMax--; CheckNextMax(); } else { res = BCmp(nextAvailMin, bingoMax); if (res == 0) { if (nextAvailMax != free) BBMv(nextAvailMax, free);

139 BBMv(nextAvailMin, nextAvailMax); free = nextAvailMin; // bingoMax = nextAvailMax; nextAvailMax--; CheckNextMax(); } } if (nextAvailMin >= nextAvailMax) return; } if (free) CheckTemp(); if (nextAvailMin >= nextAvailMax) return; } while ((nin != nextAvailMin) || (nax != nextAvailMax));

long in = (free == nextAvailMin ? 0 : nextAvailMin); long ax = (free == nextAvailMax ? 0 : nextAvailMax); res = BCmp(in, ax);

if (res < 0) { nextBingoMin = in; nextBingoMax = ax; } else if (res > 0) { nextBingoMin = ax; nextBingoMax = in; } else { nextBingoMin = in; nextBingoMax = in; } } //------int __fastcall BiBingoSort::Check(long i) { if (i == bingoMin) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(i, nextAvailMin); free = i; bingoMin = nextAvailMin; nextAvailMin++; return -1; } else if (i == bingoMax) { if (nextAvailMax != free) BBMv(nextAvailMax, free); BBMv(i, nextAvailMax); free = i; bingoMax = nextAvailMax; nextAvailMax--;

140 return 1; } else { SortCompareResult res = BCmp(i, bingoMin); if (res == 0) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(i, nextAvailMin); free = i; nextAvailMin++; return -1; } else // (res > 0) { SortCompareResult res2 = BCmp(i, bingoMax); if (res2 == 0) { if (nextAvailMax != free) BBMv(nextAvailMax, free); BBMv(i, nextAvailMax); free = i; nextAvailMax--; return 1; } else // (res2 < 0) { if (i != nextBingoMax) { res = BCmp(i, nextBingoMax); if (res > 0) nextBingoMax = i; } if (i != nextBingoMin) { res = BCmp(i, nextBingoMin); if (res < 0) nextBingoMin = i; } } } } return 0; }//------void __fastcall BiBingoSort::CheckTemp() { if (bingoMin == 0) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(0, nextAvailMin); // Application->MessageBox("0", "0", MB_OK); free = 0; bingoMin = nextAvailMin; nextAvailMin++; }

141 else if (bingoMax == 0) { if (nextAvailMax != free) BBMv(nextAvailMax, free); BBMv(0, nextAvailMax); free = 0; bingoMax = nextAvailMax; nextAvailMax--; } else { SortCompareResult res = BCmp(0, bingoMin); // if (bingoMin == 3) // Application->MessageBox("3", "3", MB_OK); if (res == 0) { if (nextAvailMin != free) BBMv(nextAvailMin, free); BBMv(0, nextAvailMin); free = 0; // bingoMin = nextAvailMin; nextAvailMin++; } else // (res > 0) { SortCompareResult res2 = BCmp(0, bingoMax); if (res2 == 0) { if (nextAvailMax != free) BBMv(nextAvailMax, free); BBMv(0, nextAvailMax); free = 0; // bingoMax = nextAvailMax; nextAvailMax--; } else // (res2 < 0) { if (nextBingoMax) { if (bingoMin == nextBingoMax) nextBingoMax = 0; else { res = BCmp(0, nextBingoMax); if (res > 0) nextBingoMax = 0; } } if (nextBingoMin) { if (bingoMax == nextBingoMin) nextBingoMin = 0; else { res = BCmp(0, nextBingoMin); if (res < 0) nextBingoMin = 0;

142 } } } } } } //------void __fastcall BiBingoSort::BBMv(long a, long b) { BMv(a, b); if (nextBingoMin == a) nextBingoMin = b; if (nextBingoMax == a) nextBingoMax = b; if (bingoMin == a) bingoMin = b; if (bingoMax == a) bingoMax = b; } //------int __fastcall BiBingoSort::Sort(long st, long en, CompareProc Compare, MoveProc Mv) { int chk; BCmp = Compare; BMv = Mv;

MaxMin3(en); bingoMin = nextBingoMax = min; nextAvailMin = st; nextAvailMax = en; bingoMax = nextBingoMin = max; free = 0; while ((nextAvailMin < nextAvailMax)) // && (BCmp(bingo, max) < 0)) { // if (free) // CheckTemp(); /* Compare(0,0); AnsiString mstr = "Min "+IntToStr(nextAvailMin)+" Max "+IntToStr(nextAvailMax); Application->MessageBox(mstr.c_str(), "N", MB_OK); */ CheckNext(); long i = nextAvailMin+1; long j = nextAvailMax-1; while (i < j) // for (long i = nextAvailMin; i <= nextAvailMax; i++) { if (i != free) { chk = Check(i); if (chk > 0) { CheckNextMax(); if (j > nextAvailMax) j = nextAvailMax; }

143 /* else if (chk < 0) { CheckNextMin(); if (i < nextAvailMin) i = nextAvailMin-1; } */ } if (j != free) // if ((j <= nextAvailMax) && (j != free)) { chk = Check(j); if (chk < 0) { CheckNextMin(); if (i < nextAvailMin) i = nextAvailMin-1; } /* else if (chk > 0) { CheckNextMax(); if (j > nextAvailMax) j = nextAvailMax+1; } */ } i++; j--; } if (i == j) Check(i); if (free) CheckTemp();

bingoMin = nextBingoMin; bingoMax = nextBingoMax; nextBingoMin = bingoMax; nextBingoMax = bingoMin; } if (free) Mv(0, free);

return true; } //------

144 Shell.h Header for Shell Sort

// SortTester by Spencer Morgan // BPShellSort is based on pseudo-code on pages 168 & 169 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _shell_H_ #define _shell_H_ #include "SortTypes.h" class BPShellSort { private: long *shellSeq; long incCnt; CompareProc ShCmp; MoveProc ShMv; void __fastcall InsertionSubsort(long st,long en, long k); void __fastcall InsertionSubsortSpencer(long st,long en, long k); long __fastcall CreateShellSequence(long n); long __fastcall CreateWeissSequence(long n); public: long seq; bool sopt; int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc Mv); };

#endif

Shell.cpp Source for Shell Sort

// SortTester by Spencer Morgan // BPShellSort is based on pseudo-code on pages 168 & 169 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul // Sequence #s are from http://www.research.att.com/~njas/sequences/

#include #include "shell.h"

// Papernov 2^k+1 long A000051[] = {32, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097, 8193, 16385, 32769, 65537, 131073, 262145, 524289, 1048577, 2097153, 4194305, 8388609, 16777217, 33554433, 67108865, 134217729, 268435457, 536870913, 1073741825}; // Hibbard 2^k-1 long A000225[] = {31, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215, 33554431, 67108863, 134217727, 268435455, 536870911, 1073741823, 2147483647}; // Knuth long A003462[] = {20, 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484, 7174453, 21523360, 64570081, 193710244, 581130733, 1743392200}; // Pratt

145 long A003586[] = {67, 1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, 27, 32, 36, 48, 54, 64, 72, 81, 96, 108, 128, 144, 162, 192, 216, 243, 256, 288, 324, 384, 432, 486, 512, 576, 648, 729, 768, 864, 972, 1024, 1152, 1296, 1458, 1536, 1728, 1944, 2048, 2187, 2304, 2592, 2916, 3072, 3456, 3888, 4096, 4374, 4608, 5184, 5832, 6144, 6561, 6912, 7776, 8192, 8748, 9216}; long A033622[] = {28, 1, 5, 19, 41, 109, 209, 505, 929, 2161, 3905, 8929, 16001, 36289, 64769, 146305, 260609, 587521, 1045505, 2354689, 4188161, 9427969, 16764929, 37730305, 67084289, 150958081, 268386305, 603906049, 1073643521}; // 4^(n+1)+3*2^n+1 long A036562[] = {16, 1, 8, 23, 77, 281, 1073, 4193, 16577, 65921, 262913, 1050113, 4197377, 16783361, 67121153, 268460033, 1073790977}; // 2^n-45, n >= 6 long A036564[] = {27, 1, 19, 83, 211, 467, 979, 2003, 4051, 8147, 16339, 32723, 65491, 131027, 262099, 524243, 1048531, 2097107, 4194259, 8388563, 16777171, 33554387, 67108819, 134217683, 268435411, 536870867, 1073741779, 2147483603}; // Sedgewick-Incerpi long A036569[] = {24, 1, 3, 7, 21, 48, 112, 336, 861, 1968, 4592, 13776, 33936, 86961, 198768, 463792, 1391376, 3402672, 8382192, 21479367, 49095696, 114556624, 343669872, 852913488, 2085837936}; // a(0)=1, a(i)= Prime[i^3] long A055875[] = {36, 1, 2, 19, 103, 311, 691, 1321, 2309, 3671, 5519, 7919, 10957, 14753, 19403, 24809, 31319, 38873, 47657, 57559, 69031, 81799, 96137, 112291, 130073, 149717, 171529, 195043, 220861, 248851, 279431, 312583, 347707, 386093, 427169, 470933, 517553}; // round[ 1 + e^(n-2) ] long A055876[] = {23, 1, 2, 4, 8, 21, 56, 149, 404, 1098, 2982, 8104, 22027, 59875, 162756, 442414, 1202605, 3269018, 8886112, 24154954, 65659970, 178482302, 485165196, 1318815735}; // Ciura long A102549[] = {9, 1, 4, 10, 23, 57, 132, 301, 701, 1750}; // Tokuda long A108870[] = {26, 1, 4, 9, 20, 46, 103, 233, 525, 1182, 2660, 5985, 13467, 30301, 68178, 153401, 345152, 776591, 1747331, 3931496, 8845866, 19903198, 44782196, 100759940, 226709866, 510097200, 1147718700};

//------long __fastcall BPShellSort::CreateShellSequence(long n) { incCnt++; if (n) {

long indx = CreateShellSequence(n/2); indx++; shellSeq[indx] = n; return indx; } else { shellSeq = new long[incCnt]; return 0; } } //------

146 long __fastcall BPShellSort::CreateWeissSequence(long n) { incCnt++; if (n) { long indx; if (n == 2) indx = CreateWeissSequence(1); else indx = CreateWeissSequence((n*5)/11); indx++; shellSeq[indx] = n; return indx; } else { shellSeq = new long[incCnt]; return 0; } } //------void __fastcall BPShellSort::InsertionSubsort(long st,long en, long k) { for (long i = st + k; i <= en; i++) { ShMv(i, 0); long position = i - k; while ((position >= st) && (ShCmp(0,position) < 0)) { ShMv(position, position + k); position -= k; } ShMv(0, position + k); } } //------void __fastcall BPShellSort::InsertionSubsortSpencer(long st,long en, long k) { for (long i = st + k; i <= en; i++) {

long position = i - k; if (ShCmp(i,position) < 0) { ShMv(i, 0); do { ShMv(position, position + k); position -= k; } while ((position >= st) && (ShCmp(0,position) < 0)); ShMv(0, position + k); } } } //------int __fastcall BPShellSort::Sort(long st, long en, CompareProc CP, MoveProc MP) {

147 long *Sequence; ShCmp = CP; ShMv = MP; int k; long size = 1+en-st; incCnt = 0; switch (seq) { case 0: shellSeq[0] = CreateShellSequence((en-st+1)/2); Sequence = shellSeq; break; case 1: shellSeq[0] = CreateWeissSequence(((en-st+1)*5)/11); Sequence = shellSeq; break; case 51: Sequence = (long*) &A000051; break; case 225: Sequence = (long*) &A000225; break; case 3462: Sequence = (long*) &A003462; break; case 3586: Sequence = (long*) &A003586; break; case 33622: Sequence = (long*) &A033622; break; case 36562: Sequence = (long*) &A036562; break; case 36564: Sequence = (long*) &A036564; break; case 36569: Sequence = (long*) &A036569; break; case 55875: Sequence = (long*) &A055875; break; case 55876: Sequence = (long*) &A055876; break; case 102549: Sequence = (long*) &A102549; break; case 108870: Sequence = (long*) &A108870; break; default: return false; } k = Sequence[0];

148 while (Sequence[k] >= size) k--; if (sopt) { while (k > 0) { InsertionSubsortSpencer(st,en, Sequence[k]); k--; } } else { while (k > 0) { InsertionSubsort(st,en, Sequence[k]); k--; } } if (incCnt) delete[] shellSeq; return true; }

BPHeap.h Header for Berman & Paul’s Heap Sort

// SortTester by Spencer Morgan // BPHeapSort is based on pseudo-code on pages 149, 151, & 153 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _bpheap_H_ #define _bpheap_H_ #include "SortTypes.h" class BPHeapSort { typedef void __fastcall (__closure *AMHProc) ( long n, long i) ; private: CompareProc BpHCmp; MoveProc BpHMv; AMHProc AMH; void __fastcall CreateMaxHeap(long n); void __fastcall AdjustMaxHeap(long n, long i); void __fastcall BPAdjustMaxHeap(long n, long i); void __fastcall SAdjustMaxHeap(long n, long i); public: bool sopt; int __fastcall Sort(long en, CompareProc Cmp, MoveProc Mv); }; #endif

149 BPHeap.cpp Source for Berman & Paul’s Heap Sort

// SortTester by Spencer Morgan // BPHeapSort is based on pseudo-code on pages 149, 151, & 153 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include "bpheap.h"

//------void __fastcall BPHeapSort::CreateMaxHeap(long n) { for(long i = n/2; i > 0; i--) { AMH(n, i); } } //------void __fastcall BPHeapSort::BPAdjustMaxHeap(long n, long i) { bool found = false; long j = 2*i;

BpHMv(i, 0);

while ((j <= n) && !found) { if ((j < n) && (BpHCmp(j, j+1) < 0)) j++; if (BpHCmp(0, j) >= 0) found = true; else { BpHMv(j, j/2); j = 2*j; } } BpHMv(0, j/2); } //------void __fastcall BPHeapSort::SAdjustMaxHeap(long n, long i) { bool found = false; long j = 2*i;

long cmp = i; // BpHMv(i, 0);

while ((j <= n) && !found) { if ((j < n) && (BpHCmp(j, j+1) < 0)) j++; if (BpHCmp(cmp, j) >= 0) found = true; else { if (cmp)

150 { BpHMv(i, 0); cmp = 0; } BpHMv(j, j/2); j = 2*j; } } if (cmp == 0) BpHMv(0, j/2); } //------int __fastcall BPHeapSort::Sort(long en, CompareProc Cmp, MoveProc Mv) { long st = 1; BpHCmp = Cmp; BpHMv = Mv;

if (sopt) AMH = SAdjustMaxHeap; else AMH = BPAdjustMaxHeap;

CreateMaxHeap(en);

long theEnd = en;

for(long i = st+1; i <= en; i++) { BpHMv(st, 0); BpHMv(theEnd, st); BpHMv(0, theEnd); theEnd--; AMH(en-i+1, 1); } return true; } // Sort; //------

151 Heap.h Header for Wikipedia Heap Sort

// SortTester by Spencer Morgan // HeapSort is based on code from WikiPedia // http://en.wikipedia.org/wiki/Heapsort

#ifndef _heap_H_ #define _heap_H_ #include "SortTypes.h" class HeapSort { private: long theStart, theEnd; CompareProc HCmp; SwapProc HSwp; void __fastcall siftdown(long st, long cnt); void __fastcall siftup(long st); public: int __fastcall Sort(long en, CompareProc Cmp, SwapProc Swp); }; #endif

Heap.cpp Source for Wikipedia Heap Sort

// SortTester by Spencer Morgan // HeapSort is based on code from WikiPedia // http://en.wikipedia.org/wiki/Heapsort

#include "heap.h"

//------void __fastcall HeapSort::siftdown(long st, long cnt) { long root = st; long child;

while (root * 2 < cnt) { child = root * 2; if ((child < cnt - 1) && (HCmp(child, child + 1) < 0)) child++;

if (HCmp(root, child) < 0) { HSwp(root, child); root = child; } else return; } }

//------void __fastcall HeapSort::siftup(long st) {

152 long child = st; long root, remainder;

while (child > theStart) { remainder = child % 2; root = (child - remainder) / 2; if (HCmp(root, child) < 0) { HSwp(root, child); child = root; } else return; } } //------int __fastcall HeapSort::Sort(long en, CompareProc Cmp, SwapProc Swp) { long st = 1; HCmp = Cmp; HSwp = Swp;

long start = st; long end = en;

theStart = st; theEnd = en;

while (start <= en - 1) { start++; siftup(start); }

while (end > st) { HSwp(end, st); siftdown(st, end); end--; } return true; } // Sort; //------

153 Merge.h Header for Merge Sort

// SortTester by Spencer Morgan // BPMergeSort is based on pseudo-code on pages 46 & 47 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _merge_H_ #define _merge_H_

#include "SortTypes.h" typedef long __fastcall (__closure *MergeProc) ( long low, long x); class BPMergeSort { private: long start; CompareProc MCmp; MoveProc MMv; MergeProc Mrg; long __fastcall MergeOptimal(long low, long x); //, long high); long __fastcall MergeStable(long low, long x); //, long high); long __fastcall MSort(long st, long en); void __fastcall MergeInPlace(long low, long x, long high); void __fastcall MSortInPlace(long st, long en); public: bool optimal; long *next; bool *equal; int __fastcall SortInPlace(long st, long en, CompareProc Cmp, MoveProc Mv); int __fastcall Sort(long st, long en, CompareProc Cmp); __fastcall BPMergeSort::BPMergeSort(); __fastcall BPMergeSort::~BPMergeSort(); };

#endif

Merge.cpp Source for Merge Sort

// SortTester by Spencer Morgan // BPMergeSort is based on pseudo-code on pages 46 & 47 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include #include "merge.h" //------void __fastcall BPMergeSort::MergeInPlace(long low, long x, long high) { long CurPos1 = low, CurPos2 = x + 1, k;

// long Counter = low; long Counter = low - high; // SM changed point to temp locations

while ((CurPos1 <= x) && (CurPos2 <= high))

154 { if (MCmp(CurPos1, CurPos2) != 1) { MMv(CurPos1, Counter); CurPos1++; } else { MMv(CurPos2, Counter); CurPos2++; } Counter++; } if (CurPos1 > x) { for(long k = CurPos2; k <= high; k++) { MMv(k, Counter); Counter++; } } else { for(k = CurPos1; k <= x; k++) { MMv(k, Counter); Counter++; } } for (k = low; k <= high; k++) { MMv(k-high, k); } } //------void __fastcall BPMergeSort::MSortInPlace(long st, long en) { if (st < en) { long mid = (st + en)/2; MSortInPlace(st,mid); MSortInPlace(mid+1,en); MergeInPlace(st,mid,en); } } //------int __fastcall BPMergeSort::SortInPlace(long st, long en, CompareProc CP, MoveProc MP) { MCmp = CP; MMv = MP; // MMv(st, st-en); // SM this will allocated all the temp storage in advance MSortInPlace(st,en); return true; } //------long __fastcall BPMergeSort::MergeOptimal(long low, long x)

155 { long CurPos1 = low, CurPos2 = x; int cmp; long ret = 0; long last = 0;

while (CurPos1 && CurPos2) { cmp = MCmp(CurPos1, CurPos2); switch (cmp) { case -1 : if (!ret) ret = CurPos1; else next[last] = CurPos1; do { last = CurPos1; CurPos1 = next[CurPos1]; } while (CurPos1 && equal[CurPos1]); break; case 0: if (!ret) ret = CurPos1; else next[last] = CurPos1; do { last = CurPos1; CurPos1 = next[CurPos1]; } while (CurPos1 && equal[CurPos1]);

equal[CurPos2] = true;

next[last] = CurPos2; do { last = CurPos2; CurPos2 = next[CurPos2]; } while (CurPos2 && equal[CurPos2]); break; case 1: if (!ret) ret = CurPos2; else next[last] = CurPos2; do { last = CurPos2; CurPos2 = next[CurPos2]; } while (CurPos2 && equal[CurPos2]); break; } } if (CurPos1) next[last] = CurPos1;

156 else if (CurPos2) next[last] = CurPos2;

return ret; } //------long __fastcall BPMergeSort::MergeStable(long low, long x) { long CurPos1 = low, CurPos2 = x;

long ret = 0; long last = 0; while (CurPos1 && CurPos2) { if (MCmp(CurPos1, CurPos2) != 1) { if (!ret) ret = CurPos1; else next[last] = CurPos1; last = CurPos1; CurPos1 = next[CurPos1]; } else { if (!ret) ret = CurPos2; else next[last] = CurPos2; last = CurPos2; CurPos2 = next[CurPos2]; } } if (CurPos1) next[last] = CurPos1; else if (CurPos2) next[last] = CurPos2; return ret; } //------long __fastcall BPMergeSort::MSort(long st, long en) { if (st < en) { long mid = (st + en)/2; long first1 = MSort(st,mid); long first2 = MSort(mid+1,en); return Mrg(first1,first2); // ,en); } else return st; } //------int __fastcall BPMergeSort::Sort(long st, long en, CompareProc CP) { start = st; MCmp = CP;

157 next = new long[en+1]; setmem(next, (en+1) * sizeof(long), 0); if (optimal) { Mrg = &MergeOptimal; equal = new bool[en+1]; setmem(equal, (en+1) * sizeof(bool), 0); } else Mrg = &MergeStable;

next[0] = MSort(st,en); return true; } //------__fastcall BPMergeSort::BPMergeSort() { next = 0; equal = 0; } //------__fastcall BPMergeSort::~BPMergeSort() { if (next) delete [] next; if (equal) delete [] equal; } //------

BPQuick.h Header for Berman & Paul’s Quick Sort

// SortTester by Spencer Morgan // BPQuickSort is based on pseudo-code on pages 50 & 51 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#ifndef _bpquick_H_ #define _bpquick_H_ #include "SortTypes.h" class BPQuickSort { private: CompareProc BPqCmp; SwapProc BPqSwp; void __fastcall QuickSort(long st, long en); long __fastcall Partition(long st, long en); public: bool __fastcall Sort(long st, long en, CompareProc Cmp, SwapProc Swp); };

#endif

158 BPQuick.cpp Source for Berman & Paul’s Quick Sort

// SortTester by Spencer Morgan // BPQuickSort is based on pseudo-code on pages 50 & 51 of // Algorithms: Sequential, Parallel, and Distributed by // Kenneth A. Berman and Jerome L. Paul

#include #include "bpquick.h" //------bool __fastcall BPQuickSort::Sort(long st, long en, CompareProc CP, SwapProc Swp) { BPqCmp = CP; BPqSwp = Swp;

QuickSort(st,en); return true; } //------void __fastcall BPQuickSort::QuickSort(long st, long en) { if (en <= st) return;

long position = Partition(st,en); QuickSort(st, position-1); QuickSort(position+1, en); } //------long __fastcall BPQuickSort::Partition(long st, long en) { long mr = st; long ml = en + 1;

// BPqMv(st, 0); Compares are done directly to st while (mr < ml) { do { mr++; } while ((mr < ml) && (BPqCmp(mr, st) < 0)); do { ml--; } while ((st < ml) && (BPqCmp(ml, st) > 0)); if (mr < ml) { BPqSwp(mr, ml); } } if (ml > st) BPqSwp(st, ml); return ml; }

159 QDQuick.h Header for Qinjian Deng’s Quick Sort

// SortTester by Spencer Morgan // QDQuickSort is based on code in the 1996 University of Cincinnati // Master of Science thesis by Qinjian Deng // Advising professor Dieter Schmidt

#ifndef _qdquick_H_ #define _qdquick_H_ #include "SortTypes.h" class QDQuickSort { private: void __fastcall reheap (int length, int i); void __fastcall invreheap (int length, int i); public: int __fastcall Sort(long st, long en, CompareProc Cmp, MoveProc MP); int __fastcall SMSort(long st, long en, CompareProc Cmp, MoveProc MP); };

#endif

QDQuick.cpp Source for Qinjian Deng’s Quick Sort

// SortTester by Spencer Morgan // QDQuickSort is based on code in the 1996 University of Cincinnati // Master of Science thesis by Qinjian Deng // Advising professor Dieter Schmidt

#include #include "qdquick.h"

//------int __fastcall QDQuickSort::Sort(long st, long en, CompareProc CP, MoveProc MP) { long n = en-st + 1; long done = 10; long l = st, r = en, mid, median, loop, left, right, l1, l2; long i = 2, j = 8, top = 0, sort; long *stack;

while (j < n) { i += 2; j += j; } stack = (long *) malloc(i * sizeof(long *));

sort = n > done;

while (sort) { i = (int) (r - l); mid = l + i / 2; median = CP(l, mid) < 0 ?

160 (CP(mid, r) < 0 ? mid : CP(l, r) < 0 ? r : l) : (CP(mid, r) > 0 ? mid : CP(l, r) > 0 ? r : l);

MP(median, 0); MP(l, median); MP(0, l);

loop = l; left = l; right = r + 1;

while (loop) { do left++; while ((left < en) && CP(l, left) > 0); // temp was assigned to l do right--; while ((right > st) && CP(l, right) < 0); // temp was assigned to l

if (left < right) { MP(left, 0); MP(right, left); MP(0, right); } else loop = 0; }

MP(l, 0); // need to restore l to temp because it was used in the partitioning MP(right, l); MP(0, right);

l1 = right - l; l2 = r - right;

if (l1 <= done && l2 <= done) { if (top == 0) sort = 0; else { top -= 2; l = stack[top]; r = stack[top+1]; } } else { if (l1 <= done || l2 <= done) if (l1 < l2) l = left; else

161 r = right - 1; else { if (l1 < l2) { stack[top] = left; stack[top+1] = r; r = right - 1; } else { stack[top] = l; stack[top+1] = right - 1; l = left; } top += 2; } } } free(stack);

for (i=en-1; i >= st; i--) { MP(i, 0); for (left = i + 1; (left <= en) && CP(left, 0) < 0; left++) MP(left, left - 1);

MP(0, left - 1); }

return true; } //------int __fastcall QDQuickSort::SMSort(long st, long en, CompareProc CP, MoveProc MP) { long n = en-st + 1; long done = 10; long l = st, r = en, mid, median, loop, left, right, l1, l2; long i = 2, j = 8, top = 0, sort; long *stack;

while (j < n) { i += 2; j += j; } stack = (long *) malloc(i * sizeof(long *));

sort = n > done;

while (sort) { i = (int) (r - l); mid = l + i / 2; median = CP(l, mid) < 0 ? (CP(mid, r) < 0 ? mid :

162 CP(l, r) < 0 ? r : l) : (CP(mid, r) > 0 ? mid : CP(l, r) > 0 ? r : l);

if (l != median) // if added by Spencer Morgan { MP(median, 0); MP(l, median); MP(0, l); }

loop = l; left = l; right = r + 1;

while (loop) { do left++; while ((left < en) && CP(l, left) > 0); // temp was assigned to l do right--; while ((right > st) && CP(l, right) < 0); // temp was assigned to l

if (left < right) { MP(left, 0); MP(right, left); MP(0, right); } else loop = 0; }

MP(l, 0); // need to restore l to temp because it was used in the partitioning MP(right, l); MP(0, right);

l1 = right - l; l2 = r - right;

if (l1 <= done && l2 <= done) { if (top == 0) sort = 0; else { top -= 2; l = stack[top]; r = stack[top+1]; } } else { if (l1 <= done || l2 <= done) if (l1 < l2)

163 l = left; else r = right - 1; else { if (l1 < l2) { stack[top] = left; stack[top+1] = r; r = right - 1; } else { stack[top] = l; stack[top+1] = right - 1; l = left; } top += 2; } } } free(stack);

for (i=en-1; i >= st; i--) { MP(i, 0); for (left = i + 1; (left <= en) && CP(left, 0) < 0; left++) MP(left, left - 1);

MP(0, left - 1); }

return true; }

SBQuick.h Header for Sedgewick & Bentley’s Quick Sort

// SortTester by Spencer Morgan // QDQuickSort is based on code in Quicksort is Optimal by // Robert Sedgewick and Jon Bentley #ifndef _sbquick_H_ #define _sbquick_H_ #include "SortTypes.h" class SBQuickSort { private: CompareProc SBqCmp; SwapProc SBqSwp; int __fastcall QuickSort(long st, long en); public: int __fastcall Sort(long st, long en, CompareProc Cmp, SwapProc Swap); }; #endif

164

SBQuick.cpp Source for Sedgewick & Bentley’s Quick Sort

// SortTester by Spencer Morgan // QDQuickSort is based on code in Quicksort is Optimal by // Robert Sedgewick and Jon Bentley

#include #include "sbquick.h"

//------int __fastcall SBQuickSort::Sort(long st, long en, CompareProc CP, SwapProc Swap) { SBqCmp = CP; SBqSwp = Swap;

return QuickSort(st,en); } //------int __fastcall SBQuickSort::QuickSort(long st, long en) { if (en <= st) return true;

long i = st - 1; long j = en; long p = i; long q = en;

for(;;) { while ((++i < en) && (SBqCmp(i, en) < 0)); while (SBqCmp(en, --j) < 0) if (j == st) break;

if (i >= j) break;

SBqSwp(i,j); if (SBqCmp(i, en) == 0) { p++; if (i != p) SBqSwp(p,i); } if (SBqCmp(en, j) == 0) { q--; if (j != q) SBqSwp(j,q); } } if (i != en) SBqSwp(i,en); j = i-1;

165 i++; long k; for ( k = st; k < p; k++, j--) if (k != j) SBqSwp(k,j); for ( k = en-1; k > q; k--, j++) if (k != i) SBqSwp(i,k); QuickSort(st,j); QuickSort(i,en);

return true; }

SQuick.h Header for Spencer’s Quick Sorts

// SortTester by Spencer Morgan // SQuickSort has versions of Quicksort that I developed. // However it does have the ability to utilized a variety of other sorts as // a secondary sort.

#ifndef _squick_H_ #define _squick_H_

#include "SortTypes.h" typedef int __fastcall (__closure *SortProc) ( long st, long en, CompareProc Cmp, MoveProc Mv) ; typedef long __fastcall (__closure *PartProc) ( long st, long en) ; class SQuickSort { private: long comp; CompareProc SQCmp; MoveProc SQMv; PartProc SQPrt; long __fastcall PartitionMinMove(long st,long en); long __fastcall PartitionMinComp(long st,long en); void __fastcall Quick1(long st,long en); void __fastcall Quick2(long st,long en); void __fastcall Quick3(long st,long en); void __fastcall Median3Adjust(long st,long en); public: SortProc SSort; bool after; long break_point; bool minMove; int __fastcall Sort1(long st, long en, CompareProc Cmp, MoveProc Mv); int __fastcall Sort2(long st, long en, CompareProc Cmp, MoveProc Mv); int __fastcall Sort3(long st, long en, CompareProc Cmp, MoveProc Mv); }; #endif

166 SQuick.cpp Source for Spencer’s Quick Sorts

// SortTester by Spencer Morgan // SQuickSort has versions of Quicksort that I developed. // However it does have the ability to utilized a variety of other sorts as // a secondary sort.

#include #include "squick.h" //------long __fastcall SQuickSort::PartitionMinMove(long st,long en) { long a[2]; long pt = 1;

a[0] = st; a[1] = en; do { if (pt==0) { if (SQCmp(0,a[0]) < 0) { SQMv(a[0],a[1]); pt = 1; a[1]--; } else a[0]++; } else { if (SQCmp(comp, a[1]) <= 0) a[1]--; else { if (comp) { SQMv(comp,0); comp = 0; } SQMv(a[1],a[0]); pt = 0; a[0]++; } } } while (a[0] < a[1]); if (!comp) SQMv(0,a[0]); return a[0]; } //------long __fastcall SQuickSort::PartitionMinComp(long st,long en) { long a[2]; long pt = 1;

167

a[0] = st; a[1] = en; do { if (pt==0) { if (SQCmp(0,a[0]) <= 0) { SQMv(a[0],a[1]); pt = 1; a[1]--; } else a[0]++; } else { if (SQCmp(comp, a[1]) <= 0) a[1]--; else { if (comp) { SQMv(comp,0); comp = 0; } SQMv(a[1],a[0]); pt = 0; a[0]++; } } } while (a[0] < a[1]); if (!comp) SQMv(0,a[0]); return a[0]; } //------void __fastcall SQuickSort::Quick1(long st,long en) { long pt;

if (en > st) { if (en-st <= break_point) { if (!after) SSort(st,en, SQCmp, SQMv); } else { comp = st; pt = SQPrt(st, en); Quick1(st,pt-1); Quick1(pt+1,en); } }

168 } //------void __fastcall SQuickSort::Quick2(long st,long en) { long pt;

if (en > st) { if (en-st <= break_point) { if (!after) SSort(st,en, SQCmp, SQMv); } else { long center = (st+en) / 2;

if (st != center) { SQMv(center, 0); SQMv(st, center); comp = 0; } else comp = st;

pt = SQPrt(st, en); Quick2(st,pt-1); Quick2(pt+1,en); } } } //------void __fastcall SQuickSort::Quick3(long st,long en) { long pt;

if (en > st) { if (en-st <= break_point) { if (!after) SSort(st,en, SQCmp, SQMv); } else { Median3Adjust(st, en); pt = SQPrt(st, en); Quick3(st,pt-1); Quick3(pt+1,en); } } } //------void __fastcall SQuickSort::Median3Adjust(long st,long en) { long center = (st+en) / 2;

169

if (center == st) { comp = st; return; } else { int cresult = SQCmp(st,center); if (cresult < 0) { if (SQCmp(st,en) < 0) { comp = 0; if (SQCmp(center,en) <= 0) { SQMv(center, 0); SQMv(st, center); } else { SQMv(en, 0); SQMv(center, en); SQMv(st, center); } } else { comp = st; } } else if (cresult > 0) { if (SQCmp(st,en) <= 0) { comp = st; } else { comp = 0; if (SQCmp(center,en) <= 0) { SQMv(en, 0); SQMv(st, en); } else { SQMv(center, 0); SQMv(en, center); SQMv(st, en); } } } else comp = st; } }

170 //------int __fastcall SQuickSort::Sort1(long st, long en, CompareProc CP, MoveProc MP) { SQCmp = CP; SQMv = MP; if (minMove) SQPrt = &PartitionMinMove; else SQPrt = &PartitionMinComp;

Quick1(st,en); if (after) SSort(st,en, SQCmp, SQMv); return true; } //------int __fastcall SQuickSort::Sort2(long st, long en, CompareProc CP, MoveProc MP) { SQCmp = CP; SQMv = MP; if (minMove) SQPrt = &PartitionMinMove; else SQPrt = &PartitionMinComp;

Quick2(st,en); if (after) SSort(st,en, SQCmp, SQMv); return true; } //------int __fastcall SQuickSort::Sort3(long st, long en, CompareProc CP, MoveProc MP) { SQCmp = CP; SQMv = MP; if (minMove) SQPrt = &PartitionMinMove; else SQPrt = &PartitionMinComp;

Quick3(st,en); if (after) SSort(st,en, SQCmp, SQMv); return true; } //------

171 frmSorts.h Header for Sort Tester Form

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited //------#ifndef frmSortsH #define frmSortsH //------#include #include #include #include #include #include #include "SortTypes.h" #include #include #include //------typedef void __fastcall (__closure *DrawProc) ( long item, long value) ; class TSortForm : public TForm { __published: // IDE-managed Components TPanel *BottomPanel; TPanel *ImagePanel; TComboBox *cbSortType; TGroupBox *gbDataSet; TRadioButton *rbRandom; TRadioButton *rbOrdered; TRadioButton *rbReversed; TRadioButton *rbEqual; TButton *btnSort; TImage *Image1; TLabel *Label1; TLabel *Label2; TLabel *Label3; TLabel *Label4; TLabel *laCompare; TLabel *laAssignToTemp; TLabel *laAssignDirect; TLabel *laAssignFromTemp; TButton *btnLoad; TEdit *edQuantity; TEdit *edRange; TLabel *Label5; TLabel *Label6; TCheckBox *chbUnique; TLabel *laCompareToTemp; TLabel *laCompareDirect; TLabel *Label7; TLabel *laAssignTotal; TLabel *laCompareTotal; TRadioButton *rbPreMerge; TSaveDialog *SaveDialog1; TOpenDialog *OpenDialog1;

172 TButton *btnFill; TButton *btnSave; TLabel *laBoth; TLabel *laTotalBoth; TGroupBox *gbDisplay; TRadioButton *rbDisplayOff; TRadioButton *rbDisplayStartEnd; TRadioButton *rbDisplayAll; TLabel *laCompareTemps; TLabel *Label8; TLabel *laAssignTemps; TLabel *Label9; TLabel *laAssignSelf; TLabel *laCompareSelf; TRadioButton *rbHalf; TLabel *laRotateTitle; TLabel *laRotate; TComboBox *cbAssign; TComboBox *cbCompare; TCheckBox *chbSequential; TComboBox *cbShell; TCheckBox *chbSOptimized; TComboBox *cbQuick; TComboBox *cbHeap; TRadioButton *rbDelayed; TTrackBar *tbDelay; TLabel *laSkipCnt; TLabel *laSkipTitle; TComboBox *cbBreak; TComboBox *cbSecondAssign; TComboBox *cbSecondCompare; TComboBox *cbSecondSort; TComboBox *cbSecondShell; TCheckBox *chbAfter; TCheckBox *chbSecondSequential; TRadioButton *rbDisplayNone; TComboBox *cbPartition; TRadioButton *rbSplayKiller; TRadioButton *rbStability; TRadioButton *rbWorstAssign; TLabel *laDelay; TLabel *laQuad; TComboBox *cbBingo; TCheckBox *chbDot; TRadioButton *rbWorstShell; void __fastcall btnSortClick(TObject *Sender); void __fastcall btnLoadClick(TObject *Sender); void __fastcall cbSortTypeChange(TObject *Sender); void __fastcall SortTypeChange(TObject *Sender); void __fastcall FormClose(TObject *Sender, TCloseAction &Action); void __fastcall btnFillClick(TObject *Sender); void __fastcall btnSaveClick(TObject *Sender); void __fastcall rbEqualClick(TObject *Sender); void __fastcall rbNotEqualClick(TObject *Sender); void __fastcall chbUniqueClick(TObject *Sender); void __fastcall edQuantityChange(TObject *Sender); void __fastcall FormCanResize(TObject *Sender, int &NewWidth,

173 int &NewHeight, bool &Resize); void __fastcall FormCreate(TObject *Sender); void __fastcall FormDestroy(TObject *Sender); void __fastcall rbDisplayClick(TObject *Sender); void __fastcall rbDisplayOffClick(TObject *Sender); void __fastcall rbSplayKillerClick(TObject *Sender); void __fastcall FormResize(TObject *Sender); void __fastcall tbDelayChange(TObject *Sender); void __fastcall chbDotClick(TObject *Sender); private: // User declarations typedef struct tElement { long num; long origOrder; } Element; int x, y; DrawProc DrawItem, EraseItem; LARGE_INTEGER startTime, endTime; AnsiString CompName; CompareProc CmProc; MoveProc MvProc; LARGE_INTEGER timerFrequency; // LONGLONG timeDisplayQuad; long skipCnt; FILE *logFile; HANDLE origDiskFile, orig, work; long extraTempCnt; long reallocCnt; tElement *extraTemps; tElement *origData; tElement *workData; long shellSeq; long numCheckSum; long orderCheckSum; long ItemCnt; long Range; long height, width, widthDiv2, hval, rval; unsigned long dispTime; UINT CompareDirectCnt, CompareToTempCnt, CompareTempsCnt, CompareSelfCnt; UINT DirectCnt, ToTempCnt, FromTempCnt, moveTempsCnt, moveToSelfCnt; UINT compErrorCnt, moveErrorCnt; AnsiString filename; AnsiString __fastcall GetLastErrorStr(); void __fastcall Working(void); void __fastcall DoneWorking(void); int __fastcall SaveFile(); int __fastcall AllocateSpace(); void __fastcall ReleaseSpace(); void __fastcall FillOrig(); void __fastcall BlankScreen(); void __fastcall StartScreen(bool copyOriginal); void __fastcall Reset(); void __fastcall Sort(); long __fastcall gcd(long a, long b); void __fastcall StartTimer(); void __fastcall StopTimer();

174 AnsiString __fastcall ElapsedTime(); void __fastcall ProcessMessage(TMsg &message, bool &handled); SortCompareResult __fastcall Compare( long a, long b); void __fastcall Move( long from, long to); void __fastcall Swap( long from, long to); SortCompareResult __fastcall CompareDisplayOn( long a, long b); void __fastcall MoveDisplayOn( long from, long to); SortCompareResult __fastcall CompareDisplayDelayed( long a, long b); void __fastcall MoveDisplayDelayed( long from, long to); SortCompareResult __fastcall CompareNone( long a, long b); void __fastcall MoveNone( long from, long to); void __fastcall DrawLine(long item, long value); void __fastcall EraseLine(long item, long value); void __fastcall DrawDot(long item, long value); void __fastcall EraseDot(long item, long value); public: // User declarations __fastcall TSortForm(TComponent* Owner); }; //------extern PACKAGE TSortForm *SortForm; //------#endif frmSorts.cpp Source for Sort Tester Form

// SortTester by Spencer Morgan 513-251-6790 [email protected] // Copyright 2007 Unauthorized duplication prohibited //------#include #include #pragma hdrstop #include "frmSorts.h" #include "bubble.h" #include "bingo.h" #include "bibingo.h" #include "insert.h" #include "shell.h" #include "heap.h" #include "bpheap.h" #include "spencer.h" #include "jsort.h" #include "merge.h" #include "bpquick.h" #include "qdquick.h" #include "sbquick.h" #include "squick.h" #include "ssort.h" #include "ras.h" //------#pragma package(smart_init) #pragma resource "*.dfm"

#define ColorCnt 7

#define DisplayMax 1000 #define BubbleMax 100

175 #define InsertMax 100

TColor ColorSelect[ColorCnt] = {clWhite,clRed,clLime,clBlue,clYellow,clFuchsia,clAqua};

TSortForm *SortForm; //------__fastcall TSortForm::TSortForm(TComponent* Owner) : TForm(Owner) { } //------int __fastcall MsgBx(AnsiString text, AnsiString cap, int flags) { return Application->MessageBox(text.c_str(), cap.c_str(), flags); } // MsgBx(AnsiString text, AnsiString cap, int flags) //------void __fastcall TSortForm::Working(void) { Screen->Cursor = crHourGlass; } // Working(void) //------void __fastcall TSortForm::DoneWorking(void) { Screen->Cursor = crDefault; } // DoneWorking(void) //------SortCompareResult __fastcall TSortForm::CompareDisplayOn( long a, long b) { long da; long db; long na; long nb; if (a < 0) { a = -a; if (a > extraTempCnt) { compErrorCnt++; return 2; // error }

da = 0; na = extraTemps[a-1].num;

if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } db = 0; if (a == b) { CompareSelfCnt++; laCompareSelf->Caption = IntToStr(CompareSelfCnt);

176 return 0; } nb = extraTemps[b-1].num; CompareTempsCnt++; laCompareTemps->Caption = IntToStr(CompareTempsCnt); } else { CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); db = b; nb = workData[b].num; } } else if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } db = 0; nb = extraTemps[b-1].num; CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); da = a; na = workData[a].num; } else { if (a == b) { CompareSelfCnt++; laCompareSelf->Caption = IntToStr(CompareSelfCnt); return 0; } da = a; na = workData[a].num; db = b; nb = workData[b].num; if (a && b) { CompareDirectCnt++; laCompareDirect->Caption = IntToStr(CompareDirectCnt); } else { CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); } } SortForm->DrawItem(da, na); SortForm->DrawItem(db, nb);

Update();

177 if (na > nb) return 1; else if (na < nb) return -1; else return 0; } //------void __fastcall TSortForm::MoveDisplayOn( long from, long to) // 0 is temporary { if (from < 0) { from = -from - 1; if (from >= extraTempCnt) { moveErrorCnt++; return; } if (to < 0) { EraseItem(0, extraTemps[from].num); to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1;

if (from == to) { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } else { extraTemps[to] = extraTemps[from]; DrawItem(0, extraTemps[to].num); moveTempsCnt++; laAssignTemps->Caption = IntToStr(moveTempsCnt); } } else { EraseItem(0, extraTemps[from].num); workData[to] = extraTemps[from]; DrawItem(to, workData[to].num); if (to)

178 { FromTempCnt++; laAssignFromTemp->Caption = IntToStr(FromTempCnt); } else { moveTempsCnt++; laAssignTemps->Caption = IntToStr(moveTempsCnt); } } } else if (to < 0) { EraseItem(from, workData[from].num); to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1; extraTemps[to] = workData[from]; DrawItem(0, extraTemps[to].num); if (from) { ToTempCnt++; laAssignToTemp->Caption = IntToStr(ToTempCnt); } else { moveTempsCnt++; laAssignTemps->Caption = IntToStr(moveTempsCnt); } } else // if (from && to) { EraseItem(from, workData[from].num); workData[to] = workData[from]; DrawItem(to, workData[to].num); if (from && to) { if (from == to) { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } else { DirectCnt++;

179 laAssignDirect->Caption = IntToStr(DirectCnt); } } else if (from) { ToTempCnt++; laAssignToTemp->Caption = IntToStr(ToTempCnt); } else if (to) { FromTempCnt++; laAssignFromTemp->Caption = IntToStr(FromTempCnt); } else { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } }

Update(); } //------SortCompareResult __fastcall TSortForm::CompareDisplayDelayed( long a, long b) { long da; long db; long na; long nb; if (a < 0) { a = -a; if (a > extraTempCnt) { compErrorCnt++; return 2; // error }

da = 0; na = extraTemps[a-1].num;

if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } db = 0; if (a == b) { CompareSelfCnt++; laCompareSelf->Caption = IntToStr(CompareSelfCnt); return 0; } nb = extraTemps[b-1].num;

180 CompareTempsCnt++; laCompareTemps->Caption = IntToStr(CompareTempsCnt); } else { CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); db = b; nb = workData[b].num; } } else if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } db = 0; nb = extraTemps[b-1].num; CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); da = a; na = workData[a].num; } else { if (a == b) { CompareSelfCnt++; laCompareSelf->Caption = IntToStr(CompareSelfCnt);

if (!a) { LARGE_INTEGER t; QueryPerformanceCounter(&t); dispTime = (ULONG)(t.QuadPart * tbDelay->Position / timerFrequency.QuadPart); Update(); } return 0; } da = a; na = workData[a].num; db = b; nb = workData[b].num; if (a && b) { CompareDirectCnt++; laCompareDirect->Caption = IntToStr(CompareDirectCnt); } else { CompareToTempCnt++; laCompareToTemp->Caption = IntToStr(CompareToTempCnt); }

181 } SortForm->DrawItem(da, na); SortForm->DrawItem(db, nb);

LARGE_INTEGER t; QueryPerformanceCounter(&t); ULONG it = (ULONG)(t.QuadPart * tbDelay->Position / timerFrequency.QuadPart); if (it != dispTime) { dispTime = it; Update(); } else { skipCnt++; }

if (na > nb) return 1; else if (na < nb) return -1; else return 0; } //------void __fastcall TSortForm::MoveDisplayDelayed( long from, long to) // 0 is temporary { if (from < 0) { from = -from - 1; if (from >= extraTempCnt) { moveErrorCnt++; return; } if (to < 0) { EraseItem(0, extraTemps[from].num); to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1;

if (from == to)

182 { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } else { extraTemps[to] = extraTemps[from]; DrawItem(0, extraTemps[to].num); moveTempsCnt++; laAssignTemps->Caption = IntToStr(moveTempsCnt); } } else { EraseItem(0, extraTemps[from].num); workData[to] = extraTemps[from]; DrawItem(to, workData[to].num); if (to) { FromTempCnt++; laAssignFromTemp->Caption = IntToStr(FromTempCnt); } else { moveTempsCnt++; laAssignTemps->Caption = IntToStr(moveTempsCnt); } } } else if (to < 0) { EraseItem(from, workData[from].num); to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1; extraTemps[to] = workData[from]; DrawItem(0, extraTemps[to].num); if (from) { ToTempCnt++; laAssignToTemp->Caption = IntToStr(ToTempCnt); } else { moveTempsCnt++;

183 laAssignTemps->Caption = IntToStr(moveTempsCnt); } } else // if (from && to) { EraseItem(from, workData[from].num); workData[to] = workData[from]; DrawItem(to, workData[to].num); if (from && to) { if (from == to) { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } else { DirectCnt++; laAssignDirect->Caption = IntToStr(DirectCnt); } } else if (from) { ToTempCnt++; laAssignToTemp->Caption = IntToStr(ToTempCnt); } else if (to) { FromTempCnt++; laAssignFromTemp->Caption = IntToStr(FromTempCnt); } else { moveToSelfCnt++; laAssignSelf->Caption = IntToStr(moveToSelfCnt); } }

LARGE_INTEGER t; QueryPerformanceCounter(&t); ULONG it = (ULONG)(t.QuadPart * tbDelay->Position / timerFrequency.QuadPart); if (it != dispTime) { dispTime = it; Update(); } else { skipCnt++; } } //------SortCompareResult __fastcall TSortForm::Compare( long a, long b) { long na; long nb; if (a < 0)

184 { a = -a; if (a > extraTempCnt) { compErrorCnt++; return 2; // error }

na = extraTemps[a-1].num;

if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } if (a == b) { CompareSelfCnt++; return 0; } nb = extraTemps[b-1].num; CompareTempsCnt++; } else { CompareToTempCnt++; nb = workData[b].num; } } else if (b < 0) { b = -b; if (b > extraTempCnt) { compErrorCnt++; return 2; // error } nb = extraTemps[b-1].num; CompareToTempCnt++; na = workData[a].num; } else { if (a == b) { CompareSelfCnt++; return 0; } na = workData[a].num; nb = workData[b].num; if (a && b) { CompareDirectCnt++; }

185 else { CompareToTempCnt++; } }

if (na > nb) return 1; else if (na < nb) return -1; else return 0; } //------void __fastcall TSortForm::Move( long from, long to) // 0 is temporary { if (from < 0) { from = -from - 1; if (from >= extraTempCnt) { moveErrorCnt++; return; } if (to < 0) { to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1;

if (from == to) { moveToSelfCnt++; } else { extraTemps[to] = extraTemps[from]; moveTempsCnt++; } } else { workData[to] = extraTemps[from]; if (to)

186 { FromTempCnt++; } else { moveTempsCnt++; } } } else if (to < 0) { to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1; extraTemps[to] = workData[from]; if (from) { ToTempCnt++; } else { moveTempsCnt++; } } else // if (from && to) { workData[to] = workData[from]; if (from && to) { if (from == to) { moveToSelfCnt++; } else { DirectCnt++; } } else if (from) { ToTempCnt++; } else if (to) { FromTempCnt++;

187 } else { moveToSelfCnt++; } } } //------SortCompareResult __fastcall TSortForm::CompareNone( long a, long b) { long na; long nb; if (a < 0) { a = -a; if (a > extraTempCnt) { return 2; // error }

na = extraTemps[a-1].num;

if (b < 0) { b = -b; if (b > extraTempCnt) { return 2; // error } if (a == b) { return 0; } nb = extraTemps[b-1].num; } else { nb = workData[b].num; } } else if (b < 0) { b = -b; if (b > extraTempCnt) { return 2; // error } nb = extraTemps[b-1].num; na = workData[a].num; } else { if (a == b) { return 0; } na = workData[a].num;

188 nb = workData[b].num; }

if (na > nb) return 1; else if (na < nb) return -1; else return 0; } //------void __fastcall TSortForm::MoveNone( long from, long to) // 0 is temporary { if (from < 0) { from = -from - 1; if (from >= extraTempCnt) { return; } if (to < 0) { to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps) { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1;

if (from != to) { extraTemps[to] = extraTemps[from]; } } else { workData[to] = extraTemps[from]; } } else if (to < 0) { to = -to; if ((to > extraTempCnt) && (reallocCnt >= 0)) { reallocCnt++; extraTemps = (tElement*) realloc(extraTemps, to * sizeof(tElement)); if (!extraTemps)

189 { MsgBx("Realloc from " + IntToStr(extraTempCnt) + " to " + IntToStr(to) + " Failed", "Realloc Failed", MB_OK); reallocCnt = -reallocCnt; } extraTempCnt = to; } to -= 1; extraTemps[to] = workData[from]; } else // if (from && to) { workData[to] = workData[from]; } } //------void __fastcall TSortForm::Swap( long a, long b) // 0 is temporary { MvProc(a, 0); MvProc(b, a); MvProc(0, b); } //------#pragma argsused void __fastcall TSortForm::FormCreate(TObject *Sender) { struct time t; struct date d;

getdate(&d); gettime(&t);

char buffer[MAX_COMPUTERNAME_LENGTH+1]; DWORD size; size=sizeof(buffer); GetComputerName(buffer,&size); CompName = buffer;

if (QueryPerformanceFrequency(&timerFrequency)) { // timerFrequency.QuadPart /= 1000; // timeDisplayQuad = timerFrequency.QuadPart / 1000; laQuad->Caption = IntToStr(timerFrequency.QuadPart); } else timerFrequency.QuadPart = 0;

logFile = fopen("Sorts.log", "a");

if (logFile) fprintf(logFile, "Sorts started at %d/%d/%d %d:%02d:%02d\n\n", d.da_mon, d.da_day, d.da_year, t.ti_hour,t.ti_min, t.ti_sec); else if (MsgBx("Log file could not be opened. Do you want to continue?", "File Error", MB_YESNO) == IDNO) Application->Terminate();

190 AnsiString splash = "Sort Tester Program\n\n"; splash += "Written by: Spencer Morgan (513) 251-6790 [email protected]\n\n"; splash += "Advisor: Dr. John Franco (513)-556-1817 [email protected]\n\n";

splash += "RAS is the new Reduced Assignment Sort that I invented which is the topic of my Master's thesis.\n\n"; splash += "SMInsert is a sort that I invented to try to have less comparisons than Insertionsort.\n\n"; splash += "The Spencer versions of Quick are: 1 is base version, 2 partitions around middle element, and\n"; splash += "3 that does median of three. MinMov leaves elements equal to the partition element where they are\n"; splash += "and MinComp moves equal elements to the same side of the partition element.\n\n";

splash += "Bingo, Insertion, Merge, Shell, and the BermanPaul versions of Quick and Heap Sorts are based on pseudo\n"; splash += "code in Algorithms: Sequential, Parallel, and Distributed by Kenneth A. Berman and Jerome L. Paul.\n"; splash += "The Shell sequence is from Donald Shell, the Weiss sequence is from Mark Allen Weiss, \n"; splash += "all the other sequences used in Shell can be found at http://www.research.att.com/~njas/sequences/\n\n";

splash += "Qinjian Deng version of Quicksort was adapted from the 1996 University of Cincinnati\n"; splash += "Master of Science thesis by Qinjian Deng titled Bottom-up Insertion- Mergesort.\n"; splash += "Committee: Dr. Dieter S. Schmidt, Dr. Kenneth A. Berman, Dr. Yizong Cheng\n\n";

splash += "SedgewickBentley version of Quicksort was adapted from the Quicksort with 3-way partitioning from\n"; splash += "slides titled Quicksort is Optimal by Robert Sedgewick and Jon Bentley.\n\n";

splash += "JSort was adapted from JSortAlgorithm.java by Patrick Morin\n"; splash += "which is attributed to Jason Morrison \n\n";

splash += "The Wikipedia version Heap sort was adapted from http://en.wikipedia.org/wiki/Heapsort.\n\n";

splash += "SOptimized versions of any algorithm are modifications I made to try to reduce assignments, and/or\n"; splash += "avoid self comparisons or moves to the same location.\n";

MsgBx(splash, "Sort Tester", MB_OK);

DrawItem = DrawLine; EraseItem = EraseLine;

FormResize(Sender); } //------#pragma argsused

191 void __fastcall TSortForm::FormDestroy(TObject *Sender) { struct time t; struct date d;

getdate(&d); gettime(&t);

if (logFile) { fprintf(logFile, "Sorts ended at %d/%d/%d %d:%02d:%02d\n", d.da_mon, d.da_day, d.da_year, t.ti_hour,t.ti_min, t.ti_sec); fclose(logFile); } } //------AnsiString __fastcall TSortForm::GetLastErrorStr() // Get error information. used if something fails { AnsiString message;

LPVOID lpMsgBuf;

FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); return (char *) lpMsgBuf; } // GetLastErrorStr //------int __fastcall TSortForm::SaveFile() // AnsiString filename) { bool ret = false; if (filename != "") { if (FileExists(filename)) { char c = '0'; do { if (c == '9') c = 'a'; else if (c == 'z') { MsgBx(filename + " exists", "File Exists", MB_OK); filename = ""; return false; } else c++; } while (FileExists(filename+c)); filename+=c;

192 } HANDLE newFile;

newFile = ::CreateFile(filename.c_str(), GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (newFile == NULL) return false;

LPDWORD bytesWritten = new DWORD; if (WriteFile(newFile, origData, (ItemCnt + 1) * sizeof(tElement), bytesWritten, NULL)) ret = (*bytesWritten == (DWORD) ((ItemCnt + 1) * sizeof(tElement))); else MsgBx(GetLastErrorStr(), "Save Failed", MB_OK); delete bytesWritten; CloseHandle(newFile); if (logFile) fprintf(logFile, "Data saved to %s (%d Items)\n\n", filename.c_str(), ItemCnt); } return ret; } //------int __fastcall TSortForm::AllocateSpace() { if (filename == "") { origDiskFile = ::CreateFile("Fill.srt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, NULL, NULL); if (logFile) fprintf(logFile, "Data filled to Fill.srt\n\n"); } else { origDiskFile = ::CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);

UINT FileSize = GetFileSize(origDiskFile, NULL); ItemCnt = FileSize / sizeof(tElement) - 1; edQuantity->Text = IntToStr(ItemCnt); if (logFile)

193 fprintf(logFile, "Data loaded from %s (%d Items)\n\n", filename.c_str(), ItemCnt); }

if (origDiskFile == NULL) { filename = ""; return false; } orig = ::CreateFileMapping(origDiskFile, NULL, PAGE_READWRITE, 0, // set the size of the file - test assumes less than 4GB (DWORD)(ItemCnt+1)*sizeof(tElement), "origSpace"); if (!orig) { ReleaseSpace(); return false; } origData = (tElement *) MapViewOfFile(orig, FILE_MAP_ALL_ACCESS,0,0,0); if (origData == NULL) { ReleaseSpace(); return false; }

work = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, // set the size of the file - test assumes less than 4GB (DWORD)(ItemCnt+1)*sizeof(tElement), "workSpace"); if (!work) { ReleaseSpace(); return false; } workData = (tElement *) MapViewOfFile(work, FILE_MAP_ALL_ACCESS,0,0,0); if (workData == NULL) { ReleaseSpace(); return false; } if (filename != "") { numCheckSum = 0; orderCheckSum = 0; Range = 0; for(long i=1; i <= ItemCnt; i++) { if (origData[i].origOrder != i) { MsgBx("Invalid Data File", "Invalid File", MB_OK); return false;

194 } numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; if (origData[i].num > Range) Range = origData[i].num; } edRange->Text = IntToStr(Range); } return true; } //------void __fastcall TSortForm::ReleaseSpace() { if (origData != NULL) { UnmapViewOfFile(origData); origData = NULL; } if (orig != NULL) { CloseHandle(orig); orig = NULL; } if (origDiskFile != NULL) { if (origDiskFile != INVALID_HANDLE_VALUE) CloseHandle(origDiskFile);

origDiskFile = NULL; } if (workData != NULL) { UnmapViewOfFile(workData); workData = NULL; } if (work != NULL) { CloseHandle(work); work = NULL; } filename = ""; } //------void __fastcall TSortForm::FillOrig() { numCheckSum = 0; orderCheckSum = 0; if (rbRandom->Checked) { randomize();

if (chbUnique->Checked) { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = i; }

195 for(long i = 1; i <= ItemCnt; i++) { int other = _lrand() % ItemCnt + 1; int t = origData[i].num; origData[i].num = origData[other].num; origData[other].num = t; } for(long i = 1; i <= ItemCnt; i++) { origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Random data %d unique items\n\n", ItemCnt); } else { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = _lrand() % Range + 1; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Random data %d items Range to %d\n\n", ItemCnt, Range); } } else if (rbEqual->Checked) { long val = Range / 2; for(long i = 1; i <= ItemCnt; i++) { origData[i].num = val; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Equal data %d items\n\n", ItemCnt); } else if (rbStability->Checked) { origData[1].num = Range-1; origData[1].origOrder = 1; numCheckSum += origData[1].num; orderCheckSum += origData[1].origOrder; long val = Range / 2; for(long i = 2; i <= ItemCnt; i++) { origData[i].num = val; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; }

196 if (logFile) fprintf(logFile, "New Stability data %d items\n\n", ItemCnt); } else if (rbHalf->Checked) { randomize(); long val = Range / 2; for(long i = 1; i <= ItemCnt; i++) { if (i & 1) origData[i].num = _lrand() % Range + 1; else origData[i].num = val; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Half Equal data %d items\n\n", ItemCnt); } else if (rbOrdered->Checked) { if (chbUnique->Checked) { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = i; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Ordered data %d unique items\n\n", ItemCnt); } else { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = (i * Range) / ItemCnt; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Ordered data %d items Range to %d\n\n", ItemCnt, Range); } } else if (rbWorstAssign->Checked) { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = i+1; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; i++;

197 if (i > ItemCnt) { origData[i-1].num = origData[i-2].num; origData[i-2].num = i; break; } origData[i].num = i-1; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New WorstAssign data %d unique items\n\n", ItemCnt); } else if (rbWorstShell->Checked) { long j = 1; long k = ItemCnt / 2; for(long i = 1; i <= ItemCnt; i++) { origData[i].num = j+k; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; i++; if (i > ItemCnt) { // origData[i-1].num = origData[i-2].num; // origData[i-2].num = i; break; } origData[i].num = j; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; j++; } if (logFile) fprintf(logFile, "New WorstAssign data %d unique items\n\n", ItemCnt); } else if (rbReversed->Checked) { if (chbUnique->Checked) { for(long i = 1; i <= ItemCnt; i++) { origData[i].num = (ItemCnt - i) + 1; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Ordered data %d unique items\n\n", ItemCnt); } else { for(long i = 1; i <= ItemCnt; i++)

198 { origData[i].num = ((ItemCnt - i) * Range) / ItemCnt; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New Ordered data %d items Range to %d\n\n", ItemCnt, Range); } } else if (rbPreMerge->Checked) { long half = ItemCnt/2; if (chbUnique->Checked) { for(long i = 1; i <= half; i++) { origData[i].num = i * 2; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } for(long i = half + 1; i <= ItemCnt; i++) { origData[i].num = ((i - half) * 2) + 1; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New PreMerge data %d unique items\n\n", ItemCnt); } else { for(long i = 1; i <= half; i++) { origData[i].num = (i * Range) / half; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } for(long i = half + 1; i <= ItemCnt; i++) { origData[i].num = ((i - half) * Range) / half; origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } if (logFile) fprintf(logFile, "New PreMerge data %d items Range to %d\n\n", ItemCnt, Range); } } else if (rbSplayKiller->Checked) { long half = ItemCnt/2;

199 long diff = 0; for(long i = 1; i <= ItemCnt; i++) { if (i & 1) { origData[i].num = half + diff; diff++; } else { origData[i].num = half - diff; } origData[i].origOrder = i; numCheckSum += origData[i].num; orderCheckSum += origData[i].origOrder; } } } //------void __fastcall TSortForm::DrawLine(long item, long value) { int x, y, colorIndex; long iw, remainder;

TCanvas* canv = Image1->Canvas; iw = (item * width) - widthDiv2;

x = iw / ItemCnt;

remainder = (iw - (x * ItemCnt)) / width;

colorIndex = remainder % ColorCnt;

y = height - (value * hval) / rval;

canv->Pen->Color = ColorSelect[colorIndex];

canv->MoveTo(x,y); canv->LineTo(x,height); } //------void __fastcall TSortForm::EraseLine(long item, long value) { int x, y;

TCanvas* canv = Image1->Canvas;

x = ((item * width) - widthDiv2) / ItemCnt; y = height - (value * hval) / rval;

canv->Pen->Color = clBlack;

canv->MoveTo(x,y); canv->LineTo(x,height); } //------void __fastcall TSortForm::DrawDot(long item, long value)

200 { int x, y, colorIndex; long iw, remainder;

TCanvas* canv = Image1->Canvas; iw = (item * width) - widthDiv2;

x = iw / ItemCnt;

remainder = (iw - (x * ItemCnt)) / width;

colorIndex = remainder % ColorCnt;

y = height - (value * hval) / rval;

canv->Pen->Color = ColorSelect[colorIndex];

canv->MoveTo(x,y); canv->LineTo(x,y-1); // height); } //------void __fastcall TSortForm::EraseDot(long item, long value) { int x, y;

TCanvas* canv = Image1->Canvas;

x = ((item * width) - widthDiv2) / ItemCnt; y = height - (value * hval) / rval;

canv->Pen->Color = clBlack;

canv->MoveTo(x,y); canv->LineTo(x,y-1); // height); }//------void __fastcall TSortForm::BlankScreen() { Image1->Canvas->Brush->Color = clBlack; Image1->Canvas->FillRect(Image1->ClientRect); } //------void __fastcall TSortForm::StartScreen(bool copyOriginal) { if (rbDisplayOff->Checked || rbDisplayNone->Checked) { if (copyOriginal) { for(long i = 1; i <= ItemCnt; i++) workData[i] = origData[i]; } } else if (copyOriginal) { for(long i = 1; i <= ItemCnt; i++) { workData[i] = origData[i]; DrawItem(i, workData[i].num);

201 } } else if (btnSort->Enabled) for(long i = 1; i <= ItemCnt; i++) DrawItem(i, workData[i].num); } //------void __fastcall TSortForm::Reset() { CompareToTempCnt = CompareDirectCnt = ToTempCnt = DirectCnt = FromTempCnt = moveTempsCnt = moveToSelfCnt = CompareTempsCnt = CompareSelfCnt = compErrorCnt = moveErrorCnt = 0; laTotalBoth->Caption = "0"; laCompareTotal->Caption = "0"; laCompareToTemp->Caption = "0"; laCompareSelf->Caption = "0"; laCompareTemps->Caption = "0"; laCompareDirect->Caption = "0"; laAssignTotal->Caption = "0"; laAssignToTemp->Caption = "0"; laAssignSelf->Caption = "0"; laAssignDirect->Caption = "0"; laAssignFromTemp->Caption = "0"; laAssignTemps->Caption = "0";

BlankScreen(); StartScreen(true); btnSort->Caption = "Sort"; } //------void __fastcall TSortForm::StartTimer() { QueryPerformanceCounter(&startTime); } //------void __fastcall TSortForm::StopTimer() { QueryPerformanceCounter(&endTime); } //------AnsiString __fastcall TSortForm::ElapsedTime() { UINT diff; AnsiString str, strtemp;

diff = (UINT)((endTime.QuadPart-startTime.QuadPart) * 1000000 / timerFrequency.QuadPart);

str.printf("%d:", diff / 3600000000); diff %= 3600000000; strtemp.printf("%02d:", diff / 60000000); diff %= 60000000; str += strtemp; strtemp.printf("%02d.%06d", diff / 1000000, diff % 1000000);

return str + strtemp; }

202 //------#pragma argsused void __fastcall TSortForm::btnSortClick(TObject *Sender) { Working(); if (btnSort->Caption == "Sort") { AnsiString dispStr; if (rbDisplayAll->Checked) { CmProc = CompareDisplayOn; MvProc = MoveDisplayOn; dispStr = "On"; if (chbDot->Checked) dispStr += "Dot"; else dispStr += "Line"; } else if (rbDelayed->Checked) { CmProc = CompareDisplayDelayed; MvProc = MoveDisplayDelayed; dispStr = "Delayed"+laDelay->Caption; if (chbDot->Checked) dispStr += "Dot"; else dispStr += "Line"; } else if (rbDisplayNone->Checked) { CmProc = CompareNone; MvProc = MoveNone; dispStr = "None"; } else { CmProc = Compare; MvProc = Move; dispStr = "Off"; }

AnsiString SortName = cbSortType->Items->Strings[cbSortType->ItemIndex]; bool ret = false; AnsiString abortStr;

extraTempCnt = 0;

if (rbDisplayAll->Checked && (ItemCnt > DisplayMax) && (MsgBx("Displaying the sort will reduce sort speed. Sort is > "+IntToStr(DisplayMax)+". Are you sure?", "Long Sort", MB_YESNO) == IDNO)) { DoneWorking(); return; }

laRotate->Caption = "0"; laSkipCnt->Caption = "0";

203 skipCnt = 0;

BlankScreen();

if (SortName == "Bubble") { BubbleSort *bs; bs = new BubbleSort; if (ItemCnt <= BubbleMax) { StartTimer(); ret = bs->Sort(1, ItemCnt, CmProc, &Swap); StopTimer(); } else if (MsgBx("BubbleSort is not good for large sorts (>"+IntToStr(BubbleMax)+"). Are you sure?", "Long Sort", MB_YESNO) == IDYES) { StartTimer(); ret = bs->Sort(1, ItemCnt, CmProc, &Swap); StopTimer(); } else abortStr = "Aborted";

delete bs; } else if (SortName == "Bingo") { if ((ItemCnt <= BubbleMax) || (MsgBx("BingoSort is not good for large sorts (>"+IntToStr(BubbleMax)+"). Are you sure?", "Long Sort", MB_YESNO) == IDYES)) { if (cbBingo->Text == "BermanPaul") { BingoSort *bs; bs = new BingoSort; StartTimer(); ret = bs->BPSort(1, ItemCnt, CmProc, &Swap); StopTimer(); delete bs; } else if (cbBingo->Text == "SOptimized") { SortName += " SOptimized"; BingoSort *bs; bs = new BingoSort; StartTimer(); ret = bs->SMSort(1, ItemCnt, CmProc, MvProc); StopTimer(); delete bs; } else // if (cbBingo->Text == "Bidirectional") { SortName += " Bidirectional"; BiBingoSort *bbs; bbs = new BiBingoSort; StartTimer();

204 ret = bbs->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); delete bbs; } } else abortStr = "Aborted"; } else if (SortName == "Quick") { SortName += " " + cbQuick->Text; if (cbQuick->Text == "BermanPaul") { BPQuickSort *bpqs; bpqs = new BPQuickSort; StartTimer(); ret = bpqs->Sort(1, ItemCnt, CmProc, &Swap); StopTimer(); delete bpqs; } else if (cbQuick->Text == "Qinjian Deng") { QDQuickSort *qdqs; qdqs = new QDQuickSort; if (chbSOptimized->Checked) { SortName += " SOptimized"; StartTimer(); ret = qdqs->SMSort(1, ItemCnt, CmProc, MvProc); StopTimer(); } else { StartTimer(); ret = qdqs->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); } delete qdqs; } else if (cbQuick->Text == "SedgewickBentley") { SBQuickSort *sbq; sbq = new SBQuickSort; StartTimer(); ret = sbq->Sort(1, ItemCnt, CmProc, &Swap); StopTimer(); delete sbq; } else if ((cbQuick->Text == "Spencer1") || (cbQuick->Text == "Spencer2") || (cbQuick->Text == "Spencer3")) { SQuickSort *sq; sq = new SQuickSort; sq->after = false; sq->minMove = (cbPartition->ItemIndex <= 0); if (sq->minMove)

205 SortName += "M"; else SortName += "C"; if (cbBreak->ItemIndex > 0) { sq->break_point = cbBreak->ItemIndex; if (sq->break_point == 21) sq->break_point = 254; else if (sq->break_point == 22) sq->break_point = 65534;

SortName += " Break:" + cbBreak->Text + " " + cbSecondSort- >Text;

SpencerSort *ss = 0; SpencerInsertSort *sis = 0; InsertionSort *is = 0; JSort *js = 0; BPShellSort *bpss = 0; BPMergeSort *bpms = 0; RASort *ras = 0; if (cbSecondSort->Text == "RAS") { ss = new SpencerSort; ss->compareType = (char) cbSecondCompare->ItemIndex; ss->sequential = chbSecondSequential->Checked; ss->assignType = (char) cbSecondAssign->ItemIndex; sq->SSort = &ss->Sort; SortName += " " + cbSecondCompare->Text; if (chbSecondSequential->Visible && chbSecondSequential- >Checked) SortName += " Sequential"; SortName += " " + cbSecondAssign->Text; } else if (cbSecondSort->Text == "RAS16") { ras = new RASort; sq->SSort = &ras->Sort; } else if (cbSecondSort->Text == "Insertion") { is = new InsertionSort; if (chbSOptimized->Checked) { SortName += " SOptimized"; sq->SSort = &is->Sort; } else sq->SSort = &is->SortBP; sq->after = chbAfter->Checked; if (sq->after) SortName += " After"; } else if (cbSecondSort->Text == "SMInsert") { sis = new SpencerInsertSort; sq->SSort = &sis->Sort;

206 } else if (cbSecondSort->Text == "JSort") { js = new JSort; sq->SSort = &js->Sort; } else if (cbSecondSort->Text == "Shell") { SortName += " " + cbSecondShell->Text; if (chbSOptimized->Checked) SortName += " SOptimized";

AnsiString seqStr = cbSecondShell->Text; seqStr = seqStr.SubString(seqStr.Length()-5, 6); long sSeq; if (seqStr.IsEmpty() || seqStr[1] < '0' || seqStr[1] > '9') sSeq = cbSecondShell->ItemIndex; else sSeq = seqStr.ToInt();

bpss = new BPShellSort; bpss->seq = sSeq; bpss->sopt = chbSOptimized->Checked; sq->SSort = &bpss->Sort; } else if (cbSecondSort->Text == "Merge") { bpms = new BPMergeSort; sq->SSort = &bpms->SortInPlace; } if (cbQuick->Text == "Spencer1") { StartTimer(); ret = sq->Sort1(1, ItemCnt, CmProc, MvProc); StopTimer(); } else if (cbQuick->Text == "Spencer2") { StartTimer(); ret = sq->Sort2(1, ItemCnt, CmProc, MvProc); StopTimer(); } else // (cbQuick->Text == "Spencer3") { StartTimer(); ret = sq->Sort3(1, ItemCnt, CmProc, MvProc); StopTimer(); } if (ss) { if (laRotate->Visible) laRotate->Caption = IntToStr(ss->rotateCnt); delete ss; } if (ras) delete ras;

207 if (is) delete is; if (sis) delete sis; if (js) delete js; if (bpss) delete bpss; if (bpms) delete bpms; } else { sq->break_point = 0;

if (cbQuick->Text == "Spencer1") { StartTimer(); ret = sq->Sort1(1, ItemCnt, CmProc, MvProc); StopTimer(); } else if (cbQuick->Text == "Spencer2") { StartTimer(); ret = sq->Sort2(1, ItemCnt, CmProc, MvProc); StopTimer(); } else // (cbQuick->Text == "Spencer3") { StartTimer(); ret = sq->Sort3(1, ItemCnt, CmProc, MvProc); StopTimer(); } } delete sq; } } else if (SortName == "Insertion") { InsertionSort *is; is = new InsertionSort; if (ItemCnt <= InsertMax) { if (chbSOptimized->Checked) { SortName += " SOptimized"; StartTimer(); ret = is->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); } else { StartTimer(); ret = is->SortBP(1, ItemCnt, CmProc, MvProc); StopTimer(); } }

208 else if (MsgBx("InsertionSort is not good for large sorts (>"+IntToStr(InsertMax)+"). Are you sure?", "Long Sort", MB_YESNO) == IDYES) { if (chbSOptimized->Checked) { SortName += " SOptimized"; StartTimer(); ret = is->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); } else { StartTimer(); ret = is->SortBP(1, ItemCnt, CmProc, MvProc); StopTimer(); } } else abortStr = "Aborted";

delete is; } else if (SortName == "SMInsert") { SpencerInsertSort *sis; sis = new SpencerInsertSort; if (ItemCnt <= InsertMax) { StartTimer(); ret = sis->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); } else if (MsgBx("InsertionSort is not good for large sorts (>"+IntToStr(InsertMax)+"). Are you sure?", "Long Sort", MB_YESNO) == IDYES) { StartTimer(); ret = sis->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); } else abortStr = "Aborted";

delete sis; } else if (SortName == "RAS") { SortName += " " + cbCompare->Text + " " + cbAssign->Text; if (chbSequential->Visible && chbSequential->Checked) SortName += " Sequential";

SpencerSort *ss; ss = new SpencerSort; ss->assignType = (char) cbAssign->ItemIndex; ss->compareType = (char) cbCompare->ItemIndex; ss->sequential = chbSequential->Checked; StartTimer(); ret = ss->Sort(1, ItemCnt, CmProc, MvProc);

209 StopTimer(); laRotate->Caption = IntToStr(ss->rotateCnt); delete ss; } else if (SortName == "RAS16") { if (ItemCnt > 65535) { MsgBx("RAS16 is only good for data sets with less than 65536 elements", "Too many elements", MB_OK); } else { RASort *rs; rs = new RASort; StartTimer(); ret = rs->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); delete rs; } } else if (SortName == "JSort") { JSort *js; js = new JSort; StartTimer(); ret = js->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); delete js; } else if (SortName == "Merge") { BPMergeSort *bpms; bpms = new BPMergeSort; StartTimer(); ret = bpms->SortInPlace(1, ItemCnt, CmProc, MvProc); StopTimer(); delete bpms; } else if (SortName == "Shell") { SortName += " " + cbShell->Text; if (chbSOptimized->Checked) SortName += " SOptimized"; BPShellSort *bpss; bpss = new BPShellSort; bpss->seq = shellSeq; bpss->sopt = chbSOptimized->Checked; StartTimer(); ret = bpss->Sort(1, ItemCnt, CmProc, MvProc); StopTimer(); delete bpss; } else if (SortName == "Heap") { SortName += " " + cbHeap->Text; if (cbHeap->Text == "BermanPaul")

210 { BPHeapSort *bphs; bphs = new BPHeapSort; bphs->sopt = chbSOptimized->Checked; if (chbSOptimized->Checked) SortName += " SOptimized"; StartTimer(); ret = bphs->Sort(ItemCnt, CmProc, MvProc); StopTimer(); delete bphs; } else { HeapSort *hs; hs = new HeapSort; StartTimer(); ret = hs->Sort(ItemCnt, CmProc, &Swap); StopTimer(); delete hs; } } else { MsgBx("Sort " + SortName + " is Unknown", "Unknown Sort", MB_OK); }

Update();

laCompareDirect->Caption = IntToStr(CompareDirectCnt); laCompareToTemp->Caption = IntToStr(CompareToTempCnt); laAssignDirect->Caption = IntToStr(DirectCnt); laAssignToTemp->Caption = IntToStr(ToTempCnt); laAssignFromTemp->Caption = IntToStr(FromTempCnt); laCompareTotal->Caption = IntToStr(CompareDirectCnt + CompareToTempCnt + CompareTempsCnt); laAssignTotal->Caption = IntToStr(DirectCnt + ToTempCnt + FromTempCnt + moveTempsCnt); laTotalBoth->Caption = IntToStr(CompareDirectCnt + CompareToTempCnt + CompareTempsCnt + DirectCnt + ToTempCnt + FromTempCnt + moveTempsCnt);

laCompareSelf->Caption = IntToStr(CompareSelfCnt); laAssignSelf->Caption = IntToStr(moveToSelfCnt); laAssignTemps->Caption = IntToStr(moveTempsCnt); laCompareTemps->Caption = IntToStr(CompareTempsCnt);

laSkipCnt->Caption = IntToStr(skipCnt);

BlankScreen(); StartScreen(false);

AnsiString messtr; AnsiString logstr;

if (ret) { long csn = workData[1].num; long cso = workData[1].origOrder;

211 bool failed = false; bool stable = true; long equalCnt = 0; for (long i = 2; i <= ItemCnt; i++) { csn += workData[i].num; cso += workData[i].origOrder; if (workData[i-1].num > workData[i].num) failed = true; else if (workData[i-1].num == workData[i].num) { equalCnt++; if (workData[i-1].origOrder > workData[i].origOrder) stable = false; } } messtr = SortName + " is Done";

if (timerFrequency.QuadPart) { messtr += " in " + ElapsedTime(); } messtr += " with Display " + dispStr + "\nData is " + (failed ? "out of" : "in") + " order, CheckSumNum is " + (csn == numCheckSum ? "correct" : "wrong") + " , CheckSumOrder is " + (cso == orderCheckSum ? "correct" : "wrong") + "\nEqual elements:" + IntToStr(equalCnt) + " ";

if (equalCnt) messtr += (stable ? "Stable (in original order)" : "Unstable (not in original order)"); messtr += "\n"; if (extraTempCnt) messtr += " " + IntToStr(extraTempCnt) + " extra temporary locations allocated with " + IntToStr(reallocCnt) + " allocations\n"; if (moveTempsCnt) messtr += " " + IntToStr(moveTempsCnt) + " moves between temporary locations\n"; if (moveToSelfCnt) messtr += " " + IntToStr(moveToSelfCnt) + " moves attempted to same location\n";

if (compErrorCnt) messtr += " " + IntToStr(compErrorCnt) + " compare errors\n"; if (moveErrorCnt) messtr += " " + IntToStr(moveErrorCnt) + " move errors\n"; MsgBx(messtr, "Sort Done", MB_OK); if (!rbDisplayNone->Checked && (filename != "")) { struct time t; struct date d;

212 getdate(&d); gettime(&t);

logstr.sprintf("%s,%s,%d/%d/%d %d:%02d:%02d,", CompName.c_str(), filename.SubString(filename.LastDelimiter("\\")+1,filename.Length()).c_str(), d.da_mon, d.da_day, d.da_year, t.ti_hour,t.ti_min, t.ti_sec);

logstr += SortName + "," + IntToStr((UINT)((endTime.QuadPart-startTime.QuadPart)*1000000 / timerFrequency.QuadPart)) + "," + dispStr + "," + (failed ? "no":"yes")+ "," + (csn == numCheckSum ? "yes":"no") + "," + (cso == orderCheckSum ? "yes":"no") + "," + edQuantity->Text + "," + edRange->Text + "," + IntToStr(equalCnt) + "," + (stable ? "yes":"no") + "," + extraTempCnt + "," + moveTempsCnt + "," + moveToSelfCnt + "," + compErrorCnt + "," + moveErrorCnt + ","; } } else { messtr = SortName + " Failed after " + ElapsedTime() + " " + abortStr; MsgBx(messtr, "Sort Failed", MB_OK); } if (!rbDisplayNone->Checked) { messtr += "Assigns = " + laAssignTotal->Caption + ", ToTemp = " + laAssignToTemp->Caption + ", FromTemp = " + laAssignFromTemp->Caption + ", Direct = " + laAssignDirect->Caption + "\n"; if (moveToSelfCnt) messtr += "Assigns to Self = " + laAssignSelf->Caption + "\n";

messtr += "Compares = " + laCompareTotal->Caption + ", ToTemp = " + laCompareToTemp->Caption + ", Direct = " + laCompareDirect->Caption + "\n"; if (CompareSelfCnt) messtr += "Compares to Self = " + laCompareSelf->Caption + "\n";

messtr += "Assigns + Compares = " + laTotalBoth->Caption + "\n"; if (ret && (filename != "")) { logstr += laAssignToTemp->Caption + "," + laAssignFromTemp->Caption + "," + laAssignDirect->Caption + "," + laCompareToTemp->Caption + "," + laCompareDirect->Caption + "," + CompareSelfCnt + "\n"; FILE *csvFile; if (FileExists("Sorts.csv")) { csvFile = fopen("Sorts.csv", "a"); if (csvFile) { fprintf(csvFile, logstr.c_str()); fclose(csvFile);

213 } else MsgBx("Sorts.csv could not be opened", "Write Failed", MB_OK); } else { csvFile = fopen("Sorts.csv", "a"); if (csvFile) { AnsiString hdrStr = (AnsiString) "Machine,File,Time,Sort,Elapsed,Display,"+

"Success,ChecksumNum,ChecksumOrder,Quantity,Range,EqualCnt,Stable," + "ExtraTemp,MoveTempsCnt,MoveToSelfCnt,CompErrorCnt," + "MoveErrorCnt,AssignToTemp,AssignFromTemp,AssignDirect," + "CompareToTemp,CompareDirect,CompareSelf\n"; fputs(hdrStr.c_str(), csvFile); fprintf(csvFile, logstr.c_str()); fclose(csvFile); } else MsgBx("Sorts.csv could not be created", "Create Failed", MB_OK); } } } messtr += "\n"; if (logFile) fprintf(logFile, messtr.c_str());

if (extraTempCnt) { free(extraTemps); extraTemps = 0; extraTempCnt = 0; reallocCnt = 0; } btnSort->Caption = "Reset"; btnSort->Hint = "Reset to the data before the sort"; } else { Reset(); btnSort->Hint = "Perform the sort"; } DoneWorking(); } //------long __fastcall TSortForm::gcd(long a, long b) { long r; while (b) { r = a % b; a = b; b = r;

214 } return a; } //------#pragma argsused void __fastcall TSortForm::btnFillClick(TObject *Sender) { Working(); ReleaseSpace();

ItemCnt = StrToInt(edQuantity->Text); Range = StrToInt(edRange->Text);

long g = gcd(Range, height); // this can reduce the posibility of overflow with large numbers

hval = height / g; rval = Range / g;

filename = ""; if (AllocateSpace()) { FillOrig();

btnSort->Enabled = true; btnSave->Enabled = true; Reset(); } DoneWorking(); }

//------#pragma argsused void __fastcall TSortForm::btnLoadClick(TObject *Sender) { if(OpenDialog1->Execute()) { Working();

ReleaseSpace();

filename = OpenDialog1->FileName;

if (!filename.AnsiPos(".")) filename += ".srt";

ItemCnt = StrToInt(edQuantity->Text); Range = StrToInt(edRange->Text);

if (AllocateSpace()) { long g = gcd(Range, height); // this can reduce the posibility of overflow with large numbers

hval = height / g; rval = Range / g; btnSort->Enabled = true;

215 Reset(); } DoneWorking(); } } //------#pragma argsused void __fastcall TSortForm::btnSaveClick(TObject *Sender) { if(SaveDialog1->Execute()) { filename = SaveDialog1->FileName; Working(); if (!filename.AnsiPos(".")) filename += ".srt"; SaveFile(); DoneWorking(); } } //------#pragma argsused void __fastcall TSortForm::cbSortTypeChange(TObject *Sender) { AnsiString SortName = cbSortType->Items->Strings[cbSortType->ItemIndex]; cbShell->Visible = (SortName == "Shell"); cbQuick->Visible = (SortName == "Quick"); cbHeap->Visible = (SortName == "Heap"); cbBingo->Visible = (SortName == "Bingo"); if (cbShell->Visible) { AnsiString seqStr = cbShell->Text; seqStr = seqStr.SubString(seqStr.Length()-5, 6); if (seqStr.IsEmpty() || seqStr[1] < '0' || seqStr[1] > '9') shellSeq = cbShell->ItemIndex; else shellSeq = seqStr.ToInt(); } cbCompare->Visible = (SortName == "RAS"); cbAssign->Visible = cbCompare->Visible && (cbCompare->Text != "BPMerge"); chbSequential->Visible = cbCompare->Visible && !cbCompare- >Text.AnsiPos("Merge"); if (cbCompare->Text == "BPMerge") cbAssign->ItemIndex = 0; cbBreak->Visible = (cbQuick->Visible && cbQuick->Text.AnsiPos("Spencer")); cbPartition->Visible = cbBreak->Visible; cbSecondSort->Visible = (cbBreak->Visible && (cbBreak->ItemIndex > 0)); chbAfter->Visible = (cbSecondSort->Visible && (cbSecondSort->Text == "Insertion")); cbSecondCompare->Visible = (cbSecondSort->Visible && (cbSecondSort->Text == "RAS")); cbSecondAssign->Visible = cbSecondCompare->Visible; cbSecondShell->Visible = (cbSecondSort->Visible && (cbSecondSort->Text == "Shell")); chbSecondSequential->Visible = cbSecondCompare->Visible && !cbSecondCompare- >Text.AnsiPos("Merge"); chbSOptimized->Visible = (cbShell->Visible || cbSecondShell->Visible || (cbSortType->Text == "Insertion") ||

216 (cbQuick->Visible && cbQuick->Text == "Qinjian Deng") || (cbHeap->Visible && cbHeap->Text == "BermanPaul") || (cbSecondSort->Visible && cbSecondSort->Text == "Insertion")); if (cbCompare->Text.AnsiPos("Splay") || (cbSecondCompare->Visible && cbSecondCompare->Text.AnsiPos("Splay"))) { laRotateTitle->Visible = true; laRotate->Visible = true; } else { laRotateTitle->Visible = false; laRotate->Visible = false; }

SortTypeChange(Sender); } //------#pragma argsused void __fastcall TSortForm::SortTypeChange(TObject *Sender) { Working(); if (btnSort->Caption == "Reset") { Reset(); } DoneWorking(); } //------#pragma argsused void __fastcall TSortForm::FormClose(TObject *Sender, TCloseAction &Action) { ReleaseSpace(); } //------#pragma argsused void __fastcall TSortForm::rbEqualClick(TObject *Sender) { chbUnique->Checked = false; chbUnique->Enabled = false;

btnSort->Enabled = false; btnSave->Enabled = false; } //------#pragma argsused void __fastcall TSortForm::rbNotEqualClick(TObject *Sender) { chbUnique->Enabled = true;

btnSort->Enabled = false; btnSave->Enabled = false; } //------void __fastcall TSortForm::rbSplayKillerClick(TObject *Sender)

217 { chbUnique->Checked = true; chbUnique->Enabled = false; chbUniqueClick(Sender); } //------#pragma argsused void __fastcall TSortForm::chbUniqueClick(TObject *Sender) { edRange->Text = edQuantity->Text;

if (chbUnique->Checked) { edRange->Enabled = false; } else { edRange->Enabled = true; }

btnSort->Enabled = false; btnSave->Enabled = false; } //------#pragma argsused void __fastcall TSortForm::edQuantityChange(TObject *Sender) { if (chbUnique->Checked) { edRange->Text = edQuantity->Text; } } //------#pragma argsused void __fastcall TSortForm::FormCanResize(TObject *Sender, int &NewWidth, int &NewHeight, bool &Resize) { Resize = (Screen->Cursor != crHourGlass); } //------#pragma argsused void __fastcall TSortForm::rbDisplayClick(TObject *Sender) { BlankScreen(); StartScreen(false); tbDelay->Visible = rbDelayed->Checked; laDelay->Visible = rbDelayed->Checked; laSkipCnt->Visible = rbDelayed->Checked; laSkipTitle->Visible = rbDelayed->Checked; chbDot->Visible = rbDisplayStartEnd->Checked || rbDelayed->Checked || rbDisplayAll->Checked; laQuad->Visible = false; } //------#pragma argsused void __fastcall TSortForm::rbDisplayOffClick(TObject *Sender) {

218 BlankScreen(); tbDelay->Visible = false; laDelay->Visible = false; laSkipCnt->Visible = false; laSkipTitle->Visible = false; chbDot->Visible = false; laQuad->Visible = rbDisplayNone->Checked; } //------#pragma argsused void __fastcall TSortForm::FormResize(TObject *Sender) { height = ImagePanel->Height; width = ImagePanel->Width; widthDiv2 = width / 2;

ItemCnt = StrToInt(edQuantity->Text); Range = StrToInt(edRange->Text);

long g = gcd(Range, height); // this can reduce the posibility of overflow with large numbers

hval = height / g; rval = Range / g; } //------#pragma argsused void __fastcall TSortForm::tbDelayChange(TObject *Sender) { laDelay->Caption = IntToStr(tbDelay->Position); } //------#pragma argsused void __fastcall TSortForm::chbDotClick(TObject *Sender) { if (chbDot->Checked) { DrawItem = DrawDot; EraseItem = EraseDot; } else { DrawItem = DrawLine; EraseItem = EraseLine; } BlankScreen(); StartScreen(false); } //------

219 frmSorts.dfm Delphi Form for Sort Tester object SortForm: TSortForm Left = 315 Top = 150 Width = 1142 Height = 849 Caption = 'Sort Tester by Spencer Morgan' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False WindowState = wsMaximized OnCanResize = FormCanResize OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy OnResize = FormResize PixelsPerInch = 96 TextHeight = 13 object BottomPanel: TPanel Left = 0 Top = 712 Width = 1134 Height = 110 Align = alBottom TabOrder = 0 object Label1: TLabel Left = 776 Top = 0 Width = 31 Height = 13 Caption = 'Assign' end object Label2: TLabel Left = 696 Top = 32 Width = 43 Height = 13 Caption = 'ToTemp:' end object Label3: TLabel Left = 696 Top = 48 Width = 31 Height = 13 Caption = 'Direct:' end object Label4: TLabel Left = 696 Top = 64 Width = 53 Height = 13

220 Caption = 'FromTemp:' end object laCompare: TLabel Left = 844 Top = 0 Width = 42 Height = 13 Alignment = taRightJustify Caption = 'Compare' end object laAssignToTemp: TLabel Left = 774 Top = 32 Width = 40 Height = 13 Alignment = taRightJustify Caption = 'ToTemp' end object laAssignDirect: TLabel Left = 786 Top = 48 Width = 28 Height = 13 Alignment = taRightJustify Caption = 'Direct' end object laAssignFromTemp: TLabel Left = 764 Top = 64 Width = 50 Height = 13 Alignment = taRightJustify Caption = 'FromTemp' end object laCompareToTemp: TLabel Left = 854 Top = 32 Width = 40 Height = 13 Alignment = taRightJustify Caption = 'ToTemp' end object laCompareDirect: TLabel Left = 866 Top = 48 Width = 28 Height = 13 Alignment = taRightJustify Caption = 'Direct' end object Label7: TLabel Left = 696 Top = 16 Width = 27 Height = 13 Caption = 'Total:' end

221 object laAssignTotal: TLabel Left = 790 Top = 16 Width = 24 Height = 13 Alignment = taRightJustify Caption = 'Total' end object laCompareTotal: TLabel Left = 870 Top = 16 Width = 24 Height = 13 Alignment = taRightJustify Caption = 'Total' end object laBoth: TLabel Left = 918 Top = 0 Width = 22 Height = 13 Alignment = taRightJustify Caption = 'Both' end object laTotalBoth: TLabel Left = 950 Top = 16 Width = 24 Height = 13 Alignment = taRightJustify Caption = 'Total' end object laCompareTemps: TLabel Left = 862 Top = 80 Width = 32 Height = 13 Alignment = taRightJustify Caption = 'Temps' end object Label8: TLabel Left = 696 Top = 80 Width = 35 Height = 13 Caption = 'Temps:' end object laAssignTemps: TLabel Left = 782 Top = 80 Width = 32 Height = 13 Alignment = taRightJustify Caption = 'Temps' end object Label9: TLabel Left = 696

222 Top = 96 Width = 21 Height = 13 Caption = 'Self:' end object laAssignSelf: TLabel Left = 796 Top = 96 Width = 18 Height = 13 Alignment = taRightJustify Caption = 'Self' end object laCompareSelf: TLabel Left = 876 Top = 96 Width = 18 Height = 13 Alignment = taRightJustify Caption = 'Self' end object laRotateTitle: TLabel Left = 918 Top = 32 Width = 32 Height = 13 Alignment = taRightJustify Caption = 'Rotate' Visible = False end object laRotate: TLabel Left = 968 Top = 48 Width = 6 Height = 13 Alignment = taRightJustify Caption = '0' Visible = False end object laSkipCnt: TLabel Left = 968 Top = 80 Width = 6 Height = 13 Alignment = taRightJustify Caption = '0' end object laSkipTitle: TLabel Left = 918 Top = 64 Width = 37 Height = 13 Alignment = taRightJustify Caption = 'SkipCnt' end object laDelay: TLabel Left = 448

223 Top = 88 Width = 12 Height = 13 Caption = '30' Color = clBtnFace ParentColor = False end object laQuad: TLabel Left = 472 Top = 88 Width = 34 Height = 13 Caption = 'laQuad' end object cbSortType: TComboBox Left = 8 Top = 40 Width = 65 Height = 21 Hint = 'The sort algorithm to use' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 0 Text = 'SortType' OnChange = cbSortTypeChange Items.Strings = ( 'Bubble' 'Insertion' 'SMInsert' 'JSort' 'Bingo' 'Shell' 'Heap' 'Merge' 'Quick' 'RAS' 'RAS16') end object gbDataSet: TGroupBox Left = 152 Top = 4 Width = 441 Height = 77 Caption = 'DataSet' TabOrder = 1 object Label5: TLabel Left = 320 Top = 16 Width = 16 Height = 13 Caption = 'Qty' end object Label6: TLabel Left = 321 Top = 35

224 Width = 32 Height = 13 Caption = 'Range' end object rbRandom: TRadioButton Left = 8 Top = 16 Width = 65 Height = 17 Hint = 'Random data' Caption = 'Random' Checked = True ParentShowHint = False ShowHint = True TabOrder = 0 TabStop = True OnClick = rbNotEqualClick end object rbOrdered: TRadioButton Left = 80 Top = 16 Width = 65 Height = 17 Hint = 'Already in order' Caption = 'Ordered' ParentShowHint = False ShowHint = True TabOrder = 1 OnClick = rbNotEqualClick end object rbReversed: TRadioButton Left = 80 Top = 32 Width = 65 Height = 17 Hint = 'Data in reverse order' Caption = 'Reversed' ParentShowHint = False ShowHint = True TabOrder = 2 OnClick = rbNotEqualClick end object rbEqual: TRadioButton Left = 8 Top = 32 Width = 65 Height = 17 Hint = 'All data is equal ' Caption = 'Equal' ParentShowHint = False ShowHint = True TabOrder = 3 OnClick = rbEqualClick end object btnLoad: TButton Left = 261 Top = 50

225 Width = 41 Height = 23 Hint = 'Loads a data set from disk' Caption = 'Load' ParentShowHint = False ShowHint = True TabOrder = 4 OnClick = btnLoadClick end object edQuantity: TEdit Left = 356 Top = 11 Width = 81 Height = 21 Hint = 'Number of items in data set' ParentShowHint = False ShowHint = True TabOrder = 5 Text = '1000' OnChange = edQuantityChange end object edRange: TEdit Left = 356 Top = 32 Width = 81 Height = 21 Hint = 'Range of items in data set' ParentShowHint = False ShowHint = True TabOrder = 6 Text = '1000' end object chbUnique: TCheckBox Left = 240 Top = 16 Width = 65 Height = 17 Hint = 'No duplicates in data' Caption = 'Unique' ParentShowHint = False ShowHint = True TabOrder = 7 OnClick = chbUniqueClick end object rbPreMerge: TRadioButton Left = 160 Top = 16 Width = 65 Height = 17 Hint = 'Two halves of data in order' Caption = 'PreMerge' ParentShowHint = False ShowHint = True TabOrder = 8 OnClick = rbNotEqualClick end object btnFill: TButton

226 Left = 221 Top = 50 Width = 41 Height = 23 Hint = 'Creates a new data set' Caption = 'Fill' ParentShowHint = False ShowHint = True TabOrder = 9 OnClick = btnFillClick end object btnSave: TButton Left = 301 Top = 50 Width = 41 Height = 23 Hint = 'Saves a data set to disk' Caption = 'Save' ParentShowHint = False ShowHint = True TabOrder = 10 OnClick = btnSaveClick end object rbHalf: TRadioButton Left = 8 Top = 48 Width = 73 Height = 17 Hint = 'Half data is equal ' Caption = 'Half Equal' ParentShowHint = False ShowHint = True TabOrder = 11 OnClick = rbEqualClick end object rbSplayKiller: TRadioButton Left = 80 Top = 48 Width = 73 Height = 17 Hint = 'Alternating extremes' Caption = 'Splay Killer' ParentShowHint = False ShowHint = True TabOrder = 12 OnClick = rbSplayKillerClick end object rbStability: TRadioButton Left = 160 Top = 48 Width = 57 Height = 17 Hint = 'All data except for one is equal ' Caption = 'Stability' ParentShowHint = False ShowHint = True TabOrder = 13

227 OnClick = rbEqualClick end object rbWorstAssign: TRadioButton Left = 160 Top = 32 Width = 81 Height = 17 Hint = 'A worst case for assignments' Caption = 'WorstAssign' ParentShowHint = False ShowHint = True TabOrder = 14 OnClick = rbSplayKillerClick end object rbWorstShell: TRadioButton Left = 240 Top = 32 Width = 73 Height = 17 Hint = 'Worst for original Shell if n power of 2' Caption = 'WorstShell' ParentShowHint = False ShowHint = True TabOrder = 15 OnClick = rbSplayKillerClick end end object btnSort: TButton Left = 8 Top = 8 Width = 75 Height = 25 Hint = 'Perform the sort' Caption = 'Sort' Enabled = False ParentShowHint = False ShowHint = True TabOrder = 2 OnClick = btnSortClick end object gbDisplay: TGroupBox Left = 600 Top = 4 Width = 89 Height = 101 Caption = 'Display' TabOrder = 3 object rbDisplayOff: TRadioButton Left = 8 Top = 32 Width = 49 Height = 17 Hint = 'No display' Caption = 'Off' ParentShowHint = False ShowHint = True TabOrder = 0

228 OnClick = rbDisplayOffClick end object rbDisplayStartEnd: TRadioButton Left = 8 Top = 48 Width = 65 Height = 17 Hint = 'Only before and after sort are displayed' Caption = 'Start/End' ParentShowHint = False ShowHint = True TabOrder = 1 OnClick = rbDisplayClick end object rbDisplayAll: TRadioButton Left = 8 Top = 80 Width = 33 Height = 17 Hint = 'Each Compare and Assign is displayed' Caption = 'All' ParentShowHint = False ShowHint = True TabOrder = 3 OnClick = rbDisplayClick end object rbDelayed: TRadioButton Left = 8 Top = 64 Width = 65 Height = 17 Hint = 'Temps are not displayed' Caption = 'Delayed' Checked = True ParentShowHint = False ShowHint = True TabOrder = 2 TabStop = True OnClick = rbDisplayClick end object rbDisplayNone: TRadioButton Left = 8 Top = 16 Width = 49 Height = 17 Hint = 'No display or counting' Caption = 'None' ParentShowHint = False ShowHint = True TabOrder = 4 OnClick = rbDisplayOffClick end object chbDot: TCheckBox Left = 48 Top = 80 Width = 38 Height = 17

229 Caption = 'Dot' TabOrder = 5 OnClick = chbDotClick end end object cbAssign: TComboBox Left = 8 Top = 85 Width = 73 Height = 21 Hint = 'How to reduce assignments' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 4 Text = 'Stable' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Stable' 'Unstable' 'Optimal') end object cbCompare: TComboBox Left = 8 Top = 64 Width = 73 Height = 21 Hint = 'How to perform comparisons' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 5 Text = 'SMerge' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Tree' 'Splay' 'Splay1' 'Splay/2' 'SplayX' 'BPMerge' 'SMerge') end object chbSequential: TCheckBox Left = 88 Top = 88 Width = 73 Height = 17 Hint = 'Add data sequentially' Caption = 'Sequential' ParentShowHint = False ShowHint = True TabOrder = 6

230 Visible = False OnClick = cbSortTypeChange end object cbShell: TComboBox Left = 8 Top = 85 Width = 161 Height = 21 Hint = 'Sequence of Increments' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 7 Text = 'Tokuda A108870' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Shell N/2' 'Weiss N/2.2' 'Hibbard A000225' 'Papernov A000051' 'Pratt A003586' '4^(n+1)+3*2^n+1 A036562' 'Incerpi-Sedgewick A036569' 'Sedgewick A033622' 'Tokuda A108870' 'Ciura A102549' '(3^n - 1)/2 A003462' '2^n-45; n >= 6 A036564' 'a(0)=1; a(i)= Prime[i^3] A055875' 'round[ 1 + e^(n-2) ] A055876') end object chbSOptimized: TCheckBox Left = 9 Top = 66 Width = 73 Height = 17 Hint = 'Use a version optimized by Spencer' Caption = 'SOptimized' ParentShowHint = False ShowHint = True TabOrder = 8 Visible = False OnClick = cbSortTypeChange end object cbQuick: TComboBox Left = 5 Top = 85 Width = 113 Height = 21 Hint = 'Quick Sort version' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 9

231 Text = 'BermanPaul' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'BermanPaul' 'Qinjian Deng' 'SedgewickBentley' 'Spencer1' 'Spencer2' 'Spencer3') end object cbHeap: TComboBox Left = 8 Top = 85 Width = 89 Height = 21 Hint = 'Heap Sort version' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 10 Text = 'BermanPaul' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'BermanPaul' 'Wikipedia') end object tbDelay: TTrackBar Left = 464 Top = 80 Width = 126 Height = 25 Hint = 'Updates per Second' Max = 60 Min = 1 Orientation = trHorizontal Frequency = 1 Position = 30 SelEnd = 0 SelStart = 0 TabOrder = 11 TickMarks = tmBottomRight TickStyle = tsAuto OnChange = tbDelayChange end object cbBreak: TComboBox Left = 125 Top = 85 Width = 52 Height = 21 Hint = 'Use secondary sort at this size' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True

232 TabOrder = 12 Text = '0' Visible = False OnChange = cbSortTypeChange Items.Strings = ( '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '10' '11' '12' '13' '14' '15' '16' '17' '18' '19' '20' '255' '65535') end object cbSecondAssign: TComboBox Left = 333 Top = 85 Width = 73 Height = 21 Hint = 'How to reduce assignments' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 13 Text = 'Stable' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Stable' 'Unstable' 'Optimal') end object cbSecondCompare: TComboBox Left = 253 Top = 85 Width = 73 Height = 21 Hint = 'How to perform comparisons' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False

233 ShowHint = True TabOrder = 14 Text = 'SMerge' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Tree' 'Splay' 'Splay1' 'Splay/2' 'SplayX' 'BPMerge' 'SMerge') end object cbSecondSort: TComboBox Left = 181 Top = 85 Width = 65 Height = 21 Hint = 'The secondary sort algorithm to use' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 15 Text = 'RAS16' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Insertion' 'SMInsert' 'JSort' 'Shell' 'Merge' 'RAS' 'RAS16') end object cbSecondShell: TComboBox Left = 252 Top = 84 Width = 161 Height = 21 Hint = 'Sequence of Increments' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 16 Text = 'Tokuda A108870' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'Shell N/2' 'Weiss N/2.2' 'Hibbard A000225' 'Papernov A000051' 'Pratt A003586'

234 '4^(n+1)+3*2^n+1 A036562' 'Incerpi-Sedgewick A036569' 'Sedgewick A033622' 'Tokuda A108870' 'Ciura A102549' '(3^n - 1)/2 A003462' '2^n-45; n >= 6 A036564' 'a(0)=1; a(i)= Prime[i^3] A055875' 'round[ 1 + e^(n-2) ] A055876') end object chbAfter: TCheckBox Left = 253 Top = 86 Width = 73 Height = 17 Hint = 'Do the secondary sort at the end' Caption = 'After' ParentShowHint = False ShowHint = True TabOrder = 17 Visible = False OnClick = cbSortTypeChange end object chbSecondSequential: TCheckBox Left = 9 Top = 66 Width = 73 Height = 17 Hint = 'Add data sequentially' Caption = 'Sequential' ParentShowHint = False ShowHint = True TabOrder = 18 Visible = False OnClick = cbSortTypeChange end object cbPartition: TComboBox Left = 88 Top = 61 Width = 65 Height = 21 Hint = 'How to partition equal elements' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 19 Text = 'MinMove' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'MinMove' 'MinComp') end object cbBingo: TComboBox Left = 5 Top = 87

235 Width = 89 Height = 21 Hint = 'Heap Sort version' DropDownCount = 28 ItemHeight = 13 ParentShowHint = False ShowHint = True TabOrder = 20 Text = 'BermanPaul' Visible = False OnChange = cbSortTypeChange Items.Strings = ( 'BermanPaul' 'SOptimized' 'Bidirectional') end end object ImagePanel: TPanel Left = 0 Top = 0 Width = 1134 Height = 712 Align = alClient Anchors = [] AutoSize = True TabOrder = 1 object Image1: TImage Left = 1 Top = 1 Width = 1132 Height = 710 Align = alClient Anchors = [] AutoSize = True end end object SaveDialog1: TSaveDialog Filter = 'Sort Data|*.srt' Left = 944 Top = 720 end object OpenDialog1: TOpenDialog Filter = 'Sort Data|*.srt' Left = 904 Top = 720 end end

236