2019春第十二周作业

这个作业属于哪个课程 C语言程序设计II
这个作业要求在哪 2019年春第十二周作业
我在这个课程的目标是 能够掌握(1)二级指针的概念,以及指针数组的应用;(2)了解指针与函数的关系,掌握指针作为函数返回值;(3)掌握单向链表的概念和操作(建立、增加、删除、修改、遍历)
这个作业在哪个具体方面帮助我实现目标 通过PTA作业实践编程学习
参考文献 C语言程序设计

基础作业

1.函数题:计算最长的字符串长度

本题要求实现一个函数,用于计算有n个元素的指针数组s中最长的字符串的长度。
~~函数接口定义:

int max_len( char *s[], int n );

其中n个字符串存储在s[]中,函数max_len应返回其中最长字符串的长度。

裁判测试程序样例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXN 10
#define MAXS 20

int max_len( char *s[], int n );

int main()
{
    int i, n;
    char *string[MAXN] = {NULL};

    scanf("%d", &n);
    for(i = 0; i < n; i++) {
        string[i] = (char *)malloc(sizeof(char)*MAXS);
        scanf("%s", string[i]);
    }
    printf("%d\n", max_len(string, n));

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

4
blue
yellow
red
green

输出样例:

6

1).实验代码

int max_len( char *s[], int n )
{
	static int lenth,i;
	for(i = 0; i < n; i++){
		lenth=lenth>strlen(s[i])?lenth:strlen(s[i]);
	}
	return lenth;
 }

2).设计思路

第一步:定义两个整型变量lenth,i;lenth记录最长的字符串的长度,i作为循环变量。
第二步:通过for循环逐个比较字符串长度,记录较长的字符串长度。
第三步:返回lenth的值。

3).本题调试过程碰到的问题以及解决办法


没有问题

4).运行结果截图

2.函数题:统计专业人数

本题要求实现一个函数,统计学生学号链表中专业为计算机的学生人数。链表结点定义如下:

struct ListNode {
    char code[8];
    struct ListNode *next;
};

这里学生的学号共7位数字,其中第2、3位是专业编号。计算机专业的编号为02。

函数接口定义:

int countcs( struct ListNode *head );

其中head是用户传入的学生学号链表的头指针;函数countcs统计并返回head链表中专业为计算机的学生人数。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct ListNode {
    char code[8];
    struct ListNode *next;
};

struct ListNode *createlist(); /*裁判实现,细节不表*/
int countcs( struct ListNode *head );

int main()
{
    struct ListNode  *head;

    head = createlist();
    printf("%d\n", countcs(head));
	
    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

1021202
2022310
8102134
1030912
3110203
4021205

输出样例:

3

1).实验代码

int countcs( struct ListNode *head )
{
    static int js;
    while(head!=NULL){
        if(head->code[1]=='0'&&head->code[2]=='2'){
            js++;
        }
        head=head->next;
    }
    return js;
}

2).设计思路

第一步:定义一个整型变量js记录计算机专业的人数。
第二步:通过while循环逐个判断学号的二三个数字是否为02,是则js++;
第三步:返回js的值。

3).本题调试过程碰到的问题以及解决办法


答案错误和段错误,仔细检查代码发现while循环的判断条件有误,由于while循环中的head=head->next;已改变了head的地址,所以判断条件应改为head!=NULL。

4).运行结果截图

3.函数题:删除单链表偶数结点

本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:

struct ListNode {
    int data;
    struct ListNode *next;
};

函数接口定义:

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );

函数createlist从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。
函数deleteeven将单链表head中偶数值的结点删除,返回结果链表的头指针。

裁判测试程序样例:

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
void printlist( struct ListNode *head )
{
     struct ListNode *p = head;
     while (p) {
           printf("%d ", p->data);
           p = p->next;
     }
     printf("\n");
}

int main()
{
    struct ListNode *head;

    head = createlist();
    head = deleteeven(head);
    printlist(head);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:
1 2 2 3 4 5 6 7 -1
输出样例:
1 3 5 7

1).实验代码

struct ListNode *createlist()
{
	struct ListNode *head=NULL,*p,*tail;
	int data;
	
