线性表详解,map函数用法详解,vector函数用法(近万字详解)

  • Post author:
  • Post category:其他



目录


一.双向链表:


1.简介:


2.实现:


(1)构建节点结构体:


(2)初始化:


(3)添加元素:


(4)去除元素:


3.优缺点:


(1)优点:


(2)缺点:


4.例题:


二.map函数:


1.map的简介:


2.map的基本用法:


(1)map的定义:


(2)map的赋值:


(3)判断是否插入成功:


(4)erase操作:


(5)find操作:


(6)clear操作:


(7)size操作:


(8)读取单个value:


(9)遍历读取map中元素:


(10)map与其他STL嵌套:


3.例题:


三.vector函数:


1.vector简介:


2.vector用法:


(1)开头,结尾表示


(2)清空操作


将vector中元素清空,a.size()=0


(3)检验是否为空


(4) 删去最后一个元素


(5)删除操作


(6)中间插入操作


(7)尾部插入操作


(8)元素个数


(9)最大容量


(10)调节元素个数


(11)调节容量大小


一.双向链表:


1.简介:

链表即将一串数字连接在一起,

形成一个闭环

,如下图所示:

为了使链表形成一个闭环,就需要将一个元素的左右元素都定义清楚,所以每个元素都会

包括两个值

:(1) 该元素左边的值;

(2) 该元素右边的值;


2.实现:


(1)构建节点结构体:

需要将一个节点的左边元素与右边元素封装在一起。

struct pot
{
    int left;
    int right;
};

此处定义了一个pot的结构体,里面包含它左侧的值与右侧的值;

(2)初始化:

如果不进行初始化,就会成为以下示意图:

这种情况最后遍历查找时就会发生无限循环,没有停止条件的情况。

所以我们引入一个“ 0 ”元素:

这样 0 就是整个链表的起止点了,具体代码:

struct pot p[105];
//先开15个结构体
p[0].left=0;
//等于自身
p[0].right=0;
//等于自身

相当于0自己连着自己;

(3)添加元素:

添加元素分为添加到某元素左边与某元素右边,此处仅以将第 j元素加到第 i 元素右侧为例。

首先如第二个图 :将 p[ i ] 的右值定义为p[ j ]右值;

然后如第三个图: 将 p[ i ] 的右值定义为 j ;

接着如第四个图: 将p[ i ]右值转移到 j ;

最后如第五个图: 建立p[ j ]与右值的关系;

完整代码如下:

p[j].right=p[i].right;

p[j].left=i;

p[i].right=j;

p[p[j].right].left=j;

持续输入数值后,就可以构成一个双向线表了。

(4)去除元素:

原理与加入相同,只用倒着看上方示例图。

直接上代码,依然以将 i 右侧的 j 除去:

q[i].right=q[j].right;


q[q[j].right].left=i;

//将j的左右两元素连接


3.优缺点:


(1)优点:


线性

表的顺序存储结构,在存、读数据时,不管是哪个位置,时间复杂度都是0(1);而插入或删除时,时间复杂度都是0(n)。这就说明,它比较适合元素个数不太变化,而更多是存取数据的应用。

(2)缺点:

A.如果我们要插入或者删除的元素是在第一个位置,那么无疑的,我们需要移动大量的元素来完成这样的操作,而且限于线性表长度必须小于数组长度,如果我们需要插入大量数据,那么很难保证空间是否充足,而如果我们要删除大量数据的时候,无疑又会造成空间的浪费

B.顺序存储空间容易满,出现上溢,程序访问容易出问题,顺序存储结构下,存储空间不便扩充;

C.顺序存储空间的分配问题,分多了浪费,分少了空间不足上溢。


4.例题:

看一道十分典型的线性表,这道题也是最基础的类型。

这道题就只用区分一下向左插入还是向右插入:

#include<iostream>
using namespace std;

struct per{
	int left;
	int right;
	int here;   //用于记录是否输出
} p[100005];

