STL中Map与二叉树的关联及拓展



管理元素集合的STL容器大致分为两类。
一类是有顺序的集合,称为序列式容器
另一类是经过排序的集合,称为关联式容器




一,概念上理解

1.Map在STL中

Map是STL 的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。

关联式容器会依据特定的排序标准来决定要添加的元素的位置。STL为用户提供了set、map、multiset、multimap容器。
而关联式容器的优点也在于开源随时采用二分搜索法,所以搜索元素的效率非常高。

由此了解到map大概就是有一种一对一数据的能力,有点像数组的表现,即a[i]=bi 每一个i都对应了相对应的bi,但是map却可以使这里的 i(int类型) 变成任一形式(string char ·····)



2.Map与二叉树的概念重合

我们可以通过map<char,char>这样进行操作进行索引,即

/*------------------*/
	map<char,char>x;
	map<char,char>y;
	char p='a';
	x[p]="the_one";
	y[p]="other_one";
/*------------------*/	

这里我们知道p相当于后面跟着“the_one"和"the_two"
所以我们进行输出的时候可以是

/*------------------*/
cout<<p;
cout<<x[p];
cout<<y[p];
/*------------------*/

看到这里有没有发现什么?
没错,这里我们可以把map和二叉树替换使用
因为我们可以发现,二叉树的根就相当于这里的p,而它的左孩子就是x[p],右孩子就是这里的y[p];

二,代码演示理解

依据的题目:
在这里插入图片描述
题目链接原处

1, 二叉树演示

如果我们用struct结构体来构造二叉树,可以有两种,一种带指针,一种不带。

(1)struct构造(带指针)

typedef struct node {
	char data;
	struct node* lx, * rx;
	int flag = 0;
	int flag_l = 0;
	int flag_r = 0;
}*BiTree,Tnode;

Tnode *p[MAX_0];//也可以用queue来替代数组

void print(BiTree& T)
{
	
		cout << T->data;
		if(T->lx!=NULL)
			print(T->lx);
		if(T->rx!=NULL)
			print(T->rx);
	
}
int main()
{
	int t;
	cin >> t;
	int i = 0;
	
	for (i = 1; i <= t; i++)
	{
		p[i] = new Tnode;
		string str;
		cin >> str;
		p[i]->data = str[0];
		
		if (str[1] != '*')
		{
			BiTree temp;
			temp = new Tnode;
			temp->data = str[1];
			temp->lx = NULL;
			temp->rx = NULL;
			p[i]->lx = temp;
		}
		else
		{
			p[i]->lx = NULL;
		}
		if (str[2] != '*')
		{
			BiTree temp0;
			temp0 = new Tnode;
			temp0->data = str[2];
			temp0->lx = NULL;
			temp0->rx = NULL;
			p[i]->rx = temp0;
		}
		else
		{
			p[i]->rx = NULL;
		}
	}
	for (int j = 1; j <= t; j++)
	{
		BiTree temp_l,temp_r;
		temp_l = p[j]->lx;
		temp_r = p[j]->rx;
		for (int k = 2; k <= t; k++)
		{
			
			if (k != j&&temp_l!=NULL&&p[k]->data!=NULL&&temp_l->data==p[k]->data&&p[k]->flag_l==0)
			{
				p[j]->lx = p[k];
				p[k]->flag_l = 1;
			}
			if (k != j && temp_r != NULL && p[k] != NULL && temp_r->data == p[k]->data && p[k]->flag_r == 0)
			{
				p[j]->rx = p[k];
				p[k]->flag_r = 1;
			}
			if (p[k]->flag_r == 1 && p[k]->flag_l == 1)
			{
				break;
			}
		}
	}
	print(p[1]);
}

这里我是把单个树构造,如何再去构造整体树
emmmmm总之就是长就对了

(2)struct构造(不带指针)

/*struct 不带指针*/

struct node {
	char dad, rx, lx;
	//node(char dad_0,char rx_0,char lx_0): dad(dad_0),rx(rx_0),lx(lx_0){}
};

node tree[MAX];

void print(char root)
{
	cout << root;
	if (tree[root].lx != '*')
		print(tree[root].lx);
	if (tree[root].rx != '*')
		print(tree[root].rx);
}

int main()
{
	int t;
	cin >> t;
	char root;
	char str;
	for (int i = 1; i <= t; i++)
	{
		cin >> str;
		if (i == 1)
		{
			root = str;
		}
		cin >> tree[str].lx >> tree[str].rx;
		tree[tree[str].lx].dad = tree[tree[str].rx].dad = str;
	}
	print(root);
}

这里我发现了一个学了计算机将近一年多来一直没发现的东东——————原来struct构造的数组里面是可以放非int类型的数据的!!!
也就是上面的tree【a】,这里的a可以是char!!!!!
(还是太菜了啊啊啊啊啊啊)
(小丑竟是我自己)

