数据结构前传--C--06

数据结构前传–C–06


循环结构

循环结构:循环次数、循环体

专题一:通过循环变量控制循环次数

例如:

​ 任意输入10个正整数,分别输出奇数、偶数的个数

​ 统计个数:(计数器)

​ 计数器一定要初始化0

​ (循环次数确定----10次)

  1. 尽可能使用算术表达式作条件
int x;
int cntodd = 0;// 奇数个数
int cnteven = 0;// 偶数个数计数器

for(int i = 0;i < 10;++i)// 循环10次
{
    scanf("%d",&x);
    
    if(x%2)// 输入为奇数
    {
        cntodd++}
    else//输入为偶数
    {
        cnteven++;
    }
}

printf("奇数个数=%d,偶数个数=%d\n",cntodd,cnteven);
  1. 要学会简化结构,学会减少分支
int x;
int cntodd = 0;// 奇数个数计数器

for(int i = 0;i < 10;++i)// 循环10次
{
    scanf("%d",&x);
    
    if(x%2)// 输入为奇数
    {
        cntodd++;
    }
    /*
    	因为要判断10个数里面奇数和偶数的个数,不是奇数就是偶数,因此可以只计数奇数的个数,通过总数减奇数个数来表示偶数个数,以此减少一条分支
    */
    
}
printf("奇数个数=%d,偶数个数=%d\n",cntodd,10-cntodd);
  1. 尽可能减少条件的使用(逻辑抽象)
int x;
int cntodd = 0;// 奇数个数计数器

for(int i = 0;i < 10;++i)// 循环10次
{
    scanf("%d",&x);
    
    cntodd = cntodd + x%2;
    /*
    	如果x是奇数,cntodd奇数计数器加1,如果x是偶数,cntodd奇数计数器不加1,也就是说cntodd加0,那么,如果x是奇数,x%2为1,如果x为偶数,那么x%2为0,因此,此处可去掉条件语句,直接对cntodd加x%2
    */
    
}
printf("奇数个数=%d,偶数个数=%d\n",cntodd,10-cntodd);

例如:

​ 任意输入一个正整数n(n>1),输出:1+2+3+···+n

​ 求和:(累加器)

​ 累加器一定要初始化0

​ (循环次数确定----n次)

int n,sum = 0;

scanf("%d",&n);

// 构建一个n次的循环
for(int i = 1;i < n+1;++i)// 尽可能不要写成双闭,最好是左闭右开
{
    sum = sum + i;
}
printf("%d\n",sum);
  1. 在程序中尽可能多的使用数学公式,降低时间复杂度,提高代码效率,但尽量少的使用系统提供的数学函数(例如:sqrt(求平方根),pow(求指数))

​ 如果怕老师会看不懂,可添加注释说明

int n,sum = 0;

scanf("%d",&n);

printf("sum=%d\n",n*(n+1)/2);

例如:

​ 任意输入10个正整数,输出最大值及其个数

怎么求最大值:

例如:

​ 3,2,5,8,4,7,6,9求最大值

​ 求最大值的方法是固定的

  	1. 三个变量:x,max,cnt
     		1. x:用来一个一个的接收输入的值
     		2. max:用来放最大值
     		3. cnt:用来放当前最大值的个数
  	2. 当x变为下一个值时,因为此时max已经为上一轮的最大值,故将x和max进行比大小,如果x比max小,则max不用变,cnt也不用变,直接进行下一轮,如果x比max大,则max更新为此时的x即当前的最大值,cnt重新变为1,继续下一轮,当x接收到的值和max当前值相等时,说明又遇到一个最大值,此时cnt加1
  1. 不要将一个循环割裂成两个过程,尽量将所有的过程统一到一个循环里面去,不要将某一个数,某一部分单独割裂出来
int x;
int max,cnt;

for(int i = 0;i < 10;++i)// 循环10次
{
    scanf("%d",&x);
    
    if(i == 0)// 第一次进循环,x接收第一个数
    {
        max = x;
        cnt = 1;
    }
    else// x接收的不是第一个数,即max、cnt已经有值
    {
        if(x > max)
        {
            max = x;
            cnt = 1;
        }
        else// x <= max
        {
            if(x == max)
            {
                cnt++;
            }
        }
    }
}
// 时间复杂度O(n)

​ 因此上面的要比下面的更好一点

int x,max,cnt;

scanf("%d",&x);// 将第一次初始化在循环外面
max = x;
cnt = 1;

for(i = 1;i < 10;++i)// 循环9次
{
    scanf("%d",&x);
    
    if(x > max)
    {
        max = x;
        cnt = 1;
    }
    else
    {
        if(x == max)
        {
            cnt++;
        }
    }
}
// 时间复杂度O(n)

​ 并且,对于顺序表等问题,会不自觉地将其割裂成多份,这样时间复杂度会变高

int a[10] = {3,2,3,5,4,5,8,2,8,8};

int max,cnt;

max = a[0];

for(int i = 1;i < 10;++i)// 找最大值
{
    if(a[i] > max)
    {
        max = a[i];
    }
}

cnt = 0;