int main(){
	for(int i=0;i<100005;i++){
		p[i].here=1;
	}
	int m,n;
	int place,v;
	p[0].left=0;
	p[0].right=0;

//初始化0

	p[1].left=0;
	p[1].right=p[0].right;
	p[0].right=1;
	p[p[1].right].left=1;
	
//先将1号放在0右边

    cin>>m;
	for(int i=2;i<=m;i++){
		cin>>v;
		cin>>place;
		if(place==1){
		p[i].left=v;
		p[i].right=p[v].right;
		p[v].right=i;
		p[p[i].right].left=i;
		}

//向右插入

		else{
		p[i].left=p[v].left;
		p[i].right=v;
		p[v].left=i;
		p[p[i].left].right=i;
		}

//向左插入

	}
	cin>>n;
	for(int j=0;j<n;j++){
		int x;
		cin>>x;
		p[x].here=0;
	}

//标记是否输出

	for(int i=p[0].right;i!=0;i=p[i].right){
		if(p[i].here==1&&p[i].right!=0) cout<<i<<" ";
		else if(p[i].here==1&&p[i].right==0) cout<<i;
	}

//从0开始向右输出

	return 0;
}

这道题除去某元素时注意一下技巧,只用here标记一下是否在队列中。


二.map函数:


1.map的简介:

map的

实质其实是映射

,也就像数组,在定义

数组

时(如int array[100]),其实是定义了一个从int型到int型的映射比如array[0]=25、array[4]=36就分别是将0映射到25、将4映射到36。         而一个double型数组则是将int型映射到double型,如db[0]=3.14,double[1]=0.01;

在数据储存上,map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器),就比如map和vector , pair , map,set等镶嵌。




但是如果是字符串到整型的映射,必须是string而不是char数组




2.map的基本用法:

(1)map的定义:

map的尖括号中包含两个元素,第一个是key值,另一个是value值。通过两者之间关系可以后续进行查找与赋值。

(2)map的赋值:

假设定义一个map<int , string> p ;

赋值主要有两种方式:使用insert直接赋key与value值     通过key赋value值

a.使用insert赋值:

//			(1).运 用 pair 函 数: 

	p.insert(pair<int,string>(1,"h1"));

//		    (2).再 次 运 用 map: 

	p.insert(map<int,string>::value_type(2,"h2"));     /*注意加上::value_type*/
	
//          (3).使用make_pair:
    
    p.insert(make_pair(3,"h3"));

前两种运用了pair, map ,第三种就比较简洁。

b.通过key赋value值:

	p[0]="h0"; 

这种方法比较常见。

(3)判断是否插入成功:

由于所学尚少,这个操作我很少用,先上码在解释。

    pair<map<int,string>::iterator,bool> insert_pair;
	insert_pair=person.insert(map<int,string>::value_type(3,"lewis3"));

    cout<<"是否插入成功:"<<boolalpha<<insert_pair.second<<endl;   

//boolalpha可以将bool类型的1和0转化为true与false 

首先,用pair定义一个变量。(pair可以考虑为一个封装着两个变量的结构体)

然后, 让该变量等于插入数值操作。(正常插入操作)

最后,输出pair中的bool变量。(小知识点:boolalpha可以将bool型的0,1转化为false,true)

(4)erase操作:

擦除操作主要分为3种:

a.设置迭代器,将迭代器擦去;(命名迭代器方法为:map<类型1,类型2>::iterator)

迭代器定义可能比较陌生,记住格式即可。

b.

直接擦key值

c.

设置迭代器,设置范围

,一起擦掉;

具体实现参考以下示例:

// 擦 除 步 骤
#include <iostream>
#include <map>
using namespace std;

int main ()
{
  map<char,int> mymap;
  map<char,int>::iterator it;
//插 入 元 素:
  mymap['a']=10;
  mymap['b']=20;
  mymap['c']=30;
  mymap['d']=40;
  mymap['e']=50;
  mymap['f']=60;

  it=mymap.find('b');
  mymap.erase (it);                   // 擦掉迭代器那一位

  mymap.erase ('c');                  // 通过key值擦去

  it=mymap.find ('e');
  mymap.erase ( it, mymap.end() );    // 擦掉连续几个

  // show content:
  for (it=mymap.begin(); it!=mymap.end(); ++it)
    cout << it->first << " => " << it->second << '\n';

  return 0;
}


结果输出:

a => 10

d => 40

(5)find操作:

简单说就是,如果key存在,map.find(key) ==> value,即找到key所对应的value值。

反之,

map.find(key)=map.end();

看以下代码演例:

map<char,int> my;

my['a']=50;
my['b']=100;
my['c']=150;
my['d']=200;

