选择排序,冒泡排序,快速排序,归并排序,计数排序

随便先发点东西吧,慢慢记录。。
从排序开始,毕竟去年我倒在了排序上。

选择排序,冒泡排序,快速排序,归并排序,计数排序————5个排序

这里的例子都是从小到大的,c语言。
我觉得一般情况下应该够用了吧,不够的话以后在学。。。

选择排序

应该是最简单的排序方式了吧?

void SelectSort(int arr[], int num)    //选择排序, 每次都将最小的数字放在i位上。
{
    
    
    int temp;
    for (int i = 0; i < num; i++) {
    
    
        for (int j = i + 1; j < num; j++) {
    
    
            if (arr[i] > arr[j]) {
    
    
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

冒泡排序

谭浩强书上的第2个排序算法,还是比较好理解的,和选择排序一样主要都是注意循环的开始和条件。

void BubbleSort(int arr[], int num)    //冒泡排序,两两比较,每次都把小的放前面
{
    
    
    int temp;
    for (int i = 0; i < num; i++) {
    
          //每次循环后数列的最后(num - j)位会变成还未排序的数字中的最大值
        for (int j = 0; j < num-i-1; j++) {
    
    
            if(arr[j] > arr[j + 1])
            {
    
    
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

快速排序

找一个基准数,把小于它的放左边,大于它的放右边。
然后把在左边的元素作为一个数组拿出来,重复上面的操作,右边同理。这样一直重复到两边被挑出来的数组中的元素少于两个

void QuickSort(int arr[],int left, int right)   //快速排序
{
    
    
    if (left >= right) {
    
          //当区域内的元素少于两个时此区域 无法排序/已经排序完成 。
        return ;
    }
    
    int temp, i, j, pivot;
    pivot = arr[right];         //基准数,每次都用数组的最后一个元素作为基准数
    i = left;         //标记位,标记较小的元素应该放置的位置
    
    for (j = left; j < right; j++) {
    
    
        if (arr[j] < pivot) {
    
         //如果元素小于基准数,那么将其移动到从left开始的左边
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;
        }
    }
    
    temp = arr[i];       //将基准数移动到i的位置,此时,左边的所有数都小于基准数,右边的所有数都大于基准数
    arr[i] = pivot;
    arr[right] = temp;
    
    QuickSort(arr, left, i - 1);      //用同样的方法处理基准数左边的所有元素
    QuickSort(arr, i + 1, right);     //用同样的方法处理基准数右边的所有元素
}

归并排序

由两个函数组成,调用的时候调用MergeSort()。
用网上的图片来解释吧。绿色的数字是在程序中执行的顺序。
归并排序
就是把数组分分分,分到单个元素,然后把相邻的两个 数组/元素 排序合在一起,合合合再合回去。
MergeSort()是用来把数组分成两个,以及调用merge()的。
merge()用来将在上一个数组被分出来的两个数组排序的。

void merge(int arr[], int left, int middle, int right)
{
    
    
    int i, j, k;
    int n1 = middle - left + 1;      //前半段的数组的元素的个数
    int n2 = right - middle;         //后半段的数组的元素的个数
    
    int L[n1], R[n2];                //用于保存两个数组
    for (i = 0; i < n1; i++) {
    
    
        L[i] = arr[left + i];
    }
    for (i = 0; i < n2; i++) {
    
    
        R[i] = arr[middle + 1 + i];
    }
    
    i = 0;            //前半段L数组的指针位置/标记位
    j = 0;            //后半段R数组的指针位置/标记位
    k = left;         //位于原数组上的指针位置/标记位
    
    while(i < n1 && j < n2)          //将被标记的两个元素中小的那个放在原数组的标记位上
    {
    
                                //并将指向较小元素的指针和指向原数组的指针分别加一。
        if (L[i] < R[j]) {
    
              //当两者中任一数组的所有元素被放回了原数组,那么结束循环
            arr[k++] = L[i++];
//            i++;
        } else {
    
    
            arr[k++] = R[j++];
//            j++;
        }
//        k++;
    }
    
    while(i < n1)       //将另一个数组中的剩余元素放回原数组
    {
    
    
        arr[k++] = L[i++];
    }
    while(j < n2)
    {
    
    
        arr[k++] = R[j++];
    }
}

void MergeSort(int arr[], int left, int right)
{
    
    
    if (left < right) {
    
            //当区域内的元素少于两个时此区域 无法排序/已经排序完成 。
        int middle = left + ( right - left ) / 2;    //分界元素的位置,即从left到middle(包括middle)在内都是
                                                     //前半段的数组,从middle+1开始到right都是后半段
        MergeSort(arr, left, middle);                 //对前半段进行同样的处理/排序
        MergeSort(arr, middle + 1, right);             //处理/排序后半段
        
        merge(arr, left, middle, right);               //排序
        
    }
}

计数排序

没有用比较,但很厉害啊我觉得。
建立一个数组,用来记住每个元素出现的次数,再依次放回去。

//在C中使用要引入stdlib.h和string.h两个库。
void CountSort(int arr[],int num)
{
    
    
    int min = arr[0], max = arr[0];
    int i, j = 0;
    
    for (i = 0; i < num; i++) {
    
         //找到数组的最大值与最小值
        if (arr[i] < min) {
    
    
            min = arr[i];
        }
        if (arr[i] > max) {
    
    
            max =  arr[i];
        }
    }
    int sum = max - min + 1;      //假设最大值最小值之间所有整数都存在的话,那么共有这么多数
//    int *temp = (int*) malloc(sizeof(int) * sum);
//    memset(temp, 0, sum*sizeof(int));        //将数组的所有值设置为0
                                 //memset()的用途是将temp地址后面的sum*sizeof(int)个字节长度的空间的值设置为0(也就是第2个参数的值)
    int *temp = calloc(sum, sizeof(int));       //动态分配,创建一个 数组/指针 用来存数组中每个元素的出现次数,calloc会把每个元素默认设置为0
    for (i = 0; i < num; i++) {
    
         //元素每出现一次,那么就在temp数组相应的位置加一
        temp[arr[i] - min]++;
    }
    
    for ( i = 0; i < sum; i++) {
    
         //temp中每个元素的值就是(下标+min)的出现次数,从小到大放回原数组里
        while(temp[i]-- > 0)
        {
    
    
            arr[j++] = i + min;
        }
    }
    free(temp);    //释放动态空间
}

5个排序的总集,还有用来测试的傻乎乎的代码

// 部分排序算法的训练和模版
//  
//  c语言

#include <stdio.h>
#include <string.h>     //计数排序中的memset()函数
#include <stdlib.h>     //计数排序中的free()函数

void SelectSort(int arr[], int num)    //选择排序, 每次都将最小的数字放在i位上。
{
    
    
    int temp;
    for (int i = 0; i < num; i++) {
    
    
        for (int j = i + 1; j < num; j++) {
    
    
            if (arr[i] > arr[j]) {
    
    
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    printf("SelectSort:\n");
}

void BubbleSort(int arr[], int num)    //冒泡排序,两两比较,每次都把小的放前面
{
    
    
    int temp;
    for (int i = 0; i < num; i++) {
    
          //每次循环后数列的最后(num - j)位会变成还未排序的数字中的最大值
        for (int j = 0; j < num - i; j++) {
    
    
            if(arr[j] > arr[j + 1])
            {
    
    
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    printf("BubbleSort:\n");
}

void QuickSort(int arr[],int left, int right)   //快速排序
{
    
    
    if (left >= right) {
    
          //当区域内的元素少于两个时此区域 无法排序/已经排序完成 。
        return ;
    }
    
    int temp, i, j, pivot;
    pivot = arr[right];         //基准数,每次都用数组的最后一个元素作为基准数
    i = left;         //标记位,标记较小的元素应该放置的位置
    
    for (j = left; j < right; j++) {
    
    
        if (arr[j] < pivot) {
    
         //如果元素小于基准数,那么将其移动到从left开始的左边
            temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;
        }
    }
    
    temp = arr[i];       //将基准数移动到i的位置,此时,左边的所有数都小于基准数,右边的所有数都大于基准数
    arr[i] = pivot;
    arr[right] = temp;
    
    QuickSort(arr, left, i - 1);      //用同样的方法处理基准数左边的所有元素
    QuickSort(arr, i + 1, right);     //用同样的方法处理基准数右边的所有元素
}

void merge(int arr[], int left, int middle, int right)
{
    
    
    int i, j, k;
    int n1 = middle - left + 1;      //前半段的数组的元素的个数
    int n2 = right - middle;         //后半段的数组的元素的个数
    
    int L[n1], R[n2];                //用于保存两个数组
    for (i = 0; i < n1; i++) {
    
    
        L[i] = arr[left + i];
    }
    for (i = 0; i < n2; i++) {
    
    
        R[i] = arr[middle + 1 + i];
    }
    
    i = 0;            //前半段L数组的指针位置/标记位
    j = 0;            //后半段R数组的指针位置/标记位
    k = left;         //位于原数组上的指针位置/标记位
    
    while(i < n1 && j < n2)          //将被标记的两个元素中小的那个放在原数组的标记位上
    {
    
                                //并将指向较小元素的指针和指向原数组的指针分别加一。
        if (L[i] < R[j]) {
    
              //当两者中任一数组的所有元素被放回了原数组,那么结束循环
            arr[k++] = L[i++];
//            i++;
        } else {
    
    
            arr[k++] = R[j++];
//            j++;
        }
//        k++;
    }
    
    while(i < n1)       //将另一个数组中的剩余元素放回原数组
    {
    
    
        arr[k++] = L[i++];
    }
    while(j < n2)
    {
    
    
        arr[k++] = R[j++];
    }
}

void MergeSort(int arr[], int left, int right)
{
    
    
    if (left < right) {
    
            //当区域内的元素少于两个时此区域 无法排序/已经排序完成 。
        int middle = left + ( right - left ) / 2;    //分界元素的位置,即从left到middle(包括middle)在内都是
                                                     //前半段的数组,从middle+1开始到right都是后半段
        MergeSort(arr, left, middle);                 //对前半段进行同样的处理/排序
        MergeSort(arr, middle + 1, right);             //处理/排序后半段
        
        merge(arr, left, middle, right);               //排序
        
    }
}


void CountSort(int arr[],int num)
{
    
    
    int min = arr[0], max = arr[0];
    int i, j = 0;
    
    for (i = 0; i < num; i++) {
    
         //找到数组的最大值与最小值
        if (arr[i] < min) {
    
    
            min = arr[i];
        }
        if (arr[i] > max) {
    
    
            max =  arr[i];
        }
    }
    int sum = max - min + 1;      //假设最大值最小值之间所有整数都存在的话,那么共有这么多数
//    int *temp = (int*) malloc(sizeof(int) * sum);
//    memset(temp, 0, sum*sizeof(int));        //将数组的所有值设置为0
                                 //memset()的用途是将temp地址后面的sum*sizeof(int)个字节长度的空间的值设置为0(也就是第2个参数的值)
    int *temp = calloc(sum, sizeof(int));       //动态分配,创建一个 数组/指针 用来存数组中每个元素的出现次数,calloc会把每个元素的值设置为0
    for (i = 0; i < num; i++) {
    
         //元素每出现一次,那么就在temp数组相应的位置加一
        temp[arr[i] - min]++;
    }
    
    for ( i = 0; i < sum; i++) {
    
         //temp中每个元素的值就是(下标+min)的出现次数,从小到大放回原数组里
        while(temp[i]-- > 0)
        {
    
    
            arr[j++] = i + min;
        }
    }
    free(temp);    //释放动态空间
    printf("CountSort:\n");
}

int main()
{
    
    
    
//    int arr[10] = {5,6,4,10,2,1,9,8,7,3};       //用于测试的两组数据。
    int arr[10] = {
    
    52,76,43,42,98,76,74,99,101,32};
    
    SelectSort(arr, 10);
    
//    BubbleSort(arr, 10);
    
//    printf("QuickSort:\n");
//    QuickSort(arr, 0, 9);
    
//    printf("MergeSort:\n");
//    MergeSort(arr, 0, 9);
    
//    CountSort(arr, 10);
    
    
    for (int i = 0; i < 10; i++) {
    
            //输出,来检查排序是否正确
        printf("%d  ",arr[i]);
    }
    printf("\n");
    
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cxujie/article/details/103256685