《啊哈!算法》 第一章 排序

前言

《啊哈!算法》是一本适用于小白的C语言算法书,里面的内容较为基础,这篇内容是我自学算法的记录,有些代码是个人的理解,与书上内容有所出入,内容如有错误,欢迎大家指正。


一、桶排序

5个数排序(数字在0 ~10之间)

#include <stdio.h>
int main(void)
{
    int a[11] = { 0 };    //初始化数组
    int i, j, k;
    for ( i = 0; i < 5; i++ )
    {
        scanf("%d", &k);    //输入5个数
        a[k]++;             //k每出现一次,对应的a[k]也会加1
    }
    // for ( i = 0; i < 11; i++)       //从小到大
    for ( i = 10; i >= 0; i-- )       //从大到小
    {
        for ( j = 0; j < a[i]; j++)
        {
            printf("%d ", i);        //a[i]是多少,就会打印多少次
        }
    }
    return 0;
}

初始化的数组中,数组的每一个元素都为0

若输入的数据为5,3,2,8,5

则变为a[2]=1,a[3]=1,a[5]=2,a[8]=1,其他元素仍为0    

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]]a[8]a[9]a[10]
00000000000
00110200100

输出则是按照数组下标进行输出

n个数排序(0~1000)(同理)

#include <stdio.h>
int main(void)
{
    int book[1001] = { 0 };    //初始化数组
    int i, j ,k, n;
    printf("Enter the total number: \n");
    scanf("%d", &n);        //输入n的值
    for ( i = 0; i < n; i++)
    {
        printf("%d: ", i + 1);
        scanf("%d", &k);
        book[k]++;
    }
    //从大到小输出数字,并且数字出现几次就输出几次
    for ( i = 1000; i >= 0; i--)
    {
        for ( j = 0; j < book[i]; j++)
        {
            printf("%d ", i);
        }
    }
    return 0;
}

 

二、冒泡排序

#include <stdio.h>
int main(void)
{
    int a[100] = { 0 };
    int i, j, t, n;
    scanf("%d", &n);    //确定输入的数字个数
    for (i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);    //依次输入数字
    }
    for (i = 1; i < n; i++)   // i的大小是从1到n-1,循环n-1次
    {
        for (j = 0; j < n - i; j++) //j是从0到n-i-1,循环n-i次
        {
            if (a[j] > a[j + 1])    //如果数组元素a[j]>a[k+1],就交换两个元素的值
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }
    for (i = 0; i < n; i++)        //输出数组中所有元素
    {
        printf("%d ", a[i]);
    }
    return 0;
}

示例:a[5] = {12, 35, 99, 18, 76}, 

ija[j]a[j+1]
101235
113599
129918
121899
139976
137699

 

j 的值从0~3,因为 i 的值为 1 ,j < n - i , 即 j < 4, 此时已经可以将最大值排到最后

此时,a[5]={12,35,18,76,99}; 

 

ija[j]a[j+1]
201235
213518
211835
223576

 

 

 同理,可将第二大的值排到倒数第二个位置,依此类推,可得结果

此时,a[5] = {12, 18, 35, 76, 99},该示例的排序已经完成,但循环仍要进行,直到 j 只能为0

 


name score
#include <stdio.h>
struct student
{
    char name[20];
    int score;
};

int main(void)
{
    struct student a[100], t;   //定义a[100]和t为结构体
    int i, j, n;
    scanf("%d", &n);
    for (i = 0; i < n; i++)     
    {
        scanf("%s %d", &a[i].name, &a[i].score);
    }
    for (i = 1; i < n; i++)
    {
        for (j = 0; j < n - i; j++)        //冒泡排序
        {
            if (a[j].score < a[j + 1].score)    
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }

        }
    }
    for (i = 0; i < n; i++)
    {
        printf("%s\n", a[i].name);        //输出以score排序后的name
    }
    return 0;
}

三、快速排序

