C语言程序设计CAP——C语言学习笔记(七) 下

7.2-1 数组的运算

• 在一组给定的数据中,如何找出某个数据是否存在?

int main(void)
{
    int a[] = {2,46,7,1,3,5,9,11,13,23,14,32};
    int x;
    int loc;
    printf("请输入一个数字:");
    scanf("%d", &x);
    loc=search(x, a, sizeof(a[0]));
    if ( loc != -1) {
        printf("%d在%d个位置上\n", x, loc);
    } else {
        printf("%d不存在\n", x);
    }
    return 0;
}
int rearch(int key, int a[], int length)
{
    int ret = -1;
    int i;
    for ( i=0; i< length; i++ ) {
        if ( a[i] == key) {
            ret = i;
            break;
        }
    }
    return ret;
}

数组的集成初始化

 • 直接用大括号给出数组的所有元素的初始值
• 不需要给出数组的大小,编译器替你数数


• 如果给出了数组的大小,但是后⾯面的初始值数量不足,则其后的元素被初始化为0

集成初始化时的定位

C99 ONLY!

 • 用[n]在初始化数据中给出定位
• 没有定位的数据接在前面的位置后⾯面
• 其他位置的值补零
• 也可以不给出数组大小,让编译器算
• 特别适合初始数据稀疏的数组

数组的大小

• sizeof给出整个数组所占据的内容的大小,单位是字节
可扩展性!
• sizeof(a[0])给出数组中单个元素的大小,于是相除就得到了数组的单元个数
• 这样的代码,一旦修改数组中初始的数据,不需要修改遍历的代码

数组的赋值

 

 • 数组变量本身不能被赋值
• 要把一个数组的所有元素交给另⼀个数组,必须采用遍历

遍历数组

 

 

 • 通常都是使用for循环,让循环变量i从0到<数组的长度,这样循环体内最大的i正好是数组最大的有效下标
• 常见错误是:
• 循环结束条件是<=数组长度,或;
• 离开循环后,继续用i的值来做数组元素的下标!

 

 7.2-2数组的例子:素数

判断素数

int isPrime(int x);

int main(void)
{
    int x;
    scanf("%d", &x);
    if (isPrime(x) ) {
        printf("%d是素数\n", x);
    } else {
        printf("%d不是素数\n", x);
    }
    return 0;
}

从2到x-1测试是否可以整除

int isPrime(int x)
{
    int ret = 1;
    int i;
    if ( x ==1 ) ret = 0;
    for ( i=2; i<x; i++ ) {
        if ( x % i == 0) {
            ret = 0;
            break;
        }
    }
    return ret;
}

• 对于n要循环n-1遍
• 当n很大时就是n遍

去掉偶数后,从3到x-1,每次加2

int isPrime(int x)
{
    int ret = 1;
    int i;
    if ( x == 1||
         (x%2 == 0 && x!=2) )
        ret = 0;
    for ( i=3; i<x; i+=2 ) {
        if ( x % i == 0 ) {
            ret = 0;
            break;
        }
    }
    return ret;
}

• 如果x是偶数,立刻
• 否则要循环(n-3)/2+1遍
• 当n很大时就是n/2遍

无须到x-1,到sqrt(x)就够了

int isPrime(int x)
{
    int ret = 1;
    int i;
    if ( x == 1||
         (x%2 == 0 && x!=2) )
        ret = 0;
    for ( i=3; i<sqrt(x); i+=2 ) {
        if ( x % i == 0 ) {
            ret = 0;
            break;
        }
    }
    return ret;
}

• 只需要循环sqrt(x)遍

sqrt

判断是否能被已知的且<x的素数整除

int main(void)

{
    const int number = 100;
    int prime[number] = {2};
    int count = 1;
    int i = 3;
    while ( count < number ) {
        if ( isPrimer(i, prime, count) ) {
            prime[count++] = i;
        }
        i++;
    }
    for ( i=0; i<number; i++) {
        printf("%d", prime[i]);
        if ( (i+1)%5 ) printf("\t");
        else printf("\n");
    }
    return 0; 
}
int isPrime(int x, int knownPrimes[], int number0knownPrimes) 
{
    int ret = 1;
    int i;
    for ( i=0; i<number0knownPrimes; i++) {
        if ( x % knownPrimes[i] ==0) {
            ret = 0;
            break;
        }
    }
    return ret;
} 

