十大经典排序算法
参考网站
2.【十大经典排序算法(C语言描述)】https://www.bilibili.com/video/BV1nN4y1M7JK?p=6&vd_source=57dbe1b7ae720516dd577f4132a0370e
分类
1.交换类
1.冒泡排序(一个基于交换的数组,每一轮搜索这个序列的最大值,并将这个最大值放在序列的尾部)
#include<stdio.h>`
#include<stdlib.h>
#include<time.h>
`//自定义数组最大长度`
`#define MAXSIZE 10`
`//取随机数`
`void initArr(int arr[], int length) {`
`for (int i = 0; i < length;i++) {`
`arr[i] = rand() % 20;//20以内的随机数`
`}`
`}`
`//打印随机数`
`void showArr(int arr[],int length) {`
`for (int i = 0; i < length; i++) {`
`printf("%d ", arr[i]);`
`}`
`printf("\n------------------------------------------------\n");`
`}`
`//给随机数排序`
`void bubSort(int arr[],int length) {`
`while (length--) {`
`for (int i = 0; i < length; i++) {`
`if (arr[i] > arr[i + 1]) {`
`int temp = arr[i];`
`arr[i] = arr[i + 1];`
`arr[i + 1] = temp;`
`}`
`}`
`}`
`}`
`int main() {`
`srand((unsigned int)time(NULL));//设置随机数种子,不然每次随机到的数都是一样的`
`int arr[MAXSIZE];`
`initArr(arr,MAXSIZE);`
`showArr(arr,MAXSIZE);`
`bubSort(arr,MAXSIZE);`
`showArr(arr,MAXSIZE);`
`return 0;`
`}`
-
优化后(加入flag后,最大值和之前一样排到最后,但是之前的序列已经完成排序,就可以不用再进行循环)
`#include<stdio.h>` `#include<stdlib.h>` `#include<time.h>` `//自定义数组最大长度` `#define MAXSIZE 10` `//取随机数` `void initArr(int arr[], int length) {` `for (int i = 0; i < length;i++) {` `arr[i] = rand() % 20;//20以内的随机数` `}` `}` `//打印随机数` `void showArr(int arr[],int length) {` `for (int i = 0; i < length; i++) {` `printf("%d ", arr[i]);` `}` `printf("\n------------------------------------------------\n");` `}` `//给随机数排序` `void bubSort(int arr[],int length) {` `int flag=1;` `while (length--&&flag) {` `flag=0;` `for (int i = 0; i < length; i++) {` `flag=1;` `if (arr[i] > arr[i + 1]) {` `int temp = arr[i];` `arr[i] = arr[i + 1];` `arr[i + 1] = temp;` `}` `}` `}` `}` `int main() {` `srand((unsigned int)time(NULL));//设置随机数种子,不然每次随机到的数都是一样的` `int arr[MAXSIZE];` `initArr(arr,MAXSIZE);` `showArr(arr,MAXSIZE);` `bubSort(arr,MAXSIZE);` `showArr(arr,MAXSIZE);` `return 0;` `}`
2.快速排序(冒泡排序的优化版本,核心思想:使用轴,每一轮左右递归后,把轴放在中间,使轴左边都比轴小,右边都比轴大,当所有的递归都结束以后就自然排好序了)
- 优化前:不适用于单链表,只适用于顺序存储
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAXSIZE 10
//获取随机数
void initArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 100;
}
}
//打印序列
void showArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
printf("\n--------------------------------------\n");
}
//快速排序
void quickSort(int arr[],int left,int right) {
if (left>=right) {return;}//函数出口
int i = left;
int j = right;
int pviot = arr[i];//轴的初始值
while(i<j){
while (i<j&&arr[j]>pviot) {
j--;
}//先从右往左找比轴大的值
arr[i] = arr[j];//找到以后j暂时代替轴的位置
while (i<j&&arr[i]<pviot) {
i++;
}//从左往右找比轴小的值
arr[j] = arr[i];//找到以后赋值给j的位置
}
arr[i] = pviot;
quickSort(arr,left,i-1);//轴左边开始递归
quickSort(arr,i+1,right);//轴右边开始递归
}
int main() {
int arr[MAXSIZE];
srand((unsigned)time(NULL));
initArr(arr, MAXSIZE);
showArr(arr, MAXSIZE);
quickSort(arr,0,MAXSIZE-1);
showArr(arr, MAXSIZE);
return 0;
}
-
;优化后:适用于链式存储
#include<stdio.h> #include<stdlib.h> #include<time.h> #define MAXSIZE 10 //获取随机数 void initArr(int arr[], int length) { for (int i = 0; i < length; i++) { arr[i] = rand() % 100; } } //打印序列 void showArr(int arr[], int length) { for (int i = 0; i < length; i++) { printf("%d ", arr[i]); } printf("\n--------------------------------------\n"); } //交换 void swap(arr[],int i,int j){ int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } //快速排序 void quickSort(int arr[],int left,int right) { if (left>=right) {return;}//函数出口,函数出口一般放在函数开头 int pviot = arr[left];//轴的初始值 int i = left + 1; int j = right + 1 ; while(j<=right){ if(arr[j]<pviot){ swap(arr,i,j); i++; } j++; } swap(arr,left,i-1); quickSort(arr,left,i-2);//轴左边开始递归 quickSort(arr,i,right);//轴右边开始递归 } int main() { int arr[MAXSIZE]; srand((unsigned)time(NULL)); initArr(arr, MAXSIZE); showArr(arr, MAXSIZE); quickSort(arr,0,MAXSIZE-1); showArr(arr, MAXSIZE); return 0; }
2.分配类
1.计数排序(统计原来数组的数据,并将数据转换成下标存储在一个临时的空间中,然后变量临时空间把对应的下标值放回原数组,当遍历临时空间完成后,原来的数组就是排好序了)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
//打印序列
void showArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
printf("\n----------------------------------------\n");
}
void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
int temp[100];//偷懒写法:临时数组
void countSort(int arr[],int length) {
for (int i = 0; i < length;i++) {
temp[arr[i]]++;//把arr[i]的数值当作temp的下标
}
for (int i = 0, j = 0; i < 100;i++) {
while (temp[i]--) {
arr[j++] = i;
}
}
}
int main() {
int arr[MAXSIZE];
srand((unsigned)time(NULL));
initArr(arr, MAXSIZE);
showArr(arr, MAXSIZE);
countSort(arr, MAXSIZE);
showArr(arr, MAXSIZE);
return 0;
}
2.基数排序(统计序列数的最大位数,第一轮从100开始,第二轮从101开始,以此类推,统计每轮相应位数的最大值,并放在最前面,直到最后)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
//打印序列
void showArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
printf("\n----------------------------------------\n");
}
void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
int temp[10][100];
void redixSort(int arr[],int length) {
for (int k = 10; k < 10000;k*=10) {
for (int i = 0; i < length;i++) {
int j = 0;
int pos = (arr[i] % k) / (k / 10);
while (temp[pos][j]) {
j++;
}
temp[pos][j] = arr[i];
}
int pos = 0;
for (int i = 0; i < 10;i++) {
for (int j = 0; j < length&& temp[i][j] != 0;j++) {
arr[pos++] = temp[i][j];
temp[i][j] = 0;
}
}
}
}
int main() {
int arr[MAXSIZE];
srand((unsigned)time(NULL));
initArr(arr, MAXSIZE);
showArr(arr, MAXSIZE);
redixSort(arr, MAXSIZE);
showArr(arr, MAXSIZE);
return 0;
}
3.选择类
1.选择排序(快速排序是在冒泡排序的基础上,每一轮找到序列中的最小值后和第一个元素进行交换,以此类推)
`#include<stdio.h>`
`#include<stdlib.h>`
`#include<time.h>`
`define MAXSIZE 10`
`//取随机数`
`void initArr(int arr[],int length) {`
`for (int i = 0; i < length; i++) {`
`arr[i] = rand() % 20;`
`}`
`}`
`//打印随机数`
`void showArr(int arr[], int length) {`
`for (int i = 0; i < length;i++) {`
`printf("%d ",arr[i]);`
`}`
`printf("\n----------------------------------------\n");`
`}`
`//给序列排序`
`void selectSort(int arr[],int length) {`
`for (int i = 0; i < length - 1;i++) {`
`int k = i;`
`for (int j = i + 1; j < length;j++) {`
`if(arr[k]>arr[j]) {`
`k = j;`
`}`
`}`
`int temp = arr[i];`
`arr[i] = arr[k];`
`arr[k] = temp;`
`}`
`}`
`int main() {`
`srand((unsigned int)time(NULL));`
`int arr[MAXSIZE];`
`initArr(arr, MAXSIZE);`
`showArr(arr, MAXSIZE);`
`selectSort(arr, MAXSIZE);`
`showArr(arr, MAXSIZE);`
`return 0;`
`}`
2.堆排序(本质上就是一个完全二叉树,每一个节点的存储都是连续的)
- 大顶堆
- 父亲的权值比左右子树的权值大
- 小顶堆
- 父亲的权值比左右子树的权值小
当前下标为current
-
从0开始计数
- 左子树–>2*current+1
- 右子树–>2*current+2
-
从1开始计数
- 左子树–>2*current
- 右子树–>2*current+1
-
外堆
- 需要一段和原来数组长度大小的内存空间,这段内存空间是用来存储堆结构的(用小顶堆)
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
//打印序列
void showArr(int arr[], int length) {
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
printf("\n----------------------------------------\n");
}
void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//堆结构
typedef struct Heap {
int* root;
int length;
}Heap;
//入堆申请内存
Heap* creatHeap(int length) {
Heap* heap = (Heap*)malloc(sizeof(Heap));
assert(heap);
heap->length = 0;
heap->root = (int*)malloc(sizeof(int) * length);
assert(heap->root);
return heap;
}
//入堆
void pushHeap(Heap* heap,int data) {
int current = heap->length++;
int parent = current / 2;//求父亲下标
heap->root[current] = data;
while (parent != current) {
if (heap->root[current] < heap->root[parent]) {
swap(heap->root, current, parent);
current = parent;
parent = current / 2;
}
else
break;
}
}
//出堆
int popHeap(Heap* heap) {
int val = heap->root[0];
int current = 0;
int rchild = 2 * current+2;
int small;
heap->root[0] = heap->root[--heap->length];
while (rchild <= heap->length) {
small = heap->root[rchild - 1] < heap->root[rchild] ? rchild - 1 : rchild;
if (heap->root[small] < heap->root[current]) {
swap(heap->root, small, current);
current = small;
rchild = 2 * current + 2;
}
else
break;
}
return val;
}
//堆排序
void heapSort(int arr[],int length) {
Heap* heap = creatHeap(MAXSIZE);
for (int i = 0; i < MAXSIZE; i++) {
pushHeap(heap, arr[i]);
}
for (int i = 0; i < MAXSIZE; i++) {
arr[i] = popHeap(heap);
}
}
int main() {
int arr[MAXSIZE];
srand((unsigned)time(NULL));
initArr(arr, MAXSIZE);
showArr(arr, MAXSIZE);
heapSort(arr,MAXSIZE);
showArr(arr, MAXSIZE);
return 0;
}
- 内堆
- 不需要重新申请内存,直接在原来的数组上排序(用大顶堆)
void heapify(int arr[], int length, int current) {
int rchild = 2 * current + 2;
int large;
while (rchild <= length) {
large = rchild == length ? rchild - 1 : (arr[rchild - 1] > arr[rchild] ? rchild - 1 : rchild);
if (arr[large] > arr[current]) {
swap(arr, large, current);
current = large;
rchild = current * 2 + 2;
}
else
break;
}
}
//内堆
void heapSort2(int arr[], int length) {
int current = length / 2;
while (current >= 0) {
heapify(arr, length, current);
current--;
}
while (length) {
swap(arr, 0, --length);
heapify(arr, length, 0);
}
}
4.归并类
归并排序(基于分而治之的思想,拿两个已经有序的序列重新组合成一个有序的新序列)
- 优化前
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[],int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
//打印序列
void showArr(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ",arr[i]);
}
printf("\n----------------------------------------\n");
}
//归并排序
//默认a和b数组都是有序的
void mergeSort(int a[], int alen,int b[],int blen,int* temp) {
int i = 0;//a下标初始化
int j = 0;//b下标初始化
int k = 0;//新数组下标初始化
while (i < alen && j < blen) {
if (a[i]<b[j]) {
temp[k] = a[i];
i++;
k++;
}
else {
temp[k] = b[j];
j++;
k++;
}
}
while (i < alen) {
temp[k] = a[i];
i++;
k++;
}
while (j < blen) {
temp[k] = b[j];
j++;
k++;
}
}
//手动输入序列
void scanfArr(int arr[]) {
printf("Please add arr:");
for (int i = 0; i < MAXSIZE;i++) {
scanf_s("%d", &arr[i]);
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr1[5] = { 1,3,5,7,9 };//序列a
int arr2[5] = { 2,4,6,8,10 };//序列b
int temp[10];//新序列
mergeSort(arr1, 5, arr2, 5, temp);
showArr(temp,10);
return 0;
}
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<assert.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[],int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
//打印序列
void showArr(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ",arr[i]);
}
printf("\n----------------------------------------\n");
}
//归并
void merge(int arr[],int low,int mid,int height,int* temp) {
int i = low;
int j = mid + 1;
int k = low;
while (i<=mid&&j<=height) {
temp[k++] = arr[i] < arr[j] ? arr[i++] : arr[j++];
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= height) {
temp[k++] = arr[j++];
}
//重新排列
for (i = low; i <= height;i++) {
arr[i] = temp[i];
}
}
//划分序列
void merge_sort(int arr[],int low,int height,int* temp) {
if (low>=height) {
return;
}
int mid = low + (height - low) / 2;//求mid
merge_sort(arr, low, mid, temp);//划分小的部分
merge_sort(arr, mid+1, height, temp);//划分大的部分
merge(arr, low, mid, height, temp);//合并序列
}
//最终归并的函数
void mergeSort(int arr[],int length) {
int* temp = (int*)malloc(sizeof(int) * length);//申请空间
assert(temp);
merge_sort(arr, 0, length - 1, temp);
free(temp);
}
int main() {
int arr[MAXSIZE];
srand((unsigned)time(NULL));
initArr(arr, MAXSIZE);
showArr(arr, MAXSIZE);
mergeSort(arr,MAXSIZE);
showArr(arr, MAXSIZE);
return 0;
}
5.插入类
1.插入排序(优点是序列已经基本有序时,再将一个新的数据插入进来比较方便,效率较高)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAXSIZE 10
//随机获取序列
void initArr(int arr[],int length) {
for (int i = 0; i < length; i++) {
arr[i] = rand() % 20;
}
}
void showArr(int arr[],int length) {
for (int i = 0; i < length;i++) {
printf("%d ",arr[i]);
}
printf("\n----------------------------------------\n");
}
//插入排序
void insertSort(int arr[],int length) {
for (int i = 1; i < length;i++) {
for (int j = i; j > 0 && arr[j] < arr[j-1];j--) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
//手动输入序列
void scanfArr(int arr[]) {
printf("Please add arr:");
for (int i = 0; i < MAXSIZE;i++) {
scanf_s("%d", &arr[i]);
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int arr[MAXSIZE];
srand((unsigned int)time(NULL));
/*initArr(arr,MAXSIZE);
showArr(arr, MAXSIZE);*/
scanfArr(arr);
insertSort(arr, MAXSIZE);
showArr(arr, MAXSIZE);
return 0;
}
2.希尔排序(优化版的插入排序,原数组很大的情况适用.如果插入排序步长是1,那么希尔排序步长可以更大,然后逐渐减小直到1形成插入排序)
-
优化前(步数是自己定义的,需要自己计算)
#include<stdio.h> #include<stdlib.h> #include<time.h> #define MAXSIZE 1000 //获取随机数 void initArr(int arr[],int length) { for (int i = 0; i < length;i++) { arr[i] = rand() % 100; } } //打印序列 void showArr(int arr[], int length) { for (int i = 0; i < length; i++) { printf("%d ", arr[i]); } printf("\n--------------------------------------\n"); } //希尔排序 void shellSort(int arr[], int length) { int h = 4; while(h>=1) { for (int i = h; i < length;i++) { for (int j = i; j >= h && arr[j] < arr[j - 1];j-=h) { int temp = arr[j]; arr[j] = arr[j - h]; arr[j - h] = temp; } } h /= 2; } } int main() { int arr[MAXSIZE]; srand((unsigned)time(NULL)); initArr(arr, MAXSIZE); showArr(arr, MAXSIZE); shellSort(arr, MAXSIZE); showArr(arr, MAXSIZE); return 0; }
-
优化后(步数是自动计算的,根据3*n+1来算需要的步数)
理想的希尔排序序列为:1,4,10,…,3*n+1.
#include<stdio.h> #include<stdlib.h> #include<time.h> #define MAXSIZE 1000 //获取随机数 void initArr(int arr[],int length) { for (int i = 0; i < length;i++) { arr[i] = rand() % 100; } } //打印序列 void showArr(int arr[], int length) { for (int i = 0; i < length; i++) { printf("%d ", arr[i]); } printf("\n--------------------------------------\n"); } //希尔排序 void shellSort(int arr[], int length) { int h = 1;//初始化h int t = length / 3;//根据经典的希尔排序(3*n+1),来使其靠近这个数值 while (h < t) { h = 3 * h + 1;//经典希尔排序序列,循环到最适合的h } while(h>=1) { for (int i = h; i < length;i++) { for (int j = i; j >= h && arr[j] < arr[j - 1];j-=h) { int temp = arr[j]; arr[j] = arr[j - h]; arr[j - h] = temp; } } h /= 3;//前面有3*n,所以要除以3 } } int main() { int arr[MAXSIZE]; srand((unsigned)time(NULL)); initArr(arr, MAXSIZE); showArr(arr, MAXSIZE); shellSort(arr, MAXSIZE); showArr(arr, MAXSIZE); return 0; }