数据结构与算法C++描述(9)---字典

1.字典的概念

字典是一些节点的集合,每个节点包含数据域和key(键值)域。字典可以通过公式化描述或链表描述的方式创建。本文将通过链表描述的方式创建字典,字典的键值是依次递增的,并对字典进行如下操作:

  1. 字典的删除;
  2. 添加一个字典元素;
  3. 判断字典是否为空;
  4. 搜索键值为k的元素值;
  5. 获取字典中的元素个数;
  6. 在键值为k的节点中插入元素x,允许键值k已存在;
  7. 在键值为k的节点中插入元素x,不允许键值k存在,即字典中的每个键值只对应一个元素;
  8. 输出字典,重载“<<”。

2. 字典节点类的声明与实现

若利用链表来描述字典,必须首先声明链表中的每个节点,即建立链表节点类。在类中,每个节点包含key和data两个域。具体实现可参考注释。

/*------------------------------------字典类(有序链表)-----------------------------------*/
template <class E,class K> class DictionaryChain;
template <class E,class K>
class DictionaryChainNode
{
    //为了让类DictionaryChain访问本类的成员,将其声明为本类的友类
    friend DictionaryChain<E,K>;
public:
    //链表节点默认构造函数,将data设为0,并指向NULL
    DictionaryChainNode() :data(0) { link = NULL; }
    //链表节点类构造函数,建立键值key=k,数据data=e的节点,并指向NULL
    DictionaryChainNode(const K &k,const E &e) :data(e), key(k) { link = NULL; }
    DictionaryChainNode<E, K> *getLink() {  //获取下一个节点
        if (link)
            return link;
        return NULL;
    }
private:  
    E data;                                //数据
    K key;                                 //键值
    DictionaryChainNode<E,K> *link;        //指向下一个节点
};

3. 字典类的声明与实现

3.1 字典类的声明与简单函数的实现

template <class E,class K>
class DictionaryChain
{
public:
    //默认构造函数,头节点first指向NULL
    DictionaryChain() { first = NULL; }                             //建立字典
    //构造初始节点的键值为k,数据data=e的字典对象
    DictionaryChain(const K &k,const E &e)
    {
        first = new DictionaryChainNode<E, K>(k, e);
    }
    ~DictionaryChain();                                             //删除字典
    bool IsEmpty() { return first == NULL; }                        //判断字典是否为空
    int Length()const;                                              //返回字典大小
    bool Search(const K&k, E &e);                                   //寻找键值为k的元素,并赋给e
    DictionaryChain<E, K>& Delete(const K&k, E &e);                 //删除键值为k的元素,并赋值给e,返回操作后的字典
    DictionaryChain<E, K>& Insert(const K&k, const E&e);            //在字典中插入元素e,并返回操作后的字典,允许有相同的关键字
    DictionaryChain<E, K>& DistinctInsert(const K&k,const E &e);    //插入元素操作,不允许有相同的关键字

    void Output(ostream &out)                                       //输出字典
    {
        DictionaryChainNode<E, K> *current = first;
        while (current)
        {
            out <<"("<< current->key << ": " << current->data<<")" << ";  ";
            current = current->getLink();                           //指向下一节点
        }
        cout << endl;
    }

private:
    DictionaryChainNode<E, K> *first;                               //头节点指针
};

3.2 字典的删除—析构函数的实现

通过依次删除字典中的每个节点,实现字典的删除。

//析构函数
template<class E,class K>
DictionaryChain<E, K>::~DictionaryChain()
{
    DictionaryChainNode<E, K> *next;
    while (first)                                  //若first不为0,即链表不为空,则继续删除节点
    {
        next = first->getLink();                   //指向下一个节点
        delete first;                              //删除当前节点
        first = next;                              //循环
    }
}

3.3 获取字典中元素的个数

//获取链表长度
template<class E, class K>
int DictionaryChain<E, K>::Length() const
{
    int len = 0;                            //记录链表长度
    DictionaryChainNode<E,K> *next=first;   //声明中间节点
    while (next)                            //只要未到末节点,则len++
    {
        len++;                              //长度+1
        next = next->getLink();             //指向下一个节点
    }
    return len;                             //返回链表长度
}

