1. 冒泡排序
2. 选择排序
3. 插入排序
4. 基数排序
5. 快速排序
6. 归并排序
1.冒泡排序
时间复杂度:O(n^2)
空间复杂度:O(1)
**核心思路:**每次比较相邻的元素,将大的元素交换至后面,每一堂操作会将最大值“冒泡”到数组后面。操作次数=待排序数组长度-1
代码演示:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define swap(a, b) {__typeof(a) __temp = a; a = b; b = __temp;}
//start,end:对arr[start] ~arr[end]进行排序
void bubbleSort(int *arr, int start, int end){
for(int i = start; i < end; i++){
for(int j = start; j < end; j++){
if(arr[j] > arr[j + 1]) swap(arr[j], arr[j + 1]);
}
}
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc(sizeof(int) * n);
for(int i = 0; i < n; i++){
scanf("%d", &arr[i]);
}
bubbleSort(arr, 0, n - 1);
for(int i = 0; i < n; i++){
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
2.选择排序
时间复杂度:O(n^2)
空间复杂度:O(1)
**核心思路:**将数组看成两个部分:已排序和未排序。每次寻找未排序部分的最小值,将最小(大)值与未排序部分的第一个元素交换,然后将已排序部分+1,未排序部分-1
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define swap(a, b){__typeof(a) __temp = a; a = b; b = __temp;}
void selectionSort(int *arr, int start, int end){
for(int i = start; i < end; i++){//[start, i)有序,[i, end]无序
int minId = i;
//在无序区间选最小值
for(int j = i; j <= end; j++){
minId = arr[j] < arr[minId] ? j : minId;
}
swap(arr[minId], arr[i]);
}
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc (sizeof(int *) * n);
for(int i = 0; i < n; i++){
scanf("%d", &arr[i]);
}
selectionSort(arr, 0, n - 1);
for(int i = 0; i < n; i++){
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
3.插入排序
时间复杂度:O(n^2)【最好是O(n)】
空间复杂度O(1)
**核心思路:**遍历每个元素,不断和它前面的元素交换直到当前元素比它前面的元素大(小)
**特点:**数组越有序,算法越高效
#include<stdio.h>
#include <stdlib.h>
#define swap(a, b){__typeof(a) __temp = a; a = b; b = __temp;}
void insertionSort(int *arr, int start, int end){
for(int i = start; i <= end; i++){
for(int j = i; j > start; j--){
if(arr[j] >= arr[j - 1]) break;
swap(arr[j], arr[j - 1]);
}
}
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc (sizeof(int) * n);
for(int i = 0; i < n; i++) scanf("%d", &arr[i]);
insertionSort(arr, 0, n - 1);
for(int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
return 0;
}
4.基数排序(桶排序)
不依靠比较的排序
时间复杂度:O(n * k)【k是数字长度】
空间复杂度:O(n)
**核心思路:**使用LSD(Least Significant Digital)方式排序。从最末位到最高位,将数字放入不同的“桶”中,从“桶”中取出数字,即完成一次排序。排序数字位数次后(eg:最长数为100,就是3次),数组有序
#include<stdio.h>
#include <stdlib.h>
//可以用10 * n的数组做桶
//也可以用队列、链表等
//这里用顺序表
typedef struct Vector{
int *data;
int total, len;
} Vector;
Vector * initVector(int total){
Vector *v = (Vector *) malloc (sizeof(Vector));
v->data = (int *) malloc (sizeof(int) * total);
v->total = total;
v->len = 0;
return v;
}
void insertToTail(Vector *v, int val){
if(!v) return ;
if(v->len == v->total) return ;
v->data[v->len] = val;
++ v->len;
}
int isEmpty(Vector *v){
return !v || v->len == 0;
}
int getLength(int num){
if(num == 0) return 1;
int temp = 0;
while(num){
num /= 10;
++temp;
}
return temp;
}
int max(int a, int b){
return a > b ? a : b;
}
//找到num的第base位
int getIndex(int num, int base){
int j = num % 10; //可以用12345模拟一下
for(int i = 0; i < base; i++){
num /= 10;
j = num % 10;
}
return j;
}
void clear(Vector *v){
v->len = 0;
}
//基数排序,依赖数字位数进行排序的算法
void radixSort(int *arr, int start, int end){
int maxLength = 0; //基数排序最多执行多少次
for(int i = start; i < end; i++){
maxLength = max(getLength(arr[i]), maxLength);
}
//10个桶
Vector **v = (Vector **) malloc(sizeof(Vector *) * 10);
for(int i = 0; i < 10; i++){
v[i] = initVector(end - start + 1);
}
//base: 取第base位数
//123 -> base == 0 --> 3
//123 -> base == 1 --> 2
//123 -> base == 2 --> 1
for(int base = 0; base < maxLength; base++){
for(int i = start; i <= end; i++){
int j = getIndex(arr[i], base);
//把arr[i]放到j桶里
insertToTail(v[j], arr[i]);
}
int index = start;
for(int i = 0; i < 10; i++){
//将j桶的数字拿出来,并放回arr[idx]
for(int j = 0; j < v[i]->len; j++){
arr[index] = v[i]->data[j];
++index;
}
//清除桶里的元素
clear(v[i]);
}
printf("No %d : ", base);
for(int i = start; i <= end; i++){
printf("%d ", arr[i]);
}
printf("\n");
}
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc (sizeof(int) * n);
for(int i = 0; i < n; i++) scanf("%d", &arr[i]);
radixSort(arr, 0, n - 1);
for(int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
return 0;
}
5.快速排序(内排序)
时间复杂度:O(n*log(n)) [均摊] 【有分配不均的问题】
空间复杂度:O(log(n))
是一种高效的排序算法,使用先 对数组进行分区 然后 向下递归的方法实现。先分区再递归
3 4 1 5 6 7 9 0 2 8
①选择基准值 pivot = 5, 设置两个指针(i, j)分别指向数组首尾
②左指针向右移,找到第一个 >= 5的数字
③右指针向左移,找到第一个 <= 5的数字
③交换两个指针所指的数字,左指针右移一格,右指针左移一格
④循环上述步骤直到两个指针相逢
将左边的部分和右边的部分分别递归处理,递归处理的两个片段也分别进行递归,当递归片段长度为1时,停止向下递归,递归结束后数组有序。
时间复杂度分析:
由于pivot的选择将直接影响快速排序的执行效率,因此最坏的情况下会退化为O(n^2)
为避免这种情况,需要谨记:不要选择首尾元素作为pivot
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define swap(a, b){__typeof(a) __temp = a; a = b; b = __temp; }
void quick_sort(int *arr, int start, int end){
if(start >= end) return ;
int pivot = arr[(start + end) >> 1];
int i = start, j = end;
while(i <= j){
while(i <= j && arr[i] < pivot) ++i;
while(i <= j && arr[j] > pivot) --j;
if(i <= j){
swap(arr[i], arr[j]);
++i, --j;
}
}
quick_sort(arr, start, j);
quick_sort(arr, i, end);
}
void quick_sort2(int *arr, int start, int end){
if(start >= end) return ;
int pivot = arr[(start + end) >> 1];
int i = start - 1, j = end + 1; //取边界
while(i < j){
do ++i; while(arr[i] < pivot);
do --j; while(arr[j] > pivot);
if(i < j) swap(arr[i], arr[j]);
}
quick_sort2(arr, start, j);
quick_sort2(arr, j + 1, end);
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc(sizeof(int) * n);
for(int i = 0; i < n; i++){
scanf("%d", &arr[i]);
}
quick_sort(arr, 0, n - 1);
for(int i = 0; i < n; i++){
printf("%d ", arr[i]);
}
return 0;
}
6.归并排序(外排序)
归并排序也是一种比较高效的排序算法,使用先递归拆分数组然后对分区一次合并的方法实现。先递归再合并。与快速排序不同,归并排序的分区一定是对半分,递归深度为log(n)。
3 4 1 5 6 7 9 0 2 8
①开辟一段临时存放数据的空间,然后设置两个指针分别指向两个子区间的第一个元素
②比较两个指针所指元素大小,将小的放入临时数组,并将对应指针后移
③将临时数组中的元素覆盖到原数组上
归并排序是一种时空复杂度都不会变化的排序算法。无论原数组的有序性如何,时间复杂度均为O(n * log(n)),空间复杂度同样为O(n * log(n))
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#define swap(a, b) {__typeof(a) __temp = a; a = b; b = __temp; }
void mergeSort(int *arr, int start, int end){
if(start >= end) return ;
int mid = (start + end) >> 1;
//归(分)
mergeSort(arr, start, mid);
mergeSort(arr, mid + 1, end);
//并(治)
int i = start, j = mid + 1;
int *temp = (int *) malloc (sizeof(int) * (end - start + 1));
int k = 0;
while(i <= mid || j <= end){
if(j > end || (arr[i] <= arr[j] && i <= mid)){
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
memcpy(arr + start, temp, sizeof(int) * k);
//for(int i = start; i <= end; i++) arr[i] = temp[i - start];
}
void mergeSort2(int *arr, int l, int r){
if(l >= r) return ;
int mid = (l + r) >> 1;
mergeSort2(arr, l, mid), mergeSort2(arr, mid + 1, r);
int k = 0, i = 1, j = mid + 1;
int *temp = (int *) malloc(sizeof(int) * (r - l + 1));
while(i <= mid && j <= r){
if(arr[i] <= arr[j]) temp[k++] = arr[i++];
else temp[k++] = arr[j++];
}
while(i <= mid) temp[k++] = arr[i++];
while(j <= r) temp[k++] = arr[j++];
for(int i = l, j = 0; i <= r; i++, j++) arr[i] = temp[j];
}
int main(){
int n;
scanf("%d", &n);
int *arr = (int *) malloc (sizeof(int) * n);
for(int i = 0; i < n; i++) scanf("%d", &arr[i]);
mergeSort(arr, 0, n - 1);
for(int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
return 0;
}
要是对您有帮助,点个赞再走吧~ 欢迎评论区讨论~