sort.h
c
#define SWAP(x,y) {int tmp = x; x = y; y = tmp;}
#define N 20000000
#define M 100
void print(int *arr);
void bubbleSort(int *arr);
void selectSort(int *arr);
void insertSort(int *arr);
void shellSort(int *arr);
void quickSort(int *arr, int left, int right);
int partition(int *arr, int left, int right);
int myCompare(const void* p1, const void *p2);
void adjustMaxHeap(int *arr, int pos, int len);
void heapSort(int *arr);
void merge(int *arr, int *brr, int left, int mid, int right);
void mergeSort(int *arr, int *brr, int left, int right);
void countSort(int *arr);
main.c
c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "sort.h"
int main() {
/*int a = 10, b = 5;
SWAP(a, b);
printf("a = %d, b = %d\n", a, b);*/
srand((unsigned int)time(NULL));
//int arr[N];
int *arr = (int *)malloc(N * sizeof(int));
//brr是用于归并排序的额外申请的空间
int *brr = (int *)malloc(N * sizeof(int));
for (int i = 0; i < N; ++i) {
arr[i] = rand() % M;
}
//print(arr);
//bubbleSort(arr);
//selectSort(arr);
//insertSort(arr);
time_t begTime = time(NULL);
//shellSort(arr);
//selectSort(arr);
//quickSort(arr, 0, N - 1);
//qsort(arr, N, sizeof(int), myCompare); //qsort函数的使用,非递归版本的快速排序
//heapSort(arr);
mergeSort(arr, brr, 0, N - 1);
time_t endTime = time(NULL);
printf("Total time = %lld s\n", endTime - begTime);
//partition(arr, 0, N - 1);
//print(arr);
}
void print(int *arr) {
for (int i = 0; i < N; ++i) {
printf("%3d", arr[i]);
}
printf("\n");
}
//0 冒泡排序
void bubbleSort(int *arr) {
for (int i = N-1; i > 0; --i) {
for (int j = 0; j < i; ++j) {
if(arr[j] > arr[j + 1]) {
SWAP(arr[j], arr[j + 1]);
}
}
}
}
//1 选择排序
void selectSort(int *arr) {
for (int i = 0; i < N - 1; ++i) {
//i 最小值将要放入的下标
//待比较的数据的下标范围 i ~ N-1
int minPos = i; //存储最小值的下标
for (int j = i + 1; j < N; ++j) {
// j 待比较的数据的下标
if (arr[minPos] > arr[j]) {
minPos = j;//更新minPos
}
}
SWAP(arr[i], arr[minPos]);
}
}
//2 插入排序
void insertSort(int *arr) {
for (int i = 1; i < N; ++i) {
//i表示来牌的下标
int insertVal = arr[i];//复制一份来牌
int j;//表示探查的手牌下标 比较之后牌要拷贝到j+1的位置
for (j = i - 1; j >= 0 && arr[j] > insertVal; --j) {
arr[j + 1] = arr[j];
}//退出循环时,j = -1 或者 arr[j] < insertVal
arr[j + 1] = insertVal;
}
}
//3 希尔排序
void shellSort(int *arr) {
for (int d = N / 2; d >= 1; d >>= 1) {
for (int i = d; i < N; ++i) {
int insertVal = arr[i];
int j;
for (j = i - d; j >= 0 && arr[j] > insertVal; j -= d) {
arr[j + d] = arr[j];
}
arr[j + d] = insertVal;
}
}
}
//4 快速排序,分而治之思想,递归
void quickSort(int *arr, int left, int right) {
if (left < right) {//数组中至少2个元素
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
}
int partition(int *arr, int left, int right) {
//i用来遍历,j表示比arr[right]大的那部分数据的最左端边界
int i, j;
for (i = left, j = left; i < right; ++i) {
if (arr[i] < arr[right]) {
SWAP(arr[i], arr[j]);
++j;
}
}
SWAP(arr[j], arr[right]);
return j;
}
//qsort中的回调函数实现
int myCompare(const void* p1, const void *p2) {
int *pleft = (int *)p1;
int *pright = (int *)p2;
return *pleft - *pright;
}
//调整堆
void adjustMaxHeap(int *arr, int pos, int len) {
//pos 调整的起点的下标 李渊的下标 编号pos+1
//左孩子编号2*pos+2 左孩子下标2*pos+1 右孩子下标 = 左孩子下标+1
//len 当前堆的规模
//最后一个结点的下标len-1
int dad = pos;
int son = 2 * pos + 1;
while (son < len) {
//如果son在堆内
// 1 兄弟阋墙
if (son + 1 < len && arr[son] < arr[son + 1]) {
++son;//右孩子存在且比左孩子强
}
// 2 父子反目
if (arr[son] > arr[dad]) {
SWAP(arr[son], arr[dad]);
dad = son;
son = 2 * dad + 1; // 李渊坐在原来李世民的位置,接受手下的挑战
}
else {
break;//李渊的位置坐稳了
}
}
}
//5 堆排序
//整体步骤:1、对无序数据进行建堆操作 2、循环执行,交换堆顶和末尾,重新调整成大根堆,缩小堆的规模,重新建堆
void heapSort(int *arr) {
//最后一个结点的编号是N 父亲的编号是N/2 下标是N/2-1
for (int i = N / 2 - 1; i >= 0; --i) {
//i表示父结点的下标
adjustMaxHeap(arr, i, N);
}//这个循环的目的从无序元素中建立大根堆
SWAP(arr[0], arr[N - 1]);
for (int i = N - 1; i >= 2; --i) {
//i表示堆的规模
adjustMaxHeap(arr, 0, i);//交换之后,从根出发调整堆
SWAP(arr[0], arr[i - 1]);//交换堆顶和末尾
}
}
//归并排序的合并操作
void merge(int *arr, int *brr, int left, int mid, int right) {
//把原来的数据从arr拷贝到brr
memcpy(brr + left, arr + left, (right - left + 1) * sizeof(int));
int i, j, k;
//i 用遍历左半边 j用来遍历右半边 k指向结果
for (i = left, j = mid + 1, k = left; i <= mid && j <= right; ++k) {
if (brr[i] < brr[j]) {
arr[k] = brr[i];
++i;
}
else {
arr[k] = brr[j];
++j;
}
}
while (i <= mid) {//右半边放完了
arr[k] = brr[i];
++i;
++k;
}
while (j <= right) {//左半边放完了
arr[k] = brr[j];
++j;
++k;
}
}
//6 归并排序
void mergeSort(int *arr, int *brr, int left, int right) {
if (left < right) {//至少有两个元素
int mid = (left + right) / 2;
mergeSort(arr, brr, left, mid);//排序左半边
mergeSort(arr, brr, mid + 1, right);//排序右半边
merge(arr, brr, left, mid, right);//合并有序的左右两个半边
}
}
//7 计数排序
void countSort(int *arr) {
//创建一个计数的数组
int count[M] = {0};
for (int i = 0; i < N; ++i) {
++count[arr[i]];
}
for (int i = 0, j = 0; i < M; ++i) {
//i表示count数组的下标
//j表示重建之后arr数组的下标
for (int k = 0; k < count[i]; ++k) {
//k用来根据count[i]的值,控制写回的次数
arr[j] = i;
++j;
}
}
}