Skip to content

Added heap_sort and alternate selection_sort #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// SPDX-FileCopyrightText: © 2023 Andrew Robbins
// SPDX-License-Identifier: MIT

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>

#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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-FileCopyrightText: © 2023 Andrew Robbins
// SPDX-License-Identifier: MIT

#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#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;
}