线性表(上)——一维数组

我们有的时候需要利用数据结构来存储有线性关系的数值,这就有了线性表。
本篇分上,中,下。
上篇主要介绍一维数组。

顺序表

用一组连续的地址来存储的线性表,叫做顺序表。
顺便一提下一篇我要写的线性表(中)——栈与队列中的栈与队列也是顺序表。

一维数组

在我看来,一维数组应该是最简单的线性结构了。而且有了一维数组,许多线性表使用C++自带的STL模板要么就是时间复杂度太高,要么就是使用太麻烦,用数组模拟就简单的多。
当然,大家也可以看《信息学奥赛一本通(C++版)》的第76~86页来自行学习。

一、一维数组的定义

类型标识符 数组名[常量表达式]
例如:

int a[101]; //此处定义合法
int res[x]; //此处定义非法,因为x不是常量
const int maxn=100001;
char s[maxn];//此处定义也合法,因为maxn为常量
 long long d=1001;
 bool sam[d];//此处依然合法,原因同上
struct data{
    int vec,val;
}k[100000001];//此处定义非法,因为空间复杂度为O(10^9),会MLE
二、一维数组的引用

数组名[下标]
与上面差不多,但有一个要求: 0 ≤ i < n 0≤i<n 0i<n其中i是下标,n是数组长度。

三、一维数组的初始化

数组名[常量表达式]={值1,值2,值3…}
例如:

int a[5]={1,2,3,4,5}

PS:下标从0开始。
另外还要介绍一个函数memset。

memset(a,b,sizeof(a));

作用是将a数组填充为b。
好的,那来道例题吧。
洛谷P1428 小鱼比可爱
其实我们只需要通过遍历此鱼前有几个不如自己可爱的就行了,模拟+暴力就能过
上AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[101];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);//输入第i个数
		int ans=0;//初始化ans
		for(int j=1;j<i;j++)if(a[j]<a[i])ans++;//统计前面比鱼i不可爱的鱼数
		printf("%d ",ans);
	}
}

字符串

说白了,就是字符数组,当然STL模板里也有自带的字符串类型string,使用习惯因人而异,反正我是喜欢用string的。
当然,大家也可以看《信息学奥赛一本通(C++版)》的第94~108页来自行学习(习题超多,超全,可以做做)。

字符数组的使用

定义,引用,初始化如一维数组。
但是字符数组有一些小便利。

一、输入

流输入(最慢,但是最万能,当然这个也是有优化的指令的):

cin>>s;

格式化输入:

scanf("%s",s);

PS:这里之所以没有‘&’,是因为数组名可当地址用这里写的其实相当于是以下程序的省略:

scanf("%s",s+0);

scanf("%s",&s[0]);

至于有关这一方面的内容,以后也抽个时间写写。
gets语句(专用于字符数组):

gets(s);

PS:以上3种方法的下标均从0开始,其实了解指针以后,你们会知道一种利用scanf从任意下标开始读入的方法:

scanf("%s",s+i);

scanf("%s",&s[i]);

i为开始输入的下标。

二、输出

流输出:

cout<<s;

格式化输出:

printf("%s",s);

puts语句(字符数组专用):

puts(s);
三、字符数组模拟字符串处理函数:
函数格式函数功能
strcat(s1,s2)将s2接到s1后面,返回s1
strncat(s1,s2,n)将s2前n个字符接到s1后面,返回s1
strcpy(s1,s2)将s2复制到s1,返回s1
strncpy(s1,s2,n)将s2前n个字符复制到s1,返回s1
strcmp(s1,s2)将s2接到s1后面,返回s1
strncmp(s1,s2,n)比较s1,s2:大于返回正整数,等于返回0,小于返回负整数
strlen(s)计算s的长度,结尾’\0’不算
strlwr(s)将s里的大写字母换成小写字母
strupr(s)将s里的小写字母换成大写字母

这些函数包括填充数组的memset都在cstring库里话说万能库stdc++.h用着不香吗

STL模板字符串的使用

支持像一维数组那样下标引用。

一、定义
string s
二、输入

流输入:

cin>>s;

getline输入(string专用):

getline(cin,s);//读到换行后停止输入
getline(cin,s,c);//读到字符c后停止输入

PS:输出只能流输出。

