【C语言】好题分享——序列中删除指定元素


前言

🎉在此先祝xdm五一快乐!!


那么,从本blog开始,往后将会定期总结整理一些本人认为较有代表性的题目,分享给大家一些我的思路以及做题过程中的心得体会,如果有错误的地方也欢迎大家指正!一起学习,共同进步。



1️⃣题目

❓ 输入一个字符串以及指定一个字符,并删除字符串中指定的字符,如果字符串中没有该字符则不删除。



2️⃣破题思路及代码演示

1.错误反思

由题目我得出一个思路,创建一个字符数组(既字符串),再从中删除指定的字符。仔细回想所学过的C语言知识,发现目前为止学到的并没有一个能直接删除数组中元素的指令,那我该如何模拟实现这个删除呢?第一次解题时我敲出了如下代码(前方高能!buggg来了):

int main()
{
	char str[99] = "0";
	gets(str);//输入目标字符串
	char del = getchar();//输入指定删除的字符
	int i = 0;
	for (i = 0;str[i]!='\0';i++)
	{
		if (str[i] == del)
		{
			str[i] = NULL;
		}
	}
	puts(str);
	return 0;
}

结果:
在这里插入图片描述

什么!删除之后整个字符串都被删除了!?
⭕这里我犯了一个错误,把空字符NULL误认为是无字符了,其实NULL也是一个字符,它就是我们熟知的’\0’字符串结束标志,ASCII码是0。这里我认为的将字符串的第一个字符删除实际上是将其替换为’\0’,因此输出字符串时遇到第一个字符就是’\0’,那么也就不会再输出后面的内容了。


2.正确示范

那么我们到底如何模拟实现“删除”功能呢?
💡思路:我们可以想象这样一个场景。当我们去食堂排队买饭时,每次前面一位同学刚刚买完离开,后面的所有同学都依次往前移动一位(这里称之为一次移动),填补掉前面的空位。每进行一次移动,原位上的人都不相同。如果队列中间有某位同学突然不想吃这家的饭离开了队列,那么他前面的队伍保持不变,而后面的队伍向前移动一次。
一样的道理,我们可以把字符串中指定删除的字符看成这位中途离开的同学,删除指定字符可以转换为后面的所有元素往前进位,填补掉这个字符。

通过动图,让原理一目了然!
在这里插入图片描述

如何用代码实现这一功能呢?
⭕代码演示如下:

#include<stdio.h>
int main()
{
	char str[99] = "0";
	gets(str);//输入目标字符串
	char del = getchar();//输入指定删除的字符
	int i = 0;
	for (i = 0;str[i]!='\0';i++)//枚举字符串中所有字符('\0'除外)
	{
		if (str[i] == del)//寻找指定删除的字符
		{
			int j = 0;
			for (j = i;str[j] != '\0';j++)//找到之后,开始从后面往前填补
			{
				str[j] = str[j + 1];
			}
			i--;
		}
	}
	printf("删除后的字符串:");
	puts(str);
	return 0;
}

⭕结果:
在这里插入图片描述
通过监视我们能更加直观的观察到删除指定字符的实现:
在这里插入图片描述在这里插入图片描述

可以看到,删除功能执行之后,第一个元素从’I’变成了逗号’,‘,而且第一个’\0’的位置从下标10变为下标9。可见,该字符串的字符个数确实减少了一个。

如果字符串中有重复多个指定删除字符,功能依然可以实现。
在这里插入图片描述


3️⃣题目延伸

🧐上述是删除字符串中的指定字符的方法。我们知道,在C语言中不仅有字符数组,更常见的是整数数组,那么想要在整数序列(也就是整数数组)中删除指定整数应该怎么实现呢?下面看一道例题。

有一个整数序列(可能有重复的整数),现删除指定的某一个整数,输出删除指定数字之后的序列,序列中未被删除数字的前后位置没有发生改变。
第一行输入一个整数(0≤N≤50)。
第二行输入N个整数,输入用空格分隔的N个整数。
第三行输入想要进行删除的一个整数。
输出描述:
输出为一行,删除指定数字之后的序列。