3.4 在字典中寻找键值为k的元素,并将其数据赋给e

在此要注意,利用链表描述字典时,字典的键值是依次递增的!!!

//寻找键值为k的元素,并赋给e
template<class E, class K>
bool DictionaryChain<E,K>::Search(const K&k, E &e)
{//搜索与k匹配的元素,结果放入e中。若存在,返回true;否则,返回false。
    DictionaryChainNode<E, K> *next = first;
    while (next && next->key < k)    //移动到key值为k的节点
        next = next->link;
    if (next && next->key == k)      //判断
    {
        e = next->data;              //赋值
        return true;
    }
    return false;                                   
}

3.5 删除键值为k的元素,并赋值给e,返回操作后的字典

//删除键值为k的元素,并赋值给e,返回操作后的字典
template <class E,class K>
DictionaryChain<E, K>& DictionaryChain<E, K>::Delete(const K&k, E &e)
{
    DictionaryChainNode<E, K> *next=first,*t=0;
    while (next && next->key < k)                               //移动到t移动到k-1处,next移动到k处
    {
        t = next;
        next = next->link;
    }
    if (next && next->key == k) {                               //确认是否为k
        e = next->data;                                         //获取第k个节点元素值
        if (t)                                                  //当前节点不是首节点,即链表不为空
            t->link = next->link;                               //将第k-1个节点指向第k+1个节点
        else                                                    //若是首节点,即链表为空
            first = next->link;                                 //指向下一个节点
        delete next;                                            //删除第k个节点
        return *this;
    }
    else                                                        //若不等于k,则抛出输入错误异常
        throw BadInput();
}

3.6 在字典中插入元素e,并返回操作后的字典,允许有相同的键值

//在字典中插入元素e,并返回操作后的字典,允许有相同的键值
template <class E, class K>
DictionaryChain<E, K>& DictionaryChain<E, K>::Insert(const K&k,const E&e)
{
    DictionaryChainNode<E, K> *next=first,*t=0; 
    while (next && next->key < k)                               //移动到t移动到k-1处,next移动到k处
    {
        t = next;  
        next = next->link;                                      //指向元素e的前一个位置
    }
    DictionaryChainNode<E, K> *p = new DictionaryChainNode<E,K>(k,e);   //新建节点   
    //插入节点p     
    p->link = next;
    if (t)                                                      //t不为首节点
        t->link = p;                                            //将p插入next之后
    else                                                        //next为首节点,即链表为空
        first = p;                                              //设置p为首节点
    return *this;
}

3.7 插入元素操作,不允许有相同的键值

//插入元素操作,不允许有相同的关键字
template <class E, class K>
DictionaryChain<E, K>& DictionaryChain<E,K>::DistinctInsert(const K &k,const E &e)
{
    DictionaryChainNode<E, K> *next = first,*t=0;
    while (next && next->key < k)                               //移动到t移动到k-1处,next移动到k处
    {
        t = next;
        next = next->link;
    }
    if (next && next->key == k)                                 //如果已经存在e节点,则抛出异常
        throw BadInput();
    DictionaryChainNode<E, K> *q = new DictionaryChainNode<E, K>(k,e);  //新建节点
    //q->data = e;
    q->link = next;
    if (t)                                                      //链表不为空
        t->link = q;
    else
        first = q;
    return *this;
}

3.8 重载操作符”<<”

//重载操作符“<<”
template <class E, class K>
ostream& operator<<(ostream &out, DictionaryChain<E, K> &S)
{
    S.Output(out);
    return out;
}

4 测试

4.1 测试样例

这里写图片描述

4.2 测试结果

这里写图片描述


参考:
[1] 数据结构算法与应用:C++描述(Data Structures, Algorithms and Applications in C++ 的中文版)
[2] http://www.cnblogs.com/haoliuhust/p/4420618.html

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值