数组及字符串相关知识

一、数组的知识

Sec1.一维数组

1.数组的引入:

当数据量很多,类型相同需要重复定义的时候,需要用数组简化问题解法。

2.数组的使用

①定义:

数组类型 数组名 [ 常亮表达式 ] 例如:int a[100];表示a数组有100个元素,下标由0到99.

②数组的引用方式:

数组名[下标] 如:a[100]表示a数组第101个元素,若 i t均为int型变量,则a[i],a[j],a[i+j],a[i*j],a[j++]等都是合法元素。数组不可以一次引用一整个数组,如int a[100],b[100]; a=b;这是不合法的引用方式。
若要将数组a每一个元素的值赋值给b数组的对应元素。可以利用循环。
for(int i=0)
{
 	b[i]=a[i];
}

③数组的初始化

使用数组时要根据要解决问题的形式决定数组是否要初始化。初始化变量可以用以下的方法,如 int a[10]={ 0 };数组元素全部为零。int b[5]={1,2};前两个元素为1和2,后续元素自动赋值为零。 特殊情况,如将数组在主函数外定义,自动赋初值。如下:
#include <iostream>
using namespace std;
int a[10];
int main()
{
	return 0;
}
此时数组a的每一个元素自动赋值为0;

④数组的注意事项

越界问题,上文已经提到a[100]的下标为0-99;使用负数,非整数或大于99的数字都会是数组越界。

⑤特殊的使用方式

memcpy函数(头文件<cstring)

数组不能直接复制,可利用memcpy函数

void *memcpy(void *dest, void *src, unsigned int count);

memcpy 函数用于 把资源内存(src所指向的内存区域) 拷贝到目标内存(dest所指向的内存区域);一个size变量控制拷贝的字节数;
使用方式memcpy(b,a,sizeof(int)*k) 从a中赋值k个元素到b数组。

sizeof(int)*k表示计算int型所占字节数,然后再乘以k。
类比sizeof(int*k),表示计算指向整型的指针变量k所占的字节数。
再浅显讨论sizeof的作用

sizeof(int)*k之所以用sizeof(int)*k而不是用k,因为sizeof(int)*k返回的是字节数,因为数组是int 型的sizeof计算每个元素的字节长度,在乘以k既k个元素的字节,因为memcyp需要知道拷贝内存的字节数。所以拷贝是从开头开始计算,即k个元素是从a[0]开始计算。由此可以推出将a中元素全部拷贝到b数组中,memcpy(b,a,sizeof(a))。

memset函数(头文件<cstring)