这个代码就不做过多解释了,感觉自己能看得懂;
我们可以观察一下这个码,怎么说呢,比指针的看上去简单易懂,但是同时也存在局限性,tree[MAX]这里的MAX可能会过多,浪费,也可能会因为数据超出范围不好把控。所以这里只适用于数据小的情况。

(3)用map构造

map<char, char>rx;
map<char, char>lx;

void print(char root)
{
	cout << root;
	if (lx[root] != '*')
		print(lx[root]);
	if (rx[root] != '*')
		print(rx[root]);
}


int main(void)
{
	int t;
	cin >> t;
	int flag = 0;
	char root;
	while (t--)
	{
		string str;
		cin >> str;
		if (flag == 0)
		{
			root = str[0];
			flag = 1;
		}
		lx[str[0]] = str[1];
		rx[str[0]] = str[2];
	}
	print(root);

	return 0;
}

其实map构造的与不带指针(2)有点相同,但是这里的优势就是不用担心数组的大小,因为这里取很多空间(只要电脑内存足够)

用三种方法将这题写完,二叉树感觉也就基本入门了·····吧

三,Map的具体操作

1,插入

map<int, string>data_1, data_2;
	data_1.insert(pair<int, string>(1, "the_one"));
	//value中:data_1.insert(map<int,string>::value_type (1,"the_one"));
	data_1.insert(pair<int, string>(2, "the_two"));
	data_1.insert(pair<int, string>(3, "the_three"));
	data_2[1] = "the_1";
	data_2[2] = "the_2";
	data_2[3] = "the_3";
	map<int, string>::iterator iter;
	cout << "下面是用insert or value_type进行插入数据" << endl;
	for (iter = data_1.begin(); iter != data_1.end(); iter++)
	{
		cout << iter->first << " " << iter->second << endl;
	}
	
	cout << "下面是用数组进行插入数据" << endl;
	for (iter = data_2.begin(); iter != data_2.end(); iter++)
	{
		cout << iter->first << " " << iter->second << endl;
	}
	cout << "现在进行修改数据,看看能否覆盖" << endl;

	data_1.insert(pair<int, string>(1, "覆盖了"));
	data_2[1] = "覆盖了";
	cout << "下面是用insert or value_type进行插入数据" << endl;
	for (iter = data_1.begin(); iter != data_1.end(); iter++)
	{
		cout << iter->first << " " << iter->second << endl;
	}

	cout << "下面是用数组进行插入数据" << endl;
	for (iter = data_2.begin(); iter != data_2.end(); iter++)
	{
		cout << iter->first << " " << iter->second << endl;
	}

(1)insert插入(或value)

这里insert并不等于value插入,只是形式差不多;
这里如果出现对同一个key赋值,则不能覆盖。

(2)数组插入

这里如果对同一key赋值,则直接覆盖原来值
在这里插入图片描述

ps:迭代器iter

这里相当于给map“数组”里面加了一个“指针”,(抽象理解,其原理不是这样)而iter可以沿着这个“数组”一直往后移动。
而map的遍历也是由这玩意进行下去,具体代码在上面已经声明,不做过多解释

2,查找

(1) 查找方式:

map名 . find( 任一key值 );
判断是否存在
将其赋给iter迭代器
如果不等于,则存在

/*--------------------------------*/
	iter = data_1.find(1);
	if (iter != data_1.end())
	{
		cout << "have this item" << endl;
	}
	else
	{
		cout << "none" << endl;
	}

	iter = data_1.find(4);
	if (iter != data_1.end())
	{
		cout << "have this item" << endl;
	}
	else
	{
		cout << "none" << endl;
	}
/*--------------------------------*/

(2) 关于map输出的容易bug的地方***

直接看码

//上面存储data_1值只存到了data_1[3];
	cout << "map " << data_1[3] << endl;
	cout << "sizeof_map  " << data_1.size() << endl;
	cout << "map " << data_1[4] << endl;
	cout << "sizeof_map  " << data_1.size() << endl;

输出结构为:
在这里插入图片描述
看到没有!!!!,这里map自己给自己加了一个结点,之前data_1.end()为data_1[3],输出data_1[4]的时候因为没有找到,所以它给自己加了一个空节点,此时end()也会改变
我们再测试一下发现:
在这里插入图片描述
所以用map的时候一定要注意这点!!!!!

3,删除

//迭代器刪除
iter = data_1.find(1);
data_1.erase(iter);
 
//用关键字刪除
int n = data_1.erase(1); //如果刪除了會返回1,否則返回0
 
//用迭代器范围刪除 : 把整个map清空
data_1.erase(data_1.begin(), data_1.end());
//等同于data_1.clear()
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值