黑马程序员_C语言冒泡算法和约瑟夫循环分析

来源:互联网 发布:淘宝比价软件app 编辑:程序博客网 时间:2024/05/16 00:38


本以为在看完了C语言的基础视频后,入学测试便可信手可得。不过拿到手试题后,接踵而来的问题不是C各种函数,循环,数据,结构体的用法。可是它们综合在一起外加上算法后,便很难了。程序员最重要的一点是思想,要不一直敲打无意义的代码成,代码会变得毫无含金量。有些看似实质性的问题,有的人能一行代码解决,有的人则需要花上几百行,并且性能优化上还没有上一个一行代码的来的好。思想,数据结构,解决问题的思路和对数学的理解,这些都是学计算机需要掌握的。哪怕是后来的OC面向对象,重要的也是思想,办什么事,就去相应的类里找。解决这件事的办法,这些思想综合起来才能进行独立的开发和综合的对于技能的掌握。


于是乎目前的任务,我决定就是完成视频内容,虽然看了忘忘了看,但是还是要“坚毅”的走完报名流程。然后如果有幸融入“黑马”,我重新巩固自己算法这方面的不足,可以买一本数据结构,买一本OC入门详解,或者网上下载C经典例题100道拿来做做。代码这东西,怎么看都是别人的,只有自己想的多了,才是自己的。我缺少的,恰恰是实践和付诸实践的时间。不过虽然C算法“临幸”的较少,不过在少数的我碰到的例题中,也学到了不少思维。
下面这两个算法是C中比较经典的解决问题实例。特记录下来,以后若有指的分析的,必也会纳入博客,成为自己知识的一部分。


(一)冒泡排序:
冒泡排序(Bubble Sort)是一种能力较为底下的排序方法,用于升序或者降序排列一个数组中的数。不过因为是两两比较,依次循环,所以性能较为低下,再次旨在提供一种思想。因为C语言关乎排序的算法非常之多,这也算一个经典思想了。


排序为两两进行比较,第一轮会把最大值沉到最后一位,然后第二轮遍历只需遍历前面的数组进行排序,找出第二大的即可。

代码实现:


#include <stdio.h>


void BubbleSort(int array[],int n);

int main()

{

    int array[] = {10,99,88,77,43,422,10,11};

    BubbleSort(array, sizeof(array)/sizeof(int));

    for (int a =0;a<sizeof(array)/sizeof(int);a++)

    {

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

    }

    

}

// 冒泡排序算法需要传入整个数组和数组数组元素个数

void BubbleSort(int array[],int n)

