C语言实现几种常见排序方法

目录

一、冒泡排序法

二、选择排序法

三、插入排序法

四、希尔排序法

五、快速排序法

六、归并排序法

七、堆排序法

八、基数排序法

九、桶排序法


一、冒泡排序法

        冒泡排序法的核心思想是比较相邻的元素,如果第一个比第二个大,就交换它们两个。对每一对相邻元素进行比较,将最大或最小的元素移动到数组末尾,直到没有任何一对数字需要比较。

#include <stdio.h>

void bubble_sort(int arr[], int len) {
    int i, j, temp;
    for (i = 0; i < len - 1; i++) {
        for (j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j+1]) {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    bubble_sort(arr, len);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 bubble_sort 的函数,该函数接受一个整型数组 arr 和数组长度 len 作为参数,对数组进行冒泡排序并修改原数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 bubble_sort 函数对数组进行排序,最后输出排序结果。

二、选择排序法

        选择排序法的核心思想是记录未排序数组的最小值或最大值,将其与无序部分的第一个元素交换位置,直到数组完全有序。其中,一次排序会确定当前无序区内的最小值或最大值,并将该值放置在正确的有序区位置上。

#include <stdio.h>

void selection_sort(int arr[], int len) {
    int i, j, temp;
    int min_index;
    for (i = 0; i < len - 1; i++) {
        min_index = i;
        for (j = i + 1; j < len; j++) {
            if (arr[min_index] > arr[j]) {
                min_index = j;
            }
        }
        if (min_index != i) {
            temp = arr[i];
            arr[i] = arr[min_index];
            arr[min_index] = temp;
        }
    }
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    selection_sort(arr, len);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 selection_sort 的函数,该函数接受一个整型数组 arr 和数组长度 len 作为参数,对数组进行选择排序并修改原数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 selection_sort 函数对数组进行排序,最后输出排序结果。

三、插入排序法

        插入排序法的核心思想是将待排序的数组分成两部分:已排序部分和未排序部分。从未排序部分取出第一个元素,与已排序部分从后向前比较,找到其应该插入的位置并插入。重复这个过程,直到未排序部分没有元素。其中,每次排序会将新的元素插入到已排序部分合适的位置,使得已排序部分保持有序。

#include <stdio.h>

void insertion_sort(int arr[], int len) {
    int i, j, temp;
    for (i = 1; i < len; i++) {
        temp = arr[i];
        j = i - 1;
        while (j >= 0 && arr[j] > temp) {
            arr[j+1] = arr[j];
            j--;
        }
        arr[j+1] = temp;
    }
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    insertion_sort(arr, len);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 insertion_sort 的函数,该函数接受一个整型数组 arr 和数组长度 len 作为参数,对数组进行插入排序并修改原数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 insertion_sort 函数对数组进行排序,最后输出排序结果。

四、希尔排序法

        希尔排序法是插入排序法的改进版本,其核心思想是将数组分割为若干个子序列,分别进行插入排序。通过逐步减小子序列的长度,并不断对整个数组进行插入排序,使得整个数组变得有序。希尔排序法中的增量序列可以设定很多种,如 Shell 增量、Hibbard 增量、Knuth 增量等,通常采用 Shell 增量。

#include <stdio.h>

void shell_sort(int arr[], int len) {
    int i, j, gap;
    int temp;
    for (gap = len / 2; gap > 0; gap /= 2) {
        for (i = gap; i < len; i++) {
            temp = arr[i];
            for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = temp;
        }
    }
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    shell_sort(arr, len);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 shell_sort 的函数,该函数接受一个整型数组 arr 和数组长度 len 作为参数,对数组进行希尔排序并修改原数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 shell_sort 函数对数组进行排序,最后输出排序结果。

五、快速排序法

        快速排序法是基于交换的排序算法,它采用了分治的思想。具体来说,每次选择一个基准值,将序列分为两个部分,左边部分都小于等于基准值,右边部分都大于等于基准值。然后递归地分别对左右两边部分进行排序,直到整个序列有序。通常采用双指针法,从左右两边同时向中间扫描找到需要交换的元素,然后进行交换。基准值的选取可以采用多种方式,如取第一个元素、取中间元素、取随机元素等,具体选取方式影响算法的效率。

#include <stdio.h>

void quick_sort(int arr[], int left, int right) {
    if (left >= right) {
        return;
    }

    int i = left, j = right;
    int pivot = arr[left];
    while (i < j) {
        while (i < j && arr[j] >= pivot) {
            j--;
        }
        arr[i] = arr[j];
        while (i < j && arr[i] <= pivot) {
            i++;
        }
        arr[j] = arr[i];
    }
    arr[i] = pivot;

    quick_sort(arr, left, i-1);
    quick_sort(arr, i+1, right);
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    quick_sort(arr, 0, len-1);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 quick_sort 的函数,该函数接受一个整型数组 arr、左边界 left 和右边界 right 作为参数,对数组进行快速排序并修改原数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 quick_sort 函数对数组进行排序,最后输出排序结果。

六、归并排序法

        归并排序法是基于比较的稳定排序算法,采用了分治的思想。具体来说,将待排序序列逐层划分为若干个子序列,每个子序列都是有序的,然后将相邻两个子序列进行合并,直到整个序列有序。合并过程中需要用到一个额外的数组来存储归并后的结果,最后将排序好的结果赋值给原数组。原始序列被均分成两个长度相等的子序列,直到子序列长度为1,然后将相邻两个子序列进行合并。

#include <stdio.h>
#include <stdlib.h>

void merge(int arr[], int left, int mid, int right) {
    int i = left, j = mid+1, k = 0;
    int* temp = (int*) malloc(sizeof(int) * (right-left+1));
    while (i <= mid && j <= right) {
        if (arr[i] <= arr[j]) {
            temp[k++] = arr[i++];
        } else {
            temp[k++] = arr[j++];
        }
    }
    while (i <= mid) {
        temp[k++] = arr[i++];
    }
    while (j <= right) {
        temp[k++] = arr[j++];
    }
    for (i = left, k = 0; i <= right; i++, k++) {
        arr[i] = temp[k];
    }
    free(temp);
}

void merge_sort(int arr[], int left, int right) {
    if (left >= right) {
        return;
    }
    int mid = left + (right - left) / 2;
    merge_sort(arr, left, mid);
    merge_sort(arr, mid+1, right);
    merge(arr, left, mid, right);
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    merge_sort(arr, 0, len-1);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        该程序使用了一个名为 merge 的函数,该函数接受一个整型数组 arr、左边界 left、中间位置 mid 和右边界 right 作为参数,对数组的左半部分和右半部分进行归并排序并修改原数组。在归并排序过程中,需要用到一个额外的数组来存储排序过程中产生的临时结果。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 merge_sort 函数对数组进行排序,最后输出排序结果。

七、堆排序法

        堆排序法是基于比较的不稳定排序算法,采用了大根堆(或小根堆)的数据结构来实现。首先将待排序序列建立成大根堆(或小根堆),然后将根节点与最后一个节点交换位置,这时候最后一个节点已经是有序的了,再对剩余部分的序列进行堆化,得到新的根节点,再将根节点与倒数第二个节点交换位置,以此类推,不断缩小排序范围,直到整个序列有序。堆排序需要额外的空间来存储堆结构,且常数因子较大。

#include <stdio.h>

void heapify(int arr[], int n, int i) {
    int largest = i;
    int l = 2*i+1, r = 2*i+2;
    if (l < n && arr[l] > arr[largest]) {
        largest = l;
    }
    if (r < n && arr[r] > arr[largest]) {
        largest = r;
    }
    if (largest != i) {
        int temp = arr[i];
        arr[i] = arr[largest];
        arr[largest] = temp;
        heapify(arr, n, largest);
    }
}

void heap_sort(int arr[], int n) {
    int i;
    for (i = n/2-1; i >= 0; i--) {
        heapify(arr, n, i);
    }
    for (i = n-1; i >= 0; i--) {
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
        heapify(arr, i, 0);
    }
}

int main() {
    int arr[] = {5, 2, 8, 3, 1};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    heap_sort(arr, len);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 heapify 的函数和一个名为 heap_sort 的函数,分别对整型数组进行堆化和堆排序。在堆化过程中,需要通过递归地调用该函数来维护大根堆的性质;在堆排序过程中,需要先将整个数组堆化,然后逐步将最大值交换到数组末尾,并重新堆化剩余部分的数组。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 heap_sort 函数对数组进行排序,最后输出排序结果。

八、基数排序法

        基数排序是一种非比较排序算法,采用了将数据按照位来比较的策略,由低位到高位依次对数据进行排序。它需要使用到计数排序或桶排序等线性时间复杂度的辅助排序算法,而且需要数据具有一定的范围限制和可比性。

#include <stdio.h>
#include <stdlib.h>

int get_digit(int num, int radix) {
    int digit = 1;
    while ((num /= radix) > 0) {
        digit++;
    }
    return digit;
}

int get_num_at_digit(int num, int digit, int radix) {
    int i;
    for (i = 1; i < digit; i++) {
        num /= radix;
    }
    return num % radix;
}

void radix_sort(int arr[], int n, int radix) {
    int i, j, k, digit, max_digit = 0;
    int* count = (int*) malloc(sizeof(int) * radix);
    int* bucket = (int*) malloc(sizeof(int) * n);

    for (i = 0; i < n; i++) {
        digit = get_digit(arr[i], radix);
        if (digit > max_digit) {
            max_digit = digit;
        }
    }

    for (k = 1; k <= max_digit; k++) {
        for (i = 0; i < radix; i++) {
            count[i] = 0;
        }
        for (i = 0; i < n; i++) {
            digit = get_num_at_digit(arr[i], k, radix);
            count[digit]++;
        }
        for (i = 1; i < radix; i++) {
            count[i] += count[i-1];
        }
        for (i = n-1; i >= 0; i--) {
            digit = get_num_at_digit(arr[i], k, radix);
            bucket[--count[digit]] = arr[i];
        }
        for (i = 0; i < n; i++) {
            arr[i] = bucket[i];
        }
    }
    free(count);
    free(bucket);
}

int main() {
    int arr[] = {35, 28, 98, 45, 67, 23, 10};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    radix_sort(arr, len, 10);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        该程序使用了一个名为 get_digit 的函数和一个名为 get_num_at_digit 的函数,分别用于获取一个整数的位数及某一位的数字;还使用了一个名为 radix_sort 的函数,基于计数排序的思想实现基数排序。在基数排序过程中,需要将待排序序列按照位数从低到高依次进行排序,每次排序需要使用计数排序对相应位上的数字进行排序。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 radix_sort 函数对数组进行排序,最后输出排序结果。

九、桶排序法

        桶排序是一种常用的排序算法,它需要根据数据的特点构建若干个桶,将数据分配到相应的桶中并对每个桶中的数据进行排序,最后按照桶的顺序依次输出所有数据。桶排序具有线性时间复杂度,但需要额外的存储空间来存放桶。

#include <stdio.h>
#include <stdlib.h>

void bucket_sort(int arr[], int n, int bucketSize) {
    int i, j, k;
    int* bucket;

    if (bucketSize <= 0) {
        return;
    }

    int min_value = arr[0], max_value = arr[0];
    for (i = 1; i < n; i++) {
        if (arr[i] < min_value) {
            min_value = arr[i];
        } else if (arr[i] > max_value) {
            max_value = arr[i];
        }
    }

    int bucket_count = (max_value - min_value) / bucketSize + 1;
    bucket = (int*) malloc(sizeof(int) * bucket_count);

    for (i = 0; i < bucket_count; i++) {
        bucket[i] = 0;
    }

    for (i = 0; i < n; i++) {
        bucket[(arr[i] - min_value) / bucketSize]++;
    }

    for (i = 1; i < bucket_count; i++) {
        bucket[i] += bucket[i-1];
    }

    int* results = (int*) malloc(sizeof(int) * n);
    for (i = n-1; i >= 0; i--) {
        j = (arr[i] - min_value) / bucketSize;
        results[--bucket[j]] = arr[i];
    }

    for (i = 0; i < n; i++) {
        arr[i] = results[i];
    }

    free(bucket);
    free(results);
}

int main() {
    int arr[] = {35, 28, 98, 45, 67, 23, 10};
    int len = sizeof(arr) / sizeof(int);
    int i;

    printf("排序前数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    bucket_sort(arr, len, 10);

    printf("排序后数组元素为:");
    for (i = 0; i < len; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

        使用了一个名为 bucket_sort 的函数来实现桶排序。在桶排序过程中,需要将待排序序列分配到若干个桶中,然后对每个桶中的数据进行排序,最后按照桶的顺序依次输出所有数据。主函数中定义了一个整型数组 arr,在使用 sizeof 获取数组长度后,调用 bucket_sort 函数对数组进行排序,最后输出排序结果。

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值