第9章习题

18060 删除空格

用指针方法解决,输入一个字符串,删除字符串中所有空格后,输出字符串
输入格式
一行字符,以换行回车结束,最多不超过80个字符
输出格式
删除所有空格后输出
输入样例
abc    456
输出样例
abc456
#include <stdio.h>
void removeSpace(char *s)
{
int j=0,i=0;//
    for(i=0;s[i]!='\0';i++)
    {
        if(s[i]!=' ')
        s[j++]=s[i];
    }
    s[j]='\0';//_______________________
}
int main()
{
    char s[81];
    gets(s);
    removeSpace(s);
    printf("%s", s);
    return 0;
}

18061 数的交换

输入10个整数,把其中最小的数与第一个数交换,最大的数与最后一个数交换。使用3个函数解决问题:
(1) 输入10个整数的函数
(2) 进行交换处理的函数
(3) 输出10个数的函数
输入格式
输入10个整数
输出格式
输出结果,一行一个数字
输入样例
2 1 3 4 5 6 7 8 9 0
输出样例
input done
swap done
0
1
3
4
5
6
7
8
2
9
display done
#include <stdio.h>
void input(int a[])
{
    for(int i=0;i<10;i++)
      scanf("%d",&a[i]);//_______________________
}

void swap(int a[])
{
   int min=a[0],max=a[0],t,j,k;
   for(int i=0;i<10;i++)
   {
       if(max<a[i])
        {max=a[i];
          j=i;}
       if(min>a[i])
        {min=a[i];
          k=i;}
   }
  t=a[0];
    a[0]=min;
    a[k]=t;//注意题目顺序,先换最小再换最大
   t=a[9];
    a[9]=max;
    a[j]=t; //_______________________
}

void display(int a[])
{
    int i;
    for(i=0; i<10; i++)
        printf("%d\n", a[i]);
}

int main()
{
    int a[10];
    input(a);
    printf("input done\n");
    swap(a);
    printf("swap done\n");
    display(a);
    printf("display done\n");
    return 0;
}

18062 二维数组每行中的最大值

输入一个4*4的二维整型数组,使用指针变量查找并输出二维整型数组中每一行的最大值。
输入格式
4*4的整数矩阵
输出格式
每行最大值,一行一个
输入样例
1 2 3 4
8 7 6 5
1 1 1 1
2 2 2 2
输出样例
4
8
1
2
#include <stdio.h>
void find(int a[][4])
{
    int (*p)[4], *q, *max;
    for(p = a;p < a + 4;p++)//for(_______________________)
    {
        max=*p;
        for(q = *p+1;q < *p + 4;q++)
        {
        if(*max < *q)   
         *max = *q; //_______________________
        }
        printf("%d\n", *max);
    }
}

int main()
{
    int a[4][4],i,j;
    for(i=0; i<4; i++)
        for(j=0; j<4; j++)
            scanf("%d", &a[i][j]);
    find(a);
    return 0;
}

18063 圈中的游戏

有n个人围成一圈,从第1个人开始报数1、2、3,每报到3的人退出圈子。编程使用链表找出最后留下的人
输入格式
输入一个数n,1000000>=n>0 
输出格式
输出最后留下的人的编号
输入样例
3
输出样例
2

//这个方法来自下面百度出来的,简简单单绝绝子
#include <stdio.h>
int main()
{
    int n,m=3,s=0;
    scanf("%d",&n);
    for (int i=2;i<=n;++i)
        s=(s+m)%i;
    printf("%d\n",s+1);
    return 0;
}

有n个人围成一圈.从第一个人开始报数(从1到m报数),凡报到m的人退出圈子, 问最后留下的是第几号人

此题可用数学方法求解。

设有n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数  (用数学方法解的时候需要注意应当从0开始编号,因为取余会取到0解。)

实质是一个递推,n个人中最终留下来的序号与n-1个人中留下来的人的序号有一个递推关系式。