{

    

    int temp  = 0;

    

    //外圈循环,用于计算整个遍历的次数,10个元素,那么就要遍历9

    for (int i =0;i<n-1;i++)

    {

        //内圈循环,用于计算每一次遍历应进行的比较数,第一次外循环已经把最大值沉淀到最底部了

        for (int j =0;j<n-1-i;j++)

        {

            if (array[j]>array[j+1])

            {

                // 交换数字(也可以不用temp

                temp = array[j];

                array[j] = array[j+1];

                array[j+1] = temp;

            }

        }

    }



下面是我遇到的入学测试题:(记忆犹新)


/*从键盘输入一大堆字符串,统计ABCD的出现次数,最后出现次数由高到低输出字母和出现次数。(C语言)

                               */



#include <stdio.h>


int main()

{

    // statistics函数声明,实现输出功能

    void statistics(char *str);

    

    //从键盘输入一串字符串,并传入name数组

    char name[1000];

    printf("请输入一串字符串\n");

    scanf("%s",name);

    

    // statistics函数调用

    statistics(name);

    return 0;

}


// statistics函数定义

void statistics(char *str)

{

    // 定义四个int类型用来存储A,B,C,D出现的次数

    int atimes=0;

    int btimes=0;

    int ctimes=0;

    int dtimes=0;

    

    //循环遍历整个字符串,取出ABCD的个数

    for (int i=0;str[i]!=0;i++)

    {

        if (str[i] =='A')

        {

            atimes++;

        }else if (str[i] =='B')

        {

            btimes++;

        }else if (str[i] =='C')

        {

            ctimes++;

        }else if (str[i] =='D')

        {

            dtimes++;

        }

    }

    //此时取出刚才ABCD出现的次数,并且按照顺序依次放入到ArraYTimes数组中

    int ArrayTimes[4] ={atimes,btimes,ctimes,dtimes};

    

    // 定义一个char类型数组依次存放字符'A','B','C','D'

    char num[4] = {'A','B','C','D'};

    

    //解题思路:现在'A','B','C','D'和其对应的数值依次储存在两个数组中,可是'A','B','C','D'的数值排序是乱序,下面要进行ArrayTimes[]数组的降序排列,并且num[]数组也相应的对应修改。以达到顺序是降序,数字和'A','B','C','D'还是一一对应。百度方法后,查找到一个两两比较,交换空间的方法,叫做冒泡排序

    

    // (sizeof(ArrayTimes)/sizeof(int))-1计算出数组内元素个数,根据个数判断循环应为n-1

    for (int i =0; i<(sizeof(ArrayTimes)/sizeof(int))-1; i++)

    {

        // 判断循环,n-1-j

        for(int j =0;j<(sizeof(ArrayTimes)/sizeof(int))-1-i;j++)

        {

            //如果前面的值小于后面的,则交换他们的位置,改变排序

            if (ArrayTimes[j] < ArrayTimes[j+1])

            {

                

                // 交换ArrayTimes[j]ArrayTimes[j+1]的值

                int changeArray = ArrayTimes[j];

                ArrayTimes[j] = ArrayTimes[j+1];

                ArrayTimes[j+1] = changeArray;

                

                // 由于ArrayTimes数组和num数组的出现次数和'A','B','C','D'是依次对应的,所以同样的方法交换num数组的值

                char changeNum=num[j];

                num[j]=num[j+1];

                num[j+1]=changeNum;

            }

        }

    } //到此,冒泡排序执行完毕,此时ArrayTimes[]应该是降序排列,并且对应的num[]里面的字符也一一对应

    

    //遍历循环输出出现次数,并打印出来

    for (int s=0;s<(sizeof(ArrayTimes)/sizeof(int));s++)

    {

        printf("%c出现了%d\n",num[s],ArrayTimes[s]);

        

    }

    

}

(二)约瑟夫循环

约瑟夫循环是一个数学应用问题,在C语言中难想到的就是如何组成一个圆,让人数越来越少的新环继续循环起来。题目如下:


/* 耶稣有15个门徒,其中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:15人围坐一圈,从第一个开始报号:123123……,凡是报到“3”就退出圈子,最后留在圈内的人就是出卖耶稣的叛徒,请找出它原来的序号。(C语言)

                               */


#include <stdio.h>


int main()

{

    

    //首先定义一个数组用来存放15个人,并依次赋值

    int person[15]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

    

    // 定义人数num=15,喊到num=0i用于遍历整个person[15]数组

    int dao = 0;

    int i = 0;

    int num = 15;

    

    //循环思路:当喊到3,这个人就剔除,这个人对应的位置值为0,当执行一圈后,终点15处定义新的起点,重新从person[0]处再次喊到,直到循环到只剩一个人

    while (num>1)

    {

        // person[i]初始赋值成功后,其!=0表示此处有人,那么喊到加1

        if (person[i] !=0)

        {

            dao ++;

        }

        

        //如果喊到等于3,那么重新从1喊,并且此处的人剔除(表现为数组中这个位置值为0,总人数减1

        if (3 == dao)

        {

            dao = 0;

            person[i] = 0;

            num -= 1;

        }

        

        //遍历下一个人,用于进入下一次循环判定时候喊到

        i++;

        

        //经由黑马论坛传授精妙解法,巧妙的把150重叠,实现了围坐一圈的效果

        if (15 ==i)

        {

            i =0;

        }

    }

    

    //循环遍历重新赋值后的person[i],其值不得0得那个人就是最后剩下的

    for (int a =0;a<15;a++)

    {

        if (person[a] !=0)

        {

            printf("15个人中叛徒是:%d\n",person[a]);

        }

    }

    

    return 0;

}




最难理解的就是

 if (15 ==i)

        {

            i =0;

        }



i的定义是为了给15个人编号,当0-14全部while循环完毕,说明15个人完全喊了一圈了,数组中是没有i= 15,16的。所以当全部喊完重新开始时,下一个人15的编号,的数组改成0,这样就恰巧模拟了他们做一圈的形态。i只是用来剔除人的,当person[i]等于0后,下次吼到就不会再顾及这个人,因为已经被剔除了。所以i在 if判定外。每一次循环都需要+1遍历每一人。整体来说,目前只能弄懂这些比较精妙的解法,如果遇到新的问题或者类似的问题,即便不能解,也许也会有一定的思路。算法多靠的是思考。和积累。对于没怎么接触过数据结构,所以感觉略难。


0 0
原创粉丝点击