void *memset(void *s , int ch , size_t n ) 在一段内存块中填充某一个给定的值,常用于较大的对结构体和数组的清零操作。
memset(结构体/数组名 , "用于替换的字符“ , 前n个字符 );
用法可以参考memcpy,也要用sizeof来计算字节。
总结内存复制需要计算字节。
我们拿出一个题来做例子

描述
某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入
第一行有两个整数L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

对于20%的数据,区域之间没有重合的部分; 对于其它的数据,区域之间有重合的情况。
输出
包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。 样例输入 500 3 150 300 100 200 470 471 样例输出
298 来源 NOIP2005复赛 普及组 第二题

#include<iostream>
    #include<cmath>
    #include<iomanip>
    using namespace std;
    int main()
    {
    	int lon[10000];
    	int l=0,n=0;
    	int sum=0;
    	cin>>l>>n;
    	int s=0,o=0;
    	memset(lon , 1 , sizeof() )
    	for(int i=0;i<n;i++)
    	{
    		cin>>s>>o;
    		for(int t=s;t<=o;t++)
    		{
    			lon[t]=0;
    		}
    	}
    	for(int i=0;i<=l;i++)
    	{
    		sum=sum+lon[i];
    	}
    	cout<<sum;
    	return 0;
    }

Sec2.二维数组

1.数组的引入:

当数据与不再是单纯的线性关系,类似坐标系的数据,矩阵的处理等;

2.数组的使用

①数组的定义及引用
数组类型 数组名 [表达常量式1][表达常量式2];例如int a [5][5]常量表达式1为行数,常量表达式2为列数。跟一维数组一样下标从0开始。
引用时 数组名 [表达常量式1][表达常量式2];例如a [5][5]
初始化参考一维数组。特殊的int a[2][5]={{1,2},{2,3},{4,6},{1,2},{2,3}};

以此题为例。

描述 给定一个5*5的矩阵(数学上,一个r×c的矩阵是一个由r行c列元素排列成的矩形阵列),将第n行和第m行交换,输出交换后的结果。

输入 输入共6行,前5行为矩阵的每一行元素,元素与元素之间以一个空格分开。 第6行包含两个整数m、n,以一个空格分开。(1 <= m,n
<= 5) 输出 输出交换之后的矩阵,矩阵的每一行元素占一行,元素之间以一个空格分开。
样例输入
1 2 2 1 2
5 6 7 8 3
9 3 0 5 3
7 2 1 4 6
3 0 8 2 4
1 5
样例输出
3 0 8 2 4
5 6 7 8 3
9 3 0 5 3
7 2 1 4 6
1 2 2 1 2
来源 1901

#include<iostream>
    using namespace std;
    int main()
    {
    	int a[6][6];
    	int l1=0,l2=0;
    	for(int t=1;t<6;t++)
    	{
    		for(int i=1;i<6;i++)
    		{
    			cin>>a[t][i];
    		}
    	}
    	cin>>l1>>l2;
    	for(int t=1;t<6;t++)
    	{
    		a[0][t]=a[l1][t];
    		a[l1][t]=a[l2][t];
    		a[l2][t]=a[0][t];
    	}
    	for(int t=1;t<6;t++)
    	{
    		for(int i=1;i<6;i++)
    		{
    			cout<<a[t][i]<<' ';
    		}
    		cout<<endl;
    	}

Sec3.字符型数组

1.数组的定义

一维数组:char 函数名[行 常量表达式] 例如:char ch[5];
二维数组:char 函数名[列 常量表达式] 例如:char ch[2][12]

2.数组的初始化

初始化过程中,没有被初始化的数组项编译器会给默认赋值’\0’;(整数数组没有被初始化的数组项被赋值为0)。例如:char c[5] = {‘a’,’b’,’c’,’d’}; 中 c[4] = ‘\0’; \0即空字符。
char c[5]="abcd"字符串初始化数组的话,字符串后会跟一个空字符,所以字符串的元素数量要少于定义的空间。

3.字符型数组特殊的赋值方式,可以直接cin>>a,a为字符型数组

其余相关操作均可参考数组与二维数组。

Mo和Larry发明了一种信息加密方法。他们首先决定好列数,然后将信息(只包含字母)从上往下依次填入各列,并在末尾补充一些随机字母使其成为一个完整的字母矩阵。例如,若信息是“There’s
no place like home on a snowy night”并且有5列,Mo会写成:

t o i o y h p k n n e l e a i r a h s g e c o n h s e m o t n l e w x
注意Mo只会填入字母,且全部是小写形式。在这个例子中,Mo用字母“x”填充了信息使之成为一个完整的矩阵,当然他使用任何字母都是可以的。

Mo根据这个矩阵重写信息:首先从左到右写下第一行,然后从右到左写下第二行,再从左到右写下第三行……以此左右交替地从上到下写下各行字母,形成新的字符串。这样,例子中的信息就被加密为:toioynnkpheleaigshareconhtomesnlewx。

你的工作是帮助Larry从加密后的信息中还原出原始信息(包括填充的字母)。

输入
第一行包含一个整数(范围2到20),表示使用的列数。
第二行是一个长度不超过200的字符串。
输出 一行,即原始信息。
样例输入 5
toioynnkpheleaigshareconhtomesnlewx
样例输出
theresnoplacelikehomeonasnowynightx
来源 East Central North America 2004

#include<iostream>
#include<cstring>
#include <stdlib.h>
using namespace std;
int main()
{
    char a[210][210];
    int n=0,w=0,s=0;
    int mid;
    string b;
    cin>>n>>b;
    w=b.size()/n;		// 这里使用的srting与srting.size()下文将会讲解
    for(int i=1;i<=w;i++)
    {
        for(int t=1;t<=n;t++)
        {
            a[i][t]=b[s];
            s++;
        }
        if(i%2==0)
        {
            for(int t=1;t<=(n+1)/2;t++)
            {
                mid=a[i][t];
                a[i][t]=a[i][n+1-t];
                a[i][n+1-t]=mid;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int t=1;t<=w;t++)
        {
            cout<<a[t][i];
        }
    }
    return 0;
}

Sec4.字符串string

C++中对于strinig的定义为:typedef basic_string string; 也就是说C++中的string类是一个泛型类,由模板而实例化的一个标准类,本质上不是一个标准数据类型.

1.字符串操作

strcpy(p, p1) 复制字符串
strncpy(p, p1, n) 复制指定长度字符串
strcat(p, p1) 附加字符串
strncat(p, p1, n) 附加指定长度字符串
strlen§ 取字符串长度
strcmp(p, p1) 比较字符串
strcasecmp忽略大小写比较字符串
strncmp(p, p1, n) 比较指定长度字符串
strchr(p, c) 在字符串中查找指定字符
strrchr(p, c) 在字符串中反向查找
strstr(p, p1) 查找字符串
strlwr§将大写字母全部换为小写字母
strupr§将小写字母全部换为大写字母

相对于字符型数组,字符串可以有以下操作
  1. s.empty(); // s为空串 返回true
  2. s.size(); // 返回s中字符个数 类型应为:string::size_type
  3. s[n]; // 从0开始相当于下标访问
  4. s1+s2; // 把s1和s2连接成新串 返回新串
  5. s1=s2; // 把s1替换为s2的副本
  6. v1==v2; // 比较,相等返回true
  7. !=, <, <=, >, >=

大小规则
1)数字0~9比字母要小。如"7"<“F”;
2)数字0比数字9要小,并按0到9顺序递增。如"3"<“8”
3)字母A比字母Z要小,并按A到Z顺序递增。如"A"<“Z”
4)同个字母的大写字母比小写字母要小。如"A"<“a”。