————来源:牛客网


我们知道,字符串数组的最后有’\0’作为结束标志,无论第一个‘\0’在什么位置,只要输出函数的输出格式是字符串(printf中格式控制符是%s和puts(字符串名)),遇到‘\0’就会停止输出,所以我们在实现删除指定字符的时候,由于‘\0’也跟着移动,字符串的长度会实时地根据‘\0’的位置而变化。但是,整数数组可没有这个功能,那该如何实现删除功能呢?

🔻🔻

💡思路一:

规定整数序列长度N后,在遍历数组过程中,每遇到一个指定删除数字,执行一次移动(后面数字往前补位)之后,序列长度N减一,最后打印出字符序列只需用一个循环变量大于0小于N的循环即可

⭕代码演示如下

#include <stdio.h>
int main()
{
    int arr[50] = { 0 };
    int N = 0;
    scanf("%d", &N);//规定了整数序列的长度

    int i = 0;
    for (i = 0;i < N;i++)//给整数序列中的每一个数赋值
    {
        scanf("%d", &arr[i]);
    }

    int del = 0;
    scanf("%d", &del);//输入想要删除的数

    for (i = 0;i < N;i++)//关键来了!!!
    {
        if (arr[i] == del)//寻找指定删除的数
        {
            int j = 0;
            for (j = i;j < N;j++)
            {
                arr[j] = arr[j + 1];//从这个数开始往后的数向前补位
            }
            N--;//删除(补位)完毕后,整数序列长度减一
            i--;//数组下标先减一再加一,确保了两个重复的删除数挨在一起的情况
        }
    }

    for (i = 0;i < N;i++)//打印出来整数序列的每一个数(不是打印整个数组)
    {
        printf("%d ", arr[i]);
    }

    return 0;
}

⭕运行结果:

在这里插入图片描述
⭕助理解图:
在这里插入图片描述

💡思路二:

所谓删除,换句话说,不就是留下想要的去除不要的吗?那么我们可以换个角度考虑,只要我们把不是指定删除的数字留下来,就可以实现与思路一同样的效果,那么具体该如何实现呢?见如下代码。

⭕代码演示如下:

#include <stdio.h>
int main()
{
    int arr[50] = { 0 };
    int N = 0;
    scanf("%d", &N);//规定了整数序列的长度

    int i = 0;
    for (i = 0;i < N;i++)//给整数序列中的每一个数赋值
    {
        scanf("%d", &arr[i]);
    }

    int del = 0;
    scanf("%d", &del);//输入想要删除的数
    int j = 0;
    for (i = 0;i < N;i++)
    {
        if (arr[i] != del)//找出每一个非指定删除数的数字。
        {
            arr[j++] = arr[i];
            //留下一个j就加一,最后j是数组长度(这里的j++是先调用j再自增1)
        }
    }
    printf("删除后的序列:");
    for (i = 0;i < j;i++)//打印出来整数序列的每一个数(这里的j表示数组长度)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

⭕运行结果:
在这里插入图片描述
⭕助理解图:
在这里插入图片描述
注:省略号后的元素都为0

回到第一道例题。利用思路二我们还可以改造一下删除字符串中的指定字符的模拟实现,具体如下:

int main()
{
	char str[99] = "0";
	gets(str);
	char del = getchar();
	int i = 0;
	int j = 0;
	for (i = 0;str[i] != '\0';i++)
	{
		if (str[i] != del)
		{
			str[j++] = str[i];
		}
	}
	printf("删除后的字符串:");
	for (i = 0;i < j;i++)
	{
		printf("%c", str[i]);
	}
	return 0;
}

📌对比思路一,思路二的效率会更快一些。但两种模拟实现删除指定元素的方法,思路一却似乎更有“删除”的意思。



4️⃣总结:

今天的分享就到这里啦!欢迎大家批评指正,如果看过之后有收获,不妨点个赞呀!如果大家有更好的思路,欢迎向我留言!
🎉🎊🎈最后,祝大家五一快乐,天天进步,写程序永远写不出bug!!!!

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 21
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值