	scanf("%d",&data);
	while(data!=-1){
		p=(struct ListNode *)malloc(sizeof(struct ListNode));
		if(head==NULL)
		    head=p;
	    else
	        tail->next=p;
	
	p->data=data;
	tail=p;
	scanf("%d",&data);
}
    p->next=NULL;
	return head;
 } 
 
 struct ListNode *deleteeven( struct ListNode *head )
 {
 	struct ListNode *ptr1,*ptr2;
 	while(head!=NULL&&head->data%2==0){
 		free(head)
                head=head->next;
	 }	
	 if(head==NULL)
	 return NULL;
	 
	 ptr1=head;
	 ptr2=head->next;
	 while(ptr2!=NULL){
	 	if(ptr2->data%2==0){
	 	ptr1->next=ptr2->next;
                free(ptr2);
	 }
	    else
	    ptr1=ptr2;
	 
	 ptr2=ptr1->next;
 }
 return head;
}

2).设计思路


创建链表函数:申请一个空间存结构,把申请到的空间的地址给指针p,输入结构成员的值,把p的成员的值给另一个指针tail,如果不是第一次申请空间,就把p的地址给上一个结构也就是指针tail所指的结构。循环上述过程,直到输入结束符。
删除节点函数:定义两个结构指针ptr1和ptr2,通过第一个while循环找到一个成员的值为奇数的结构作为链表首地址,再通过第二个while逐个判断下一个结构成员的值是否为奇数,是则把下一个结构的地址给当前结构,否则把下下个结构的地址给当前结构,循环上述过程,直到最后一个结构。

3).本题调试过程碰到的问题以及解决办法


没有问题

4).运行结果截图

挑战作业

1.编程题:八皇后问题(用递归法)

在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。
现在我们把棋盘扩展到 n × n 的棋盘上摆放 n 个皇后,请问该怎么摆?请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两格之间空一格)。

输入格式

正整数 n (0 < n ≤ 12)

输出格式

若问题有解,则输出全部摆法(两种摆法之间空一行),否则输出 None。
要求:试探的顺序逐行从左往右的顺序进行,请参看输出样例2。

输入样例1

3

输出样例1

None

输入样例2

6

输出样例2

. Q . . . .
. . . Q . .
. . . . . Q
Q . . . . .
. . Q . . .
. . . . Q .

. . Q . . .
. . . . . Q
. Q . . . .
. . . . Q .
Q . . . . .
. . . Q . .

. . . Q . .
Q . . . . .
. . . . Q .
. Q . . . .
. . . . . Q
. . Q . . .

. . . . Q .
. . Q . . .
Q . . . . .
. . . . . Q
. . . Q . .
. Q . . . .

1).实验代码

#include<stdio.h>
void queen(int i,int j);     
int check(int i,int j);      
char chess[12][12];          
int a,b,n,sum=0;             
int main(void){
    scanf("%d",&n);
    queen(0,0);
    if(sum==0&&n!=0){
        printf("None"); 
    }
    return 0;
}

void queen(int i,int j){
    if(j>=n){
    return ;  
    }
    if(check(i,j)==1){    
        chess[i][j]='Q';   
        if(i==n-1){        
            sum++;
            if(sum!=1){
            printf("\n\n");
        }         
            for(a=0;a<n;a++){    
                for(b=0;b<n;b++){
                    if(chess[a][b]!='Q'){
                        if(b!=n-1)
                            printf(". ");
                        else
                            printf(".");
                    }
                    if(chess[a][b]=='Q'){
                        if(b!=n-1)
                            printf("Q ");
                        else
                            printf("Q");
                    }
                }
                if(a!=n-1)
                printf("\n");
            
            }
        }
        else{
            queen(i+1,0); 
        }
    }
    chess[i][j]='.';                  
    queen(i,j+1);
}

int check(int i,int j){
    int k;
    for(k=0;k<n;k++){
        if(chess[i][k]=='Q')
            return 0;                   
    }
    for(k=0;k<n;k++){
        if(chess[k][j]=='Q')
            return 0; 
    }
    for(k=-n;k<=n;k++){                 
        if(i+k>=0&&i+k<n&&j+k>=0&&j+k<n)
            if(chess[i+k][j+k]=='Q') return 0;
        if(i-k>=0&&i-k<n&&j+k>=0&&j+k<n)
            if(chess[i-k][j+k]=='Q') return 0;
    }
    return 1;
}

2).设计思路


