Chain中,数据对象实例的每个元素都放在节点中描述。节点不能被公式进行定位,所以,每个节点中都有与其他节点相关的位置信息。
(盗图了。。。)
可以分别定义Chain和ChainNode类,并将Chain设为ChainNode的友类,使其能够访问ChainNode的所有成员。
单链表类定义
template
class ChainNode {
friend Chain
; //允许Chain访问私有成员
private:
T data;
ChainNode
*link;
};
template
class Chain {
public:
Chain() {first = 0;}
~Chain();
bool IsEmpty() const {return first == 0;}
int Length() const;
bool Find(int k, T& x) const; //不修改数据成员 常成员函数
int Search(const T& x) const;
Chain
& Delete(int k, T& x); Chain
& Insert(int k, const T& x); void Output(ostream& out) const; //将链表元素送至输出流 private: ChainNode
*first; //指向第一个节点的指针 }; class OutOfBounds { //定义异常类 public: OutOfBounds() {cout<<"Out of Range!\n";} };
这样就可以用
Chain<int> Human;
创建一个空的整形单链表。同时,这样不需要指定表的最大长度。
然后,几个函数的实现
普通函数实现
template
Chain
::~Chain() {
//链表的析构函数,用于删除表中的所有节点
ChainNode
*next;
while(first) {
next = first->link;
delete first;
first = next;
}
}
template
int Chain
::Length() const { //返回链表的长度 ChainNode
*current = first; int len = 0; while(current) { len++; current = current->link; } return len; } template
bool Chain
::Find(int k, T& x) const { //查找链表中第k个元素,并将其提取到x //查询成功返回true,否则false if(k < 1) return false; //防止错误输入 ChainNode
*current = first; int index = 1; while(index < k && current) { //防止链表长度不足k current = current->link; index++; } if(current) { x = current->data; return true; } return false; //不存在第k个元素 } template
int Chain
::Search(const T& x) const { //寻找x,如果找到返回x的索引 //查询失败返回0 ChainNode
*current = first; int index = 1; //current的索引 while(current && current-> != x) { current = current->link; index++; } if(current) return index; return 0; } template
void Chain
::Output(ostream& out) const { //将链表元素送至输出流 ChainNode
*current; for(current = first; current; current = current->link ) { out<
data<<" "; } } //重载<< template
ostream& operator<<(ostream& out, const Chain
& x) { x.Output(out); return out; }
后面就是删除和插入的函数功能实现
删除插入实现
template
Chain
& Chain
::Delete(int k, T& x) {
//将第k个元素提取到x,然后删除第k个元素
//如果不存在,则引发OutOfBounds异常
if(k < 1 || !first ) throw OutOfBounds(); //不存在第k个元素
ChainNode
*p = first; //p最终将指向第k个元素
if(k == 1) first = first->link; //p已经指向第k个元素,将其删除
else {
ChainNode
*q = first; //q最终指向第k-1个元素 for(int index = 1; index < k-1; index++) { q = q->link; if(!q || !q->link) throw OutOfBounds(); //不存在第k个元素 } p = q->link; //存在第k个元素 q->link = p->link; //从链表中删除第k个元素 } //保存第k个元素并释放节点p x = p->data; delete p; return *this; } template
Chain
& Chain
::Insert(int k, const T& x) { //在第k个元素后插入x //如果不存在第k个元素,则引发异常OutOfBounds if(k<0) throw OutOfBounds(); ChainNode *p = first; //p将指向第k个元素 for(int index = 1; index < k; index++) { p = p->link; if(!p) throw OutOfBounds(); //如果不存在第k个元素,则抛出异常 } ChainNode
*q = new ChainNode
; y->data = x; if(k) { //在p后插入 q->link = p->link; p->link = y; } else { //作为第一个元素插入 q->link = first; first = q; } return *this; }
扩展单链表功能
添加清空、归零、尾部添加的功能
首先,清空...易知,析构函数其实可以简单的定义为对clear的调用
Zero实现很简单,建议还是定义为内联函数
push_back的实现,为了达到效率最高,需要借助一个新的成员
ChainNode<T> *last;
同时,需要修改Delete和Insert中分别加入
if(p == last) last = q;
if(!q->link) last = q;
随后便可以正常运行了
template
void Chain
::Clear() {
ChainNode
*next;
while(first) {
next = first->link;
delete first;
first = next;
}
}
template
void Chain
::Zero() {first = 0;} template
Chain
& Chain
::push_back(const T& x) { ChainNode
*p; p = new ChainNode
; p->data = x; y->link = 0; if(first) { last->link = p; last = p; } else { first = last = y; } return *this; }