for(int i = 0;i < 10;++i)// 数最大值个数
{
    if(a[i] == max)
    {
        cnt++;
    }
}
//时间复杂度O(2n)

​ 将求最大值和统计个数压缩合成到一起

int a[10] = {3,2,3,5,4,5,8,2,8,8};

for(int i = 0;i < 10;++i)// 循环10次
{
    if(i == 0)// 第一次循环
    {
        max = a[i];
        cnt = 1;
    }
    else
    {
        if(a[i] > max)
        {
            max = a[i];
            cnt = 1;
        }
        else
        {
            if(a[i] == max)
            {
                cnt++;
            }
        }
    }
}
// 时间复杂度O(n)

专题二:查找区间内满足条件的值(区间值作条件)

例如:

​ 输出100~999之间的水仙花数(穷举法)

​ (穷举法效率低)

​ (水仙花数:abx = a^3 + b^3 + c^3)

  1. 尽可能不要使用穷举法,除非这个题只能用穷举法,或者实在想不出来更好的办法时,用穷举法
// 本题水仙花数毫无规律可言,因此只能使用穷举法

for(x = 100;x < 1000;++x)// 100循环到999
{
    t1 = x%10;// 拆分个位数
    t2 = x/10%10;// 拆分十位数
    t3 = x/100;// 拆分百位数
    
    if(x == t1*t1*t1 + t2*t2*t2 + t3*t3*t3)// 尽量不要用到系统函数pow()等
    {
        printf("%5d",x); 
    }
}

例如:

​ 输出100~999之间的完全平方数

​ 平方根:10^2 ~ 31^2

​ (完全平方数:是某个数的平方,且至少有两位数字相同)

for(int x = 100;x < 1000;++x)// 先把循环架出来
{
    t1 = x%10;// 拆分个位数
    t2 = x/10%10;// 拆分十位数
    t3 = x/100;// 拆分百位数
    
    if(t1 == t2 || t2 == t3 || t3 == t1)// 至少有两位数字相同的数进来
    {
         for(int k = 10;k < 32;++k)// 穷举法
         {
             if(x == k*k)
             {
                 printf("%5d",x);
             }
         }
    }
}
// 时间复杂度O(n^2)
// 循环次数(900x22)
  1. 必须要用穷举法时,要尽可能简化结构
for(int k = 10;k < 32;++k)// 只循环平方根,通过平方根的平方来寻找
{
    x = k*k;// x是某个数的平方在100~999内的数
    
    t1 = x%10;// 拆分个位数
    t2 = x/10%10;// 拆分十位数
    t3 = x/100;// 拆分百位数
    
    if(t1 == t2 || t2 == t3 || t3 == t1)
    {
        printf("%5d",x);
    }
}
// 时间复杂度O(n)
// 循环次数(22)

例如:

​ 男人、女人、小孩吃饭问题:

​ man:3¥/人

​ woman:2¥/人

​ kid:1¥/人

​ 要求去够30个人,花够50元钱

​ 问:man、woman、kid各有多少人?

假设男人x,女人y,小孩z,

列方程组:3x+2y+z = 50,x+y+z = 30

两个方程组无法求解三个未知量

因此,

无法通过已有知识建立公式模型

只能穷举

男人最多去16个,女人最多去25个,小孩最多去30个

男人去0个,女人就对相应可以去0 ~ 25个,女人去0个,小孩就可以去0 ~ 30个,以此映射,嵌套

for(x = 0;x < 17;++x)// 男人从0~16取
{
    for(y = 0;y < 26;++y)// 女人从0~25取
    {
        for(z = 0;z < 31;++z)// 小孩从0~30取
        {
            if(x+y+z == 30 && 3*x+2*y+z == 50)
            {
                printf("%5d%5d%5d\n",x,y,z);
            }
        }
    }
}
// 时间复杂度O(n^3)
// 循环次数(17*26*31)

​ 简化结构:

for(x = 0;x < 17;++x)// 确定男人
{
    for(y = 0;y < 26;++y)// 确定女人
    {
        z = 30-x-y;// 确定z,并保证x+y+z=30
        
        // 减法要考虑范围,因为两数相减可能产生负值
        if(z >= 0 && 3*x+2*y+z == 50)
        {
            printf("%5d%5d%5d\n",x,y,z);
        }
    }
}
// 时间复杂度O(n^2)
// 循环次数(17*26)

​ 再次简化结构:

for(x = 0;x < 17;++x)// 确定男人
{
    y = 20-2*x;// 确定女人,因为有两个三元一次方程组,所以可以消掉一个元
    z = 30-x-y;// 确定小孩
    
    // 减法要考虑范围,因为两数相减可能产生负值
    if(y >= 0 && z >= 0 && 3*x+2*y+z == 50)
    {
        printf("%5d%5d%5d\n",x,y,z);
    }
}
// 时间复杂度O(n)
// 循环次数(17)

​ 注意:

​ 减法:一定要考虑取值范围,两数相减出现负值时,可能不符合题意,干扰结果。


总结

本文仅是个人考研备考所作的课堂笔记,多处内容仅贴合个人的学习习惯,若带来什么阅读上的不良体验,还望海涵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值