第一步:假如要在n*n的棋盘上摆放n个皇后,首先要确定第1行皇后的位置,然后确定第2行皇后的位置,直到确定第n行皇后的位置。
第二步:假如第m行皇后没有位置可以摆放了,就要改变第m-1行皇后的位置,然后确定第m行皇后的位置,如果还是没有位置可以摆放,就再改变第m-1行皇后的位置,然后再确定第m行皇后的位置,如果直到第m-1行没有其它位置可以改变,还没有找到第m行皇后的位置,就要改变m-2行皇后的位置,从而改变第m-1行皇后可以摆放的位置,然后再通过第m-1行皇后的位置确定第m行皇后的位置,以此类推,如果直到第1行都没有其他位置可以改变,则输出None。
第三步:通过第二步的方法,如果找到了第n行皇后的位置,输出矩阵,是皇后的位置输出Q,不是则输出.

3).本题调试过程碰到的问题以及解决办法


有一个测试点答案错误,不知道这个测试点测试的是什么,然后拿着完全正确的代码试了一下,发现输入0的时候应该什么都不输出,而我的代码会输出None,将是否输出None的判定条件改为if(sum==0&&n!=0)后答案正确。

4).运行结果截图

2.编程题:求迷宫最短通道

递归求解迷宫最短通道的总步长。输入一个迷宫,求从入口通向出口的可行路径中最短的路径长度。为简化问题,迷宫用二维数组 int maze[10][10]来存储障碍物的分布,假设迷宫的横向和纵向尺寸的大小是一样的,并由程序运行读入, 若读入迷宫大小的值是n(3<n<=10),则该迷宫横向或纵向尺寸都是n,规定迷宫最外面的一圈是障碍物,迷宫的入口是maze[1][1],出口是maze[n-2][n-2], 若maze[i][j] = 1代表该位置是障碍物,若maze[i][j] = 0代表该位置是可以行走的空位(0<=i<=n-1, 0<=j<=n-1)。求从入口maze[1][1]到出口maze[n-2][n-2]可以走通的路径上经历的最短的总步长。要求迷宫中只允许在水平或上下四个方向的空位上行走,走过的位置不能重复走。

输入格式:

输入迷宫大小的整数n, 以及n行和n列的二维数组(数组元素1代表障碍物,0代表空位)

输出格式:

若有可行的通道则输出一个整数,代表求出的通道的最短步长;若没有通道则输出"No solution"

输入样例:

10
1 1 1 1 1 1 1 1 1 1
1 0 0 1 0 0 0 1 0 1
1 0 0 1 0 0 0 1 0 1
1 0 0 0 0 1 1 0 0 1
1 0 1 1 1 0 0 0 0 1
1 0 0 0 1 0 0 0 0 1
1 0 1 0 0 0 1 0 0 1
1 0 1 1 1 0 1 1 0 1
1 1 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
上述输入代表的是如下这样一个迷宫:

其中红色的小方块是障碍物,蓝色的小方块是空位,白色的小圆连起来是一条从入口到出口的通道,两个圆之间代表一个步长。

输出样例:

14

1).实验代码

#include<stdio.h>

void hanshu1(int h,int l);

int n,i,j,short_bushu=999,bushu=0;
int maze[12][12];

int main()
{
	scanf("%d",&n);

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

	hanshu1(1,1);

	if(short_bushu==999){
		printf("No solution");return 0;
	}

	printf("%d",short_bushu);
	return 0;
} 
	
void hanshu1(int h,int l)
{
	if(maze[h-1][l]==0){
		bushu++; maze[h-1][l]=2;
		if(h-1==n-2&&l==n-2){
			if(short_bushu>bushu)
			short_bushu=bushu;
		}
		hanshu1(h-1,l);
	}

	if(maze[h+1][l]==0){
		bushu++; maze[h+1][l]=2;
		if(h+1==n-2&&l==n-2){
			if(short_bushu>bushu)
			short_bushu=bushu;
		}
		hanshu1(h+1,l);
	}

	if(maze[h][l-1]==0){
		bushu++; maze[h][l-1]=2;
		if(h==n-2&&l-1==n-2){
			if(short_bushu>bushu)
			short_bushu=bushu;
		}
		hanshu1(h,l-1);
	}

	if(maze[h][l+1]==0){
		bushu++; maze[h][l+1]=2;
		if(h==n-2&&l+1==n-2){
			if(short_bushu>bushu)
			short_bushu=bushu;
		}
		hanshu1(h,l+1);
	}

	bushu--;
	maze[h][l]=0;
}

