第十二周作业

这个作业属于那个课程 C语言程序设计II
这个作业要求在哪里 第十二周作业要求
我在这个课程的目标是 (1)二级指针的概念,以及指针数组的应用;(2)了解指针与函数的关系,掌握指针作为函数返回值;
这个作业在哪个具体方面帮助我实现目标 锻炼了我的编程能力,加深了我对二级指针和链表的使用
参考文献 C语言程序设计II第十一章

6-1 计算最长的字符串长度 (15 分)

本题要求实现一个函数,用于计算有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
", max_len(string, n));
    return 0;
}

/* 你的代码将被嵌在这里 */
输入样例:
4
blue
yellow
red
green
输出样例:
6

实验代码

int max_len( char *s[], int n )
{   int max1=0,i;
    for(i=0;i<n;i++){
        if(strlen(s[i])>max1)          //还可以用三元运算符( ?:),如后: max1=strlen(s[i])>max1?strlen(s[i]):max1;
        max1=strlen(s[i]);
    }
    return max1;
}

具体思路


具体:简单的一个求最大值的题,唯一难点是被判断的数不是像一维数组中的数那么直观。

正确截图

6-2 统计专业人数 (15 分)

本题要求实现一个函数,统计学生学号链表中专业为计算机的学生人数。链表结点定义如下:
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
", countcs(head));
    return 0;
}

/* 你的代码将被嵌在这里 */
输入样例:
1021202
2022310
8102134
1030912
3110203
4021205

输出样例:
3

实验代码

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

具体思路

正确截图

6-3 删除单链表偶数节点 (20 分)

本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:
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("
");
}
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

实验代码

struct ListNode *createlist()
{
    struct ListNode *address,*p,*head=NULL;
    int x;
    scanf("%d",&x);
    while(x!=-1){
        address=(struct ListNode *)malloc(sizeof(struct ListNode));       //获得新地址
        if(head==NULL)
            head=address;                                                            
        else
            p->next=address;                  //使得上一个结构体中结构指针指向新的结构体
            
        address->data=x;                      //向新的结构体里的date赋值
        p=address;                            //保留地址,当有下一个新结构体地址时,使得上一个结构体内的next指向新结构体
        scanf("%d",&x);
    }
    address->next=NULL;                       //添加链表的结束标志
    return head;
} 

struct ListNode *deleteeven( struct ListNode *head )
{
    struct ListNode *p,*q;
    int x=0;
    p=head;
    while (p!=NULL) {
        if(p->data%2!=0&&x==0){            //确定新链表头
            head=p;
            x++;
        }
        
        if(p->next==NULL)             //如果判断要不要删除的结构体是最后一个,就跳出循环,否则会导致错误
            break;
        
        if(x==1&&p->next->data%2==0){           //如果有头指针了,判断下一个链表是否是偶数节点
            if(p->next->next==NULL){            //如果下一个节点是偶数节点并且是尾指针的话,直接使得判断结构体内的next=NULL
                p->next=NULL;
                break; 
            }
            if(p->next->next->data%2==0){       //如果偶数节点是连续的
                q=p->next->next;                //用新指针来判断,从p后面的第二个连续的偶数节点开始
                while(q!=NULL){
                    if(q->data%2!=0)           //判断是否为奇数节点
                       break;
                    q=q->next;                 //不是就判断下一个
                }
                p->next=q;                   //找到后面的第一个奇数节点后,赋值给p->next,使得下一个链表一定是奇数节点
            }
            else
                p->next=p->next->next;       //如果偶数节点不是两个或两个以上连接在一起的话,直接赋值,使得下一个指向奇数节点
        }
        
        p=p->next;
    }
    if(x==0)
        head=NULL;                          //全为偶数节点,就什么都不输出
    
    return head;
}

struct ListNode deleteeven( struct ListNode head )的精简优化代码:

struct ListNode *deleteeven( struct ListNode *head )
{
    struct ListNode *p,*q,*s;
    int x=0;
    p=head;
    while (p!=NULL) {
        if(p->data%2!=0&&x==0){
            head=p;
            x++;
        }
        if(x==1&&p->next->data%2==0){
            q=p->next;
            while(q!=NULL){
                if(q->data%2!=0)
                    break;
                            s=q;
                q=q->next;
                            free(s);
            }
            p->next=q;
        }
        p=p->next;
    }
    if(x==0)
        head=NULL;
    return head;
}

具体思路


正确截图

遇到的问题及解决方法

单独难以做出这道题,向室友寻求帮助。

预习中的疑惑

(1)二级指针的概念,以及指针数组的应用;(2)了解指针与函数的关系,掌握指针作为函数返回值;(3)游戏的制作该怎么开始。

对自己作业的评价

不满意,基础题的完成还是要人帮助,挑战题只完善了一些,还没有完全解决。

学习进度条

