算法分析之排序(C语言)

算法分析之排序--C语言

排序函数具体操作

下面是函数具体操作:(文件名称:sort.c)

//FILE: sort.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

//函数声明
void bubbleSort(int *a, int n); //冒泡排序
void selectSort(int *a, int n); //选择排序
void insertSort(int *a, int n); //插入排序
void MergeArray(int *a, int begin, int mid, int end, int *temp); //归并排序(合并数组)
void MergeSort(int *a, int begin, int end, int *temp); //归并排序
void QuickSort_Recursion(int *a, int begin, int end); //快速排序(递归)
void PartitionQuickSort(int *a, int begin, int end); //快速排序(枢轴存放)
int NumberOfThree(int *a, int begin, int end);//枢轴为三数取中
void Swap(int *x, int *y); //数据交换
void CountSort(int *a, int size , int max); //计数排序
void RadixCountSort(int *a, int size); //基数排序
int arrayMax(int *arr, int size); //数组中的最大值
int getDigitNum(int x); //得到数据的位数

//函数具体操作
//冒泡排序
void bubbleSort(int *a, int n)
{
    int i, j, temp;

    for (i = 0; i < n - 1; i++)
    {
        for (j = 0; j < n - i; j++)
        {
            if (a[j] > a[j+1])
            {
                temp = a[j];
                a[j] = a[j + 1];
                a[j+1] = temp;
            }
        }
    }
}

//选择排序
void selectSort(int *a, int n)
{
    int i, j, min, temp;

    for (i = 0; i < n - 1; i++)
    {
        min = i;
        for (j = i + 1; j < n; j++)
        {
            if (a[min] > a[j])
            {
                min = j;
            }
        }
        temp = a[min];
        a[min] = a[i];
        a[i] = temp;
    }
}

//插入排序
void insertSort(int *a,int n)
{
    int i, j, temp;
    for(i = 1; i < n; i++)
    {
        temp = a[i];
        for(j = i - 1; j >= 0 && a[j] > temp; j--)
        {
            a[j + 1] = a[j];
        }
        a[j + 1] = temp;
    }
}

//归并排序(合并数组)
void MergeArray(int *a,int begin,int mid,int end,int *temp)
{
    int k = begin;
    int left_begin = begin, left_end = mid;
    int right_begin = mid + 1, right_end = end;

    while(left_begin <= left_end && right_begin <= right_end)
    {
        if(a[left_begin] < a[right_begin])
        {
            temp[k++] = a[left_begin++];
        }
        else
        {
            temp[k++] = a[right_begin++];
        }
    }

    while(left_begin <= left_end)
    {
        temp[k++] = a[left_begin++];
    }
    while(right_begin <= right_end)
    {
        temp[k++] = a[right_begin++];
    }

    for(k = begin; k <= end; k++)
    {
        a[k] = temp[k];
    }
}

//归并排序
void MergeSort(int *a,int begin,int end,int *temp)
{
    if(begin >= end)
    {
        return;
    }
    else
    {
        int mid = (begin + end) / 2;
        MergeSort(a, begin, mid, temp);
        MergeSort(a, mid + 1, end, temp);
        MergeArray(a, begin, mid, end, temp);
    }
}

//快速排序(递归)
void QuickSort_Recursion(int *a, int begin, int end)
{
    int i = begin, j = end;
    int temp;
    int pivot = a[begin]; //选取第一个元素为基准点
    
    while(i <= j)
    {
        //找到左边大于基准点的元素
        while(a[i] < pivot)
        {
            i++;
        }
        //找到右边小于基准点的元素
        while(a[j] > pivot)
        {
            j--;
        }

        //当左边下标小于右边时,互换元素
        if(i <= j)
        {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
            //互换后i, j继续靠近
            i++;
            j--;
        }
    }

    //左边进行递归
    if(i < end)
    {
        QuickSort_Recursion(a, i, end);
    }
    //右边进行递归
    if(begin < j)
    {
        QuickSort_Recursion(a, begin, j);
    }
}

