|  这个作业属于哪个班级    |  C语言--网络2011/2012 |
| ---- | ---- | ---- |
|    这个作业的地址  |  C博客作业04--数组  |
|    这个作业的目标  |  学习如何设计函数、C语言基本数据类型   |
目录
0. 展示PTA总分
1. 本章学习总结
2. PTA实验作业
0.展示PTA总分
1. 本章学习总结
1.1 学习内容总结
1)查找数据
- 顺序查找
- 无序、有序排列的数组均可以使用
- 即按照顺序逐个查找目标数字/字符
- 伪代码:(计数指定数据的个数)
 
/*计数目标数据的数量时,利用count++自增运算*/
// 跳出循环后,可以通过count的值,判断数组里是否有目标数据
//
/*需要利用目标数据的位置时(如增、删、改),将count++改为break,利用break跳出循环;或用return返回目标数据的下标*/
//可以使用flag,当找到目标数据时,flag = 1,反之 flag = 0。若未找到则及时结束函数,避免数组越界
//
            For i=0 to n-1
                  IF a[i] = target
                  then
                        count++   
                  END IF
            END For
- 二分查找
- 适用于有序排列的数据
- 即判断区间中间的数据是否为目标数据。若不为目标数据,判断该数据与目标数据的关系后,进入减半的区间,继续判断中间数据
- 代码(查找目标数据,并返回下标)(以从小到大顺序排列的数组为例)
 
int BinSearch(int a[99], int n, int key, int count)      
{
    int locMin = 0;           //最小下标
    int locMax = n - 1;       //最大下标
    int mid;                  //中间下标
    while (locMin <= locMax)            //当最小下标不大于最大下标时,继续遍历数组
    {
        mid = (locMax + locMin) / 2;    //取查找区间内的中间下标
        if (a[mid] == key)              //找到目标数据时,返回目标数据的下标    
        {
            return mid; 
        }
      /*根据目标数据和中间数据的关系,重新确定查找的区间*/
        else
        {
            if (key < a[mid])            
            {
                locMax = mid - 1;      
            }
            else if (key > a[mid])
            {
                locMin = mid + 1;
            }
        }
    }
    return -1;      //循环结束后,若未找到目标数据,则返回负数。通过该函数的返回值,确定是否有目标数据存在于数组之中
}
2)插入数据
- 伪代码(以升序排列为例)
      //①先查找到需要插入的位置
      For i = 0 to n-1
            IF putNum < a[i]
               break跳出循环
            END IF
      END For
      //②再移动数组
      For j = n-1 to i
            a[j+1] = a[j]
      END For
      //③将需要插入的数据插入,并将表示数组数据个数的n加一
      a[i] = putNum
      n++
- 流程图:
  
3)删除数据
- 
原数组删除:删除数据较少时使用 - (步骤1:先删除一个目标数据)
- 利用查找数据,找到需要删除数据的位置
- 确定删除的数据位置后,将数组左移一位,覆盖掉要删除的数据
- 最后将数组元素个数,n--
- (步骤2:)
- 循环步骤1,直到在数组中找不到目标数据。(可以使用flag,判断数组中是否找到目标数据)
- 简易流程图:
  
 
- 
新构造数组:删除数据较多时使用 - 新构造一个数组
- 定义两个数组下标,一个为原数组的下标i,一个为重构数组的下标j
- 遍历原数组进行判断,若数据不为要删除的目标数据,将数据写入新构造的数组中,并且此时新构造数组的下标自增
- 简易流程图:
  
 
4)排序方法
- 冒泡排序
- (步骤1:将两个相邻的数比较,先将一个最值“冒泡”,移到右边)
- (步骤2:范围减小后,循环重复步骤1,将每个区间内的最值“冒泡”出去)
- 代码:(以升序排列为例)
 
      int i,j;      //外循环控制次数,遍历的范围;内循环遍历数组
      int temp;
      for(i = 0; i < n-1; i++)                 //每执行一次冒泡,内循环的范围减小
      {
            for(j = 0; j < n-1-i; j++)         //通过逐个判断,将区间内的最大值移动到区间的最右边
            {
                  if(num[j] > num[j+1])      //逐个判断,若a[j+1] < a[j], 交换a[j] 和a[j+1]
                  {
                        temp = num[j];
                        num[j] = num[j+1];
                        num[j+1] = temp;
                  }
            }
       }
- 选择排序
- (步骤1:遍历数组,选择出最值,将最值放到指定位置)
- (步骤2:范围减小,循环重复步骤1)
- 代码:(以升序排列为例)
 
      int i,j;
      int minloc;           //最小值的下标       
      int temp;
      for(i = 0; i < n-1; i++)
      {
            minloc = i;      //使最小值的下标等于内循环开始时,数组的下标
            for(j = i; j < n; j++)      //从num[i]开始遍历数组,找到区间内的最小下标   
            {
                  if(num[minloc] > num[j])
                  {
                        minloc = j;
                  }
            }
            
            temp = num[i];            //交换,将范围内最小值与a[i]交换
            num[i] = num[minloc];
            num[minloc] = temp;
      }
