C语言数据结构之扩展字符详解

 更新时间:2024年03月26日 15:17:34   作者:小小的V  
掌握C语言数据结构的关键在于理解其核心概念,扩展字符作为其中的重要一环,对于编程人员来说至关重要,本指南将为您深入剖析扩展字符的相关知识,带您轻松掌握C语言数据结构,让我们一起探索这个令人着迷的领域吧!

题目展示

【问题描述】

从键盘输入包含扩展符'-'的字符串,将其扩展为等价的完整字符,例如将a-d扩展为abcd,并输出扩展后的字符串。

要求:只处理[a-z]、[A-Z]、[0-9]范围内的字符扩展,即只有当扩展符前后的字符同时是小写字母、大写字母或数字,并且扩展符后的字符大于扩展符前的字符时才进行扩展,其它情况不进行扩展,原样输出。例如:a-R、D-e、0-b、4-B等字符串都不进行扩展。

【输入形式】

从键盘输入包含扩展符的字符串
【输出形式】
输出扩展后的字符串

【输入样例1】
ADEa-g-m02
【输出样例1】
ADEabcdefghijklm02

【输入样例2】
cdeT-bcd
【输出样例2】
cdeT-bcd

【样例说明】
将样例1的输入ADEa-g-m02扩展为:ADEabcdefghijklm02;样例2的输入cdeT-bcd中,扩展符前的字符为大写字母,扩展符后的字符为小写字母,不在同一范围内,所以不进行扩展。 

思路分析

首先我们明确一下这道题的目的,即:如果出现“-”且前后均为同类型的字符(整数,大写小写字母),并且满足扩展的顺序(前面的小于后面的),则对其进行扩展,将“-”替换为前后两个字符中间的字符。

所以我们要处理以下的问题:

1.如何判断前后字符是否符合条件

2.如何进行替换,选择什么样的数据结构来进行实现?是否只需要对原来的字符串进行操作?还是需要额外再申请空间?

切入点是:把“-”替换成为中间的字符,那么,首先想到的是读到“-”的时候就去把相应的位置替换。但是原来的字符串没有办法扩展空间(当然如果是使用的动态内存申请另说),而且就算使用的是动态内存申请,那么每添加一个字符就会需要把后面所有的字符全部向后移动一位,因此耗费时间很大,并不划算。(这里没有使用链表,当然,如果使用链表的话会非常简单)

在不使用链表的情况下,我们只能选择数组来进行数据的存储。这里我来谈谈第一个很重要的思想:删除/替换,不一定非要盯着原来的结构不放,不妨换个思路,使用另外一个数组来把符合条件的元素留下,再把需要进行操作的元素进行相应的操作后再放进新的数组里面,这样就会节省很多的时间。

因此,我们使用新数组newstr来存储改变后的字符串。具体的操作如下:

1.从头开始遍历,当元素不是要被替换的元素时,直接把他存储到新数组中。

2.当遇到“-”的时候,把前面一个字符记为begin,后面一个字符记为end,然后对这两个字符进行是否符合条件的判断,如果符合,那么进行一个while循环,把从begin到end的所有字符放入新数组中,然后原数组继续前进;如果不符合条件,直接原数组前进,跳过“-”。

3.最后在新数组后面加上“\0”,代表他是一个字符串。

其实整个过程还是十分清晰的,关键点有几个:

1.使用新数组进行存储,让时间复杂度为O(n).

2.最后要给新的字符串加上‘\0’让输出能够正常输出。

小小的延申

针对这道题,其实还有一个很相像的操作,即删除字符串中的指定字符,这个由于我们一种思路是可以使用新数组来存储,但是需要花费额外的空间;还有一种的可行思路是:只针对字符串的本身进行操作,使用类似双指针的方法,设置快慢指针(即快慢下标),如果是正常的字符,快慢下标同时向前移动,快指针给满指针赋值;当遇到要被删除的指针时,快指针还是正常向前,但是慢指针则停在原处,此时快指针已经跳过了待删除的字符,直接将下一位字符赋值给仍然处在待删除位置的慢指针,将原来的内容覆盖掉了,巧妙地实现了覆盖。

那么如何实现快与慢呢?快指针由于是全过程都需要遍历的,因此我们可以把它放在循环的条件中,不受条件的约束;而慢指针则需要用if条件来判断,他的向前是依靠于是否有条件出现的。在条件中赋值时把慢指针的前移用j++放在数组下标中实现,i++则在循环的条件中,当遇到指定字符时,不执行慢指针向前并赋值的操作,实现跳过。