三、string处理函数
函数格式函数功能
s.length()或s.size()s的长度
s . at(i)将s2前n个字符接到s1后面,返回s1
s.push_back( c )在s的末尾添加字符或字符串变量c,等价于s+=c
s.append(n,c)在s的末尾添加n个字符c
s1.insert(n,s2)将s2插入到s1的第n个字符后面
s1.replace(i,j,s2)将s1从i开始的j个字符替换成s2
s.erase(n)将s从n开始的字符全部删除
s.erase(i,j)将s从i开始的j个字符删除
s.substr()返回s
s.substr(n)返回s从n开始的所有内容
s.substr(i,j)s从i开始的连续j个字符
s1.find(s2)在s1里面查找s2,返回第一次找到的位置
s1.find(s2,n)在s1里面从位置n开始查找s2,返回第一次找到的位置
s1.rfind(s2)在s1里面右边查找s2,返回第一次找到的位置
s1.rfind(s2,n)在s1里面从右边开始数的位置n开始查找s2,返回第一次找到的位置
s.c_str()返回内容为s的字符数组
s.copy()返回内容为s的字符数组到已有的字符数组里

PS:以上内容都在string库里。大小比较可直接使用数值比较的符号,赋值可直接使用“=”,在字符串前添加用“+”:

s=c+s;//c为字符或字符串变量
四、字符串流

字符串流可实现字符串流与各个类型的转换。
定义:

stringstream s;

利用流转换:

stringstream ss;
int i;
string s;
ss<<i;
ss>>s;

当然,你假如用同一个流来进行操作,时不时的要用ss.clear()来清除状态信息。
反复读写数据,会造成大量消耗了,于是我们需要用ss.str()来清理一下缓存。
现在我们再来看看字符串的例题。
P5733 【深基6.例1】自动修正
这道题自然就有了手写和懒人两种方式。
懒人方法倒是用到了字符数组。怎么做呢?利用strupr.
本机测完全没问题,但是上洛谷就CE了。
献上CE代码:

#include<bits/stdc++.h>
using namespace std;
char s[101];
int main(){
   gets(s);
   strupr(s);
   puts(s);
   return 0;
}

手写的AC代码根本连字符数组都不需要,直接边读边写。
当然,你要是为了扯上字符串读完再写也成
其实手写很暴力的:就是判断是不是小写,是小写就转大写输出,不是就直接输出。
上AC代码:

#include<bits/stdc++.h>
using namespace std;
char c;
int main(){
   if(scanf("%c",&c)!=EOF){//假如还有输入就继续输,Ctrl+Z结束输入
       if(c>='a'&&c<='z')c+='A'-'a';//判断并转换
       printf("%c",c);//输出
       main();//调用主程序,不想这么写的上面打while循环
   }
   return 0;
}

vector

这是一个不用设定长度的数组,当你加入时,会对数组长度自行扩大。访问如普通数组,下标从0开始。

一、定义
vector<int> a;

其中的<>中可填任何类型,包括自定义结构体。

二、vector处理函数
函数格式函数功能
a.clear()清空a但不释放内存
a.push_back(x)在a中加入x
a.size()a的长度
for(auto x:a)利用x遍历a(C++11新功能)
sort(a.begin(),a.end(),cmp)根据cmp将a排序
a.insert(a.begin()+i,x)在下标为i的位置插入x
a.erase(a.begin()+i,a.begin()+j)将a从i开始到j结束全部删除

PS:以上函数均在vector库,并且insert和erase时间复杂度均为O(n),不推荐使用。
好了,那我们再来看一道例题。
P3156 询问学号
其实vector的主要应用还是在图论上,上面的这一道题,普通数组也能过。
其实就是依次读入,然后访问下标,但要注意,vector的下标从0开始,使用vector的话访问时要减1.
普通数组AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,x,a[20000001];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);//读入
    for(int i=1;i<=m;i++){
        scanf("%d",&x);
        printf("%d\n",a[x]);//询问
    }
}

vectorAC代码:

#include<bits/stdc++.h>
using namespace std;
vector<int> a;
int n,m,x;
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&x);//读入
        a.push_back(x);//加入a
    }
    for(int i=1;i<=m;i++){
        scanf("%d",&x);
        printf("%d\n",a[x-1]);//询问
    }
}

好的,那我们的线性表(上)——普通数组就完结了,敬请期待线性表(中)——栈与队列!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值