Data Structure Learning (C ++) Continued - Sort [5] Multiple Sort

zhaozj2021-02-16  58

[5] Multiple sort

When I learned the linked list, we have done the practice of synthesizing two ordered chain tables. At that time, we knew that it was characterized by synthesizing the overall ordered sequence of segmented sequences. In the internal sorting, the position of the merge is not very important, mainly because of the additional O (N) storage space; however, the return is the outside of the outside, we can only use the inner segmentation The sequence, in order to obtain the final ordered sequence, a method of merge must be used.

Iterative 2 ways to sort

2 is the simplest, and simple to data operation 2 on memory is often the best (such as balanced tree, AVL tree is often better than the balance tree of M fork). The so-called iteration is N / 2 sequences of Len = 2, then N / 4 sequences of LEN = 4, and then completed 2 sequences. When you are actually written, you need a temporary array as the original sequence. Perform an even number of "one 趟 并" can make the final result in the original array.

// Iterate 2 ways and sorted and the subroutine required

Template

Void Merge (T S [], T D [], INT L, INT M, INT N, INT & KCN, INT & RMN)

{

// s [] Source Table, D [] Monatic table, L Source Table The starting number of the first segment, the start number of the M source table, the length of the N source table

INT i = L, j = m, k = L; // i 1 pointer, J second paragraph, K target table pointer

For (; i

IF ( KCN && S [i]> s [j]) {d [k] = s [j]; j ;} else {d [k] = s [i]; i ;}

IF (i

For (; i

Else

For (; J

}

Template

Void MergePass (T s [], T D [], INT LEN, INT N, INT & KCN, INT & RMN

{

INT i = 0;

For (; i 2 * len

IF (i len

Else for (; i

}

Template

Void Mergesort (T A [], INT N, INT & KCN, INT & RMN)

{

KCN = 0; RMN = 0;

T * TEMP = New T [N]; int LEN = 1;

While (Len

{

MergePass (A, TEMP, LEN, N, KCN, RMN); LEN * = 2; MergePass (TEMP, A, LEN, N, KCN, RMN); len * = 2;

}

DELETE [] TEMP;

}

Test results, take directly N = 100000:

Sort ascending n = 100000 Timespared: 210ms

KCN = 877968 KCN / N = 8.77968 KCN / N ^ 2 = 8.77968E-005KCN / NLOGN = 0.528589

RMN = 1800000 rmn / n = 18 RMN / N ^ 2 = 0.00018 RMN / NLOGN = 1.08371

Sort randomness n = 100000 Timespared: 230ms

KCN = 1529317 kcn / n = 15.2932 kcn / n ^ 2 = 0.000152932kcn / nlogn = 0.920741

RMN = 1800000 rmn / n = 18 RMN / N ^ 2 = 0.00018 RMN / NLOGN = 1.08371

Sort descending n = 100000 Timespared: 201ms

KCN = 815024 kcn / n = 8.15024 kcn / n ^ 2 = 8.15024e-005kcn / nlogn = 0.490693

RMN = 1800000 rmn / n = 18 RMN / N ^ 2 = 0.00018 RMN / NLOGN = 1.08371

It can be seen that the RMN is a set value, and the value of RMN / N is not less than the minimum number of log2n. It is interested in comparing the difference between n = 1 and n = 2. Compared with the quick rules (n = 100,000, the order), although the merged KCN and RMN have fewer, the speed of the fast-row is still twice as fast as the altering, and the extraction of the description is more than one movement). The phenomenon is indeed worth thinking, this is also an unexpected harvest in the KCN and RMN statistics - the summary is not because KCN and RMN are more fast, but some extra things.

Careful analysis will find that the amount of merged time consumption is mainly in the small segment. If we use the most efficient direct insertion in N very small, it will replace the return at this time and should be able to bring efficiency. As described below, first use the direct plug to generate the initial merged segment of Len = 32, and then return to:

Template

Void Mergesort (T A [], INT N, INT & KCN, INT & RMN)

{

KCN = 0; RMN = 0;

T * Temp = new T [N]; int LEN = 32, i, J, k;

// segmentation is inserted and sorted, generating the initial LEN long merged segment

FOR (k = 1; k

{

For (i = k; i

{

T Temp = a [i]; RMN ;

For (j = i; j> = k && kcn && temp

}

}

While (Len

{

MergePass (A, TEMP, LEN, N, KCN, RMN); len * = 2;

MergePass (TEMP, A, LEN, N, KCN, RMN); len * = 2;

}

DELETE [] TEMP;

}

Test Results:

Sort ascending n = 100000 Timespared: 160ms

KCN = 724843 kcn / n = 7.24843 kcn / n ^ 2 = 7.24843e-005kcn / nlogn = 0.436399

RMN = 1393750 RMN / N = 13.9375 RMN / N ^ 2 = 0.000139375RMN / NLOGN = 0.839121

Sort randomness n = 100000 Timespared: 160ms

KCN = 2009896 kcn / n = 20.099 kcn / n ^ 2 = 0.00020099 KCN / NLOGN = 1.21008

RMN = 2166630 RMN / N = 21.6663 RMN / N ^ 2 = 0.000216663RMN / NLOGN = 1.30444

Sort descending n = 100000 Timespared: 170ms

KCN = 2115024 kcn / n = 21.1502 kcn / n ^ 2 = 0.000211502kcn / nlogn = 1.27337

RMN = 2943750 RMN / N = 29.4375 RMN / N ^ 2 = 0.000294375RMN / NLOGN = 1.77231

It should be said to be more satisfactory for N = 100,000 chart.

Retrinted 2 road table

Naturally, in addition to two or two returns from Len = 1, it is also possible to start from Len = N, 1/2 split into left and right sequences, sorted, respectively, which is a recursive process. If we carefully observe this recursive, it will find that this is the same as the previous iteration (n = 2K). The benefits of recursive are convenient to use static linked lists (very easy to achieve dynamic generation and dying of the head), if we don't use a linked list, it is not meaningful to study recursive mergers.

// Remature 2 road table merges and its desired subroutine

Template

Int ListMerge (T A [], Int link [], int head1, int head2, int & kcn)

{

INT K, Head, I = HEAD1, J = Head2; // i, J is the cursor of two linked lists, k is the result of the latheclament, the result of the list of the list is Head

// Because there is no head node, the head needs to be handled separately.

IF ( KCN && A [i]> a [j]) {head = j; k = j; j = link [j];}

Else {head = i; k = i; i = link [i];} while (i! = -1 && j! = -1)

{

IF ( KCN && A [i]> a [j]) {link [k] = j; k = j; j = link [j];}

Else {link [k] = i; k = i; i = link [i];

}

IF (i == -1) LINK [K] = J; // i chain test, J link

Else Link [K] = i; / / Otherwise, i link

Return head; // Return to head pointer

}

Template

INT RMERGESORT (T A [], Int Link [], Int Low, Int High, Int & KCN)

{

IF (low> = high) Return Low;

INT MID = (Low High) / 2;

Return ListMerge (A, LINK, RMERGESORT (A, LINK, LOW, MID, KCN), RMERGESORT (A, LINK, MID 1, HIGH, KCN), KCN);

}

Template

Void ListMergesort (T A [], INT N, INT & KCN, INT & RMN)

{

KCN = 0; RMN = 0; INT I, CUR, PRE;

INT * Link = new int [n];

For (i = 0; i

Cur = RmergeSort (A, Link, 0, N - 1, KCN);

For (i = 0; i

{

While (Cur

Pre = link [cur];

IF (Cur! = i)

{

SWAP (A [I], A [Cur]); RMN = 3;

LINK [CUR] = LINK [I]; LINK [i] = CUR;

}

Cur = pre;

}

DELETE [] LINK;

}

The RmergeSort here can be an indirectly recursive example, pay attention to how the recursive is automatically completed and recycled - it is indeed a very delicate implementation. If it is an iteration, it will be troublesome.

Test Results:

Sort ascending n = 100000 Timespared: 50ms

KCN = 853904 kcn / n = 8.53904 kcn / n ^ 2 = 8.53904E-005KCN / NLOGN = 0.514101

RMN = 0 RMN / N = 0 RMN / N ^ 2 = 0 RMN / NLOGN = 0

Sort randomness n = 100000 Timespared: 350ms

KCN = 1509031 KCN / N = 15.0903 kcn / n ^ 2 = 0.000150903kcn / nlogn = 0.908527

RMN = 299973 RMN / N = 2.99973 RMN / N ^ 2 = 2.99973e-005RMN / NLOGN = 0.180602

Sort descending n = 100000 Timespared: 70mskcn = 815024 kcn / n = 8.15024 kcn / n ^ 2 = 8.15024e-005kcn / nlogn = 0.490693

RMN = 150000 RMN / N = 1.5 RMN / N ^ 2 = 1.5e-005 RMN / NLOGN = 0.090309

There are fewer sorting methods in positive and reverse sequences, but they are not very excellent on their average performance.


New Post(0)