void squeez(char s[],char c)
{
 int i,j;
 for(i=j=0;s[i]!='\0';i++)//i是正常移动的
  if(s[i]!=c)
   s[j++]=s[i];//如果等于c时,则不执行j++操作,意味着慢指针不移动
 s[j]='\0';
}
 

代码实现:

#include <stdio.h>  
#include <ctype.h>  
#include <string.h>  
#include <stdlib.h>  
  
int main() {  
    char s[1000];  
    char *newstr;  
    int begin, end;  
    gets(s); 
    int len = strlen(s);  
    newstr = (char *)malloc(sizeof(char)*(len+1000));
   int j = 0;  
    for (int i = 0; i < len; i++) {  
        if (s[i] == '-') {//这个if是如果有“-”相应操作 
            if ((i > 0 && i < len - 1) &&((isupper(s[i - 1]) && isupper(s[i + 1]) )||(isdigit(s[i - 1]) && isdigit(s[i + 1]))||(islower(s[i-1])&&islower(s[i+1])))) //条件判断1,是否符合类型一致
            {   
                begin = s[i - 1];  
                end = s[i + 1];  
                if ((isupper(begin) && isupper(end) && end > begin) ||(isdigit(begin) && isdigit(end) && end > begin)||(islower(s[i-1])&&islower(s[i+1])))//条件判断2,是否顺序正确
                {  
                    for (char c = begin+1; c <= end; c++) 
                    {  
                        newstr[j++] = c;  //把缺失的补全
                    }  
                    i++; //原数组向前移一位,进行下一位的判断
                    continue;  
                }  
            }  
        } 
        newstr[j++] = s[i]; //正常的字符直接读入即可
    }  
    newstr[j] = '\0';
    printf("%s\n", newstr);  
    free(newstr);
    return 0;  
}

到此这篇关于C语言数据结构之扩展字符详解的文章就介绍到这了,更多相关C语言数据结构扩展字符内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解vs2022创建及调用.lib的方法

    详解vs2022创建及调用.lib的方法

    这篇文章主要介绍了vs2022创建及调用.lib的方法,调用Lib的原则就是可以让编译器找到头文件和库文件的目录,并正确引入,本文给大家详细讲解需要的朋友可以参考下
    2022-11-11
  • vector,map,list,queue的区别详细解析

    vector,map,list,queue的区别详细解析

    如果我们需要随机访问一个容器则vector要比list好得多。如果我们已知要存储元素的个数则vector 又是一个比list好的选择。如果我们需要的不只是在容器两端插入和删除元素则list显然要比vector好
    2013-09-09
  • C++中的覆盖和隐藏详解

    C++中的覆盖和隐藏详解

    这篇文章主要介绍了C++中重载、重写(覆盖)和隐藏的区别,是C++面向对象程序设计非常重要的概念,需要的朋友可以参考下,希望能够给你带来帮助
    2021-08-08
  • C++中封装与信息隐藏的详解及其作用介绍

    C++中封装与信息隐藏的详解及其作用介绍

    这篇文章主要介绍了C++中封装与信息隐藏的详解及其作用介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • c++读写文件流实例程序讲解

    c++读写文件流实例程序讲解

    这篇文章主要介绍了c++读写文件流实例,大家参考使用吧
    2013-12-12
  • C/C++实现图形学扫描线填充算法

    C/C++实现图形学扫描线填充算法

    这篇文章主要介绍了C/C++实现图形学扫描线填充算法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C语言如何写类实现教程示例

    C语言如何写类实现教程示例

    这篇文章主要为大家介绍了C语言如何写类的实现教程示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • VC中SDK与MFC的区别浅析

    VC中SDK与MFC的区别浅析

    这篇文章主要介绍了VC中SDK与MFC的区别浅析,需要的朋友可以参考下
    2014-07-07
  • 老生常谈C语言静态函数库的制作和使用

    老生常谈C语言静态函数库的制作和使用

    下面小编就为大家带来一篇老生常谈C语言静态函数库的制作和使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • C++ LeetCode1769移动所有球到每个盒子最小操作数示例

    C++ LeetCode1769移动所有球到每个盒子最小操作数示例

    这篇文章主要为大家介绍了C++ LeetCode1769移动所有球到每个盒子所需最小操作数示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12

最新评论