cout << "elements in mymap:" << '\n';
cout << "a => " << mymap.find('a')->second << '\n';
cout << "c => " << mymap.find('c')->second << '\n';
cout << "d => " << mymap.find('d')->second << '\n';

结果:

a => 50

c => 150

d => 200

(6)clear操作:

将map清空,size化为0;

eg:设map变量为p:

p.clear();

(7)size操作:

得到map中元素个数;

(8)读取单个value:

相当于输入的反过程,直接输出map[key]输出value;

eg:

map<int,string> person;
	
person[0]="lewis0";   

cout<<person[0];

输出:lewis0

(9)遍历读取map中元素:

遍历读取时主要有两种操作:定义迭代器    使用auto

不用恐惧太麻烦,遍历主要记模板,使用的频率不如单个读取高,注意auto自动匹配数据类型,十分好用,也可以用在一般循环。

排序按照字典序输出。

输一个完整代码:

#include<iostream>
#include<map>
using namespace std;

int main()
{
	map<int,string> person;
	
//一.赋 值 操 作:
//		1.直 接 赋 值:	
	person[0]="lewis0";                                      /*每个赋值都要注意带上标号*/ 
	person[0]="lewis10";

//如 果 直 接 改 变 value,那 person[0] 的 值 就 会 随 之 改 变

//		2.使 用 insert 赋 值:
//			(1).运 用 pair 函 数: 
	person.insert(pair<int,string>(1,"lewis1"));
//		    (2).再 次 运 用 map: 
	person.insert(map<int,string>::value_type(2,"lewis2"));   /*注意加上::value_type*/
	
	
//二.读 取 操 作:
//		1.一 般 法 读 取: 
	map<int,string>::iterator it;                  /*注意加上::iterator*/          
	for(it=person.begin();it!=person.end();it++)
	{
		cout<<it->first<<":"<<it->second<<endl;
	}
	
//		2.使 用 auto 自 动 定 义 类 型:
	for(auto it=person.begin();it!=person.end();it++)   /*auto有自动定义数据类型的功能,不必再定义it */
	{
		cout<<it->first<<":"<<it->second<<endl; 
	} 
	
//  	3.使 用 auto 直 接 遍 历:
	for(auto it:person)
	{
		cout<<it.first<<":"<<it.second<<endl;	
	} 
 
 
//三.判 断 是 否 数 据 插 入 成 功:
 	  pair<map<int,string>::iterator,bool> insert_pair;
	  insert_pair=person.insert(map<int,string>::value_type(3,"lewis3"));
	  cout<<"是否插入成功:"<<boolalpha<<insert_pair.second<<endl;   //boolalpha可以将bool类型的1和0转化为true与false 


//四.获取map中的元素:
	map<int,string>::iterator it1;
	it1=person.find(1);
	if(it1!=person.end())
	{
		cout<<it1->second<<endl;
	} 
	else
	{
		cout<<"not find"<<endl;
	}
	
	
//五.删除的方法:
//		1.通过设置it: 
	map<int,string>::iterator it2;
	it2 =person.find(1);
	person.erase(it2);
	
//		2.通过直接改变key值:
	person.erase(2);
	for(auto it:person)
	{
		cout<<"-------------------------"<<endl;
		cout<<it.first<<":"<<it.second<<endl;
	} 
	
	
	
//六.对字符进行操作:
	map<string,string>person2;
	person2["0"]="10";
	person2["1"]="11";
	person2["2"]="12";         ///只需要将数字改为字符 
	
	map<string,string>::iterator it3;
	it3=person2.find("1");
	person2.erase(it3);
	
	for(auto it:person2)
	{
		cout<<it.first<<":"<<it.second<<endl;
	}
	cout<<endl<<endl;
	cout<<person2["0"];		
} 

(10)map与其他STL嵌套:

首先嵌套vector:

一般vector作为value值,对于一个key对应多个value值。相当于二维数组a[m][n],key即为m,vector即为n。

见代码:

    map<int,vector<int> >Q;

	for(int i=5;i<=10;i++){
		Q[1000].push_back(i);
	}//向1000对应的vector里插入5 6 7 8 9 10


	Q[1000].erase(Q[1000].begin(),Q[1000].begin()+3);//删除1000对应的vector里前三个元素 
	for(int i=0;i<Q[1000].size();i++){
		cout<<Q[1000][i]<<" ";
	}
	return 0;
}


