mirror of
https://github.com/TheAlgorithms/C
synced 2024-11-25 06:49:36 +03:00
5bf2c42bff
* updating DIRECTORY.md * updating DIRECTORY.md * feat: Add Patience Sort https://en.wikipedia.org/wiki/Patience_sorting * updating DIRECTORY.md * Update sorting/patience_sort.c Co-authored-by: David Leal <halfpacho@gmail.com> * Update sorting/patience_sort.c Co-authored-by: David Leal <halfpacho@gmail.com> --------- Co-authored-by: github-actions[bot] <github-actions@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com>
161 lines
5.0 KiB
C
161 lines
5.0 KiB
C
/**
|
|
* @file
|
|
* @brief [Patience Sort](https://en.wikipedia.org/wiki/Patience_sorting)
|
|
* @details From Wikipedia:
|
|
* In computer science, patience sorting is a sorting algorithm inspired by, and named after, the card game patience.
|
|
* Given an array of n elements from some totally ordered domain, consider this array as a collection of cards and simulate the patience sorting game.
|
|
* When the game is over, recover the sorted sequence by repeatedly picking off the minimum visible card;
|
|
* in other words, perform a k-way merge of the p piles, each of which is internally sorted.
|
|
* @author [CascadingCascade](https://github.com/CascadingCascade)
|
|
*/
|
|
|
|
#include <assert.h> /// for assertions
|
|
#include <stdio.h> /// for IO operations
|
|
#include <stdlib.h> /// for memory management
|
|
|
|
/**
|
|
* @brief Sorts the target array by dividing it into a variable number of internally sorted piles then merge the piles
|
|
* @param array pointer to the array to be sorted
|
|
* @param length length of the target array
|
|
* @returns void
|
|
*/
|
|
void patienceSort(int *array, int length) {
|
|
// An array of pointers used to store each pile
|
|
int* *piles = (int* *) malloc(sizeof(int*) * length);
|
|
for (int i = 0; i < length; ++i) {
|
|
piles[i] = malloc(sizeof(int) * length);
|
|
}
|
|
|
|
// pileSizes keep track of the indices of each pile's topmost element, hence 0 means only one element
|
|
// Note how calloc() is used to initialize the sizes of all piles to zero
|
|
int *pileSizes = (int*) calloc(length,sizeof(int));
|
|
|
|
// This initializes the first pile, note how using an array of pointers allowed us to access elements through two subscripts
|
|
// The first subscript indicates which pile we are accessing, the second subscript indicates the location being accessed in that pile
|
|
piles[0][0] = array[0];
|
|
int pileCount = 1;
|
|
|
|
for (int i = 1; i < length; ++i) {
|
|
// This will be used to keep track whether an element has been added to an existing pile
|
|
int flag = 1;
|
|
|
|
for (int j = 0; j < pileCount; ++j) {
|
|
if(piles[j][pileSizes[j]] > array[i]) {
|
|
// We have found a pile this element can be added to
|
|
piles[j][pileSizes[j] + 1] = array[i];
|
|
pileSizes[j]++;
|
|
flag--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(flag) {
|
|
// The element in question can not be added to any existing piles, creating a new pile
|
|
piles[pileCount][0] = array[i];
|
|
pileCount++;
|
|
}
|
|
}
|
|
|
|
// This will keep track of the minimum value of all 'exposed' elements and which pile that value is from
|
|
int min, minLocation;
|
|
|
|
for (int i = 0; i < length; ++i) {
|
|
// Since there's no guarantee the first pile will be depleted slower than other piles,
|
|
// Example: when all elements are equal, in that case the first pile will be depleted immediately
|
|
// We can't simply initialize min to the top most element of the first pile,
|
|
// this loop finds a value to initialize min to.
|
|
for (int j = 0; j < pileCount; ++j) {
|
|
if(pileSizes[j] < 0) {
|
|
continue;
|
|
}
|
|
min = piles[j][pileSizes[j]];
|
|
minLocation = j;
|
|
break;
|
|
}
|
|
|
|
for (int j = 0; j < pileCount; ++j) {
|
|
if(pileSizes[j] < 0) {
|
|
continue;
|
|
}
|
|
if(piles[j][pileSizes[j]] < min) {
|
|
min = piles[j][pileSizes[j]];
|
|
minLocation = j;
|
|
}
|
|
}
|
|
|
|
array[i] = min;
|
|
pileSizes[minLocation]--;
|
|
}
|
|
|
|
// Deallocate memory
|
|
free(pileSizes);
|
|
for (int i = 0; i < length; ++i) {
|
|
free(piles[i]);
|
|
}
|
|
free(piles);
|
|
}
|
|
|
|
/**
|
|
* @brief Helper function to print an array
|
|
* @param array pointer to the array
|
|
* @param length length of the target array
|
|
* @returns void
|
|
*/
|
|
void printArray(int *array,int length) {
|
|
printf("Array:");
|
|
for (int i = 0; i < length; ++i) {
|
|
printf("%d",array[i]);
|
|
if (i != length - 1) putchar(',');
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
/**
|
|
* @brief Testing Helper function
|
|
* @param array pointer to the array to be used for testing
|
|
* @param length length of the target array
|
|
* @returns void
|
|
*/
|
|
|
|
void testArray(int *array,int length) {
|
|
printf("Before sorting:\n");
|
|
printArray(array,length);
|
|
|
|
patienceSort(array,length);
|
|
|
|
printf("After sorting:\n");
|
|
printArray(array,length);
|
|
|
|
for (int i = 0; i < length - 1; ++i) {
|
|
assert(array[i] <= array[i + 1]);
|
|
}
|
|
printf("All assertions have passed!\n\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Self-test implementations
|
|
* @returns void
|
|
*/
|
|
static void test() {
|
|
int testArray1[] = {2,8,7,1,3,5,6,4};
|
|
int testArray2[] = {2,2,5,1,3,5,6,4};
|
|
int testArray3[] = {1,2,3,4,5,6,7,8};
|
|
int testArray4[] = {8,7,6,5,4,3,2,1};
|
|
|
|
testArray(testArray1,8);
|
|
testArray(testArray2,8);
|
|
testArray(testArray3,8);
|
|
testArray(testArray4,8);
|
|
|
|
printf("Testing successfully completed!\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Main function
|
|
* @returns 0 on exit
|
|
*/
|
|
int main() {
|
|
test(); // run self-test implementations
|
|
return 0;
|
|
}
|