5)数组统计
- 思路:
- 循环步骤1
- 步骤1:输入数据,将该数据作为静态数组的下标,该下标对应的数据自增
 
- 代码:
      static int vote[1000];    //定义静态数组,使数组各项为0
      for(i=0; i<n; i++)
      {
          scanf("%d",&num);     //输入需要统计的数据
          vote[num]++;          //将该数据作为静态数组下标。每次出现时,vote[]对应的值加1,统计出数据出现的次数  
      }
- 案例一:7-4 点赞
- 案例二:7-5 调查电视节目受欢迎程度
  
6)哈希数组
- 用法
- 定义静态数组,int hash[256],
- 与投票类似,将输入的数据作为hash[]数组的下标
- 出现的数据对应下标的数组数据 = 1
- 遍历数组,输出值等于1,对应的下标
- 这样就完成了删除重复的数据,并将数据按照ASCII码的排序
 
- 案例
- 删除重复数据,并按照ASCII码升序排列(伪代码)
 
      定义 static int hash[256] //因为ASCII码的范围为[0,255],共256个元素
      输入要输入的数据数 n
      For i = 0 tp n-1
      {
            输入数据 str
            hash[str] = 1;      //将str对应下标的数组赋值为1。用于接下来判断数据是否存在
      }
      END For
      
      For i = 0 to 255          //遍历hash数组,输出出现的数据
      {
            IF hash[i] = 1
            than
                  输出i         //也可以在定义一个新的数组,将i的值放入新的数组中
            END IF
      }
      END For      
7)二维数组
- 二维数组特点:
- 定义: 类型名 数组名[行长度][列长度]
- 存放:二维数组在内存中是按行连续存放的
- 赋初值:
 分行赋初值: int num[2][2] = {{1}, {2,1}};
 顺序赋初值: int num[2][2] = {1, 0, 2, 1};
- 省略行长度:
 对所有元素都赋了初值
 分行赋值中,列出了所有行 int num[ ][3] = {{1, 2}, { }};
- 根据题意,理清行(i)与列(j)的关系,有利于解决关于二维数组的图形问题
 
8)字符数组
- 
字符串特点 - 
字符串是特殊的一维数组,需要用一维数组来存放 
- 
字符串的末尾有结束标志'\0',而'\0'之后的其它数组元素与字符串无关 
- 
与数字数组相比,字符数组并不需要明确的有效元素个数作为循环的限制条件。 
- 
字符数组的限制条件一般为结束标志'\0'。当用fgets输入字符串时,字符串末尾往往会接一个'\n',再接上结束标志,这种情况结束条件要适当改变 
 条件:while(str[i]) 或者 while(str[i] && str[i] != '\n')
 
