JDK中的Map类型采用键值对的方式保存数据,且键(key)不能重复。在HashMap的实现中实际采用了Hash分类加数组排序的方式。在C++中我没有采用这样的算法。而是通过首先对Key值进行二叉树排序,再查找对应的Value。而对整个树型结构排序则使用最基本的中序遍历。这些都是数据结构的知识,不太了解的可以查看我之前的博客(查找树ADT)。下面言归正传。

假设场景是我需要输入一系列的人名+年龄,然后按照人名字典排序显示所有数据。以下是测试方法:

 int main() {
using namespace std;
Item<string, int>* it1 = new Item<string, int>("Done", );
it1->put("Tom", );
it1->put("Kate", );
it1->put("Lory", );
it1->put("Xiaom", );
it1->put("Kate", ); // 重复记录 cout << it1->size() << endl; // 結果:5 Item<string, int>* it2 = it1; // 调用拷贝构造
Item<string, int>::Entry* ep = it2->sort(); // 获取数组指针 for (int i = ; i < it2->size(); i++) { // 遍历指针
cout << ep[i].str_k << "=" << ep[i].str_v << endl;
}
return ;
}

(1)第8行添加了一条重复数据,应该覆盖第5行的数据。

(2)第12行调用拷贝函数,测试指针赋值是否正确。

(3)第15行遍历数组,查询数据。

下面是模板类的设计:

#ifndef ITEM_H_
#define ITEM_H_
#include <iostream>
template<typename K, typename V>
class Item {
public:
struct Entry { // 构造一个内部结构用来保存排序对象
K str_k;
V str_v;
};
private:
static int len; // 每次新增一个元素+1,作为size()的返回值
static int index; //返回数组的下标
K _key; // 键
V _value; // 值
Item* _left; // 左子树
Item* _right; // 右子树
void _sort(Item& item, Entry entry[]); // 内部排序方法
public:
Item(const K& key, const V& value) :
_key(key), _value(value), _left(), _right() {
len++;
}
virtual ~Item() { // 析构左子树指针和右子树指针
if (_left != )
delete _left;
if (_right != )
delete _right;
}
Item(const Item& o) : // 拷贝构造
_key(o._key), _value(o._value), _left(o._left), _right(o._right) {
}
Item& operator=(const Item& it) { // 默认赋值函数
_key = it._key;
_value = it._value;
if (_left != )
delete _left;
if (_right != )
delete _right;
_left = it._left;
_right = it._right;
return *this;
}
void put(const K& key, const V& value); V get(const K& key) const; int size() const; Entry* sort() { // 采用中序遍历方法排序
Entry* entry = new Entry[len];
_sort(*this, entry);
return entry;
}
}; template<typename K, typename V>
int Item<K, V>::len = ; template<typename K, typename V>
int Item<K, V>::index = ; template<typename K, typename V>
void Item<K, V>::put(const K& key, const V& value) {
if (key == _key) {
_key = key;
_value = value;
} else if (key > _key) {
if (_right == ) {
Item* r = new Item(key, value);
_right = r;
} else {
_right->put(key, value);
}
} else if (key < _key) {
if (_left == ) {
Item* l = new Item(key, value);
_left = l;
} else {
_left->put(key, value);
}
}
} template<typename K, typename V>
V Item<K, V>::get(const K& key) const {
if (key == _key) {
return _value;
} else if (key < _key) {
if (_left == ) {
return ;
} else {
_left->get(key);
}
} else if (key > _key) {
if (_right == ) {
return ;
} else {
_right->get(key);
}
}
}
template<typename K, typename V>
int Item<K, V>::size() const {
return len;
} template<typename K, typename V>
void Item<K, V>::_sort(Item& item, Entry entry[]) {
if (item._left == ) {
entry[index].str_k = item._key;
entry[index].str_v = item._value;
index++;
} else {
_sort(*item._left, entry);
entry[index].str_k = item._key;
entry[index].str_v = item._value;
index++;
}
if (item._right == ) {
return;
} else {
_sort(*item._right, entry);
}
} #endif /* ITEM_H_ */

部分注释我已经下载的代码中,这里做几点说明:

(1)二叉树排序的原则是先形成树根,然后新进入的数据与树根比较。如果小于树根则形成新的二叉树结构并放在左侧形成左子树。反之形成右子树。如果左子树(右子树)已经存在则采取递归的方式插入。

(2)二叉树遍历的原则是先处理左子树,再处理树根,最后处理右子树。同样也需要采用递归查询。

(3)C++不同于Java,最好是自己实现拷贝构造和重载赋值函数。通常情况下,拷贝构造和重载赋值函数效果相同,但在本例中大家可以看到。重载赋值函数需要首先对自己的左右子树的指针析构再赋值。

(4)由于C++编译方式的不同,类中的静态常量是不可以直接赋值的。需要在声明之后再定义数据,并且定义的顺序也很重要。

