diff --git a/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/CMakeLists.txt b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/CMakeLists.txt index 1df9f70..a73eb70 100644 --- a/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/CMakeLists.txt +++ b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/CMakeLists.txt @@ -5,19 +5,27 @@ cmake_minimum_required(VERSION 3.17) get_filename_component(COMPNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${COMPNAME}) -add_executable(algorithm_s_straight_selection_sort algorithm_s_straight_selection_sort.c) +add_executable(algorithm_s_straight_selection_sort_zmajeed algorithm_s_straight_selection_sort_zmajeed.c) +add_executable(algorithm_s_straight_selection_sort_andydude algorithm_s_straight_selection_sort_andydude.c) +add_executable(algorithm_h_heap_sort_andydude algorithm_h_heap_sort_andydude.c) if(CMAKE_C_COMPILER_ID MATCHES GNU) - target_compile_options(algorithm_s_straight_selection_sort PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_s_straight_selection_sort_zmajeed PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_s_straight_selection_sort_andydude PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_h_heap_sort_andydude PRIVATE -g -Wall -Werror -O0 -std=c18) elseif(CMAKE_C_COMPILER_ID MATCHES MSVC) - target_compile_options(algorithm_s_straight_selection_sort PRIVATE -Wall -WX -Od) + target_compile_options(algorithm_s_straight_selection_sort_zmajeed PRIVATE -Wall -WX -Od) + target_compile_options(algorithm_s_straight_selection_sort_andydude PRIVATE -Wall -WX -Od) + target_compile_options(algorithm_h_heap_sort_andydude PRIVATE -Wall -WX -Od) elseif(CMAKE_C_COMPILER_ID MATCHES Clang) - target_compile_options(algorithm_s_straight_selection_sort PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_s_straight_selection_sort_zmajeed PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_s_straight_selection_sort_andydude PRIVATE -g -Wall -Werror -O0 -std=c18) + target_compile_options(algorithm_h_heap_sort_andydude PRIVATE -g -Wall -Werror -O0 -std=c18) endif() diff --git a/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_h_heap_sort_andydude.c b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_h_heap_sort_andydude.c new file mode 100644 index 0000000..d073ab4 --- /dev/null +++ b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_h_heap_sort_andydude.c @@ -0,0 +1,172 @@ +// SPDX-FileCopyrightText: © 2023 Andrew Robbins +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include + +#define LIST_SWAP(X, i, j, t) \ + if (i != j) { \ + t = X[i]; \ + X[i] = X[j]; \ + X[j] = t; \ + } + + +static void usage() +{ + puts("usage: algorithm_h_heap_sort < in.dat > out.dat"); +} + +/* + * Williams INHEAP(X, N, K), + * Williams SWAPHEAP(X, N, K, R) + * Knuth Algorithm H3U (Sift up) + * + * **Program 5.2.3H3U** (*Sift up*) + * + * (Omitted because we are focusing on C.) + * + * **Algorithm 5.2.3H3U** (*Sift up*) + * + * **H3.** [Prepare for siftup.] Set `j <- l`. (At this point + * we have `K_floor(k/2) >= K_k` for `l < floor(k/2) < k <= r`; + * and record `R_k` is in its final position for `r < k <= N`. + * Steps H3-H8 are called the *siftup algorithm*; their effect + * is equivalent to setting `R_l <- R` and then rearranging + * `R_l, ..., R_r` so that condition (6) holds for + * `l = floor(k/2)`.) + * **H4.** [Advance downward.] Set `i <- j` and `j <- 2j`. + * (In the following steps we have `i = floor(j/2)`.) + * If `j < r`, go right on to step H5; if `j = r`, + * go to step H6; and if `j > r`, go to H8. + * **H5.** [Find larger child.] If `K_j < K_j+1`, then set `j <- j + 1`. + * **H6.** [Larger than K?] If `K >= K_j`, then go to step H8. + * **H7.** [Move it up.] Set `R_i <- R_j`, and go back to step H4. + * **H8.** [Store R.] Set `R_i <- R`. + * (This terminates the siftup algorithm initiated in step H3.) + * Return to step H2. + */ +void +subroutine_5_2_3_h3u_sift_up( + int64_t *X, uint64_t l, + uint64_t k, uint64_t r) +{ + int64_t t; // Temp for swap + uint64_t i; // RosettaCode root + uint64_t j; // RosettaCode child + + // **H3.** [Prepare for sift up.] + i = l; + + while (true) { + // **H4.** [Advance downward.] + j = 2*i; + + if ((j < r) && (X[j] < X[j + 1])) { + // **H5.** [Find larger child.] + ++j; + } + + if ((j > r) || !(X[i] < X[j])) { + // **H8.** [Store the record.] + LIST_SWAP(X, l, k, t); + break; + } + + if (X[i] < X[j]) { + // **H6.** [Larger than the key?.] + // **H7.** [Move it up.] + LIST_SWAP(X, i, j, t); + i = j; + } + } +} + +/* + * Knuth Algorithm H (Heap sort) + * Williams Algorithm 232 HEAPSORT() + * + * **Program 5.2.3H** (*Heap sort*) + * + * (Omitted because we are focusing on C.) + * + * **Algorithm 5.2.3H** (*Heap sort*) + * + * Records `R_1, ..., R_N` are rearranged in place; after + * sorting is complete, their keys will be in order, + * `K_1 <= ... <= K_N`. First we rearrange the file so that + * it forms a heap, then we repeatedly remove the top of the + * heap and transfer it to its proper final position. + * Assume that `N >= 2`. + * + * **H1.** [Initialize.] Set l <- floor(N/2) + 1, r <- N. + * **H2.** [Decrease l or r.] If l > 1, set l <- l - 1, R <- R_l, K <- K_l. + * Otherwise set R <- R_r, K <- K_r, R_r <- R_1, and r <- r - 1; + * if this makes r = 1, set R_1 <- R and terminate the algorithm. + */ +void +subroutine_5_2_3_h_heap_sort( + int64_t *X, uint64_t n) +{ + // **H1.** [Initialize.] + + // RosettaCode start + uint64_t l = n/2 + 1; + + // RosettaCode end + uint64_t r = n; + + /* + * **H2L.** [Decrease l.] + * Knuth H2L() + * Williams SETHEAP() + * RosettaCode heapify() + */ + while (l > 1) { + // Williams INHEAP(X, j, X[j + 1]) + subroutine_5_2_3_h3u_sift_up(X, l, l, r); + + // Decrease l. + --l; + } + + /* + * **H2R.** [Decrease r.] + * Knuth H2R() + * Williams OUTHEAP() + * RosettaCode unheapify() + */ + while (r > 1) { + // Williams SWAPHEAP(X, n - 1, X[n], R) + subroutine_5_2_3_h3u_sift_up(X, l, r, r); + + // Decrease r. + --r; + } +} + +int main(int argc, char* argv[]) +{ + if(argc > 1) { + usage(); + exit(0); + } + + // Read input. + uint64_t N; + fread(&N, sizeof N, 1, stdin); + int64_t X[N + 1]; + fread(&X[1], sizeof(*X), N, stdin); + + // Main logic: heap sort. + subroutine_5_2_3_h_heap_sort(X, N); + + // Write output. + fwrite(&N, sizeof N, 1, stdout); + fwrite(&X[1], sizeof(*X), N, stdout); + return 0; +} diff --git a/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort_andydude.c b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort_andydude.c new file mode 100644 index 0000000..15ba093 --- /dev/null +++ b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort_andydude.c @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: © 2023 Andrew Robbins +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include + +#define LIST_SWAP(X, i, j, t) \ + if (i != j) { \ + t = X[i]; \ + X[i] = X[j]; \ + X[j] = t; \ + } + +static void usage() +{ + puts("usage: algorithm_s_straight_selection_sort < in.dat > out.dat"); +} + +/* + * (Note that unlike almost every other algorithm-program + * pair in TAOCP, the section numbers of these two do not + * match. We could have picked either of these section + * numbers for the name of the subroutine below, + * and so we chose the one with the number 3 in it.) + * + * **Program 1.3.2M** (*Find the maximum*) + * + * (Omitted because we are focusing on C.) + * + * **Algorithm 1.2.10M** (*Find the maximum*) + * + * Given `n` elements `X[1], X[2], ..., X[n]`, + * we will find `m` and `j` such that `m = X[j]`, + * where `j` is the largest such index that + * satisfies this relation. + * + * **M1.** [Initialize.] Set `j <- n`, `k <- n - 1`, `m <- X[n]`. + * (During this algorithm we will have `m = X[j]`.) + * **M2.** [All tested?] If `k = 0`, the algorithm terminates. + * **M3.** [Compare.] If `X[k] <= m`, go to M5. + * **M4.** [Change `m`.] Set `j <- k`, `m <- X[k]`. + * (This value of m is a new current maximum.) + * **M5.** [Decrease `k`.] Decrease `k` by one and return to M2. + */ +void +subroutine_1_3_2_find_the_maximum( + int64_t *X, + uint64_t n, + int64_t *max_value, + uint64_t *max_index) +{ + // **M1.** [Initialize.] + int64_t j, k; + j = k = n; + int64_t m = X[j]; + + // In TAOCP, this is represented by the step M1, + // which says `j <- n`, `k <- n - 1`, and so + // `k` must be one less than `j`. + --k; + + // **M2.** [All tested?] + while(k >= 1) { + // **M3.** [Compare.] + if (m < X[k]) { + // **M4.** [Change m.] + m = X[j = k]; + } + // **M5.** [Decrease k.] + --k; + } + + *max_value = m; + *max_index = j; +} + +/* + * **Program 5.2.3S** (*Straight selection sort*) + * + * (Omitted because we are focusing on C) + * + * **Algorithm 5.2.3S** (*Straight selection sort*) + * + * Records `R_1, ..., R_N` are rearranged in place; + * after sorting is complete, their keys will be + * in order `K_1 <= ... <= K_N`. + * + * **S1.** [Loop on j.] Perform steps S2 and S3 for + * `j = N, N-1, ..., 2`. + * **S2.** [Find `max(K_1, ..., K_j)`.] Search through keys + * `K_j, ..., K_1` to find the maximal one; let it be `K_i`, + * where `i` is as large as possible. + * **S3.** [Exchange with `R_j`.] Interchange records + * `R_i <-> R_j`. (Now records `R_j, ..., R_N` are in their + * final position.) + */ +void +subroutine_5_2_3_straight_selection_sort( + int64_t *X, + uint64_t n) +{ + uint64_t i, j; + int64_t m, t; + j = n; + + // **S1.** [Loop on `j`.] + while (j >= 2) { + /* + * **S2.** [Find `max(K_1, ..., K_j)`.] + * + * This renames the variables + * from Algorithm 5.2.3S to Algorithm 1.2.10M. + * + * M.X == S.X + * M.m == S.m + * M.n == S.j -- confusing! + * M.j == S.i -- confusing! + */ + subroutine_1_3_2_find_the_maximum( + X, j, &m, &i); + + // **S3.** [Exchange with `R_j`] + LIST_SWAP(X, i, j, t); + + /* + * Decrement j. + * + * This is implied by Knuth Algorithm 5.2.3S, + * step (S1) [Loop on `j`.] but it is not very + * explicit. It is also referenced by Knuth + * Program 5.2.3S, on line 14: `DEC1 1`, but + * this line is uncommented. + */ + --j; + } +} + +int main(int argc, char* argv[]) +{ + if(argc > 1) { + usage(); + exit(0); + } + + // Read input. + uint64_t N; + fread(&N, sizeof N, 1, stdin); + int64_t X[N + 1]; + fread(&X[1], sizeof(*X), N, stdin); + + // Main logic: selection sort. + subroutine_5_2_3_straight_selection_sort(X, N); + + // Write output. + fwrite(&N, sizeof N, 1, stdout); + fwrite(&X[1], sizeof(*X), N, stdout); + return 0; +} diff --git a/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort.c b/vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort_zmajeed.c similarity index 100% rename from vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort.c rename to vol_3_sorting_and_searching_chap_5_sorting/sec_5.2.3_sorting_by_selection/algorithm_s_straight_selection_sort_zmajeed.c