/*实现内容
*
* 一、插入排序 平均 最坏 辅助存储
* ①直接插入排序 n² n² 1
* ②折半插入排序 n² n² 1
* ③希尔排序 和所取增量函数delt有关
* 二、交换排序
* ①冒泡排序 n² n² 1
* ②快速排序 nlogn n² logn(栈空间)
* 三、选择排序
* ①简单选择排序 n² n² 1
* ②堆排序 nlogn nlogn 1
* 四、归并排序 nlogn nlogn n
* 五、基数排序 dn dn rd
*
* 堆、快速、希尔 不稳定
* 注意基数排序需要关键字的个数相同,也就是说 数字位数要一样 比如都是个位数、两位数、三位数
*
* VS2019编译通过 王大花 2019.8.21
*
*/
/*实现内容
*
* 一、插入排序 平均 最坏 辅助存储
* ①直接插入排序 n² n² 1
* ②折半插入排序 n² n² 1
* ③希尔排序 和所取增量函数delt有关
* 二、交换排序
* ①冒泡排序 n² n² 1
* ②快速排序 nlogn n² logn(栈空间)
* 三、选择排序
* ①简单选择排序 n² n² 1
* ②堆排序 nlogn nlogn 1
* 四、归并排序 nlogn nlogn n
* 五、基数排序 dn dn rd
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define Number_Num 12
#define Max_Stack_Size 100
#define Radix 10
#define Max_Key_Num 2
//非递归需要用到的栈以及函数
typedef struct _StackNode {
int head;
int tail;
}StackNode;
typedef struct _Stack {
StackNode* SNode;
int tail;
}Stack;
void InitStack(Stack* S) {
S->SNode = (StackNode*)malloc(sizeof(StackNode) * Max_Stack_Size);
S->tail = 0;
}
void Push(Stack* S, int head, int tail) {
S->SNode[S->tail].head = head;
S->SNode[S->tail++].tail = tail;
}
StackNode Pop(Stack* S) {
return S->SNode[--S->tail];
}
//基数排序需要的结构
typedef struct _SLNode {
int key;
int next;
}SLNode;
typedef struct _SLList {
SLNode* r;
//关键字个数
int KeyNum;
}SLList;
int* Get_Rand_Num() {
int* tmp = (int*)malloc(sizeof(int) * (Number_Num + 1));
if (NULL == tmp)
return NULL;
for (int i = 1; i <= Number_Num; i++)
tmp[i] = rand() % 100;
return tmp;
}
void Print(int* Num) {
for (int i = 1; i <= Number_Num; i++)
printf("%d ", Num[i]);
printf("\n");
}
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
// 一、插入排序(0号为哨兵)
// (1)直接插入排序
void Insert_Sort(int* Num) {
//1号自己肯定有序 然后把后面的元素往前面有序队列里面插入
for (int i = 2; i <= Number_Num; i++) {
//如果新数字比上一个数字小 就把新的数字赋给哨兵 然后把上一个数字移到这个数字的位置
if (Num[i] < Num[i - 1]) {
Num[0] = Num[i];
int pos;
//寻找应该插入的位置
for (pos = i - 1; Num[pos] > Num[0]; pos--)
Num[pos + 1] = Num[pos];
Num[pos + 1] = Num[0];
}
}
}
// (2)折半插入排序(注意看的是high)
void Binary_Insert_Sort(int* Num) {
for (int i = 2; i <= Number_Num; i++) {
if (Num[i] < Num[i - 1]) {
Num[0] = Num[i];
int high = i - 1, low = 1, mid;
while (high >= low) {
mid = (high + low) / 2;
if (Num[mid] > Num[0])
high = mid - 1;
else if (Num[mid] < Num[0])
low = mid + 1;
else break;
}
for (int j = i; j > high + 1; j--)
Num[j] = Num[j - 1];
Num[high + 1] = Num[0];
}
}
}
// (3)①希尔排序辅助函数(间距为n的直接插入排序)
void Sup_Shell_Sort(int* Num, int n) {
for (int i = 1; i <= Number_Num; i++) {
for (int j = i + n; j <= Number_Num; j += n) {
if (Num[j] < Num[j - n]) {
int tmp = Num[j], pos;
for (pos = j - n; Num[pos] > tmp && pos >= i; pos -= n)
Num[pos + n] = Num[pos];
Num[pos + n] = tmp;
}
}
}
}
// (3)②希尔排序
void Shell_Insert_Sort(int* Num) {
//创建▲序列
int delt[4] = { 5,3,2,1 };
for (int i = 0; i < 4; i++)
Sup_Shell_Sort(Num, delt[i]);
}
//二、交换排序
//(1)冒泡排序
void Bubble_Sort(int* Num) {
for (int i = 0; i < Number_Num; i++) {
int pos, min = INT_MAX, flag = 0;
for (int j = i; j < Number_Num; j++) {
if (Num[j] < min) {
flag = 1;
min = Num[j];
pos = j;
}
}
if (!flag)
break;
Swap(Num + pos, Num + i);
}
}
// (2)快速排序
// ①快速排序(递归)
void Quick_Sort(int* Num, int head, int tail) {
if (head >= tail)
return;
int i = head, j = tail;
while (i < j) {
while (i < j && Num[head] <= Num[j])
j--;
while (i < j && Num[head] >= Num[i])
i++;
Swap(Num + i, Num + j);
}
Swap(Num + head, Num + i);
Quick_Sort(Num, head, i - 1);
Quick_Sort(Num, i + 1, tail);
}
// ②快速排序(非递归)
void Quick_Sort2(int* Num) {
Stack S;
InitStack(&S);
Push(&S, 1, Number_Num);
while (0 != S.tail) {
StackNode tmp = Pop(&S);
int mid = (tmp.head + tmp.tail) / 2;
int i = tmp.head, j = tmp.tail;
while (i < j) {
while (i < j && Num[tmp.head] <= Num[j])
j--;
while (i < j && Num[tmp.head] >= Num[i])
i++;
Swap(Num + i, Num + j);
}
Swap(Num + tmp.head, Num + i);
if (tmp.head < i - 1)
Push(&S, tmp.head, i - 1);
if (i + 1 < tmp.tail)
Push(&S, i + 1, tmp.tail);
}
}
//三、选择排序
// (1)直接选择排序
void Select_Sort(int* Num) {
for (int i = 1; i <= Number_Num; i++) {
int min = INT_MAX, pos;
for (int j = i; j <= Number_Num; j++) {
if (Num[j] < min) {
min = Num[j];
pos = j;
}
}
Swap(Num + pos, Num + i);
}
}
// (2)堆排序
//一开始建堆的时候 从n/2 -> 1 之后调整的时候自上而下
// ①调整成小根堆
void Heap_Adjust(int* Num, int n, int max) {
while (2 * n <= max) {
//只有左儿子的特殊情况
if (2 * n + 1 > max) {
if (Num[2 * n] < Num[n])
Swap(Num + 2 * n, Num + n);
break;
}
if (Num[n] > Num[2 * n] || Num[n] > Num[2 * n + 1]) {
if (Num[2 * n] < Num[2 * n + 1]) {
Swap(Num + 2 * n, Num + n);
n *= 2;
}
else {
Swap(Num + 2 * n + 1, Num + n);
n = 2 * n + 1;
}
}
else
break;
}
}
// ②堆排序
void Heap_Sort(int* Num) {
//建立小根堆
for (int i = Number_Num / 2; i > 0; i--)
Heap_Adjust(Num, i, Number_Num);
printf("堆排序后:\t\t");
//输出堆顶,再继续调整堆
for (int i = Number_Num; i > 0; i--) {
printf("%d ", Num[1]);
Swap(Num + 1, Num + i);
Heap_Adjust(Num, 1, i - 1);
}
printf("\n\n");
}
// 四、归并排序
// 归并(把Num数组上的两组数[head,mid],[mid+1,tail]合并到一个数组pos上)
void Merge(int* Num, int* pos, int head, int mid, int tail) {
int i = head, j = mid + 1, k = head;
while (i < mid + 1 && j <= tail) {
if (Num[i] < Num[j])
pos[k++] = Num[i++];
else
pos[k++] = Num[j++];
}
while (i < mid + 1)
pos[k++] = Num[i++];
while (k <= tail)
pos[k++] = Num[j++];
}
//归并排序
void Merge_Sort(int* Num, int* pos, int head, int tail) {
int tmp[Number_Num + 1];
if (head == tail) {
pos[head] = Num[head];
return;
}
Merge_Sort(Num, tmp, head, (head + tail) / 2);
Merge_Sort(Num, tmp, (head + tail) / 2 + 1, tail);
Merge(tmp, pos, head, (head + tail) / 2, tail);
}
// 五、基数排序
//分配函数 把串好的静态链表按照关键字大小重新分配(注意还有f、e数组所指也要更新) n代表第几个关键字
void Distribute(SLList S, int n, int* f, int* e) {
//初始化头尾指针
for (int i = 0; i < Radix; i++) {
f[i] = e[i] = 0;
}
//S.r[0].next类似于链表的头指针
for (int p = S.r[0].next; 0 != p; p = S.r[p].next) {
int tmp = S.r[p].key;
for (int i = 1; i < n; i++)
tmp /= 10;
tmp %= 10;
//如果此位没有数字
if (0 == f[tmp]) {
f[tmp] = p;
e[tmp] = p;
}
else {
S.r[e[tmp]].next = p;
e[tmp] = p;
}
}
}
//Collect辅助函数 找到n后方第一个非空结点
int Find_Next_Node(int n, int* f) {
for (int i = n + 1; i < Radix; i++)
if (0 != f[i])
return i;
return 0;
}
//把分散的各个结点重新组合 收集成一个链表
void Collect(SLList S, int* f, int* e) {
//找到第一个非空结点
int pre;
for (pre = 0; pre < Radix; pre++) {
if (0 != f[pre])
break;
}
//更改头指针
S.r[0].next = f[pre];
int cur;
for (cur = Find_Next_Node(pre, f); 0 != cur; pre = cur, cur = Find_Next_Node(pre, f))
S.r[e[pre]].next = f[cur];
//更新尾结点
S.r[e[pre]].next = 0;
}
//基数排序 注意数字位数要一样 比如都是两位数 都是三位数
void Radix_Sort(int* Num) {
//建立、初始化静态链表 f、e指针组
int* f = (int*)malloc(sizeof(int) * Radix), * e = (int*)malloc(sizeof(int) * Radix);
SLList S;
S.r = (SLNode*)malloc(sizeof(SLNode) * (1 + Number_Num));
for (int i = 0; i <= Number_Num; i++) {
S.r[i].key = Num[i];
S.r[i].next = i + 1;
}
S.r[Number_Num].next = 0;
S.KeyNum = Number_Num;
//有几个关键字 就分配收集几次
for (int i = 1; i <= Max_Key_Num; i++) {
Distribute(S, i, f, e);
Collect(S, f, e);
}
//更新Num数组
int tmp = S.r[0].next;
for (int i = 1; i <= Number_Num; i++) {
Num[i] = S.r[tmp].key;
tmp = S.r[tmp].next;
}
}
int main() {
srand((unsigned)time(NULL));
int* Num = Get_Rand_Num();
printf("数组内的元素为:\t");
Print(Num);
printf("插入排序后:\t\t");
Insert_Sort(Num);
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Binary_Insert_Sort(Num);
printf("折半插入排序后:\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Shell_Insert_Sort(Num);
printf("希尔排序后:\t\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Bubble_Sort(Num);
printf("冒泡排序后:\t\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Quick_Sort(Num, 1, Number_Num);
printf("快速排序(递归)后:\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Quick_Sort2(Num);
printf("快速排序(非递归)后:\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Select_Sort(Num);
printf("选择排序后:\t\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Heap_Sort(Num);
Num = Get_Rand_Num();
printf("数组内的元素为:\t");
Print(Num);
Merge_Sort(Num, Num, 1, Number_Num);
printf("归并排序后:\t\t");
Print(Num);
Num = Get_Rand_Num();
printf("\n数组内的元素为:\t");
Print(Num);
Radix_Sort(Num);
printf("基数排序后:\t\t");
Print(Num);
return 0;
}
C语言实现五大排序算法(插入、交换、选择、归并、基数)
最新推荐文章于 2022-06-11 20:07:53 发布