假设除去第k个人,则

0, 1, 2, 3, ..., k-2, k-1, k, ..., n-1          // 原始序列 (1)

0, 1, 2, 3, ..., k-2,      , k, ..., n-1        // 除去第k人,即除去序号为k-1的人   (2)

k, k+1, ..., n-1,    0,    1,        ..., k-2  // 以序号k为起始,从k开始报0  (3)

0, 1,     ..., n-k-1, n-k, n-k+1, ..., n-2   // 作编号转换,此时队列为n-1人  (4)

变换后就完完全全成为了(n-1)个人报数的子问题,注意(1)式和(4)式,是同一个问题,不同的仅仅是人数。比较(4)和(3),不难看出,0+k=k, 1+k=k+1, ... ,(3)式中'0'后面的数字,((n-3)+k)%n=k-3,((n-2)+k)%n=k-2,
对于(3)式中'0'前面的数字,由于比n小,也可看作(0+k)%n=k,  (1+k)%n=k+1,  故可得出规律:设(3)中某一数为x' , (4)中对应的数为x,则有:x'=(x+k)%n。设x为最终留下的人序号时,队列只剩下1人时,显然x=0; 此时可向前回溯至2人时x对应的序号,3人时x对应的序号……直至n人时x的序号,即为所求。

#include <stdio.h>
int main()
{
    int n,m,s=0;
    scanf("%d%d",&n,&m);
    for (int i=2;i<=n;++i)
        s=(s+m)%i;
    printf("%d\n",s+1);
    return 0;
}

 其他方法:

//标程,我是傻子没看懂
#include <stdio.h>
int c[1000000];
int main()
{
    int i, j, n, pre, cur;
    scanf("%d", &n);
    if(n==1) printf("1\n");
    else
    {
        for(i=0; i<n-1; i++) c[i]=i+1;
        c[n-1]=0;
        cur=n-1;
        for(i=0; i<n-1; i++)
        {
            for(j=0; j<3; j++)
            {
                pre = cur;
                cur=c[cur];
            }
            c[pre]=c[cur];
        }
        printf("%d", pre+1);
    }
    return 0;
}
#include <stdio.h>

int peopleNum[1000010];
int main()
{
    int n;
    scanf("%d",&n);//总人数
    int restNum = n;//剩余人数,初始为n
    int count = 1;//报的数
    int position = 1;//指针的位置,初始指向表头

    while(restNum > 0){
        //初始/剩余一个人且指针的位置为0
        if(restNum == 1 && peopleNum[position] == 0){
            printf("%d",position);//直接输出
            return 0;
        }
        if(peopleNum[position] == 0){ //指针在表头
            if(count == 3){
                peopleNum[position] = 1;//设1为被剔除的人
                count = 0;//重新报数
                restNum--;//剩余人数-1
            }
            count++;//继续报数
        }
        if (position == n){
            position = 1; //指针遍历完一轮表,重新回到表头再次遍历
        }
        else{
            position++;//指针遍历表
        }
    }
    return 0;
}

  类似题目(循环队列解决):洛谷P1996 约瑟夫问题

#include <stdio.h>
#include <stdlib.h>
typedef struct people
{
    int id;              //数据域
    struct people *next;  //指针域
} LinkList;
int main()
{
    int n, i;
    scanf("%d", &n);
    LinkList *head, *node, *end;         //定义头节点,普通节点,尾部节点;
    head = (LinkList *)malloc(sizeof(LinkList));    //分配空间
    head->id = 1;   //头节点
    head->next = NULL;
    end = head;          //空链表头等于尾部

    for (i = 2; i <= n; ++i){  //创建普通节点
        node = (LinkList *)malloc(sizeof(LinkList));
        node->id = i;      //对应ID
        end->next = node;    //第一次运行时此处r为头节点地址,所以将p的指针域指向第一个s
        end = end->next;    //将r向后移
    }
    end->next = head;    //本题特殊的地方,因为题目是个圈,所以要回到开头!!
    int num = 0;
    while (n > 1){     //循环到只剩一个人
        if (head->id != 0){     //如果头节点不等于0
            num++;      //报数号
            if (num % 3 == 0){  //如果报到3
                n--;
                head->id = 0;  //将id设为0表示已经踢出,这里是网上一个人的方法
            }
            head = head->next;  //下一个
        }
        else head = head->next;     //如果头节点为0则跳过,不用报数
    }
    while (!head->id)head = head->next;      //如果id为0则是已经被踢出的
    printf("%d", head->id);
    return 0;
}

