#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#define BEGIN_TIMESTAMP() \
struct timespec startTime, endTime; \
char buf[512] = {0}; \
int32_t err; \
uint64_t startTm = 0, endTm, diffTime; \
errno = 0; \
memset(&startTime, 0, sizeof(startTime)); \
err = clock_gettime(CLOCK_REALTIME, &startTime); \
if (err != 0) { \
(void)strerror_r(errno, buf, sizeof(buf)); \
printf("clock_gettime error, err:%d, reason:%s", err, buf); \
} else { \
startTm = (uint64_t)(startTime.tv_sec * 1000) + (uint64_t)(startTime.tv_nsec / (1000 * 1000)); \
}
#define END_TIMESTAMP() \
errno = 0; \
memset(&endTime, 0, sizeof(endTime)); \
err = clock_gettime(CLOCK_REALTIME, &endTime); \
if (err != 0) { \
memset(buf, 0, sizeof(buf)); \
(void)strerror_r(errno, buf, sizeof(buf)); \
printf("clock_gettime error, err:%d, reason:%s", err, buf); \
} else { \
endTm = (uint64_t)(endTime.tv_sec * 1000) + (uint64_t)(endTime.tv_nsec / (1000 * 1000)); \
if (endTm >= startTm && startTm != 0) { \
diffTime = endTm - startTm; \
printf("[%s] blocking time:%lums\n", __FUNCTION__, diffTime); \
} \
}
#define TRACE_IN() //printf(">>>trace in: %s\n", __func__ )
#define TRACE_OUT() // printf("<<<trace out: %s\n\n", __func__ )
#define BUBBLE_SORT 0
#define SELECTION_SORT 1
#define INSERTION_SORT 2
#define QUICK_SORT 3
#define SORT INSERTION_SORT
#define LOG_OUTPUT_FD stdout
void PrintArray(const int * const arr, const int len)
{
TRACE_IN();
for (int index = 0; index < len; index++)
{
fprintf(LOG_OUTPUT_FD,"%02d ", arr[index]);
}
fprintf(LOG_OUTPUT_FD, "\n");
TRACE_OUT();
}
void Swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
/*
* 冒泡排序(Bubble Sort)是一种简单的排序算法
* 它的工作原理重复地走访过要排序的数列,一次比较两个元素,
* 如果他们的顺序(如从大到小/首字母从A到Z)错误就把他们交换过来
*/
void bubble_sort(int arr[], int len, bool asc = true) {
int i, j, temp;
BEGIN_TIMESTAMP();
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len - 1 - i; j++)
{
bool dir;
if (asc) {
dir = (arr[j] > arr[j + 1]);
} else {
dir = (arr[j] < arr[j + 1]);
}
if (dir)
{
Swap(arr[j], arr[j+1]);
}
}
fprintf(stdout, "第%d轮冒泡排序结果:\n", i + 1);
PrintArray(arr, len);
}
END_TIMESTAMP();
}
/*
* 选择排序(Selection sort)是一种简单直观的排序算法
* 它的工作原理如下:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,
* 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾,
* 以此类推,直到所有元素均排序完毕
*/
void selection_sort(int *arr, int len, bool asc = true)
{
int i, j;
int tmp;
BEGIN_TIMESTAMP();
for (i = 0; i <= len - 1; i++)
{
int min_or_max = i;
for ( j = i + 1; j <= len -1; j++)
{
bool dir ;
if (asc) {
dir = (arr[min_or_max] > arr[j]);
} else {
dir = (arr[min_or_max] < arr[j]);
}
if (dir) {
min_or_max = j;
}
}
Swap(arr[i], arr[min_or_max]);
}
END_TIMESTAMP();
}
/*
* 插入排序(Insertion Sort)是一种简单直观的排序算法
* 它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,
* 找到相应位置并插入,插入排序在实现上,通常采用in-place排序
* (即只需用到 {\displaystyle O(1)} {\displaystyle O(1)}的额外空间的排序)
* 因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
*/
void insertion_sort(int *arr, int len, bool asc = true)
{
int i, j, tmp;
if (len < 2) {
return;
}
BEGIN_TIMESTAMP();
/* 外循环控制未排序数据 */
for (i = 1; i < len; i++) {
tmp = arr[i];
/* 内循环控制已排序的数据 */
for (j = i; j > 0;) {
bool dir;
if (asc) {
dir = tmp < arr[j - 1];
} else {
dir = tmp > arr[j - 1];
}
if (dir) {
/* 一直在已排序的数组中把不是最大或最小的元素往后挪,为最新元素提供插入空间 */
arr[j] = arr[j - 1];
j--;
continue;
}
/* 直到找到i新元素插入的坐标 */
break;
}
arr[j] = tmp;
fprintf(LOG_OUTPUT_FD, "第%d轮排序结果:\n", i);
PrintArray(arr, len);
}
END_TIMESTAMP();
}
/* 递归 */
void quick_sort_recursive(int arr[], int start, int end)
{
if (start >= end)
return;
int mid = arr[end];
int left = start, right = end - 1;
while (left < right) {
/* 先找到左边第一个比mid大的 */
while (arr[left] <= mid && left < right)
left++;
/* 再找到右边起第一个比mid小的 */
while (arr[right] > mid && left < right)
right--;
Swap(arr[left], arr[right]);
}
if (arr[left] >= arr[end])
Swap(arr[left], arr[end]);
else
left++;
if (left)
quick_sort_recursive(arr, start, left - 1);
quick_sort_recursive(arr, left + 1, end);
}
/*
*快速排序(quick sort):
* 它工作的原理在区间中随机挑选一个元素作基准,将小于基准的元素放在基准之前,大于基准的元素放在基准之后,
* 再分别对小数区与大数区进行排序
* index 0 1 2 3 4 5 6 7 8
* e.g.:{ 22, 34, 3, 32, 82, 55, 89, 50, 37}
* 第一大轮:
left = 0;right=8;key=22
1.1 right=2 ==> {3, 34, 22, 32, 82, 55, 89, 50, 37}
1.2 left=1 ==> {3, 22, 34, 32, 82, 55, 89, 50, 37}
2.1 right=1 ==> {3, 22, 34, 32, 82, 55, 89, 50, 37}
2.2 left=1 ==> {3, 22, 34, 32, 82, 55, 89, 50, 37}
最终排序:
{3, 22, 34, 32, 82, 55, 89, 50, 37}
下一轮分区:
小: start=0 end=0;直接跳过
大: start=2 end=8
* 第二大轮:
*大数区递归-->left = 2;right=8;key=34; {34, 32, 82, 55, 89, 50, 37}
3.1 right=3 ==> {32, 34, 82, 55, 89, 50, 37}
3.2 left=3 ==> {32, 34, 82, 55, 89, 50, 37}
大数区最终排序:
{32, 34, 82, 55, 89, 50, 37}
本轮综合排序:
{03, 22, 32, 34, 82, 55, 89, 50, 37}
下一轮分区:
小: start=2 end=2;直接跳过
大: start=4 end=8
* 第三大轮:
*大数区递归-->left = 4;right=8;key=82; {82, 55, 89, 50, 37}
4.1 right=8 ==>{37, 55, 89, 50, 82}
4.2 left =6 ==>{37, 55, 82, 50, 89}
5.1 right=7 ==>{37, 55, 50, 82, 89}
5.2 left =7 ==>{37, 55, 50, 82, 89}
大数区最终排序:
{37, 55, 50, 82, 89}
本轮综合排序:
{ 03, 22, 32, 34, 37, 55, 50, 82, 89}
下一轮分区:
小: start=4 end=6
大: start=8 end=8;直接跳过
第四大轮:
*小数区递归-->left=4;right=6;key=37;{37, 55, 50, 82,}
6.1 right=4 ==>{37, 55, 50, 82,}
6.2 left =4 ==>{37, 55, 50, 82,}
小数区最终排序:
{37, 55, 50, 82,}
本轮综合排序:
{ 03, 22, 32, 34, 37, 55, 50, 82, 89}
下一轮分区:
小: start=4 end=3;直接跳过
大: start=5 end=6
第五大轮:
大数区递归-->left=5;right=6;key=55;{55,50}
7.1 right=6 ==>{50, 55}
7.2 left =6 ==>{50, 55}
本轮综合排序:
{ 03, 22, 32, 34, 37, 50, 55, 82, 89}
下一轮分区:
小: start=5;end=5;直接跳过
大: start=7;end=6;直接跳过
*/
void quick_sort(int *arr,int len, int start, int end, bool asc = true)
{
if (start >= end) {
fprintf(LOG_OUTPUT_FD, "跳过start%d==end==%d\n", start, end);
return;
}
static int loop = 0;
loop++;
int left = start; /* 小数区(以基数判断) */
int right = end; /* 大数区(以基数判断) */
int key = arr[left]; /* 基数 */
static int seq = 1;
float index = 0.0f;
fprintf(LOG_OUTPUT_FD, "\n>>>>>>>>>>>>>>>>>>>>>start:%d end:%d key:%d<<<<<<<<<<<<<<<<<<\n", start, end, key);
while (left < right) {
if (asc) {
/* 找到大数区第一个比基数小的值 */
while (key <= arr[right] && right > left) {
right--;
fprintf(LOG_OUTPUT_FD, "right[%d]:%d\t", right, arr[right]);
}
fprintf(LOG_OUTPUT_FD, "\n找到大数区第一个比基数小的值 arr[%d]:%d \n", right, arr[right]);
} else {
/* 找到大数区第一个比基数大的值 */
while (key >= arr[right] && right > left) {
right--;
fprintf(LOG_OUTPUT_FD, "right[%d]:%d\t", right, arr[right]);
}
fprintf(LOG_OUTPUT_FD, "\n找到大数区第一个比基数大的值 arr[%d]:%d \n", right, arr[right]);
}
/* 把从大数区找到的第一个比基数小的数放在小数区 */
if (left != right)
arr[left++] = arr[right];
index = 0.1 + seq;
fprintf(LOG_OUTPUT_FD, "第%d轮中%.1f小轮排序结果:\n", loop, index);
PrintArray(arr, len);
if (asc) {
/* 找到小数区第一个比基数大的值 */
while (key > arr[left] && left < right)
{
left++;
fprintf(LOG_OUTPUT_FD, "left[%d]:%d\t", left, arr[left]);
}
fprintf(LOG_OUTPUT_FD, "\n找到小数区第一个比基数大的值 arr[%d]:%d \n", left, arr[left]);
} else {
/* 找到小数区第一个比基数小的值 */
while (key < arr[left] && left < right)
{
left++;
fprintf(LOG_OUTPUT_FD, "left[%d]:%d\t", left, arr[left]);
}
fprintf(LOG_OUTPUT_FD, "\n找到小数区第一个比基数小的值 arr[%d]:%d \n", left, arr[left]);
}
/* 把从小数区找到的第一个比基数大的数放在大数区 */
if (left != right)
arr[right--] = arr[left];
index = 0.2 + seq;
fprintf(LOG_OUTPUT_FD, "第%d轮中%.1f小轮排序结果:\n", loop, index);
PrintArray(arr, len);
seq++;
fprintf(LOG_OUTPUT_FD, "right:%d left:%d key:%d\n", right, left, key);
}
arr[left] = key;
fprintf(LOG_OUTPUT_FD, "第%d轮排序结果:\n", loop);
PrintArray(arr, len);
quick_sort(arr, len, start, left - 1, asc);
quick_sort(arr, len, left + 1, end, asc);
fprintf(LOG_OUTPUT_FD, "\n<<<<<<<<<<<<<<<<<<start:%d end:%d key:%d>>>>>>>>>>>>>>>>>>>>>\n", start, end, key);
}
void User_QuickSort(int *arr, int start, int end)
{
if (start >= end) {
return;
}
int s = start;
int e = end;
int base = arr[s];
while (s < e) {
/* 大分区数:从后往前找第一个比基数小的数 */
while (arr[e] <= base && s < e) {
e--;
}
if (s < e)
arr[s++] = arr[e];
/* 小分区数:从前往后找第一个比基数大的数 */
while (arr[s] > base && s < e) {
s++;
}
if (s < e)
arr[e--] = arr[s];
}
arr[s] = base;
User_QuickSort(arr, start, e - 1);
User_QuickSort(arr, e + 1, end);
}
int main() {
int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 100};
int len = (int) sizeof(arr) / sizeof(*arr);
PrintArray(arr, len);
#if (SORT == BUBBLE_SORT)
bubble_sort(arr, len, false);
#elif (SORT == SELECTION_SORT)
selection_sort(arr, len, true);
#elif (SORT == INSERTION_SORT)
insertion_sort(arr, len, false);
#elif (SORT == QUICK_SORT)
quick_sort(arr, len, 0, len - 1, true);
//User_QuickSort(arr, 0, len - 1);
#endif
fprintf(LOG_OUTPUT_FD, "=================排序后=================\n\n");
PrintArray(arr, len);
return 0;
}
参考菜鸟教程:
https://www.runoob.com/cprogramming/c-sort-algorithm.html