2.字符串的引用

可以直接使用名称,例如string a;可以直接使用a代指一整个字符串。
也可以使用string a[1]代指字符串a的第二个元素。
以一个例题为例

描述 给定N个单词(每个单词长度不超过100,单词字符串内仅包含小写字母)。

请求出N个单词中共有多少个不同的单词。

输入 第1行包含1个正整数N。
接下来N行每行包含一个字符串。
输出 一个整数,代表不同单词的个数
样例输入
5 lalala
hahaha
haha
lalala
haha
样例输出 3
提示

  • N <= 10000000
  • 不同单词个数不超过100000
#include<iostream>
#include<set>
#include <vector>
using namespace std;
int main()
{
    vector<string> a;
    set<string>  b;
    string c;
    int n;
    cin>>n;
    while(n--)
{
    cin>>c;
    a.push_back(c);
}
    b.insert(a.begin(),a.end());
    cout<<b.size()<<endl;
   return 0;
}

文中所使用的stl容器在本篇不做介绍,后续会发布更详细的知识。

二、对于数组部分学习的心得

对于近期程序设计的学习感到了恐惧,因为通过string到接触stl开始发现程序设计的知识体系太庞大了,有更多的知识要去学习,现在学到的基础还算不上九牛一毛,有种井底之蛙的感觉,也正是如此,要更要去克服这些困难,像在做OJ题时总会碰到一些不知道的知识,再由这些知识就能发现更多知识,及时不会,也开始对C的知识体系有了一些认识,但是从Acm院级的比赛来看,有些知识很简单,考的是想法,是解决问题的“算法”,也接触到了STL的容器,算法,但是对于迭代器,还是没有清晰的概念,从题中学习知识的方法确实很慢,比主动去看知识要慢的很多,但是只有从题目与知识的串联中才能将这些知识记牢会用。对于语言的学习,要愿意去接受新知识,也要有斗志,耐得住寂寞的克服一个个问题。

posted @ 2018-12-23 14:34  风骨散人  阅读(124)  评论(0编辑  收藏  举报