#include <stdio.h>
int a[100], n;
void quicksort(int left, int right)
{
    int i, j, t, temp;
    if (left > right)
    {
        return;
    }
//temp中存放基准数,若基准数在右侧,左侧先动
      
    temp = a[right];//右侧(b)  

    i = left;
    j = right;
    while (i != j)
    {
        
        //从左往右(b)
        while (a[i] <= temp && i < j)
        {
            i++;
        }
        while (a[j] >= temp && i < j) 
        {
            j--;
        }

        if (i < j)    //在 i 和 j 未相遇时,交换a[i]和a[j]的值
        {
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    //在 i 和 j 相遇时,交换基准数与相遇位置的数值
    
    a[right] = a[i];        //右侧(b)
    a[i] = temp;

    quicksort(left, i - 1);        //递归
    quicksort(i + 1, right);
}

int main(void)
{
    int i, j, t;
    scanf("%d", &n);
    for (i = 0; i< n; i++)
    {
        scanf("%d", &a[i]);
    }
    quicksort(0, n - 1);
    for (i = 0; i < n; i++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

 

a[10]={6, 1, 2, 7, 9, 3, 4, 5, 10, 8};

设左侧移动的为i, 右侧的为j

基准数为8,i 先动,直到找到比8大的数,即a[4];

然后 j 再动,直到找到比8小的数,即a[7]

交换a[4]与a[7]的值

a[10] = {6, 1, 2, 7, 5, 3, 4, 9, 10, 8};

i 移动到a[7], 与 j 重合,

此时, 将基准数与a[7] 的值互换,

a[10] = {6, 1, 2, 7, 5, 3, 4, 8, 10, 9};

现在,基准数左侧的数都小于基准数,右侧的都大于,也就是基准数已经到了排序后自己该在的位置。

再用同样的方法分别计算基准数两侧的数组,就可以完成数组的排序。

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]
61279345108
61275349108
61275348109

 注意:基准数在右端时,先移动左端,是为了保证基准数可以交换到对应的位置,如上表所示,在 i 和 j 相遇时, 右侧除了,还有一个比8大的数10,将8与 i , j 相遇位置的值9交换,就可以保证8右侧有两个大于8的数字,即保证了8已经到了正确的位置

同理可得,基准数在左端时,先移动右端

#include <stdio.h>
int a[100], n;
void quicksort(int left, int right)
{
    int i, j, t, temp;
    if (left > right)
    {
        return;
    }
//temp中存放基准数,若基准数在左侧,右侧先动;在右侧,左侧先动
    temp = a[left];//左侧(a)     
    // temp = a[right];//右侧(b)  

    i = left;
    j = right;
    while (i != j)
    {
        // //从右往左(a)
        while (a[j] >= temp && i < j)       //  a[j] >= temp
        {
            j--;
        }
        while (a[i] <= temp && i < j)       //  a[i] <= temp
        {
            i++;
        }

        //从左往右(b)
        // while (a[i] <= temp && i < j)
        // {
        //     i++;
        // }
        // while (a[j] >= temp && i < j) 
        // {
        //     j--;
        // }

        if (i < j)    //在 i 和 j 未相遇时,交换a[i]和a[j]的值
        {
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    //在 i 和 j 相遇时,交换基准数与相遇位置的数值
    a[left] = a[i];      //左侧(a)
    // a[right] = a[i];        //右侧(b)
    a[i] = temp;

    quicksort(left, i - 1);        //递归
    quicksort(i + 1, right);
}

int main(void)
{
    int i, j, t;
    scanf("%d", &n);
    for (i = 0; i< n; i++)
    {
        scanf("%d", &a[i]);
    }
    quicksort(0, n - 1);
    for (i = 0; i < n; i++)
    {
        printf("%d ", a[i]);
    }
    return 0;
}

四、排序练习

 输入一组数字,进行排序和重组

1.先排序,再去重(桶排序)

#include <stdio.h>
int main(void)
{
    int a[1001] = { 0 };    //初始化为0
    int n, i, t;

    scanf("%d",&n);

    for (i = 0; i < n; i++)
    {
        scanf("%d", &t);
        a[t] = 1;       //标记出现过的编号
    }

    for (i = 0; i < 1000; i++)
    {
        if (a[i] == 1)  //判断是否被标记
        {
            printf("%d ", i);
        }
    }
    return 0;
}

2.先去重,在排序(冒泡排序/快速排序)

#include <stdio.h>
int main(void)
{
    int a[100] = { 0 };
    int n, i, j, t;
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }

    for (i = 1; i < n; i++)        //冒泡排序
    {
        for (j = 0; j < n - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }

    printf("%d ", a[0]);        //先打印a[0]
    for (i = 1; i < n ; i++)    
    {
        if (a[i] != a[i - 1])  //判断从a[1]开始的代码是否与前一项的值相同
        {
            printf("%d ", a[i]);
        }
    }

    return 0;
}
//快速排序
#include <stdio.h>
int a[100], n;            
void quicksort(int left, int right)
{
    int i, j, t, temp;
    if (left > right)
    {
        return;
    }
      
    temp = a[right];

    i = left;
    j = right;
    while (i != j)
    {
        while (a[i] <= temp && i < j)
        {
            i++;
        }
        while (a[j] >= temp && i < j) 
        {
            j--;
        }
        if (i < j)   
        {
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    
    a[right] = a[i];        
    a[i] = temp;

    quicksort(left, i - 1);        
    quicksort(i + 1, right);
}

int main(void)
{
    int i, j, t;
    scanf("%d", &n);
    for (i = 0; i< n; i++)
    {
        scanf("%d", &a[i]);
    }
    quicksort(0, n - 1);

    printf("%d ", a[0]);

    for (i = 1; i < n ; i++)
    {
        if (a[i] != a[i - 1])
        {
            printf("%d ", a[i]);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值