构造素数表

• 欲构造n以内的素数表
1. 令x为2
2. 将2x、3x、4x直至ax<n的数标记为非素数
3. 令x为下⼀一个没有被标记为非素数的数,重复2;直到所有的数都已经尝试完毕

• 欲构造n以内(不含)的素数表
1. 开辟prime[n],初始化其所有元素为1,prime[x]为1表示x是素数
2. 令x=2
3. 如果x是素数,则对于(i=2;x*i<n;i++)令prime[i*x]=0
4. 令x++,如果x<n,重复3,否则结束

const int maxNumber = 25;
int isPrime[maxNumber];
int i;
int x;
for ( i=0; i<maxNumber; i++ ) {
    isPrime[i] = 1;
}
for ( x=2; x<maxNumber; x++ ){
    if (isPrime[x] ){
        for( i=2; i*x<maxNumber; i++ ) {
            isPrime[i*x] = 0;
        }
    }
}
for ( i=2; i<maxNumber; i++ ){
    if ( isPrime[i] ) {
        printf("%d\t", i);
    }
}
printf("\n");

• 算法不一定和人的思考方式相同

7.2-3 二维数组

二维数组

• int a[3][5];
• 通常理解为a是一个3行5列的矩阵

二维数组的遍历

for ( i=0; i<3; i++ ) {
    for ( j=0; j<5; j++ ) {
        a[i][j] = i*j;
    }
}

 • a[i][j]是一个int
• 表示第i行第j列上的单元
• a[i,j]是什么?

二维数组的初始化

int a[][5] = {
    {0,1,2,3,4},
    {2,3,4,5,6},
};

• 列数是必须给出的,行数可以由编译器来数
• 每行⼀一个{},逗号分隔
• 最后的逗号可以存在,有古老的传统
• 如果省略,表示补零
• 也可以用定位(*C99 ONLY

tic-tac-toe游戏

• 读入一个3X3的矩阵,矩阵中的数字为1表示该位置上有⼀一个X,为0表示为O
• 程序判断这个矩阵中是否有获胜的一方,输出表示获胜一方的字符X或O,或输出无⼈获胜

读入矩阵

const int size = 3;
int board[size][size];
int i,j;
int numofx;
int numofo;
int result = -1;       //-1:没人赢 , 1:x赢, 0:o赢

//读入矩阵

for ( i=0; i<size; i++ ) {
    for (j=0; j<size; j++ ) {
        scanf("%d", &board[i][j]);
    }
}

检查行

//检查⾏
for ( i=0; i<size && result == -1; i++ ) {
    numofo = num0fx = 0;
    for ( j=0; j<size; j++ ) {
        if ( board[i][j] == 1 ) {
            numofx ++;
        } else {
        numofo ++;
        }
    }
    if ( numofo == size ) {
        result = 0;
    } else if (numofx == size ) {
        result = 1;
    }
}

检查列

if ( result == -1 ) {
    for ( j=0; j<size && result == -1; j++ ) {
        numofo = numofx = 0;
        for ( i=0; i<size; i++ ) {
            if ( board[i][j] == 1 ) {
                numofx ++;
            } else {
                numofo ++;
            }
        }
        if ( numofo == size ) {
            result = 0;
        } else if (numofx == size ) {
            result = 1;
        }
    }   
}

行和列?

 能否用一个两重循环来检查行和列?

检查对角线

思考题:

如何用一个两重循环实现行和列的检查

用一个两重循环实现行和列的检查该怎么做?

可以直接一次循环就检查完行和列

这里就简写

i循环体

    j循环体

        board[i][j] //检查行

        语句        

        board[j][i] //变换一下i,j坐标就可以检查列了

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值