这周所花的时间 代码行 学到的知识点简介 目前比较迷惑的问题
第十二周 十多个小时 200多行 链表的基本使用方法 怎么做出游戏
第十一周 十八个小时以上 200多行 递归思想,具体的递归实现大概规律 命令行参数怎么定义和使用呢
第九周 六个小时 130行 学到了结构体更深层次的用法 命令行参数怎么使用
第八周 八个小时 170多行 学到了结构体的基本用法和性质 结构体里能用static吗?
第七周 六个小时 200多行 学到了scanf的自定输入 在函数声明的形参表中定义一个char *,什么意思
第六周 七个小时 156行 学到了指针的基本用法,还有用指针做自定义函数的形参用法 在函数声明的形参表中定义一个char *,什么意思
第五周 七个多小时 137行 字符串头文件:#include<string.h>.字符串函数:strcpy.字符和字符串的区别。 指针的拓展使用不会
第四周 十多个小时 134行 选择排序法,字符数组和字符串的使用 为什么我在PTA和上用的也是c++编译器,但是在c++上能正确输出,在PTA上就不正确,为什么呢
第三周 八小时 106 二维数组的基本知识 PTA的测试点是啥,第一个题除了穷举法还有没有其他方法?指针在文件中的写入位置在哪?怎么来确定的?
第二周 六个多小时 153 文件的打开与关闭,读取数据与写入数据 指针的用法还是有点不会

学习感悟

自己还是缺少实践能力,对稍难一点题目就没什么办法了。

挑战作业

7-3 ***八皇后问题 (20 分)

#include<stdio.h>
void queen(int i,int j);    //递归函数, 
int check(int i,int j);     //判断是否会遇到其他皇后 的函数 

char chess[13][13];         //最大棋盘 
int a,b,n,sum=0;            //sum记录能摆放的方法次数 

int main(void){
    
    scanf("%d",&n);
    queen(0,0);
    if(sum==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("
");
        
            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");
                    }
                }
                printf("
");
            }
        }
        else{
            queen(i+1,0); //不是最后一行就分析下一行
        }
    }
    chess[i][j]='.';        //如果此位置不能放,就置空(0),判断旁边的格子。
                           //如果此位置能放,走到这里就意味着上面的代码全部执行了,把皇后拿走(置零),再讨论其他情况,拿旁边位置试探。
    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;                   //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.编程题:求迷宫最短通道

7-2 求迷宫最短通道 (20 分)

递归求解迷宫最短通道的总步长。输入一个迷宫,求从入口通向出口的可行路径中最短的路径长度。为简化问题,迷宫用二维数组 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。

思路:用和八皇后一样的回溯算法,不过这次判断的有四个函数,就判断四个方向,一个方向一直试探着走如果走不通就返回上一个走的地方,继续判断四个方向哪里可以坐,一直回溯递归,如果能走到最终点,和上一次走到终点的步长比较,取步长短的。

实验代码

#include<stdio.h>

void pathfinding(int line,int column);

int maze[10][10];
int n,step_length=0,x=1,min_step=0;

int main(void)
{
    int i,i_;
    scanf("%d",&n);
    
    for(i=0;i<n;i++){
        for(i_=0;i_<n;i_++)
            scanf("%d",&maze[i][i_]);
    }

    pathfinding(1,1);
        
    if(x==1)
        printf("No solution");
    else
        printf("%d",min_step);        
}

void pathfinding(int line,int column)
{
    if(line==n-2&&column==n-2){           //走到终点,判断步长 
        if(x==1)                          //不复杂的一般是第一次的步长就是最短 
            min_step=step_length;
        else{                             //复杂的迷宫,有环状回路的 ,会多加一个步长,减掉就行 
            step_length--;
            min_step=step_length<min_step?step_length:min_step;
        } 
        x=0;
        return;
    }
    
    maze[line][column]=1;
    if(maze[line+1][column]!=1){          //判断下面能不能走 
        step_length++;
        pathfinding(line+1,column);
    }
    if(maze[line][column+1]!=1){          //判断右边能不能走
        step_length++;
        pathfinding(line,column+1);
    }
    if(maze[line-1][column]!=1){         //判断上面能不能走
        step_length++;
        pathfinding(line-1,column);
    }
    if(maze[line][column-1]!=1){         //判断左边能不能走
        step_length++;
        pathfinding(line,column-1);
    }
    
    maze[line][column]=0;                //回溯,使走过的变回没走的‘0’ 
    step_length--;                       //步长减一 
}

PTA截图

遇到的问题

测试点出现错误,修改数次也没有办法。
在室友的帮助下,成功地写出这道题。

预习作业
暂时还没有开始游戏的设计。
小组成员名单和进度安排。(课程设计阶段:13-17周)
宋志豪(组长) 尹志 刘硕

原文地址:https://www.cnblogs.com/songzhihaoT1/p/10882872.html