C++ 模拟Map的更多相关文章

  1. js模拟Map对象,实现key---value

    js模拟Map对象,实现key---value 根据java中map的属性,实现key----value保存 function Map() { var struct = function (key, ...

  2. ES6之前模拟Map数据结构的写法

    在ES6之前JavaScript 里面本身没有map对象,但是用JavaScript的Array.Object来模拟实现Map的数据结构. 现在已经有Map对象了,这里记录一下之前的写法 Array方 ...

  3. POJ 3087 Shuffle'm Up (模拟+map)

    题目链接:http://poj.org/problem?id=3087 题目大意:已知两堆牌s1和s2的初始状态, 其牌数均为c,按给定规则能将他们相互交叉组合成一堆牌s12,再将s12的最底下的c块 ...

  4. POJ 3087 Shuffle'm Up【模拟/map/string】

    Shuffle'm Up Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14471 Accepted: 6633 Descrip ...

  5. [CSP-S模拟测试]:z(模拟+map+小根堆)

    题目背景 $\frac{1}{4}$遇到了一道水题,$eooooo$完全不会做,于是去请教小$D$.结果小$D$已经去了阿塞拜疆,于是,$\frac{1}{4}$只好来问你,这道题是这样的: 题目描述 ...

  6. HDU - 3347 Calculate the expression — 模拟 + map存变量

    传送门 题意:从输入开始,1.输入样例数:2.然后输入一组样例中的行数n:3.前n-1行为定义变量(之间使用空格隔开),只需要map存进去就可以了(这里有覆盖的情况,故使用mp["s&quo ...

  7. js 模拟java 中 的map

    //js模拟map Map = { obj : {}, put : function(key , value){ this.obj[key] = value; }, get : function(ke ...

  8. webservice返回值为Map类型的处理方法

    在写一个webservice的时候,方法的返回值是一个复杂类型,处理方法是写一个结果类(Javabean)作为返回值.想着webservice方法返回值为Map的没写过,然后就试着写了一个简单的Dem ...

  9. ES6中的Set和Map集合

    前面的话 在ES6标准制定以前,由于可选的集合类型有限,数组使用的又是数值型索引,因而经常被用于创建队列和栈.如果需要使用非数值型索引,就会用非数组对象创建所需的数据结构,而这就是Set集合与Map集 ...

随机推荐

  1. MySQL优化性能my.cnf详解

    提供一个MySQL 5.6版本适合在1GB内存VPS上的my.cnf配置文件(点击这里下载文件): [client] port=3306 socket=/tmp/mysql.sock [mysqld] ...

  2. Oracle数据库基础知识2

    字符操作相关_1 1.CONCAT关键字作用:连接字符串语法:CONCAT(字串1, 字串2)例如: CONCAT('hello','world') FROM DUAL; 注意:Oracle的CONC ...

  3. BZOJ 3365 Distance Statistics 点分治

    这道题是一道点分治的题目,难度不大,可以拿来练手. 关键是对于找出来的重心的删除操作需要删掉这条边,这很重要. 还有每次找重心的时候,不但要考虑他的子节点的siz,还要考虑父节点的siz. 然后就A了 ...

  4. SQL常用代码段

    --STUFF 函数将字符串插入另一字符串.它在第一个字符串中从开始位置删除指定长度的字符:然后将第二个字符串插入第一个字符串的开始位置. STUFF ( character_expression , ...

  5. KITTI数据集格式说明

    由于上一篇博客所提到的论文中的训练数据是KITTI的数据集,因此如果我想要用自己的数据集进行训练的话,就需要先弄清楚KITTI数据集的格式,在以下的网址找到了说明: 首先,数据描述中是这样的: 在以下 ...

  6. 接口测试之基于LoadRunner的一个简单示例

    这几天一直在捣鼓接口测试,以下总结一下: 1.什么是接口测试:接口是指系统模块与模块之间或者系统与系统之间进行交互,一般我们用的多的是HTTP协议的接口.WebService协议的接口.还有RPC(R ...

  7. Net中httpResponse和httpRequest的简单实用;

    这对象很简单,封装很多常用的方法和属性:使用起来也很方便: 这个关键是要对我们的 http中的各种协议要很了解滴呀: 模拟一个简单的暴力破解: public static class HttpInfo ...

  8. 学霸数据处理项目之数据处理网页以及后台以及C#代码部分开发者手册

    写在前面,本文将详细介绍学霸数据处理项目中的数据处理网页与后台函数,以及c#代码中每一个方法的意义及其一些在运行方面需要注意的细节,供开发人员使用,开发人员在阅读相关方法说明时请参照相关代码,对于本文 ...

  9. ASP.NET MVC 4 视图页去哪里儿

    这里特别感谢 swagon 提到了Displaymodeprovider,所以才有了本篇博客,也使我对[View的呈现]中寻找视图页的过程有了清晰的认识! 前戏 在MVC中,执行完Action之后,会 ...

  10. varsh4.1 安装清除cache

    yum install automake autoconf ncurses-devel libxslt groff pkgconfig python-docutils readline-devel - ...