18064 链表的有序合并

已知有两个链表a和b,结点类型相同,均包括一个int类型的数据。编程把两个链表合并成一个,结点按升序排列。
输入格式
第一行一个数n,表示第一个列表的数据个数
每二行为n个数
第三行为一个数m
第四行为m个数
输出格式
输出合并后的有序的数据,一行一个数
输入样例
2
4 8
3
9 1 5
输出样例
1
4
5
8
9
//这道题我愿称之为我是裁缝,三段代码都是从实验9复制过来的
#include "stdio.h"
#include "malloc.h"
#define LEN sizeof(struct DATA)
struct DATA
{
     long num;
     struct DATA *next;
};

struct DATA *create(int n)
{
     struct DATA *head=NULL,*p1=NULL,*p2=NULL;
     int i;
     for(i=1;i<=n;i++)
     {  p1=(struct DATA *)malloc(LEN);
        scanf("%ld",&p1->num);
        p1->next=NULL;
        if(i==1) head=p1;
        else p2->next=p1;
        p2=p1;
      }
      return(head);
}

struct DATA *merge(struct DATA *head, struct DATA *head2)
{
    struct DATA *p1;//------------------------
   p1=head;
   while (p1->next!=NULL)
    p1=p1->next;
   p1->next=head2;//--------------------------
    return head;
}

struct DATA *insert(struct DATA *head, struct DATA *d)
{
   struct DATA *p0,*p1,*p2;//---------------------
    p1=head;
    p0=d;
    if(head==NULL)//如果head是空表 则令head指向p0 ,p0的next指向null
    {
        head=p0;
        p0->next=NULL;
    }
    else //否则当需要插入的号码大于原有表中的号码且原有表p1的next不为空时,     
    {     //让p2指向p1,p1指向下一个
        while((p0->num>p1->num)&&(p1->next!=NULL))
        {
            p2=p1;
            p1=p1->next;
        }
        if(p0->num<=p1->num)
//说明p0在p1前面,如果前面没有其他元素了,head->p0->p1;
//如果前面还有其他元素head->...->p2->p0->p1
        {
            if(head==p1)head=p0;
            else p2->next=p0;
            p0->next=p1;
        }
        else//如果p0在p1后面 p1->p0->null
        {
            p1->next=p0;
            p0->next=NULL;
        }
    }//------------------------------------------
    return head;
}

struct DATA *sort(struct DATA *head) 
{ 
   struct DATA *head2=NULL;//-------------------
    if(head==NULL) return NULL;
    struct DATA *p=head, *p2;
    while(p!=NULL)
    {    //应该是将链表中的结点依次,按顺序大小插入到链表中的位置
        p2=p->next;
        p->next=NULL;
        head2=insert(head2,p);
        p=p2;
    }
    return head2;//-----------------------
    return head;
} 

void print(struct DATA *head)
{
    struct DATA *p;
    p=head;
    while(p!=NULL)
    {
        printf("%ld",p->num);
        p=p->next;
        printf("\n");
    }
}

main()
{
    struct DATA *head, *head2;
    int n;
    long del_num;
    scanf("%d",&n);
    head=create(n);
    scanf("%d",&n);
    head2=create(n);
    head = merge(head, head2);
    head = sort(head);
    print(head);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值