//快速排序(枢轴存放)
void PartitionQuickSort(int *a, int begin, int end)
{
    int i = begin, j = end;
    int temp;
    int pivot = NumberOfThree(a, begin, end); //三数取中作为基准元素
    
    while(i <= j)
    {
        //找到左边大于基准点的元素
        while(a[i] < pivot)
        {
            i++;
        }
        //找到右边小于基准点的元素
        while(a[j] > pivot)
        {
            j--;
        }

        //当左边下标小于右边时,互换元素
        if(i <= j)
        {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
            //互换后i, j继续靠近
            i++;
            j--;
        }
    }

    //左边进行递归
    if(i < end)
    {
        QuickSort_Recursion(a, i, end);
    }
    //右边进行递归
    if(begin < j)
    {
        QuickSort_Recursion(a, begin, j);
    }
}

//枢轴为三数取中
int NumberOfThree(int *a,int begin,int end)
{
	int mid = (begin + end) / 2 + begin;
 
	if (a[mid] > a[end])
	{
		Swap(&a[mid], &a[end]);
	}
	if (a[begin] > a[end])
	{
		Swap(&a[begin], &a[end]);
	}
	if (a[mid] > a[begin]) 
	{
		Swap(&a[mid], &a[begin]);
	}
	//此时a[mid] <= a[begin] <= a[end]
	return a[begin];
}

