六种排序算法详解(含代码演示)

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;
}

要是对您有帮助,点个赞再走吧~ 欢迎评论区讨论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值