- 
- 
需注意事项 - 区分"a"和'a'
 初始化:char str[6] = "a"; //其中"a"为字符串
 赋值: str[0] = 'a'; //其中'a'为字符
 备注:初始化——> str[0] = 'a'; str[1] = '\0' - 字符串的输入:
 注意空格:scanf(输入的字符串(%s)不能含有空格,scanf遇到空格时停止输入)
 注意回车:fgets(输入的字符串遇到回车时结束,但如果输入的元素加上结束标志没有填满数组,则数组结束标志前还会有一个换行符('\n')
 注意结束标志:循环getchar()输入(逐个输入字符构成字符数组,但在输入完成后,需记住在末尾添加结束标志)
 
- 区分"a"和'a'
2. PTA实验作业
2.1 数组左移
- 2.1.1 伪代码
        输入数组元素个数n,左移位数moveNum
        moveNum = moveNum % n        //解决位移位数不小于元素个数的情况。若左移位数与元素个数相等,则不进行位移。若位移位数大于元素个数,则将位移位数为原来位移位数与元素个数的余数
        定义一个新数组tempNum[moveNum]
        For i = 0 to moveNum         //原数组的前几位放入新数组中               
        {
             tempNum[i] = moveNum[i];
        }
        END For
      For  i = moveNum to n - 1
      {
		number[i - moveNum] = number[i];      //数组内后几位数前移
	}
        END For
       For  (j = 0, i = n - moveNum; i < n; i++, j++)
	{
		number[i] = temp[j];
	}
        END For
- 2.1.2 代码截图
  
  
  
- 2.1.3 同学的代码
#include <stdio.h>
#define MAXN 100
int ArrayShift( int a[], int n, int m );
int main()
{
    int a[MAXN], n, m;
    int i;
    scanf("%d %d", &n, &m);
    for ( i = 0; i < n; i++ ) scanf("%d", &a[i]);
    ArrayShift(a, n, m);
    for ( i = 0; i < n; i++ ) {
        if (i != 0) printf(" ");
        printf("%d", a[i]);
    }
    printf("\n");
    return 0;
}
int ArrayShift(int a[], int n, int m)
{
	for (int i = 0; i < m; i++)
	{
		int temp = a[n - 1];
		a[n - 1] = a[0];
		for (int A = 0; A < n - 2; A++)
		{
			a[A] = a[A + 1];
		}
		a[n - 2] = temp;
	}
    return 1;
}
- 
优点: 
 同学:- 代码思路清晰,可读性强,易于理解
- 代码简洁明了
 
- 
不足: 
 同学:- 注释较少
 自己:
- 代码冗长
- 定义的全局变量过多
- 函数形参的设置有所不足,应该使用形参将需要的参数传入函数,而不是过多地定义全局变量
- 函数的返回类型。该代码中函数的返回类型多为void,所做的仅仅是将代码切分开来,没有很好地利用函数的返回值
 
- 注释较少
2.2 阅览室
- 2.2.1 伪代码
      /*数据表达*/
/*需要输入的变量*/
      定义 dayNum bookNum ch hh mm
      定义静态数组 lend[1001][2] 
      定义静态数组 back[1001][2] 
      // lend[][0] 放置是否借书
      // lend[][1] 放置借书的时间
/*与时间计算相关的变量*/
      定义 sumtime //存放总时间
      定义 times   //存放次数
      定义 avgTime //存放平均时间     
      定义bookMax  //最大书号
      /*数据处理*/
      For i = 0 to dayNum - 1
      {
            
                  /*重置一些变量的值*/
                  清空数组lend[][]
                  清空数组book[][]
                  bookMax = 0;
                  times = 0;
                  sumTime = 0;
            
                  while(1)
                  {
                      输入书号 bookNum
                        输入借出或归还 ch
                        输入时间 hh:mm
                        
                        IF bookMax < bookNum
                        then 
                              bookMax = bookNum
                        END IF
                  
                        IF bookNum = 0
                        then 
                              break
                        END IF
                        IF ch = 'S' || ch = 'E'
                        then
                              IF ch = 'S'
                                    lend[bookNum][1] = hh * 60 + mm /*存储时间(分钟)*/
                                    lend[bookNum][0] = 1     /*已借书*/
                              END IF
                              ELSE IF ch = 'E' && (back[bookNum][0] = 0 || back[bookNum][1] < lend[bookNum][1])
                              then
                                    存储时间(分钟)
                                    back[bookNum][0] = 1     /*已还书*/
                              END IF
                        END IF
                              
                        /*借出并归还,且时间合法时*/
                        IF lend bookNum][0] == 1 && back[bookNum][0] == 1 && back[bookNum][1] >= lend[bookNum][1]		
                        then
                              sumTime += back[bookNum][1] - lend[bookNum][1]; // 计算借阅时间的总和   
               	              times++;      //次数累计
              		      lend[bookNum][0] = back[bookNum][0] = 0;      //将借阅判断归零
                        END IF
                  }           
                  END while
、
                        输出借阅总时间和次数
      }
      END For
                               
- 
2.2.2 代码截图 
  
  
  
  
  
  
- 
2.2.3 说明和超星视频做法区别,各自优缺点 - 
超星: 
 1.将每天借阅记录存放在二维数组之中
 2.思路清晰,代码简洁明了
- 
自己: 
 不足
 1.没有使用二维数组存放阅读记录
 2.代码冗长
 
- 
2.3 切分表达式
- 2.3.1 伪代码
      定义 flag //判断是否为”首个“数字
      定义 sign //判断是否为负数、正数
      For i = 0 to str[i] = '\n'
            IF flag = 1		//判断首个数字是否为带符号的正负数
            then
                  IF str[i] = '-'
                  then 
                        sign = 1;
		  END IF
                  ELSE IF str[i] = '+'
                  then
                        sign = 2;
                  END IF
            END IF
            
            flag = 0
      
            IF str[i]为0~9的字符
            then
                  将str[i]转化为数字,赋道number中
            
            IF str[i+1]不为0~9的字符
            then 
                  IF str[i+] = '.'
                  then
                        通过sign判断首个数字有没有带有正负号
                        IF sign = 1 || sign = 2
                        then
                              通过switch分支,将输出的number前填上‘+'或’-‘,输出的number不换行
                        END IF
                        
                        ELSE       
                        then
                              输出number不换行
                        END IF
                   END IF
                   ELSE
                   then
                        直接输出number,并换行     
                        
                        number = 0;
			sign = 0;       //变量归零
                   END IF
            END IF
            ELSE
                  IF sign = 0
                  then      
                        IF str[i] = '.'
                        then      
                              输出小数点,不换行
                        END IF
                        
                        ELSE 
                        then
                              输出字符,换行
                        END IF
                        IF str[i] = 40 //左括弧的ASCII码值
                        then
                              flag = 1
                        END IF
                  END IF
            END IF
- 
2.3.2 代码截图 
  
  
  
  
  
- 
2.3.3 说明和超星视频做法区别,各自优缺点 - 超星:
 1.遇到数字或小数点,或是符号位的+、-,直接输出不换行
- 自己:
 不足
 1.将字符数字转化为了数值,未考虑到可以直接输出,导致代码冗长
 2.多判断了符号位的+、-,将+、-连同数值一起输出
 
- 超星:
 
                    
                 


 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号