zoukankan      html  css  js  c++  java
  • C++ 模拟Map

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

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

     1 int main() {
     2     using namespace std;
     3     Item<string, int>* it1 = new Item<string, int>("Done", 18);
     4     it1->put("Tom", 17);
     5     it1->put("Kate", 15);
     6     it1->put("Lory", 22);
     7     it1->put("Xiaom", 14);
     8     it1->put("Kate", 23); // 重复记录
     9 
    10     cout << it1->size() << endl; // 結果:5
    11 
    12     Item<string, int>* it2 = it1; // 调用拷贝构造
    13     Item<string, int>::Entry* ep = it2->sort(); // 获取数组指针
    14 
    15     for (int i = 0; i < it2->size(); i++) { // 遍历指针
    16         cout << ep[i].str_k << "=" << ep[i].str_v << endl;
    17     }
    18     return 0;
    19 }

    (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(0), _right(0) {
            len++;
        }
        virtual ~Item() { // 析构左子树指针和右子树指针
            if (_left != 0)
                delete _left;
            if (_right != 0)
                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 != 0)
                delete _left;
            if (_right != 0)
                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 = 0;
    
    template<typename K, typename V>
    int Item<K, V>::index = 0;
    
    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 == 0) {
                Item* r = new Item(key, value);
                _right = r;
            } else {
                _right->put(key, value);
            }
        } else if (key < _key) {
            if (_left == 0) {
                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 == 0) {
                return 0;
            } else {
                _left->get(key);
            }
        } else if (key > _key) {
            if (_right == 0) {
                return 0;
            } 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 == 0) {
            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 == 0) {
            return;
        } else {
            _sort(*item._right, entry);
        }
    }
    
    #endif /* ITEM_H_ */

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

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

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

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

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

  • 相关阅读:
    SignalR2结合ujtopo实现拓扑图动态变化
    SignalR2简易数据看板演示
    使用SignalR 2进行服务器广播
    使用SignalR实时Web应用程序
    ZooKeeper安装
    MongoDB安装
    线程安全与非线程安全
    监听器,事件对象,事件源
    Graphics与Canvas
    JDialog
  • 原文地址:https://www.cnblogs.com/learnhow/p/6137913.html
Copyright © 2011-2022 走看看