2).设计思路

第一步:从起点开始,记录上下左右能走的点。
第二步:分别以上一次记录的点为起点,记录上下左右能走的点,记录过的点为不能走的点,步数加一。
第三步:如果该点的上下左右都不能走,则停止这条线的记录,步数减一。
第四步:如果能走的点为终点,记录这条线走过的点的数量,比较多条到终点的线走过的点的数量,输出最少的数量减去一的值。

3).本题调试过程碰到的问题以及解决办法

部分答案错误,多为判断条件的问题,多次调试后解决。

4).运行结果截图

预习作业

从第十三周开始,将进入课程设计阶段,请在本次作业中给出:
1.所在小组想要开发的项目的名称和目标;
项目的名称:人抓鹿 目标:实现游戏设想
2.项目主体功能的描述;
通过鼠标控制人物移动,键盘控制人物攻击,鹿躲开人随机移动,地图随机生成道具,道具的功能包括:伤害人物,不同的武器,加血,增减移动速度等,人可以通过武器或手对鹿造成不同的伤害,鹿没血后游戏胜利,人物没血后游戏失败。
3.现阶段已做的准备工作;
游戏创意,学习用的书籍。
4.小组成员名单和进度安排。(课程设计阶段:13-17周)
何磊 李代传 颜晴 汤云云
先学习游戏制作的基础技能,然后逐步实现游戏创意,最后测试。

二、学习进度统计

周/日期 这周所花的时间 代码行 学到的知识点简介 目前比较迷惑的问题
3/2-3/8 2h 23行 数组
3/9-3/11 3h 29行 读取文件数据
3/12-3/18 5h 70行 用数组输出矩阵
3/19-3/25 8h 140行 多种排序方法
3/26-4/1 5h 82行 字符(串)数组的相关知识
4/2-4/8 2h 63行 指针的相关知识
4/9-4/15 10h 90行 指针的相关知识
4/16-4/22 5h 152行 常用字符串函数以及使用指针操作字符串的方法,掌握动态内存分配
4/23-4/29 2h 60行 能够根据实际情况合理定义结构,能够使用结构变量与结构数组进行熟练编程,掌握结构指针的操作,并应用于函数传递
5/7-5/13 20h 200行 能够对相对复杂的问题,合理定义程序的多函数结构;能够使用递归函数进行编程;掌握宏的基本用法;掌握编译预处理的概念。 怎样又快又好的总结出递归式子
5/14-5/20 10h 185行 能够掌握(1)二级指针的概念,以及指针数组的应用;(2)了解指针与函数的关系,掌握指针作为函数返回值;(3)掌握单向链表的概念和操作(建立、增加、删除、修改、遍历)

三、学习感悟

这周学习了(1)二级指针的概念,以及指针数组的应用;(2)了解指针与函数的关系,掌握指针作为函数返回值;(3)掌握单向链表的概念和操作(建立、增加、删除、修改、遍历),新知识的学习提升了我的能力,以后可以解决更多问题了,遇到的困难要善于寻求帮助,问题不解决就永远都是问题!

四、结对编程过程和结对编程的优缺点

队员优点:1.对不懂的问题善于寻求帮助:结对编程过程中,碰到一个棘手的问题,队员及时百度并向大佬询问,问题一下就解决了。
2.有灵性:对于要用到的新知识点一看就理解了,对于疑惑一点就通
3.冷静不浮躁:当遇到难以解决的问题时,能冷静的需求解决办法,而不是怨天尤人。
缺点:不主动和队友交流:经常有新的想法时不第一时间和队友交流,而是自己独自思考。
结对编程的优点:(1)在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
(2)对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。
(3)在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。
(4)在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。
总之,如果运用得当,结对编程能得到更高的投入产出比(Return of Investment)。
不适合结对编程的情况:
并不是所有的项目都适合结对编程,下面是一些不适合使用的例子。
1)处于探索阶段的项目,需要深入地研究,在这种情况下,一个人长时间的独立钻研是有必要的。
2)在做后期维护的时候,如果维护的技术含量不高,只需要做有效的复审即可,不必拘泥于形式,硬拉一个人来结对唱二人转。
3)如果验证测试需要运行很长时间,那么两个人在那里等待结果是有点浪费时间。

posted @ 2019-05-16 15:01  hlywww  Views(187)  Comments(1Edit  收藏  举报