1.字典的概念
字典是一些节点的集合,每个节点包含数据域和key(键值)域。字典可以通过公式化描述或链表描述的方式创建。本文将通过链表描述的方式创建字典,字典的键值是依次递增的,并对字典进行如下操作:
- 字典的删除;
- 添加一个字典元素;
- 判断字典是否为空;
- 搜索键值为k的元素值;
- 获取字典中的元素个数;
- 在键值为k的节点中插入元素x,允许键值k已存在;
- 在键值为k的节点中插入元素x,不允许键值k存在,即字典中的每个键值只对应一个元素;
- 输出字典,重载“<<”。
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