输出:8 9 10

其次,嵌套map,pair,具体应用参考例题。


3.例题:

#include<cstdio>
#include<iostream> 
#include<map>//引用STL里的map库
using namespace std;
map<int,map<int,int> > a;//建立二维映射
int main(){
	int n,q,x,y,k,z;
    cin>>n>>q;//输入寄包柜个数及询问次数
    for(int i=1;i<=q;++i){//循环q次
        cin>>k>>x>>y;
        if(k==1){//存放操作
            cin>>z;
            a[x][y]=z;//建立一次映射
        }
        else{//查询操作
            cout<<a[x][y]<<endl;//直接输出所映射的值
        }
    }
	return 0;
} 

这种方法是两个map固定2个key值,以确定物品位置。

#include <bits/stdc++.h>
using namespace std;
map <int, int> mat[10005];  //二维map
int main() {
	int n, q;
	scanf("%d%d", &n, &q);//输入
	while (q--) {
		int x, i, j, k;
		scanf("%d", &x);
		if (x == 1) {
			scanf("%d%d%d", &i, &j, &k);  
			mat[i][j] = k;  //直接映射
		} else {
			scanf("%d%d", &i, &j);
			printf("%d\n", mat[i][j]); //直接查找对应元素,输出
		}
	} 
	return 0;
}

此方法是直接定义二维数组,定义map时比较出奇。

#include<cstdio>
#include<map>
using namespace std;
int n,q,p,k;
map<long long,int>b;
long long i,j;
int main()
{
	scanf("%d%d",&n,&q);
	while(q--)
	{
		scanf("%d%d%d",&p,&i,&j);
		if(p==1)
		{
			scanf("%d",&k);
			b[i*100000+j]=k;
		}
		else printf("%d\n",b[i*100000+j]);
	}
	return 0;
}

这种方法就很巧妙了,直接将二维数组化为一维数组,错开了二维数组两位重复的情况。


三.vector函数:


1.vector简介


他像是一个动态变化的数组,可以根据自己输入改变容器大小,以大大减少空间。尖括号中时数据类型。具体初始vector如下:

vector<int> a;           //无参数 - 构造一个空的vector,

vector<int> a(10);       //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。

vector<int> a(10,1);     //定义了10个整型元素的向量,且给出每个元素的初值为1

vector<int> a(b);        //用b向量来创建a向量,整体复制性赋值, 拷贝构造

vector<int> a(b.begin(),b.begin+3);   //定义了a值为b中第0个到第2个(共3个)元素

int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+6);    //从数组中获得初值,b[0]~b[5]



2.vector用法:


假设vector<int>a;

(1)开头,结尾表示

a.front();

//返回第一个元素

a.back();

//返回最后一个元素

(2)清空操作

将vector中元素清空,a.size()=0

a.clear();

//将vector中元素清空,a.size()=0

(3)检验是否为空

空返回true,假返回false

a.empty();

//判断是否空

(4) 删去最后一个元素

即删去最后加入的元素

a.pop_back();

//即删去最后加入的元素

(5)删除操作

与map的erase相似,删除区间元素

a.erase(a.begin()+1, a.begin()+3);  
//删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
    

删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起


(包括它)


一直到a.begin()+3


(不包括它)

(6)中间插入操作

使用insert操作:

a.加一个元素

a.insert(a.begin()+1,5);    
//在第0位后1位上加入5  

b.加一串元素

a.insert(a.begin()+1, 3,5);       
//在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5

(7)尾部插入操作

a.push_back(k);
//在a的最后一个向量后插入一个元素,其值为k

(8)元素个数

a.size();
//数字个数

(9)最大容量

a.capacity()
//总容量大小

(10)调节元素个数

a.不赋值改变个数,如果需要补位,则出随机值;

如果位数过多,删除多余项

a.resize(10);
//多删少补

b.将补位元素赋值:

a.resize(10,2)
//如果数位不足,补2

(11)调节容量大小

a.reserve(100)
//将容量调节至100

线性表,map,vector对于初学者来说比较抽象,需要熟练掌握基本操作,才能感受到他的便捷。

以上为本次主要内容,如有不当,欢迎评论区讨论!



版权声明:本文为m0_73064964原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。