//数据交换
void Swap(int *x, int *y)
{
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

//计数排序
void CountSort(int *a, int size , int max)
{
    int i;
    int *count, *sorted;
    
    //给计数器和已排序数组分配空间
    count = (int *)malloc(sizeof(int) * (max + 1));
    sorted = (int *)malloc(sizeof(int) * size);
    if(count == NULL || sorted == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }
    
    //计数数组初始化为0
    for(i = 0; i < max + 1; i++)
    {
        count[i] = 0;
    }
    //收集原数组中每种值的个数
    for(i = 0; i < size; i++)
    {
        count[a[i]]++;
    }
    //统计所有小于等于该值的元素个数
    for(i = 1; i < max + 1; i++)
    {
        count[i] += count[i - 1];
    }
    //将所有元素按收集表分配到对应位置,反向填充目标数组
    for(i = size - 1; i >= 0; i--)
    {
        //先将计数数组中对应值-1
        count[a[i]]--;
        sorted[count[a[i]]] = a[i];
    }
    //已排序数组替代原数组
    for(i = 0; i < size; i++)
    {
        a[i] = sorted[i];
    }

    //释放内存
    free(count);
    free(sorted);
}

/* 下面是基数排序,第二个在第一个的基础上进行了优化,
改变了循环位数的方法,在20万个范围为0-999的随机数的排序测试下,
第一个基数排序耗时十几分钟,第二个基数排序耗时十几毫秒(质的飞跃) */

/* //基数排序
void RadixCountSort(int *a,int size)
{
    int base = 10; //基数设为10
    int i, n, index, max, maxnum, pval;
    int *count, *sorted;
    
    //计算数组中的最大值
    max = arrayMax(a, size);
    //计算数据最高位
    maxnum = getDigitNum(max);
    
    //给计数器和已排序数组分配空间
    count = (int *)malloc(sizeof(int) * base); 
    sorted = (int *)malloc(sizeof(int) * size);
    if(count == NULL || sorted == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }

    for(n = 0; n < maxnum; n++)
    {
        //计数数组初始化为0
        for(i = 0; i < base; i++)
        {
            count[i] = 0;
        }
        //计算位置值
        pval = pow(base, n);
        //统计当前位上每个数值出现的次数
        for(i = 0; i < size; i++)
        {
            index = a[i] / pval % base;
            count[index]++;
        }
        //统计所有小于等于该值的元素个数
        for(i = 1; i < base; i++)
        {
            count[i] += count[i - 1];
        }
        //将所有元素按收集表分配到对应位置
        for(i = size - 1; i >= 0; i--)
        {
            index = a[i] / pval % base;
            count[index]--;
            sorted[count[index]] = a[i];
        }
        //已排序数组替代原数组
        memcpy(a, sorted, sizeof(int) * size);
    }

    //释放内存
    free(count);
    free(sorted);
} */

//优化后的基数排序
void RadixCountSort(int *a,int size)
{
    int i, index, max;
    int rad = 1; //从个位开始
    int *count, *sorted;
    
    //计算数组中的最大值
    max = arrayMax(a, size);
    
    //给计数器和已排序数组分配空间
    count = (int *)malloc(sizeof(int) * 10); 
    sorted = (int *)malloc(sizeof(int) * size);
    if(count == NULL || sorted == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }

    while(max / rad > 0)
    {
        //计数数组初始化为0
        for(i = 0; i < 10; i++)
        {
            count[i] = 0;
        }
        //统计当前位上每个数值出现的次数
        for(i = 0; i < size; i++)
        {
            index = a[i] / rad % 10;
            count[index]++;
        }
        //统计所有小于等于该值的元素个数
        for(i = 1; i < 10; i++)
        {
            count[i] += count[i - 1];
        }
        //将所有元素按收集表分配到对应位置
        for(i = size - 1; i >= 0; i--)
        {
            index = a[i] / rad % 10;
            count[index]--;
            sorted[count[index]] = a[i];
        }
        //已排序数组替代原数组
        for(i = 0; i < size; i++)
        {
            a[i] = sorted[i];
        }
        rad *= 10; //位数乘10
    }

    //释放内存
    free(count);
    free(sorted);
}

//求数组最大值
int arrayMax(int *arr, int size)
{
    int i, max = arr[0];
    for(i = 0; i < size; i++)
    {
        if(arr[i] > max)
        {
            max = arr[i];
        }
    }
    return max;
}

//得到数据的位数
int getDigitNum(int x)
{
    if(x == 0)
    {
        return 1;
    }
    else
    {
        int res;//数据最高位
        while(x != 0)
        {
            x /= 10;
            res++;
        }
        return res;
    }
}

main函数

下面是调用排序函数(文件名称:sort_main.c)

//FILE: sort_main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<windows.h>
#include "sort.c"

//main函数
int main(void)
{
    int len, max, i; //数组长度,数组最大值,计数器
    int *data; //存入原始数据
    int *arr1, *arr2, *arr3, *arr4, *arr5, *arr6, *arr7, *arr8; //进行各种排序的数组
    int *temp = NULL;

    printf("没有写防脸滚键盘的功能,测试的时候请按要求输入!\n");
    //录入数据
    printf("请输入数组长度:");
    scanf("%d", &len);
    data = (int *)malloc(sizeof(int) * len);
    if(data == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    printf("请录入整型数据(以回车间隔):\n");
    for(i = 0; i < len; i++)
    {
        scanf("%d", data + i);
    }
    //打印原始数据
    printf("数据录入完毕\n录入的数据为:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(data + i));
    }
    printf("\n");

    //进行冒泡排序
    arr1 = (int *)malloc(sizeof(int) * len);
    if(arr1 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr1, data, sizeof(int) * len);
    bubbleSort(arr1, len);
    printf("冒泡排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr1 + i));
    }
    printf("\n");

    //进行选择排序
    arr2 = (int *)malloc(sizeof(int) * len);
    if(arr2 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr2, data, sizeof(int) * len);
    selectSort(arr2, len);
    printf("选择排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr2 + i));
    }
    printf("\n");

    //进行插入排序
    arr3 = (int *)malloc(sizeof(int) * len);
    if(arr3 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr3, data, sizeof(int) * len);
    insertSort(arr3, len);
    printf("插入排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr3 + i));
    }
    printf("\n");

    //进行归并排序
    arr4 = (int *)malloc(sizeof(int) * len);
    if(arr4 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    temp = (int *)malloc(sizeof(int) * len);
    if(temp == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr4, data, sizeof(int) * len);
    MergeSort(arr4, 0, len - 1, temp);
    printf("归并排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr4 + i));
    }
    free(temp);
    printf("\n");

    //进行快速排序(递归)
    arr5 = (int *)malloc(sizeof(int) * len);
    if(arr5 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr5, data, sizeof(int) * len);
    QuickSort_Recursion(arr5, 0, len - 1);
    printf("快速排序(递归)后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr5 + i));
    }
    printf("\n");

    //进行快速排序(枢轴存放)
    arr6 = (int *)malloc(sizeof(int) * len);
    if(arr6 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr6, data, sizeof(int) * len);
    PartitionQuickSort(arr6, 0, len - 1);
    printf("快速排序(枢轴存放)后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr6 + i));
    }
    printf("\n");

    //进行计数排序
    arr7 = (int *)malloc(sizeof(int) * len);
    if(arr7 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr7, data, sizeof(int) * len);
    //找到数组中的最大值
    max = arrayMax(arr7, len);
    CountSort(arr7, len, max);
    printf("计数排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr7 + i));
    }
    printf("\n");

    //进行基数排序
    arr8 = (int *)malloc(sizeof(int) * len);
    if(arr8 == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        return -1;
    }
    memcpy(arr8, data, sizeof(int) * len);
    RadixCountSort(arr8, len);
    printf("基数排序后结果:\n");
    for(i = 0; i < len; i++)
    {
        printf("%d\t", *(arr8 + i));
    }
    printf("\n");

    //释放内存
    free(data);
    free(arr1);
    free(arr2);
    free(arr3);
    free(arr4);
    free(arr5);
    free(arr6);
    free(arr7);
    free(arr8);

    system("pause");
    return 0;
}

测试程序

下面是对排序算法的测试
PS:快排会压栈,测试快排请注释掉其他排序

//FILE: sort_test.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
#include<windows.h>
#include "sort.c"

//宏定义常量
#define LEN 10000 //测试大数据下排序的数组长度
#define N 100000 //执行次数
#define M 100 //每个数组的长度
#define RANGE 1000 //随机数范围

int main(void)
{
    int i, j, max;
    int test1[LEN], test2[M];
    int *temp;
    clock_t start, end;
    //生成大数据
    for(i = 0; i < LEN; i++) //生成LEN个随机数
    {
        test1[i] = rand() % RANGE; //生成0~999的数据(range - 1)
    }

    //大数据测试
    printf("下面是%d个数据的排序情况:\n", LEN);
    
    //插入排序
    start = clock();
    insertSort(test1, LEN);
    end = clock();
    printf("插入排序:%d ms\n", end - start);
    
    //归并排序
    temp = (int *)malloc(sizeof(int) * LEN);
    if(temp == NULL)
    {
        printf("内存分配失败\n");
        system("pause");
        exit(0);
    }
    start = clock();
    MergeSort(test1, 0, LEN - 1, temp);
    end = clock();
    printf("归并排序:%d ms\n", end - start);
    free(temp);
    
    //快速排序(递归)
    start = clock();
    QuickSort_Recursion(test1, 0, LEN - 1);
    end = clock();
    printf("快速排序(递归):%d ms\n", end - start);
    
    //快速排序(枢轴存放)
    start = clock();
    PartitionQuickSort(test1, 0, LEN - 1);
    end = clock();
    printf("快速排序(枢轴存放):%d ms\n", end - start);
    
    //计数排序
    start = clock();
    max = arrayMax(test1, LEN);
    CountSort(test1, LEN, max);
    end = clock();
    printf("计数排序:%d ms\n", end - start);
    
    //基数排序
    start = clock();
    RadixCountSort(test1, LEN);
    end = clock();
    printf("基数排序:%d ms\n", end - start);

    //测试大量小数组
    //进行100k次排序,每次对大小为100的数组进行排序
    printf("下面测试大量小数组\n");

    //插入排序
    start = clock();
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        insertSort(test2, M);
    }
    end = clock();
    printf("插入排序:%d ms\n", end - start);

    //归并排序
    start = clock();
    for(i = 0; i < N; i++)
    {
        temp = (int *)malloc(sizeof(int) * M);
        if(temp == NULL)
        {
            printf("内存分配失败\n");
            system("pause");
            exit(0);
        }
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        MergeSort(test2, 0, M - 1, temp);
        free(temp);
    }
    end = clock();
    printf("归并排序:%d ms\n", end - start);

    //快速排序(递归)
    start = clock();
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        QuickSort_Recursion(test2, 0, M - 1);
    }
    end = clock();
    printf("快速排序(递归):%d ms\n", end - start);

    //快速排序(枢轴存放)
    start = clock();
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        PartitionQuickSort(test2, 0, M - 1);
    }
    end = clock();
    printf("快速排序(枢轴存放):%d ms\n", end - start);

    //计数排序
    start = clock();
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        max = arrayMax(test2, M);
        CountSort(test2, M, max);
    }
    end = clock();
    printf("计数排序:%d ms\n", end - start);

    //基数排序
    start = clock();
    for(i = 0; i < N; i++)
    {
        for(j = 0; j < M; j++)
        {
            test2[j] = rand() % RANGE;
        }
        RadixCountSort(test2, M);
    }
    end = clock();
    printf("基数排序:%d ms\n", end - start);

    system("pause");
    return 0;
}

以上就是全部内容,有错误还请在评论中指出来,一起学习,一起进步。还有很多的排序方法,有时间学习后再进行补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不要做码农呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值